diff --git a/Makefile.am b/Makefile.am index 1b33ee233..c869a6f3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,15 +1,9 @@ ## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign ACLOCAL_AMFLAGS = -I m4 -SUBDIRS=desktop pkg-config include @top_dirs@ -DIST_SUBDIRS=desktop pkg-config include \ - libs hw nq qtv qw tools ruamoko\ - RPM debian doc vc2005 vc2008 - -## configure.ac needs to be listed here for older autoconfs -EXTRA_DIST= ChangeLog configure.ac bootstrap \ +EXTRA_DIST = \ + ChangeLog configure.ac bootstrap \ $(top_srcdir)/.version \ config.d/git-version-gen \ tools/cross/droid/cross-configure.sh \ @@ -26,9 +20,142 @@ EXTRA_DIST= ChangeLog configure.ac bootstrap \ tools/gas2masm/gas2masm.dsp tools/gas2masm/gas2masm.dsw \ tools/gas2masm/gas2masm.mak tools/gas2masm/gas2masm.mdp -NOCONV_DIST= $(distdir)/include/win32/resources/icon1Vista.ico \ +NOCONV_DIST= \ + $(distdir)/include/win32/resources/icon1Vista.ico \ $(distdir)/include/win32/resources/icon1XP.ico +BUILT_SOURCES = $(top_srcdir)/.version +#AM_CFLAGS= @PREFER_NON_PIC@ +AM_CPPFLAGS= -I$(top_srcdir)/include $(PTHREAD_CFLAGS) + +common_ldflags= -export-dynamic @PTHREAD_LDFLAGS@ + +TESTS = +XFAIL_TESTS = +bin_PROGRAMS = +bin_SCRIPTS = +check_PROGRAMS = +lib_LTLIBRARIES = +man_MANS = +noinst_LTLIBRARIES = +noinst_LIBRARIES = +noinst_PROGRAMS = +noinst_HEADERS = +plugin_LTLIBRARIES = + +RANLIB=touch +ARFLAGS=cr + +EXTRA_HEADERS = +EXTRA_LTLIBRARIES = +EXTRA_PROGRAMS = +EXTRA_LIBRARIES = + +CLEANFILES = +DISTCLEANFILES = + +YFLAGS = -v -d -Wno-yacc -Werror +PTHREAD_LDFLAGS=@PTHREAD_LDFLAGS@ +PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ + +lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ + -rpath $(libdir) -no-undefined +plugin_ldflags= @plugin_ldflags@ -avoid-version -module -rpath $(plugindir) +plugin_libadd= @plugin_libadd@ + +SDL_LIBS= @SDL_LIBS@ +XMMS_LIBS= @XMMS_LIBS@ + +PAK=$(top_builddir)/pak$(EXEEXT) +QFCC_DEP=qfcc$(EXEEXT) +QFCC=$(top_builddir)/$(QFCC_DEP) +GZ=@progs_gz@ + +V_QFCC = $(V_QFCC_@AM_V@) +V_QFCC_ = $(V_QFCC_@AM_DEFAULT_V@) +V_QFCC_0 = @echo " QFCC " $@; +V_QFCC_1 = + +V_QFCCLD = $(V_QFCCLD_@AM_V@) +V_QFCCLD_ = $(V_QFCCLD_@AM_DEFAULT_V@) +V_QFCCLD_0 = @echo " QFCCLD " $@; +V_QFCCLD_1 = + +QCSYSTEM=--no-default-paths -I$(top_srcdir) -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide +QCPPFLAGS=$(QCSYSTEM) +QCLINKFLAGS=--no-default-paths -Lruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) +MKDIR_P = @MKDIR_P@ + +am__mv = mv -f + +SUFFIXES=.o .r .pas +.r.o: + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(QCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ + sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ + $(am__mv) $$depbase.Tqo $$depbase.Qo +.pas.o: + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(QCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ + sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ + $(am__mv) $$depbase.Tqo $$depbase.Qo + +qcautodep = $(join $(addsuffix $(DEPDIR)/,$(dir $(basename $(1)))),$(addsuffix .Qo,$(notdir $(basename $(basename $(1)))))) +r_depfiles_remade= +pas_depfiles_remade= + +V_GLSLANG = $(V_GLSLANG_@AM_V@) +V_GLSLANG_ = $(V_GLSLANG_@AM_DEFAULT_V@) +V_GLSLANG_0 = @echo " GLSLANG " $@; +V_GLSLANG_1 = + +V_XXD = $(V_XXD_@AM_V@) +V_XXD_ = $(V_XXD_@AM_DEFAULT_V@) +V_XXD_0 = @echo " XXD " $@; +V_XXD_1 = + +%.spv: % + @$(mkdir_p) $(builddir)/`dirname $@` + $(V_GLSLANG)(((($(GLSLANGVALIDATOR) -V $< -o $@; echo $$? >&3) | sed -e '1d' 1>&2) 3>&1) | (read xs; exit $$xs)) + +%.spvc: % + @$(mkdir_p) $(builddir)/`dirname $@` + $(V_GLSLANG)(((($(GLSLANGVALIDATOR) --vn `basename $< | tr . _` -V $< -o $@; echo $$? >&3) | sed -e '1d' 1>&2) 3>&1) | (read xs; exit $$xs)) + +shaderdir = @shaderdir@ +shader_DATA = + +include doc/Makemodule.am +include RPM/Makemodule.am +include debian/Makemodule.am +include desktop/Makemodule.am +include pkg-config/Makemodule.am +include include/Makemodule.am +include libs/Makemodule.am +include hw/Makemodule.am +include nq/Makemodule.am +include qtv/Makemodule.am +include qw/Makemodule.am +include tools/Makemodule.am +include ruamoko/Makemodule.am + +DISTCLEANFILES += $(r_depfiles_remade) $(pas_depfiles_remade) +CLEANFILES += $(shader_DATA) + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '$@' | sed -e 's@\$(DEPDIR)/@@' -e 's@\(.*\)\.Qo$$@\1.o: $(top_srcdir)/\1.r qfcc@' >$@-t && $(am__mv) $@-t $@ + +$(pas_depfiles_remade): + $(MKDIR_P) $(@D) + echo '$@' | sed -e 's@\$(DEPDIR)/@@' -e 's@\(.*\)\.Qo$$@\1.o: $(top_srcdir)/\1.pas qfcc@' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) $(pas_depfiles_remade) + echo findme $(ruamoko_gui_libgui_a_dep) + changelog: ChangeLog ChangeLog: FORCE @if test -d "$(top_srcdir)/.git"; then \ @@ -63,7 +190,6 @@ dist-all-local: distdir ZIP="-r9ql" zip $(distdir).zip $(distdir) -rm -rf $(distdir) -BUILT_SOURCES = $(top_srcdir)/.version $(top_srcdir)/.version: echo $(VERSION) > $@-t && mv $@-t $@ dist-hook: diff --git a/RPM/Makefile.am b/RPM/Makefile.am deleted file mode 100644 index 13616e183..000000000 --- a/RPM/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST= build_rpm.in quakeforge.conf.in quakeforge.spec.in - -rpm: build_rpm quakeforge.conf quakeforge.spec - ./build_rpm - -CLEANFILES = *.rpm diff --git a/RPM/Makemodule.am b/RPM/Makemodule.am new file mode 100644 index 000000000..583cc8506 --- /dev/null +++ b/RPM/Makemodule.am @@ -0,0 +1,6 @@ +EXTRA_DIST += RPM/build_rpm.in RPM/quakeforge.conf.in RPM/quakeforge.spec.in + +rpm: RPM/build_rpm RPM/quakeforge.conf RPM/quakeforge.spec + cd RPM && ./build_rpm + +CLEANFILES += rpm/*.rpm diff --git a/bootstrap b/bootstrap index 4986a6ca4..abd34252f 100755 --- a/bootstrap +++ b/bootstrap @@ -18,7 +18,7 @@ if test "$1" = "clean"; then find . -name '*.orig' -type f -print0 | xargs $ARGS rm -f rm -f aclocal.m4 build-stamp changelog-stamp config.cache config.log \ config.status configure configure-stamp install-sh libtool missing \ - mkinstalldirs quakeforge-config quakeforge.lsm + mkinstalldirs quakeforge-config quakeforge.lsm test-driver rm -f compile config.guess config.sub depcomp ltmain.sh ylwrap rm -rf autom4te.cache rm -f m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \ diff --git a/config.d/ac_config_files.m4 b/config.d/ac_config_files.m4 index 587a515d9..d84505483 100644 --- a/config.d/ac_config_files.m4 +++ b/config.d/ac_config_files.m4 @@ -1,103 +1,4 @@ Makefile - - include/Makefile - include/QF/Makefile - - libs/Makefile - libs/audio/Makefile - libs/audio/targets/Makefile - libs/audio/renderer/Makefile - libs/audio/test/Makefile - libs/console/Makefile - libs/client/Makefile - libs/gamecode/Makefile - libs/gib/Makefile - libs/image/Makefile - libs/models/Makefile - libs/models/alias/Makefile - libs/models/brush/Makefile - libs/models/iqm/Makefile - libs/models/sprite/Makefile - libs/models/test/Makefile - libs/net/Makefile - libs/net/nc/Makefile - libs/net/nm/Makefile - libs/qw/Makefile - libs/ruamoko/Makefile - libs/util/Makefile - libs/util/test/Makefile - libs/video/Makefile - libs/video/renderer/Makefile - libs/video/renderer/gl/Makefile - libs/video/renderer/glsl/Makefile - libs/video/renderer/sw/Makefile - libs/video/renderer/sw32/Makefile - libs/video/targets/Makefile - - hw/Makefile - hw/include/Makefile - hw/source/Makefile - - nq/Makefile - nq/include/Makefile - nq/source/Makefile - - qtv/Makefile - qtv/include/Makefile - qtv/source/Makefile - - qw/Makefile - qw/include/Makefile - qw/source/Makefile - - tools/Makefile - tools/bsp2img/Makefile - tools/carne/Makefile - tools/pak/Makefile - tools/qfbsp/Makefile - tools/qfbsp/include/Makefile - tools/qfbsp/source/Makefile - tools/qfcc/Makefile - tools/qfcc/doc/Makefile - tools/qfcc/doc/man/Makefile - tools/qfcc/include/Makefile - tools/qfcc/source/Makefile - tools/qfcc/test/Makefile - tools/qflight/Makefile - tools/qflight/include/Makefile - tools/qflight/source/Makefile - tools/qflmp/Makefile - tools/qfmodelgen/Makefile - tools/qfmodelgen/include/Makefile - tools/qfmodelgen/source/Makefile - tools/qfspritegen/Makefile - tools/qfvis/Makefile - tools/qfvis/include/Makefile - tools/qfvis/source/Makefile - tools/qwaq/Makefile - tools/qwaq/progs.src - tools/wad/Makefile - tools/wav/Makefile - - ruamoko/Makefile - ruamoko/Doxyfile - ruamoko/include/Makefile - ruamoko/lib/Makefile - ruamoko/game/Makefile - ruamoko/gui/Makefile - ruamoko/cl_menu/Makefile - ruamoko/scheme/Makefile - - pkg-config/Makefile pkg-config/qfcc.pc pkg-config/quakeforge.pc - - doc/Makefile doc/quakeforge.dox.conf - doc/man/Makefile - - debian/Makefile - desktop/Makefile - - vc2005/Makefile - vc2008/Makefile diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index a236a09dc..3094a69a6 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -39,8 +39,9 @@ if test "x$HAVE_FBDEV" = xyes; then QW_TARGETS="$QW_TARGETS qw-client-fbdev\$(EXEEXT)" NQ_TARGETS="$NQ_TARGETS nq-fbdev\$(EXEEXT)" CL_TARGETS="$CL_TARGETS FBDEV" - VID_TARGETS="$VID_TARGETS libQFfbdev.la" + VID_TARGETS="$VID_TARGETS libs/video/targets/libQFfbdev.la" QF_NEED(vid_render, [sw]) + QF_NEED(render, [sw]) QF_NEED(models, [sw]) QF_NEED(alias, [sw]) QF_NEED(brush, [sw]) @@ -66,12 +67,22 @@ if test "x$HAVE_X" = xyes; then if test "x$ENABLE_clients_x11" = xyes; then QW_TARGETS="$QW_TARGETS qw-client-x11\$(EXEEXT)" NQ_TARGETS="$NQ_TARGETS nq-x11\$(EXEEXT)" - QWAQ_TARGETS="$QWAQ_TARGETS qwaq-x11\$(EXEEXT)" - QW_DESKTOP_DATA="$QW_DESKTOP_DATA quakeforge-qw-x11.desktop" - NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA quakeforge-nq-x11.desktop" + QWAQ_TARGETS="$QWAQ_TARGETS ruamoko/qwaq/qwaq-x11\$(EXEEXT)" + QW_DESKTOP_DATA="$QW_DESKTOP_DATA desktop/quakeforge-qw-x11.desktop" + NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA desktop/quakeforge-nq-x11.desktop" CL_TARGETS="$CL_TARGETS X11" - VID_TARGETS="$VID_TARGETS libQFx11.la" + VID_TARGETS="$VID_TARGETS libs/video/targets/libQFx11.la" + if test "$HAVE_VULKAN" = "yes"; then + QF_NEED(vid_render, [vulkan]) + QF_NEED(render, [vulkan]) + QF_NEED(models, [vulkan]) + QF_NEED(alias, [vulkan]) + QF_NEED(brush, [vulkan]) + QF_NEED(iqm, [vulkan]) + QF_NEED(sprite, [vulkan]) + fi QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(render, [sw sw32 gl glsl]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -91,11 +102,20 @@ if test "x$HAVE_SDL" = xyes; then if test "x$ENABLE_clients_sdl" = xyes; then QW_TARGETS="$QW_TARGETS qw-client-sdl\$(EXEEXT)" NQ_TARGETS="$NQ_TARGETS nq-sdl\$(EXEEXT)" - QW_DESKTOP_DATA="$QW_DESKTOP_DATA quakeforge-qw-sdl.desktop" - NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA quakeforge-nq-sdl.desktop" + QW_DESKTOP_DATA="$QW_DESKTOP_DATA desktop/quakeforge-qw-sdl.desktop" + NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA desktop/quakeforge-nq-sdl.desktop" CL_TARGETS="$CL_TARGETS SDL" - VID_TARGETS="$VID_TARGETS libQFsdl.la" + VID_TARGETS="$VID_TARGETS libs/video/targets/libQFsdl.la" + if test "$HAVE_VULKAN" = "yes"; then + QF_NEED(vid_render, [vulkan]) + QF_NEED(render, [vulkan]) + QF_NEED(alias, [vulkan]) + QF_NEED(brush, [vulkan]) + QF_NEED(iqm, [vulkan]) + QF_NEED(sprite, [vulkan]) + fi QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(render, [sw sw32 gl glsl]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -116,8 +136,9 @@ if test "x$HAVE_SVGA" = xyes; then QW_TARGETS="$QW_TARGETS qw-client-svga\$(EXEEXT)" NQ_TARGETS="$NQ_TARGETS nq-svga\$(EXEEXT)" CL_TARGETS="$CL_TARGETS SVGAlib" - VID_TARGETS="$VID_TARGETS libQFsvga.la" + VID_TARGETS="$VID_TARGETS libs/video/targets/libQFsvga.la" QF_NEED(vid_render, [sw]) + QF_NEED(render, [sw]) QF_NEED(models, [sw]) QF_NEED(alias, [sw]) QF_NEED(brush, [sw]) @@ -138,7 +159,7 @@ if test "x$mingw" = xyes; then QW_TARGETS="$QW_TARGETS qw-client-win\$(EXEEXT)" NQ_TARGETS="$NQ_TARGETS nq-win\$(EXEEXT)" CL_TARGETS="$CL_TARGETS WIN" - VID_TARGETS="$VID_TARGETS libQFwin.la" + VID_TARGETS="$VID_TARGETS libs/video/targets/libQFwin.la" QF_NEED(vid_render, [sw sw32 gl glsl]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) @@ -166,8 +187,8 @@ if test "x$ENABLE_servers_nq" = xyes; then QF_NEED(libs,[util gamecode ruamoko gib image models console net]) fi if test "x$ENABLE_servers_qtv" = xyes; then - QTV_TARGETS="qtv\$(EXEEXT) $QTV_TARGETS" - SV_TARGETS="$SV_TARGETS qtv" + QTV_TARGETS="qtv-server\$(EXEEXT) $QTV_TARGETS" + SV_TARGETS="$SV_TARGETS qtv-server" # QF_NEED(qtv, [common server]) QF_NEED(console, [server]) QF_NEED(top, [qtv]) @@ -230,7 +251,11 @@ if test "x$ENABLE_tools_qfvis" = xyes; then QF_NEED(libs,[util]) fi if test "x$ENABLE_tools_qwaq" = xyes; then - QF_NEED(tools,[qwaq]) + if test "x$HAVE_PANEL" = xyes -a "x$HAVE_PTHREAD" = xyes; then + QWAQ_TARGETS="$QWAQ_TARGETS ruamoko/qwaq/qwaq-curses\$(EXEEXT)" + fi + QF_NEED(tools,[qfcc]) + QF_NEED(ruamoko,[qwaq]) QF_NEED(libs,[ruamoko gamecode util]) fi if test "x$ENABLE_tools_wad" = xyes; then @@ -244,39 +269,52 @@ fi QF_NEED(top, [libs hw nq qtv qw]) -QF_PROCESS_NEED_DIRS(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav]) -QF_PROCESS_NEED_FUNC(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav], QF_NEED(top,tools)) - -QF_PROCESS_NEED_DIRS(libs,[util gamecode ruamoko gib audio image models video console net qw client]) +QF_PROCESS_NEED_FUNC(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav], QF_NEED(top,tools)) if test "$ENABLE_tools_qfcc" = "yes" -a "$ENABLE_tools_pak" = "yes"; then QF_NEED(top, [ruamoko]) + qfac_qfcc_include_qf="\$(qfcc_include_qf)" fi +QF_SUBST(qfac_qfcc_include_qf) + +if test x"${top_need_libs}" = xyes; then + qfac_include_qf="\$(include_qf)" + qfac_include_qf_gl="\$(include_qf_gl)" + qfac_include_qf_glsl="\$(include_qf_glsl)" + qfac_include_qf_math="\$(include_qf_math)" + qfac_include_qf_plugin="\$(include_qf_plugin)" + qfac_include_qf_vulkan="\$(include_qf_vulkan)" +fi +QF_SUBST(qfac_include_qf) +QF_SUBST(qfac_include_qf_gl) +QF_SUBST(qfac_include_qf_glsl) +QF_SUBST(qfac_include_qf_math) +QF_SUBST(qfac_include_qf_plugin) +QF_SUBST(qfac_include_qf_vulkan) + progs_gz= if test "$HAVE_ZLIB" = "yes"; then progs_gz=".gz" fi QF_SUBST(progs_gz) -QF_PROCESS_NEED_DIRS(top, [libs hw nq qtv qw tools ruamoko]) - QF_PROCESS_NEED_LIBS(swrend, [asm]) -QF_PROCESS_NEED_DIRS(vid_render, [gl glsl sw sw32]) -QF_PROCESS_NEED_LIBS(models, [gl glsl sw]) -QF_PROCESS_NEED_LIBS(alias, [gl glsl sw]) -QF_PROCESS_NEED_LIBS(brush, [gl glsl sw]) -QF_PROCESS_NEED_LIBS(iqm, [gl glsl sw]) -QF_PROCESS_NEED_LIBS(sprite, [gl glsl sw]) +QF_PROCESS_NEED_LIBS(render, [gl glsl sw sw32 vulkan], [libs/video/renderer]) +QF_PROCESS_NEED_LIBS(models, [gl glsl sw vulkan], [libs/models]) +QF_PROCESS_NEED_LIBS(alias, [gl glsl sw vulkan], [libs/models/alias]) +QF_PROCESS_NEED_LIBS(brush, [gl glsl sw vulkan], [libs/models/brush]) +QF_PROCESS_NEED_LIBS(iqm, [gl glsl sw vulkan], [libs/models/iqm]) +QF_PROCESS_NEED_LIBS(sprite, [gl glsl sw vulkan], [libs/models/sprite]) -QF_PROCESS_NEED_LIBS(vid, [common sdl svga win x11]) -QF_PROCESS_NEED_LIBS(qw, [client common sdl win server], a) -QF_PROCESS_NEED_LIBS(nq, [client common sdl win server], a) +QF_PROCESS_NEED_LIBS(vid, [common sdl svga win x11], [libs/video/targets]) +QF_PROCESS_NEED_LIBS(qw, [client common sdl win server], [qw/source], a) +QF_PROCESS_NEED_LIBS(nq, [client common sdl win server], [nq/source], a) if test -n "$CL_TARGETS"; then - CD_TARGETS="libQFcd.la" - SND_TARGETS="libQFsound.la" + CD_TARGETS="libs/audio/libQFcd.la" + SND_TARGETS="libs/audio/libQFsound.la" AUDIO_TARGETS="testsound\$(EXEEXT)" - JOY_TARGETS="libQFjs.la" + JOY_TARGETS="libs/video/targets/libQFjs.la" else unset CDTYPE unset SOUND_TYPES @@ -311,13 +349,13 @@ if test "x$static_plugins" = xauto; then fi fi if test "x$static_plugins" = xyes; then - QF_PROCESS_NEED_STATIC_PLUGINS(vid_render, [sw sw32 glsl gl]) - QF_PROCESS_NEED_STATIC_PLUGINS(console, [server], [\$(top_builddir)/libs/console], [server]) - QF_PROCESS_NEED_STATIC_PLUGINS(console, [client], [\$(top_builddir)/libs/console], [client]) + QF_PROCESS_NEED_STATIC_PLUGINS(vid_render, [sw sw32 glsl gl vulkan], [libs/video/renderer]) + QF_PROCESS_NEED_STATIC_PLUGINS(console, [server], [libs/console], [server]) + QF_PROCESS_NEED_STATIC_PLUGINS(console, [client], [libs/console], [client]) - QF_PROCESS_NEED_STATIC_PLUGINS(snd_output, [sdl mme sgi sun win dx oss alsa], [targets]) - QF_PROCESS_NEED_STATIC_PLUGINS(snd_render, [jack default], [renderer]) - QF_PROCESS_NEED_STATIC_PLUGINS(cd, [xmms sdl sgi win linux file]) + QF_PROCESS_NEED_STATIC_PLUGINS(snd_output, [sdl mme sgi sun win dx oss alsa], [libs/audio/targets]) + QF_PROCESS_NEED_STATIC_PLUGINS(snd_render, [jack default], [libs/audio/renderer]) + QF_PROCESS_NEED_STATIC_PLUGINS(cd, [xmms sdl sgi win linux file], [libs/audio]) AC_DEFINE(STATIC_PLUGINS, 1, [Define this if you are building static plugins]) if test -n "$SOUND_TYPES"; then SOUND_TYPES="$SOUND_TYPES (static)" @@ -326,12 +364,12 @@ if test "x$static_plugins" = xyes; then CDTYPE="$CDTYPE (static)" fi else - QF_PROCESS_NEED_PLUGINS(vid_render, [sw sw32 glsl gl]) - QF_PROCESS_NEED_PLUGINS(console, [server], [server]) - QF_PROCESS_NEED_PLUGINS(console, [client], [client]) - QF_PROCESS_NEED_PLUGINS(snd_output, [sdl mme sgi sun win dx oss alsa]) - QF_PROCESS_NEED_PLUGINS(snd_render, [jack default]) - QF_PROCESS_NEED_PLUGINS(cd, [xmms sdl sgi win linux file]) + QF_PROCESS_NEED_PLUGINS(vid_render, [sw sw32 glsl gl vulkan], [libs/video/renderer]) + QF_PROCESS_NEED_PLUGINS(console, [server], [libs/console], [server]) + QF_PROCESS_NEED_PLUGINS(console, [client], [libs/console], [client]) + QF_PROCESS_NEED_PLUGINS(snd_output, [sdl mme sgi sun win dx oss alsa], [libs/audio/targets]) + QF_PROCESS_NEED_PLUGINS(snd_render, [jack default], [libs/audio/renderer]) + QF_PROCESS_NEED_PLUGINS(cd, [xmms sdl sgi win linux file], [libs/audio]) fi dnl Do not use -module here, it belongs in makefile.am due to automake @@ -375,6 +413,7 @@ QF_DEPS(QFCC, QF_DEPS(QFCC_TEST, [], [$(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) @@ -407,8 +446,9 @@ QF_DEPS(QFVIS, [$(WIN32_LIBS)], ) QF_DEPS(QWAQ, - [], + [-I$(top_srcdir)/ruamoko/qwaq], [$(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) @@ -416,6 +456,7 @@ QF_DEPS(CARNE, [], [$(top_builddir)/libs/gib/libQFgib.la $(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) diff --git a/config.d/compiling.m4 b/config.d/compiling.m4 index 457882d09..7a4908efa 100644 --- a/config.d/compiling.m4 +++ b/config.d/compiling.m4 @@ -82,6 +82,11 @@ AC_ARG_ENABLE(optimize, optimize=yes ) +QF_CC_OPTION(-mavx2) +dnl fma is not used as it is the equivalent of turning on +dnl -funsafe-math-optimizations +dnl QF_CC_OPTION(-mfma) + AC_MSG_CHECKING(for optimization) if test "x$optimize" = xyes -a "x$leave_cflags_alone" != "xyes"; then AC_MSG_RESULT(yes) @@ -213,6 +218,16 @@ if test $CC_MAJ -gt 4 -o $CC_MAJ -eq 4 -a $CC_MIN -ge 5; then fi QF_CC_OPTION(-Wtype-limits) QF_CC_OPTION_TEST([-fvisibility=hidden], [VISIBILITY=-fvisibility=hidden]) +QF_CC_OPTION(-Wsuggest-attribute=pure) +QF_CC_OPTION(-Wsuggest-attribute=const) +QF_CC_OPTION(-Wsuggest-attribute=noreturn) +QF_CC_OPTION(-Wsuggest-attribute=format) + +AC_ARG_ENABLE(coverage, +[ --enable-coverage Enable generation of data for gcov]) +if test "x$enable_coverage" = xyes; then + QF_CC_OPTION(-fprofile-arcs -ftest-coverage) +fi dnl QuakeForge uses lots of BCPL-style (//) comments, which can cause problems dnl with many compilers that do not support the latest ISO standards. Well, @@ -241,8 +256,7 @@ if test "x$GCC" != xyes; then fi AC_ARG_ENABLE(Werror, -[ --disable-Werror Do not treat warnings as errors] -) +[ --disable-Werror Do not treat warnings as errors]) dnl We want warnings, lots of warnings... dnl The help text should be INVERTED before release! dnl when in git, this test defaults to ENABLED. diff --git a/config.d/curses.m4 b/config.d/curses.m4 index 80a2b0415..02d9ce7f4 100644 --- a/config.d/curses.m4 +++ b/config.d/curses.m4 @@ -2,7 +2,9 @@ AC_ARG_ENABLE(curses, [ --disable-curses disable curses support] ) if test "x$enable_curses" != "xno"; then - AC_CHECK_HEADERS(curses.h) + AC_CHECK_HEADER([curses.h], + [AC_DEFINE([HAVE_CURSES_H], [1], + [Define to 1 if you have .])]) AC_CHECK_LIB(ncurses, initscr, CURSES_LIBS=-lncurses, AC_CHECK_LIB(pdcurses, initscr, @@ -13,7 +15,32 @@ if test "x$enable_curses" != "xno"; then ) ) ) + if test "x$CURSES_LIBS" != "x"; then + AC_DEFINE(HAVE_CURSES, 1, [Define if you have the ncurses library]) + HAVE_CURSES=yes + else + HAVE_CURSES=no + fi else + HAVE_CURSES=no CURSES_LIBS= fi AC_SUBST(CURSES_LIBS) + +if test "x$HAVE_CURSES" == "xyes"; then + AC_CHECK_HEADER(panel.h, + [AC_CHECK_LIB(panel, new_panel, + [AC_DEFINE(HAVE_PANEL, 1, + [Define if you have the ncurses panel library]) + PANEL_LIBS=-lpanel + HAVE_PANEL=yes], + [HAVE_PANEL=no], + $CURSES_LIBS + )], + HAVE_PANEL=no, + [] + ) +else + PANEL_LIBS= +fi +AC_SUBST(PANEL_LIBS) diff --git a/config.d/library_functions.m4 b/config.d/library_functions.m4 index 66ff31edc..ba76c574e 100644 --- a/config.d/library_functions.m4 +++ b/config.d/library_functions.m4 @@ -35,6 +35,25 @@ if test "x$ac_cv_func_dlopen" != "xyes"; then fi AC_SUBST(DL_LIBS) +if test "x$DL_LIBS" != "x"; then +AC_MSG_CHECKING([for RTLD_NOW]) +AC_TRY_COMPILE( + [#include ], + [int foo = RTLD_NOW], + AC_DEFINE(HAVE_RTLD_NOW, 1, [Define if you have RTLD_NOW.]) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) +) +AC_MSG_CHECKING([for RTLD_DEEPBIND]) +AC_TRY_COMPILE( + [#include ], + [int foo = RTLD_DEEPBIND], + AC_DEFINE(HAVE_RTLD_DEEPBIND, 1, [Define if you have RTLD_DEEPBIND.]) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) +) +fi + dnl Checks for stricmp/strcasecmp #AC_CHECK_FUNC(strcasecmp, # , diff --git a/config.d/paths.m4 b/config.d/paths.m4 index f340eda78..c5ce432ce 100644 --- a/config.d/paths.m4 +++ b/config.d/paths.m4 @@ -98,6 +98,19 @@ eval expanded_plugindir="$expanded_plugindir" AC_DEFINE_UNQUOTED(FS_PLUGINPATH, "$expanded_plugindir", [Define this to the path from which to load plugins]) AC_SUBST(plugindir) +SHADERDIR="\${libdir}/quakeforge/shaders" +if test "x$shaderdir" = "xauto" -o "x$shaderdir" = "xyes" -o "x$shaderdir" = "x"; then + shaderdir="$SHADERDIR" +elif test "x$shaderdir" = xno; then + shaderdir="." +else + SHADERDIR="$shaderdir" +fi +eval expanded_shaderdir="$shaderdir" +eval expanded_shaderdir="$expanded_shaderdir" +AC_DEFINE_UNQUOTED(FS_SHADERPATH, "$expanded_shaderdir", [Define this to the path from which to load shaders]) +AC_SUBST(plugindir) + AC_ARG_WITH(gl-driver, [ --with-gl-driver=NAME Name of OpenGL driver DLL/DSO], gl_driver=$withval, diff --git a/config.d/qfcc.m4 b/config.d/qfcc.m4 index 3e1d87ae7..380e6a31c 100644 --- a/config.d/qfcc.m4 +++ b/config.d/qfcc.m4 @@ -9,7 +9,7 @@ AC_ARG_WITH(cpp, if test "x$cpp_name" != xauto; then CPP_NAME="$cpp_name" else - CPP_NAME="cpp %d -o %o %i" + CPP_NAME="cpp %u %d %s -o %o %i" case "$host_os" in *freebsd*) CPP_NAME="cpp %d %i %o" diff --git a/config.d/rpm.m4 b/config.d/rpm.m4 index 95ac34cf7..d4406cf2a 100644 --- a/config.d/rpm.m4 +++ b/config.d/rpm.m4 @@ -1,2 +1,2 @@ -AC_CONFIG_FILES(RPM/Makefile RPM/quakeforge.conf RPM/quakeforge.spec) +AC_CONFIG_FILES(RPM/quakeforge.conf RPM/quakeforge.spec) AC_CONFIG_FILES(RPM/build_rpm, [chmod +x RPM/build_rpm]) diff --git a/config.d/typedefs_structs_compiler.m4 b/config.d/typedefs_structs_compiler.m4 index 3ba73b7d6..8e6acac2e 100644 --- a/config.d/typedefs_structs_compiler.m4 +++ b/config.d/typedefs_structs_compiler.m4 @@ -74,9 +74,9 @@ AH_VERBATIM([HAVE___ATTRIBUTE__GCC_STRUCT], #endif]) AC_MSG_CHECKING(for __builtin_expect) -AC_TRY_COMPILE( - [long (*foo) (long, long) = __builtin_expect;], - [], +AC_TRY_LINK( + [int x;], + [if (__builtin_expect(!x, 1)) {}], AC_DEFINE(HAVE___BUILTIN_EXPECT) AC_MSG_RESULT(yes), AC_MSG_RESULT(no) diff --git a/config.d/vulkan.m4 b/config.d/vulkan.m4 new file mode 100644 index 000000000..0c780e98a --- /dev/null +++ b/config.d/vulkan.m4 @@ -0,0 +1,21 @@ +dnl Check for vulkan support +AC_ARG_ENABLE(vulkan, +[ --disable-vulkan do not use Vulkan], + HAVE_VULKAN=$enable_vulkan, HAVE_VULKAN=auto) +if test "x$HAVE_VULKAN" != xno; then + save_CPPFLAGS="$CPPFLAGS" + AS_IF([test x"$VULKAN_SDK" != x], [ + CPPFLAGS="$CPPFLAGS -I$VULKAN_SDK/include" + LDFLAGS="$LDFLAGS -L$VULKAN_SDK/lib" + glslangvalidator="$VULKAN_SDK/bin/glslangValidator" + ], [glslangvalidator="glslangValidator"]) + AC_CHECK_HEADER([vulkan/vulkan.h], [HAVE_VULKAN=yes], [HAVE_VULKAN=no]) + CPPFLAGS="$save_CPPFLAGS" +fi +if test "x$HAVE_VULKAN" = xyes; then + AC_DEFINE([HAVE_VULKAN], [1], [Define if yhou have the Vulkan libs]) +fi +AC_SUBST(VULKAN_LIBS) +AC_SUBST(GLSLANGVALIDATOR, [$glslangvalidator]) + +AM_CONDITIONAL(X11_VULKAN, test "x$HAVE_VULKAN" = "xyes") diff --git a/configure.ac b/configure.ac index ea203472c..db59908b8 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.61) dnl This is the only place where the package name and version appear AC_INIT([QuakeForge], m4_esyscmd([config.d/git-version-gen --prefix '' .tarball-version])) -AM_INIT_AUTOMAKE([foreign]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) dnl LT_INIT messes with CFLAGS (evil bastard) if test "x${CFLAGS-unset}" = xunset; then @@ -63,6 +63,7 @@ m4_include(config.d/compression.m4) m4_include(config.d/mgl.m4) m4_include(config.d/fbdev.m4) m4_include(config.d/svga.m4) +m4_include(config.d/vulkan.m4) m4_include(config.d/x11.m4) m4_include(config.d/sdl.m4) diff --git a/debian/Makefile.am b/debian/Makefile.am deleted file mode 100644 index ec13849c4..000000000 --- a/debian/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -# find -type f | sed -e 's:^\./::g' | grep -v Makefile | sort >> Makefile.am - -EXTRA_DIST= \ - changelog control copyright quakeforge.conf rules source/format \ - qfcc.install \ - quakeforge-alsa.install quakeforge-alsa.postinst quakeforge-alsa.prerm \ - quakeforge-common.install quakeforge-common.postinst \ - quakeforge-dev.install \ - quakeforge-gl.install \ - quakeforge-glsl.install \ - quakeforge-jack.install \ - quakeforge-maptools.install \ - quakeforge-oss.install quakeforge-oss.postinst quakeforge-oss.prerm \ - quakeforge-sdl.install \ - quakeforge-servers.install \ - quakeforge-stub.postinst \ - quakeforge-sw32.install \ - quakeforge-sw.install \ - quakeforge-utils.install \ - quakeforge-x11.install diff --git a/debian/Makemodule.am b/debian/Makemodule.am new file mode 100644 index 000000000..9ef80d06a --- /dev/null +++ b/debian/Makemodule.am @@ -0,0 +1,28 @@ +EXTRA_DIST += \ + debian/changelog \ + debian/control \ + debian/copyright \ + debian/quakeforge.conf \ + debian/rules \ + debian/source/format \ + debian/qfcc.install \ + debian/quakeforge-alsa.install \ + debian/quakeforge-alsa.postinst \ + debian/quakeforge-alsa.prerm \ + debian/quakeforge-common.install \ + debian/quakeforge-common.postinst \ + debian/quakeforge-dev.install \ + debian/quakeforge-gl.install \ + debian/quakeforge-glsl.install \ + debian/quakeforge-jack.install \ + debian/quakeforge-maptools.install \ + debian/quakeforge-oss.install \ + debian/quakeforge-oss.postinst \ + debian/quakeforge-oss.prerm \ + debian/quakeforge-sdl.install \ + debian/quakeforge-servers.install \ + debian/quakeforge-stub.postinst \ + debian/quakeforge-sw32.install \ + debian/quakeforge-sw.install \ + debian/quakeforge-utils.install \ + debian/quakeforge-x11.install diff --git a/desktop/Makefile.am b/desktop/Makefile.am deleted file mode 100644 index 5aa61578b..000000000 --- a/desktop/Makefile.am +++ /dev/null @@ -1,49 +0,0 @@ -## Process this file with automake to produce Makefile.in -# -# Makefile.am -# -# Automake-using build system for QuakeForge -# -# Copyright (C) 2000 Jeff Teunissen -# -# This Makefile 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: -# -# Free Software Foundation, Inc. -# 59 Temple Place - Suite 330 -# Boston, MA 02111-1307, USA -# -# $Id$ -# - -AUTOMAKE_OPTIONS= foreign - -# Stuff that is common to both client and server -# Desktop files -if HAVE_XDG -desktopdir=$(datarootdir)/applications -desktop_DATA= @NQ_DESKTOP_DATA@ @QW_DESKTOP_DATA@ -endif - -# Stuff that doesn't get linked into an executable NEEDS to be mentioned here, -# or it won't be distributed with 'make dist' - -EXTRA_DIST= quakeforge-nq-glx.desktop quakeforge-nq-sdl.desktop \ - quakeforge-nq-sdl32.desktop quakeforge-nq-sgl.desktop \ - quakeforge-nq-x11.desktop quakeforge-qw-glx.desktop \ - quakeforge-qw-sdl.desktop quakeforge-qw-sdl32.desktop \ - quakeforge-qw-sgl.desktop quakeforge-qw-x11.desktop - -# Kill the temp files, hopefully. -CLEANFILES = *.i *.s $(YACCLEX_CLEANFILES) diff --git a/desktop/Makemodule.am b/desktop/Makemodule.am new file mode 100644 index 000000000..bb0acd969 --- /dev/null +++ b/desktop/Makemodule.am @@ -0,0 +1,10 @@ +if HAVE_XDG +desktopdir=$(datarootdir)/applications +desktop_DATA = @NQ_DESKTOP_DATA@ @QW_DESKTOP_DATA@ +endif + +EXTRA_DIST += \ + desktop/quakeforge-nq-sdl.desktop \ + desktop/quakeforge-nq-x11.desktop \ + desktop/quakeforge-qw-sdl.desktop \ + desktop/quakeforge-qw-x11.desktop diff --git a/desktop/quakeforge-nq-glx.desktop b/desktop/quakeforge-nq-glx.desktop deleted file mode 100644 index 67c4ca509..000000000 --- a/desktop/quakeforge-nq-glx.desktop +++ /dev/null @@ -1,18 +0,0 @@ -[Desktop Entry] -Version=1.0 - -Type=Application - -Name=QuakeForge (GLX) -GenericName=Quake (GLX) -Comment=A first person shooter game -Comment[fr]=Un jeu de tir subjectif -Comment[it]=Sparatutto in prima persona -Icon=quake - -Categories=Game;ActionGame; - -Exec=nq-glx -TryExec=nq-glx -Terminal=false -StartupNotify=false diff --git a/desktop/quakeforge-nq-sdl32.desktop b/desktop/quakeforge-nq-sdl32.desktop deleted file mode 100644 index f39050155..000000000 --- a/desktop/quakeforge-nq-sdl32.desktop +++ /dev/null @@ -1,18 +0,0 @@ -[Desktop Entry] -Version=1.0 - -Type=Application - -Name=QuakeForge (SDL32) -GenericName=Quake (SDL32) -Comment=A first person shooter game -Comment[fr]=Un jeu de tir subjectif -Comment[it]=Sparatutto in prima persona -Icon=quake - -Categories=SDL;Game;ActionGame; - -Exec=nq-sdl32 -TryExec=nq-sdl32 -Terminal=false -StartupNotify=false diff --git a/desktop/quakeforge-nq-sgl.desktop b/desktop/quakeforge-nq-sgl.desktop deleted file mode 100644 index 82645eeb6..000000000 --- a/desktop/quakeforge-nq-sgl.desktop +++ /dev/null @@ -1,18 +0,0 @@ -[Desktop Entry] -Version=1.0 - -Type=Application - -Name=QuakeForge (SDL GL) -GenericName=Quake (SDL GL) -Comment=A first person shooter game -Comment[fr]=Un jeu de tir subjectif -Comment[it]=Sparatutto in prima persona -Icon=quake - -Categories=SDL;Game;ActionGame; - -Exec=nq-sgl -TryExec=nq-sgl -Terminal=false -StartupNotify=false diff --git a/desktop/quakeforge-qw-glx.desktop b/desktop/quakeforge-qw-glx.desktop deleted file mode 100644 index fab7cab4e..000000000 --- a/desktop/quakeforge-qw-glx.desktop +++ /dev/null @@ -1,18 +0,0 @@ -[Desktop Entry] -Version=1.0 - -Type=Application - -Name=QuakeForge QuakeWorld (GLX) -GenericName=QuakeWorld (GLX) -Comment=A first person shooter game -Comment[fr]=Un jeu de tir subjectif -Comment[it]=Sparatutto in prima persona -Icon=quake - -Categories=Game;ActionGame; - -Exec=qw-client-glx -TryExec=qw-client-glx -Terminal=false -StartupNotify=false diff --git a/desktop/quakeforge-qw-sdl32.desktop b/desktop/quakeforge-qw-sdl32.desktop deleted file mode 100644 index d2862ecb6..000000000 --- a/desktop/quakeforge-qw-sdl32.desktop +++ /dev/null @@ -1,18 +0,0 @@ -[Desktop Entry] -Version=1.0 - -Type=Application - -Name=QuakeForge QuakeWorld (SDL32) -GenericName=QuakeWorld (SDL32) -Comment=A first person shooter game -Comment[fr]=Un jeu de tir subjectif -Comment[it]=Sparatutto in prima persona -Icon=quake - -Categories=SDL;Game;ActionGame; - -Exec=qw-client-sdl32 -TryExec=qw-client-sdl32 -Terminal=false -StartupNotify=false diff --git a/desktop/quakeforge-qw-sgl.desktop b/desktop/quakeforge-qw-sgl.desktop deleted file mode 100644 index 36ae08f24..000000000 --- a/desktop/quakeforge-qw-sgl.desktop +++ /dev/null @@ -1,18 +0,0 @@ -[Desktop Entry] -Version=1.0 - -Type=Application - -Name=QuakeForge QuakeWorld (SDL GL) -GenericName=QuakeWorld (SDL GL) -Comment=A first person shooter game -Comment[fr]=Un jeu de tir subjectif -Comment[it]=Sparatutto in prima persona -Icon=quake - -Categories=SDL;Game;ActionGame; - -Exec=qw-client-sgl -TryExec=qw-client-sgl -Terminal=false -StartupNotify=false diff --git a/doc/Makefile.am b/doc/Makefile.am deleted file mode 100644 index 8511d72f3..000000000 --- a/doc/Makefile.am +++ /dev/null @@ -1,55 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= man - -DOX= \ - bind.dox config.dox connect.dox cshifts.dox dirconf.dox faq.dox \ - filesystem.dox mapformat.dox property-list.dox qtv.dox quakeforge.dox \ - qw-cap-spec.dox qw-download-spec.dox sound.dox specifications.dox \ - surround-sound.dox timestamps.dox - -GIB= \ - gib/GIB.lyx gib/break.gib gib/continue.gib gib/curly.gib gib/examples.sh \ - gib/for.gib gib/gib_head.eps gib/if-chain.gib gib/if-else.gib \ - gib/if-simple.gib gib/while.gib - -PROGS= \ - progs/vm-exec.c progs/vm-mem.fig - -EXTRA_DIST= qf.ico \ - \ - skybox.fig template.c template.h \ - quakeforge.dox.conf.in \ - \ - ${DOX} ${GIB} ${PROGS} \ - \ - config/glspeed-v1.cfg config/glspeed-v3.cfg config/swspeed.cfg \ - \ - config/gib/adjustvolume.gib config/gib/infobot.gib config/gib/ln.gib \ - config/gib/qfadmin.gib config/gib/sshot.gib config/gib/zoom.gib \ - \ - qtv/qwtv.fig - -SUFFIXES=.eps .fig .png -.fig.png: - @mkdir -p `dirname $@` - fig2dev -L png $< $@ - -.fig.eps: - @mkdir -p `dirname $@` - fig2dev -L ps $< $@ - -.fig.svg: - @mkdir -p `dirname $@` - fig2dev -L svg $< $@ - -clean-local: - -rm -fr doxygen - -progs/vm-mem.svg: progs/vm-mem.fig -progs/vm-mem.eps: progs/vm-mem.fig -qtv/qwtv.svg: qtv/qwtv.fig -qtv/qwtv.eps: qtv/qwtv.fig - -doc: quakeforge.dox.conf progs/vm-mem.svg progs/vm-mem.eps qtv/qwtv.svg qtv/qwtv.eps ${DOX} - doxygen quakeforge.dox.conf diff --git a/doc/Makemodule.am b/doc/Makemodule.am new file mode 100644 index 000000000..91d9270b7 --- /dev/null +++ b/doc/Makemodule.am @@ -0,0 +1,81 @@ +man_MANS += doc/man/quakeforge.1 + +DOX= \ + doc/bind.dox \ + doc/config.dox \ + doc/connect.dox \ + doc/cshifts.dox \ + doc/dirconf.dox \ + doc/faq.dox \ + doc/filesystem.dox \ + doc/mapformat.dox \ + doc/property-list.dox \ + doc/qtv.dox \ + doc/quakeforge.dox \ + doc/qw-cap-spec.dox \ + doc/qw-download-spec.dox \ + doc/sound.dox \ + doc/specifications.dox \ + doc/surround-sound.dox \ + doc/timestamps.dox + +GIB= \ + doc/gib/GIB.lyx \ + doc/gib/break.gib \ + doc/gib/continue.gib \ + doc/gib/curly.gib \ + doc/gib/examples.sh \ + doc/gib/for.gib \ + doc/gib/gib_head.eps \ + doc/gib/if-chain.gib \ + doc/gib/if-else.gib \ + doc/gib/if-simple.gib \ + doc/gib/while.gib + +PROGS= \ + doc/progs/vm-exec.c \ + doc/progs/vm-mem.fig + +EXTRA_DIST += \ + ${DOX} ${GIB} ${PROGS} \ + doc/qf.ico \ + doc/skybox.fig \ + doc/template.c \ + doc/template.h \ + doc/quakeforge.dox.conf.in \ + doc/config/glspeed-v1.cfg \ + doc/config/glspeed-v3.cfg \ + doc/config/swspeed.cfg \ + doc/config/gib/adjustvolume.gib \ + doc/config/gib/infobot.gib \ + doc/config/gib/ln.gib \ + doc/config/gib/qfadmin.gib \ + doc/config/gib/sshot.gib \ + doc/config/gib/zoom.gib \ + doc/man/quakeforge.1 \ + doc/qtv/qwtv.fig + +SUFFIXES += .eps .fig .png +.fig.png: + @mkdir -p `dirname $@` + fig2dev -L png $< $@ + +.fig.eps: + @mkdir -p `dirname $@` + fig2dev -L ps $< $@ + +.fig.svg: + @mkdir -p `dirname $@` + fig2dev -L svg $< $@ + +clean-local: + -rm -fr doxygen + +doc/progs/vm-mem.svg: doc/progs/vm-mem.fig +doc/progs/vm-mem.eps: doc/progs/vm-mem.fig +doc/qtv/qwtv.svg: doc/qtv/qwtv.fig +doc/qtv/qwtv.eps: doc/qtv/qwtv.fig + +.PHONY: doc +doc: doc/quakeforge.dox.conf doc/progs/vm-mem.svg doc/progs/vm-mem.eps doc/qtv/qwtv.svg doc/qtv/qwtv.eps ${DOX} + doxygen doc/quakeforge.dox.conf diff --git a/doc/connect.dox b/doc/connect.dox index 44d83586a..14295294e 100644 --- a/doc/connect.dox +++ b/doc/connect.dox @@ -3,38 +3,39 @@ /** \page connection_sequence QW Connection Sequence \msc -Client,Server; -Client=>Server [label = "getchallenge\n"]; -Server=>Client [label = "c[challenge][ext]"]; -Client=>Server [label = "connect [protover] [qport] [challenge] [userinfo]"]; -Server=>Client [label = "j"]; -Client->Server [label = "[clc_stringcmd]new"]; -Server->Client [label = "[svc_serverdata][data]"]; -|||; -Client->Server [label = "[clc_stringcmd]soundlist [svcount] 0"]; ---- [label = "soundlist loop start"]; -Server->Client [label = "[svc_soundlist][data][next]"]; -Client->Server [label = "[clc_stringcmd]soundlist [svcount] [next]"]; ---- [label = "soundlist loop end"]; -Server->Client [label = "[svc_soundlist][data]0"]; -|||; -Client->Server [label = "[clc_stringcmd]modellist [svcount] 0"]; ---- [label = "modellist list loop start"]; -Server->Client [label = "[svc_modellist][data][next]"]; -Client->Server [label = "[clc_stringcmd]modellist [svcount] [next]"]; ---- [label = "modellist list loop end"]; -Server->Client [label = "[svc_modellist][data]0"]; -|||; -Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n=0] [wcsum]"]; ---- [label = "prespawn loop start"]; -Server->Client [label = "[signon buffer n][stuffcmd]prespawn..."]; -Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n]"]; ---- [label = "prespawn loop end"]; -Server->Client [label = "[signon buffer n][stuffcmd]spawn..."]; -|||; -Client->Server [label = "[clc_stringcmd]spawn [svcount] 0"]; -Server->Client [label = "[spawn info][stuffcmd]skins"]; -Client->Server [label = "[clc_stringcmd]begin [svcount]"]; -#... [label = "in game message sequence"]; +Client [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black], +Server [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client=>Server [label = "getchallenge\n", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server=>Client [label = "c[challenge][ext]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client=>Server [label = "connect [protover] [qport] [challenge] [userinfo]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server=>Client [label = "j", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]new", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[svc_serverdata][data]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]soundlist [svcount] 0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +--- [label = "soundlist loop start", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[svc_soundlist][data][next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]soundlist [svcount] [next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +--- [label = "soundlist loop end", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[svc_soundlist][data]0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]modellist [svcount] 0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +--- [label = "modellist list loop start", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[svc_modellist][data][next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]modellist [svcount] [next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +--- [label = "modellist list loop end", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[svc_modellist][data]0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n=0] [wcsum]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +--- [label = "prespawn loop start", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[signon buffer n][stuffcmd]prespawn...", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +--- [label = "prespawn loop end", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[signon buffer n][stuffcmd]spawn...", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]spawn [svcount] 0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Server->Client [label = "[spawn info][stuffcmd]skins", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +Client->Server [label = "[clc_stringcmd]begin [svcount]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; +... [label = "in game message sequence", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black]; \endmsc */ diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am deleted file mode 100644 index 5249e3a26..000000000 --- a/doc/man/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST= quakeforge.1 diff --git a/doc/progs/vm-exec.c b/doc/progs/vm-exec.c index 0234c2158..1f9ae4b8e 100644 --- a/doc/progs/vm-exec.c +++ b/doc/progs/vm-exec.c @@ -23,6 +23,7 @@ call_progs_main (progs_t *pr, int argc, const char **argv) PR_RESET_PARAMS (pr); P_INT (pr, 0) = argc; P_POINTER (pr, 1) = PR_SetPointer (pr, pr_argv); + pr->pr_argc = 2; PR_ExecuteProgram (pr, progs_main); PR_PopFrame (pr); PR_Zone_Free (pr, pr_argv); diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index 9db22207d..3d22be413 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.9.1 +# Doxyfile 1.8.16 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -179,6 +187,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -226,16 +244,15 @@ TAB_SIZE = 4 # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) ALIASES = QF=QuakeForge -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -264,17 +281,26 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # @@ -285,7 +311,7 @@ EXTENSION_MAPPING = no_extension=C # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -293,6 +319,15 @@ EXTENSION_MAPPING = no_extension=C MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -318,7 +353,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -343,6 +378,13 @@ IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = YES + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -417,6 +459,12 @@ EXTRACT_ALL = YES EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -437,7 +485,7 @@ EXTRACT_STATIC = @STATIC_DOC@ EXTRACT_LOCAL_CLASSES = NO -# This flag is only useful for Objective-C code. When set to YES, local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. @@ -495,7 +543,7 @@ INTERNAL_DOCS = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# (including Cygwin) ands Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO @@ -682,7 +730,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. @@ -727,11 +775,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -755,7 +810,7 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = @TOPSRC@/include \ @@ -770,7 +825,7 @@ INPUT = @TOPSRC@/include \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. @@ -778,12 +833,17 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.h \ @@ -871,9 +931,8 @@ EXAMPLE_RECURSIVE = NO # \image command). IMAGE_PATH = @TOPSRC@/doc \ - @builddir@ \ - @builddir@/progs \ - @builddir@/qtv + @builddir@/doc/progs \ + @builddir@/doc/qtv # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -889,6 +948,10 @@ IMAGE_PATH = @TOPSRC@/doc \ # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. INPUT_FILTER = @@ -898,6 +961,10 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. FILTER_PATTERNS = @@ -950,7 +1017,7 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -982,12 +1049,12 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1015,7 +1082,7 @@ VERBATIM_HEADERS = NO # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was -# compiled with the --with-libclang option. +# generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO @@ -1028,6 +1095,16 @@ CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1039,13 +1116,6 @@ CLANG_OPTIONS = ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 4 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1146,7 +1216,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1182,6 +1252,17 @@ HTML_COLORSTYLE_GAMMA = 100 HTML_TIMESTAMP = NO +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. @@ -1205,13 +1286,13 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1250,7 +1331,7 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1326,7 +1407,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1334,7 +1415,7 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1343,7 +1424,7 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1351,7 +1432,7 @@ QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1359,7 +1440,7 @@ QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1452,7 +1533,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # @@ -1464,7 +1545,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1472,7 +1553,7 @@ FORMULA_TRANSPARENT = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = NO +USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: @@ -1491,8 +1572,8 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest @@ -1553,7 +1634,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1566,7 +1647,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1618,21 +1699,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. @@ -1648,12 +1743,15 @@ COMPACT_LATEX = YES # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1750,12 +1848,28 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1795,9 +1909,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1806,8 +1920,8 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = @@ -1893,6 +2007,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -1925,9 +2046,9 @@ DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sf.net) file that captures the -# structure of the code including all documentation. Note that this feature is -# still experimental and incomplete at the moment. +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -2010,7 +2131,6 @@ SEARCH_INCLUDES = YES # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @TOPSRC@/include \ - @TOPSRC@/hw/include \ @TOPSRC@/nq/include \ @TOPSRC@/qw/include \ @TOPSRC@/qtv/include @@ -2101,12 +2221,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2120,15 +2234,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2207,7 +2312,7 @@ COLLABORATION_GRAPH = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GROUP_GRAPHS = NO +GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling @@ -2261,7 +2366,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2272,7 +2378,8 @@ CALL_GRAPH = NO # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2295,13 +2402,17 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = NO # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). # Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, # png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd and svg. +# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2352,6 +2463,11 @@ DIAFILE_DIRS = PLANTUML_JAR_PATH = +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. diff --git a/hw/Makefile.am b/hw/Makefile.am deleted file mode 100644 index 77e3cbf5b..000000000 --- a/hw/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source diff --git a/hw/Makemodule.am b/hw/Makemodule.am new file mode 100644 index 000000000..cfd2f1e31 --- /dev/null +++ b/hw/Makemodule.am @@ -0,0 +1 @@ +include hw/source/Makemodule.am diff --git a/hw/include/Makefile.am b/hw/include/Makefile.am deleted file mode 100644 index b36df17ad..000000000 --- a/hw/include/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST = diff --git a/hw/source/Makefile.am b/hw/source/Makemodule.am similarity index 69% rename from hw/source/Makefile.am rename to hw/source/Makemodule.am index d5ad0658e..9f86d3283 100644 --- a/hw/source/Makefile.am +++ b/hw/source/Makemodule.am @@ -27,27 +27,17 @@ # $Id$ # -AUTOMAKE_OPTIONS= foreign +bin_PROGRAMS += @HW_TARGETS@ -# Stuff that is common to both client and server -AM_CPPFLAGS= -I$(top_srcdir)/include -I$(top_srcdir)/hw/include -SDL_LIBS = @SDL_LIBS@ +EXTRA_PROGRAMS += hw-master -bin_PROGRAMS= @HW_TARGETS@ - -EXTRA_PROGRAMS= hw-master - -common_ldflags= -export-dynamic hw_master_libs= \ - $(top_builddir)/libs/net/libnet_chan.la \ + libs/net/libnet_chan.la \ @server_static_plugin_libs@ \ - $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/util/libQFutil.la + libs/console/libQFconsole.la \ + libs/util/libQFutil.la hw_master_LDFLAGS= $(common_ldflags) hw_master_LDADD= $(hw_master_libs) $(NET_LIBS) hw_master_DEPENDENCIES= $(hw_master_libs) -hw_master_SOURCES= master.c - -# Kill the temp files, hopefully. -CLEANFILES = *.i *.s +hw_master_SOURCES= hw/source/master.c diff --git a/hw/source/master.c b/hw/source/master.c index 4617e3c7d..2142eaa81 100644 --- a/hw/source/master.c +++ b/hw/source/master.c @@ -121,7 +121,7 @@ FL_Add (filter_t * filter) filter_list = filter; } -static filter_t * +static __attribute__((pure)) filter_t * FL_Find (netadr_t adr) { filter_t *filter; @@ -209,7 +209,7 @@ SVL_Add (server_t *sv) sv_list = sv; } -static server_t * +static __attribute__((pure)) server_t * SVL_Find (netadr_t adr) { server_t *sv; @@ -469,13 +469,10 @@ SV_WriteFilterList (void) } static void -SV_Shutdown (void) +SV_Shutdown (void *data) { - NET_Shutdown (); - // write filter list SV_WriteFilterList (); - Con_Shutdown (); } static void @@ -525,7 +522,7 @@ main (int argc, const char **argv) mst_cbuf = Cbuf_New (&id_interp); - Sys_RegisterShutdown (SV_Shutdown); + Sys_RegisterShutdown (SV_Shutdown, 0); Sys_Init (); diff --git a/include/Makefile.am b/include/Makefile.am deleted file mode 100644 index 56b084ae1..000000000 --- a/include/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign -SUBDIRS = QF -EXTRA_DIST = \ - adivtab.h alsa_funcs_list.h anorm_dots.h anorms.h asm_draw.h asm_i386.h \ - block16.h block8.h buildnum.h clview.h compat.h context_sdl.h \ - context_x11.h d_iface.h d_ifacea.h d_local.h dga_check.h exp.h fbset.h \ - garbage.h getopt.h gib_buffer.h gib_builtin.h gib_classes.h \ - gib_execute.h gib_function.h gib_handle.h gib_object.h gib_parse.h \ - gib_process.h gib_regex.h gib_semantics.h gib_thread.h gib_tree.h \ - gib_vars.h gl_warp_sin.h in_win.h logos.h mod_internal.h net_dgrm.h \ - net_loop.h net_udp.h net_vcr.h net_wins.h netchan.h netmain.h \ - noisetextures.h old_keys.h ops.h pstdint.h qfalloca.h qstring.h \ - quakeasm.h r_cvar.h r_dynamic.h r_internal.h r_local.h r_screen.h \ - r_shared.h regex.h rua_internal.h sbar.h skin_stencil.h snd_internal.h \ - sv_console.h varrays.h vgamodes.h vid_internal.h vregset.h winquake.h \ - world.h \ - \ - client/entities.h \ - \ - qw/bothdefs.h qw/msg_backbuf.h qw/msg_ucmd.h qw/pmove.h qw/protocol.h \ - \ - win32/dirent.h win32/fnmatch.h win32/stdint.h \ - \ - win32/resources/icon1Vista.ico win32/resources/icon1XP.ico \ - win32/resources/quakeforge.rc win32/resources/resource.h diff --git a/include/Makemodule.am b/include/Makemodule.am new file mode 100644 index 000000000..0755ed1b5 --- /dev/null +++ b/include/Makemodule.am @@ -0,0 +1,94 @@ +## Process this file with automake to produce Makefile.in +include include/QF/Makemodule.am + +EXTRA_DIST += \ + include/adivtab.h \ + include/alsa_funcs_list.h \ + include/anorm_dots.h \ + include/anorms.h \ + include/asm_draw.h \ + include/asm_i386.h \ + include/block16.h \ + include/block8.h \ + include/buildnum.h \ + include/compat.h \ + include/context_sdl.h \ + include/context_x11.h \ + include/d_iface.h \ + include/d_ifacea.h \ + include/d_local.h \ + include/dga_check.h \ + include/exp.h \ + include/fbset.h \ + include/garbage.h \ + include/getopt.h \ + include/gib_buffer.h \ + include/gib_builtin.h \ + include/gib_classes.h \ + include/gib_execute.h \ + include/gib_function.h \ + include/gib_handle.h \ + include/gib_object.h \ + include/gib_parse.h \ + include/gib_process.h \ + include/gib_regex.h \ + include/gib_semantics.h \ + include/gib_thread.h \ + include/gib_tree.h \ + include/gib_vars.h \ + include/gl_warp_sin.h \ + include/in_win.h \ + include/logos.h \ + include/mod_internal.h \ + include/net_dgrm.h \ + include/net_loop.h \ + include/net_udp.h \ + include/net_vcr.h \ + include/net_wins.h \ + include/netchan.h \ + include/netmain.h \ + include/noisetextures.h \ + include/old_keys.h \ + include/ops.h \ + include/pstdint.h \ + include/qfalloca.h \ + include/qstring.h \ + include/quakeasm.h \ + include/r_cvar.h \ + include/r_dynamic.h \ + include/r_internal.h \ + include/r_local.h \ + include/r_screen.h \ + include/r_shared.h \ + include/regex.h \ + include/rua_internal.h \ + include/sbar.h \ + include/skin_stencil.h \ + include/snd_internal.h \ + include/sv_console.h \ + include/varrays.h \ + include/vgamodes.h \ + include/vid_gl.h \ + include/vid_internal.h \ + include/vid_sw.h \ + include/vid_vulkan.h \ + include/vregset.h \ + include/winquake.h \ + include/world.h \ + include/client/effects.h \ + include/client/entities.h \ + include/client/temp_entities.h \ + include/client/locs.h \ + include/client/view.h \ + include/qw/bothdefs.h \ + include/qw/msg_backbuf.h \ + include/qw/msg_ucmd.h \ + include/qw/pmove.h \ + include/qw/protocol.h \ + include/win32/dirent.h \ + include/win32/fnmatch.h \ + include/win32/stdint.h \ + include/win32/resources/icon1Vista.ico \ + include/win32/resources/icon1XP.ico \ + include/win32/resources/quakeforge.rc \ + include/win32/resources/resource.h diff --git a/include/QF/GL/qf_lightmap.h b/include/QF/GL/qf_lightmap.h index c048b181a..e0a05d4dd 100644 --- a/include/QF/GL/qf_lightmap.h +++ b/include/QF/GL/qf_lightmap.h @@ -50,6 +50,6 @@ void gl_lightmap_init (void); void GL_BuildLightmaps (struct model_s **models, int num_models); void R_BlendLightmaps (void); void R_CalcLightmaps (void); -extern void (*R_BuildLightMap) (msurface_t *surf); +extern void (*R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); #endif // __QF_GL_lightmap_h diff --git a/include/QF/GLSL/qf_lightmap.h b/include/QF/GLSL/qf_lightmap.h index ef828d6d8..507eaeae6 100644 --- a/include/QF/GLSL/qf_lightmap.h +++ b/include/QF/GLSL/qf_lightmap.h @@ -36,8 +36,8 @@ void glsl_lightmap_init (void); void glsl_R_BuildLightmaps (struct model_s **models, int num_models); void glsl_R_CalcLightmaps (void); -extern void (*glsl_R_BuildLightMap) (msurface_t *surf); -int glsl_R_LightmapTexture (void); +extern void (*glsl_R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); +int glsl_R_LightmapTexture (void) __attribute__((pure)); void glsl_R_FlushLightmaps (void); #endif//__QF_GLSL_lightmap_h diff --git a/include/QF/GLSL/qf_textures.h b/include/QF/GLSL/qf_textures.h index 1447d797a..2298c3e16 100644 --- a/include/QF/GLSL/qf_textures.h +++ b/include/QF/GLSL/qf_textures.h @@ -31,15 +31,6 @@ #include "QF/qtypes.h" typedef struct scrap_s scrap_t; -typedef struct subpic_s { - const struct subpic_s * const next; - const scrap_t * const scrap; - const struct vrect_s * const rect; - const int tnum; ///< texture number - const int width; ///< requested width - const int height; ///< requested height - const float size; ///< size factor for tex coords (mult) -} subpic_t; int GLSL_LoadQuakeTexture (const char *identifier, int width, int height, byte *data); @@ -55,10 +46,12 @@ void GLSL_TextureInit (void); scrap_t *GLSL_CreateScrap (int size, int format, int linear); void GLSL_DestroyScrap (scrap_t *scrap); void GLSL_ScrapClear (scrap_t *scrap); -int GLSL_ScrapTexture (scrap_t *scrap); -subpic_t *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height); //XXX slow! -void GLSL_SubpicDelete (subpic_t *subpic); //XXX slow! -void GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch); +int GLSL_ScrapTexture (scrap_t *scrap) __attribute__((pure)); +//XXX slow! +struct subpic_s *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height); +//XXX slow! +void GLSL_SubpicDelete (struct subpic_s *subpic); +void GLSL_SubpicUpdate (struct subpic_s *subpic, byte *data, int batch); void GLSL_ScrapFlush (scrap_t *scrap); #endif//__QF_GLSL_textures_h diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am deleted file mode 100644 index ffb0ff56b..000000000 --- a/include/QF/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -AUTOMAKE_OPTIONS = foreign -pkgincludedir = $(includedir)/QF -nobase_pkginclude_HEADERS = \ - alloc.h bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ - console.h crc.h csqc.h cvar.h dstring.h draw.h gib.h hash.h hl.h \ - idparse.h image.h in_event.h info.h input.h iqm.h joystick.h keys.h \ - link.h llist.h locs.h mathlib.h mdfour.h mersenne.h model.h modelgen.h \ - msg.h object.h pak.h pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h \ - pr_obj.h progs.h qargs.h qdefs.h qendian.h qfplist.h qtypes.h quakefs.h \ - quakeio.h render.h riff.h ruamoko.h screen.h script.h segtext.h set.h \ - sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h tga.h uint32.h va.h \ - ver_check.h vid.h vrect.h view.h wad.h wadfile.h winding.h zone.h \ - \ - GL/ati.h GL/defines.h GL/extensions.h GL/funcs.h GL/qf_draw.h \ - GL/qf_explosions.h GL/qf_funcs_list.h GL/qf_iqm.h GL/qf_lightmap.h \ - GL/qf_rlight.h GL/qf_rmain.h GL/qf_rsurf.h GL/qf_sky.h GL/qf_textures.h \ - GL/qf_vid.h GL/types.h \ - \ - GLSL/defines.h GLSL/funcs.h GLSL/qf_alias.h GLSL/qf_bsp.h GLSL/qf_draw.h \ - GLSL/qf_funcs_list.h GLSL/qf_iqm.h GLSL/qf_lightmap.h GLSL/qf_particles.h \ - GLSL/qf_textures.h GLSL/qf_vid.h GLSL/types.h \ - \ - math/dual.h math/half.h math/matrix3.h math/matrix4.h math/quaternion.h \ - math/vector.h \ - \ - plugin/cd.h plugin/console.h plugin/general.h plugin/input.h \ - plugin/snd_output.h plugin/snd_render.h plugin/vid_render.h diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am new file mode 100644 index 000000000..4c190feae --- /dev/null +++ b/include/QF/Makemodule.am @@ -0,0 +1,169 @@ +include_qf = \ + include/QF/alloc.h \ + include/QF/bspfile.h \ + include/QF/cbuf.h \ + include/QF/cdaudio.h \ + include/QF/checksum.h \ + include/QF/clip_hull.h \ + include/QF/cmd.h \ + include/QF/console.h \ + include/QF/crc.h \ + include/QF/csqc.h \ + include/QF/cvar.h \ + include/QF/darray.h \ + include/QF/dstring.h \ + include/QF/draw.h \ + include/QF/gib.h \ + include/QF/hash.h \ + include/QF/idparse.h \ + include/QF/image.h \ + include/QF/in_event.h \ + include/QF/info.h \ + include/QF/input.h \ + include/QF/iqm.h \ + include/QF/joystick.h \ + include/QF/keys.h \ + include/QF/link.h \ + include/QF/llist.h \ + include/QF/mathlib.h \ + include/QF/mdfour.h \ + include/QF/mersenne.h \ + include/QF/model.h \ + include/QF/modelgen.h \ + include/QF/msg.h \ + include/QF/object.h \ + include/QF/pak.h \ + include/QF/pakfile.h \ + include/QF/pcx.h \ + include/QF/png.h \ + include/QF/plist.h \ + include/QF/plugin.h \ + include/QF/pr_comp.h \ + include/QF/pr_debug.h \ + include/QF/pr_obj.h \ + include/QF/pr_type.h \ + include/QF/progs.h \ + include/QF/qargs.h \ + include/QF/qdefs.h \ + include/QF/qendian.h \ + include/QF/qtypes.h \ + include/QF/quakefs.h \ + include/QF/quakeio.h \ + include/QF/render.h \ + include/QF/riff.h \ + include/QF/ringbuffer.h \ + include/QF/ruamoko.h \ + include/QF/screen.h \ + include/QF/script.h \ + include/QF/segtext.h \ + include/QF/set.h \ + include/QF/sizebuf.h \ + include/QF/skin.h \ + include/QF/sound.h \ + include/QF/spritegn.h \ + include/QF/sys.h \ + include/QF/teamplay.h \ + include/QF/tga.h \ + include/QF/txtbuffer.h \ + include/QF/va.h \ + include/QF/ver_check.h \ + include/QF/vid.h \ + include/QF/vrect.h \ + include/QF/view.h \ + include/QF/wad.h \ + include/QF/wadfile.h \ + include/QF/winding.h \ + include/QF/zone.h + +include_qf_gl = \ + include/QF/GL/ati.h \ + include/QF/GL/defines.h \ + include/QF/GL/extensions.h \ + include/QF/GL/funcs.h \ + include/QF/GL/qf_draw.h \ + include/QF/GL/qf_explosions.h \ + include/QF/GL/qf_funcs_list.h \ + include/QF/GL/qf_iqm.h \ + include/QF/GL/qf_lightmap.h \ + include/QF/GL/qf_rlight.h \ + include/QF/GL/qf_rmain.h \ + include/QF/GL/qf_rsurf.h \ + include/QF/GL/qf_sky.h \ + include/QF/GL/qf_textures.h \ + include/QF/GL/qf_vid.h \ + include/QF/GL/types.h + +include_qf_glsl = \ + include/QF/GLSL/defines.h \ + include/QF/GLSL/funcs.h \ + include/QF/GLSL/qf_alias.h \ + include/QF/GLSL/qf_bsp.h \ + include/QF/GLSL/qf_draw.h \ + include/QF/GLSL/qf_funcs_list.h \ + include/QF/GLSL/qf_iqm.h \ + include/QF/GLSL/qf_lightmap.h \ + include/QF/GLSL/qf_particles.h \ + include/QF/GLSL/qf_textures.h \ + include/QF/GLSL/qf_vid.h \ + include/QF/GLSL/types.h + +include_qf_math = \ + include/QF/math/dual.h \ + include/QF/math/half.h \ + include/QF/math/matrix3.h \ + include/QF/math/matrix4.h \ + include/QF/math/quaternion.h \ + include/QF/math/vector.h + +include_qf_plugin = \ + include/QF/plugin/cd.h \ + include/QF/plugin/console.h \ + include/QF/plugin/general.h \ + include/QF/plugin/input.h \ + include/QF/plugin/snd_output.h \ + include/QF/plugin/snd_render.h \ + include/QF/plugin/vid_render.h + +include_qf_vulkan = \ + include/QF/Vulkan/buffer.h \ + include/QF/Vulkan/command.h \ + include/QF/Vulkan/cvars.h \ + include/QF/Vulkan/descriptor.h \ + include/QF/Vulkan/device.h \ + include/QF/Vulkan/funclist.h \ + include/QF/Vulkan/image.h \ + include/QF/Vulkan/instance.h \ + include/QF/Vulkan/memory.h \ + include/QF/Vulkan/pipeline.h \ + include/QF/Vulkan/qf_draw.h \ + include/QF/Vulkan/qf_vid.h \ + include/QF/Vulkan/renderpass.h \ + include/QF/Vulkan/swapchain.h + +# headers shared with ruamoko +qfcc_include_qf = include/QF/keys.h + +qf_includedir = $(includedir)/QF +qf_gl_includedir = $(includedir)/QF/GL +qf_glsl_includedir = $(includedir)/QF/GLSL +qf_math_includedir = $(includedir)/QF/math +qf_plugin_includedir = $(includedir)/QF/plugin +qf_vulkan_includedir = $(includedir)/QF/vulkan +qf_include_HEADERS = @qfac_include_qf@ +qf_gl_include_HEADERS = @qfac_include_qf_gl@ +qf_glsl_include_HEADERS = @qfac_include_qf_glsl@ +qf_math_include_HEADERS = @qfac_include_qf_math@ +qf_plugin_include_HEADERS = @qfac_include_qf_plugin@ +qf_vulkan_include_HEADERS = @qfac_include_qf_vulkan@ + +ruamoko_qf_includedir = $(ruamoko_includedir)/QF +ruamoko_qf_include_HEADERS = @qfac_qfcc_include_qf@ + +EXTRA_HEADERS += \ + $(include_qf) \ + $(include_qf_gl) \ + $(include_qf_glsl) \ + $(include_qf_math) \ + $(include_qf_plugin) \ + $(include_qf_vulkan) \ + $(qfcc_include_qf) diff --git a/include/QF/Vulkan/barrier.h b/include/QF/Vulkan/barrier.h new file mode 100644 index 000000000..56438aeba --- /dev/null +++ b/include/QF/Vulkan/barrier.h @@ -0,0 +1,22 @@ +#ifndef __QF_Vulkan_barrier_h +#define __QF_Vulkan_barrier_h + +typedef struct { + VkPipelineStageFlags src; + VkPipelineStageFlags dst; +} qfv_pipelinestagepair_t; + +//XXX Note: imageLayoutTransitionBarriers, imageLayoutTransitionStages and +// the enum must be kept in sync +enum { + qfv_LT_Undefined_to_TransferDst, + qfv_LT_TransferDst_to_ShaderReadOnly, + qfv_LT_ShaderReadOnly_to_TransferDst, + qfv_LT_Undefined_to_DepthStencil, + qfv_LT_Undefined_to_Color, +}; + +extern const VkImageMemoryBarrier imageLayoutTransitionBarriers[]; +extern const qfv_pipelinestagepair_t imageLayoutTransitionStages[]; + +#endif//__QF_Vulkan_barrier_h diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h new file mode 100644 index 000000000..712b14a96 --- /dev/null +++ b/include/QF/Vulkan/buffer.h @@ -0,0 +1,48 @@ +#ifndef __QF_Vulkan_buffer_h +#define __QF_Vulkan_buffer_h + +#include "QF/darray.h" + +typedef struct qfv_buffertransition_s { + VkBuffer buffer; + VkAccessFlags srcAccess; + VkAccessFlags dstAccess; + uint32_t srcQueueFamily; + uint32_t dstQueueFamily; + VkDeviceSize offset; + VkDeviceSize size; +} qfv_buffertransition_t; + +typedef struct qfv_buffertransitionset_s + DARRAY_TYPE (qfv_buffertransition_t) qfv_buffertransitionset_t; +typedef struct qfv_bufferbarrierset_s + DARRAY_TYPE (VkBufferMemoryBarrier) qfv_bufferbarrierset_t; + +typedef struct qfv_bufferset_s + DARRAY_TYPE (VkBuffer) qfv_bufferset_t; +#define QFV_AllocBufferSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_bufferset_t, num, allocator) + +struct qfv_device_s; +VkBuffer QFV_CreateBuffer (struct qfv_device_s *device, + VkDeviceSize size, + VkBufferUsageFlags usage); + +VkDeviceMemory QFV_AllocBufferMemory (struct qfv_device_s *device, + VkBuffer buffer, + VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset); + +int QFV_BindBufferMemory (struct qfv_device_s *device, + VkBuffer buffer, VkDeviceMemory object, + VkDeviceSize offset); + +qfv_bufferbarrierset_t * +QFV_CreateBufferTransitions (qfv_buffertransition_t *transitions, + int numTransitions); + +VkBufferView QFV_CreateBufferView (struct qfv_device_s *device, + VkBuffer buffer, VkFormat format, + VkDeviceSize offset, VkDeviceSize size); + +#endif//__QF_Vulkan_buffer_h diff --git a/include/QF/Vulkan/capture.h b/include/QF/Vulkan/capture.h new file mode 100644 index 000000000..a2fa1397b --- /dev/null +++ b/include/QF/Vulkan/capture.h @@ -0,0 +1,43 @@ +#ifndef __QF_Vulkan_capture_h +#define __QF_Vulkan_capture_h + +#include "QF/darray.h" +#include "QF/qtypes.h" + +typedef struct qfv_capture_image_s { + VkImage image; + VkImageLayout layout; + VkCommandBuffer cmd; + byte *data; +} qfv_capture_image_t; + +typedef struct qfv_capture_image_set_s + DARRAY_TYPE (qfv_capture_image_t) qfv_capture_image_set_t; + +#define QFV_AllocCaptureImageSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_capture_image_set_t, num, allocator) + +typedef struct qfv_capture_s { + struct qfv_device_s *device; + + int canBlit; + VkExtent2D extent; + qfv_capture_image_set_t *image_set; + size_t memsize; + VkDeviceMemory memory; +} qfv_capture_t; + +struct qfv_swapchain_s; + +qfv_capture_t *QFV_CreateCapture (struct qfv_device_s *device, int numframes, + struct qfv_swapchain_s *swapchain, + VkCommandPool cmdPool); +void QFV_RenewCapture (qfv_capture_t *capture, + struct qfv_swapchain_s *swapchain); +void QFV_DestroyCapture (qfv_capture_t *capture); + +VkCommandBuffer QFV_CaptureImage (qfv_capture_t *capture, VkImage scImage, + int frame); +const byte *QFV_CaptureData (qfv_capture_t *capture, int frame) __attribute__((pure)); + +#endif//__QF_Vulkan_capture_h diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h new file mode 100644 index 000000000..c9ed3021e --- /dev/null +++ b/include/QF/Vulkan/command.h @@ -0,0 +1,47 @@ +#ifndef __QF_Vulkan_command_h +#define __QF_Vulkan_command_h + +#include "QF/darray.h" + +typedef struct qfv_cmdbufferset_s + DARRAY_TYPE (VkCommandBuffer) qfv_cmdbufferset_t; + +#define QFV_AllocCommandBufferSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_cmdbufferset_t, num, allocator) + +typedef struct qfv_semaphoreset_s + DARRAY_TYPE (VkSemaphore) qfv_semaphoreset_t; + +typedef struct qfv_fenceset_s + DARRAY_TYPE (VkFence) qfv_fenceset_t; + +#define QFV_AllocFenceSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_fenceset_t, num, allocator) + +typedef struct qfv_bufferimagecopy_s + DARRAY_TYPE (VkBufferImageCopy) qfv_bufferimagecopy_t; + +#define QFV_AllocBufferImageCopy(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_bufferimagecopy_t, num, allocator) + +struct qfv_queue_s; +struct qfv_device_s; +VkCommandPool QFV_CreateCommandPool (struct qfv_device_s *device, + uint32_t queueFamily, + int transient, int reset); +/** Allocate bufferset->size command buffers + */ +int QFV_AllocateCommandBuffers (struct qfv_device_s *device, + VkCommandPool pool, int secondary, + qfv_cmdbufferset_t *bufferset); + +VkSemaphore QFV_CreateSemaphore (struct qfv_device_s *device); +VkFence QFV_CreateFence (struct qfv_device_s *device, int signaled); +int QFV_QueueSubmit (struct qfv_queue_s *queue, + qfv_semaphoreset_t *waitSemaphores, + VkPipelineStageFlags *stages, + qfv_cmdbufferset_t *buffers, + qfv_semaphoreset_t *signalSemaphores, VkFence fence); +int QFV_QueueWaitIdle (struct qfv_queue_s *queue); + +#endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/cvars.h b/include/QF/Vulkan/cvars.h new file mode 100644 index 000000000..54a34048b --- /dev/null +++ b/include/QF/Vulkan/cvars.h @@ -0,0 +1,8 @@ +#ifndef __QF_Vulkan_cvars_h +#define __QF_Vulkan_cvars_h + +extern struct cvar_s *vulkan_use_validation; +extern struct cvar_s *vulkan_presentation_mode; +extern struct cvar_s *vulkan_frame_count; + +#endif//__QF_Vulkan_cvars_h diff --git a/include/QF/Vulkan/debug.h b/include/QF/Vulkan/debug.h new file mode 100644 index 000000000..3250d5aca --- /dev/null +++ b/include/QF/Vulkan/debug.h @@ -0,0 +1,115 @@ +#ifndef __QF_Vulkan_debug_h +#define __QF_Vulkan_debug_h + +#define QFV_duCmdBeginLabel(device, cmd, name...)\ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkCmdBeginDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkCmdBeginDebugUtilsLabelEXT (cmd, &label); \ + } \ + } while (0) + +#define QFV_duCmdEndLabel(device, cmd) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkCmdEndDebugUtilsLabelEXT) { \ + dfunc->vkCmdEndDebugUtilsLabelEXT (cmd); \ + } \ + } while (0) + +#define QFV_duCmdInsertLabel(device, cmd, name...) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkCmdInsertDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkCmdInsertDebugUtilsLabelEXT (cmd, &label); \ + } \ + } while (0) + +#define QFV_duCreateMessenger(inst, severity, type, callback, data, messenger)\ + do { \ + if (inst->funcs->vkCreateDebugUtilsMessengerEXT) { \ + VkDebugUtilsMessengerCreateInfoEXT createInfo = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 0, 0,\ + severity, type, callback, data \ + }; \ + inst->funcs->vkCreateDebugUtilsMessengerEXT (inst, &createInfo, 0,\ + messenger); \ + } \ + } while (0) + +#define QFV_duDestroyMessenger(inst, messenger) \ + do { \ + if (inst->funcs->vkDestroyDebugUtilsMessengerEXT) { \ + inst->funcs->vkDestroyDebugUtilsMessengerEXT (inst, messenger, 0);\ + } \ + } while (0) + +#define QFV_duQueueBeginLabel(device, queue, name...) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkQueueBeginDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkQueueBeginDebugUtilsLabelEXT (queue, &label); \ + } \ + } while (0) + +#define QFV_duQueueEndLabel(device, queue) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkQueueEndDebugUtilsLabelEXT) { \ + dfunc->vkQueueEndDebugUtilsLabelEXT (queue); \ + } \ + } while (0) + +#define QFV_duQueueInsertLabel(device, queue, name...) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkQueueInsertDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkQueueInsertDebugUtilsLabelEXT (queue, &label); \ + } \ + } while (0) + +#define QFV_duSetObjectName(device, type, handle, name) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkSetDebugUtilsObjectNameEXT) { \ + VkDebugUtilsObjectNameInfoEXT nameInfo = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 0, \ + type, (uint64_t) handle, name \ + }; \ + dfunc->vkSetDebugUtilsObjectNameEXT (device->dev, &nameInfo); \ + } \ + } while (0) + +#define QFV_duSetObjectTag(device, type, handle, name, size, tag) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkSetDebugUtilsObjectTagEXT) { \ + VkDebugUtilsObjectTagInfoEXT tagInfo = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT, 0, \ + type, handle, name, size, tag \ + }; \ + dfunc->vkSetDebugUtilsObjectTagEXT (device->dev, &tagInfo); \ + } \ + } while (0) + +#define QFV_duSubmitMessage(inst, severity, types, data) \ + do { \ + if (inst->funcs->vkSubmitDebugUtilsMessageEXT) { \ + inst->funcs->vkSubmitDebugUtilsMessageEXT (inst, severity, types, \ + data); \ + } \ + } while (0) + +#endif//__QF_Vulkan_debug_h diff --git a/include/QF/Vulkan/descriptor.h b/include/QF/Vulkan/descriptor.h new file mode 100644 index 000000000..6dd09bff4 --- /dev/null +++ b/include/QF/Vulkan/descriptor.h @@ -0,0 +1,62 @@ +#ifndef __QF_Vulkan_descriptor_h +#define __QF_Vulkan_descriptor_h + +#include "QF/darray.h" + +typedef struct qfv_bindingset_s + DARRAY_TYPE (VkDescriptorSetLayoutBinding) qfv_bindingset_t; + +typedef struct qfv_descriptorsetlayoutset_s + DARRAY_TYPE (VkDescriptorSetLayout) qfv_descriptorsetlayoutset_t; + +#define QFV_AllocDescriptorSetLayoutSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_descriptorsetlayoutset_t, num, allocator) + +typedef struct qfv_descriptorsets_s + DARRAY_TYPE (VkDescriptorSet) qfv_descriptorsets_t; + +#define QFV_AllocDescriptorSets(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_descriptorsets_t, num, allocator) + +typedef struct qfv_writedescriptorsets_s + DARRAY_TYPE (VkWriteDescriptorSet) qfv_writedescriptorsets_t; + +#define QFV_AllocWriteDescriptorSets(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_writedescriptorsets_t, num, allocator) + +typedef struct qfv_copydescriptorsets_s + DARRAY_TYPE (VkCopyDescriptorSet) qfv_copydescriptorsets_t; + +#define QFV_AllocCopyDescriptorSets(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_descriptorsetlayoutset_t, num, allocator) + +struct qfv_device_s; + +VkSampler QFV_CreateSampler (struct qfv_device_s *device, + VkFilter magFilter, VkFilter minFilter, + VkSamplerMipmapMode mipmapMode, + VkSamplerAddressMode addressModeU, + VkSamplerAddressMode addressModeV, + VkSamplerAddressMode addressModeW, + float mipLodBias, + VkBool32 anisotryEnable, float maxAnisotropy, + VkBool32 compareEnable, VkCompareOp compareOp, + float minLod, float maxLod, + VkBorderColor borderColor, + VkBool32 unnormalizedCoordinates); + +VkDescriptorSetLayout +QFV_CreateDescriptorSetLayout (struct qfv_device_s *device, + qfv_bindingset_t *bindings); + +VkDescriptorPool +QFV_CreateDescriptorPool (struct qfv_device_s *device, + VkDescriptorPoolCreateFlags flags, uint32_t maxSets, + qfv_bindingset_t *bindings); + +qfv_descriptorsets_t * +QFV_AllocateDescriptorSet (struct qfv_device_s *device, + VkDescriptorPool pool, + qfv_descriptorsetlayoutset_t *layouts); + +#endif//__QF_Vulkan_descriptor_h diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h new file mode 100644 index 000000000..2ebc7b1d9 --- /dev/null +++ b/include/QF/Vulkan/device.h @@ -0,0 +1,39 @@ +#ifndef __QF_Vulkan_device_h +#define __QF_Vulkan_device_h + +typedef struct qfv_devfuncs_s { +#define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#include "QF/Vulkan/funclist.h" +} qfv_devfuncs_t; + +typedef struct qfv_queue_s { + struct qfv_device_s *device; + + int32_t queueFamily; + VkQueue queue; +} qfv_queue_t; + +struct qfv_instance_s; +typedef struct qfv_device_s { + VkDevice dev; + struct qfv_physdev_s *physDev; + qfv_devfuncs_t *funcs; + qfv_queue_t queue; + struct strset_s *enabled_extensions; + int (*extension_enabled) (struct qfv_device_s *inst, + const char *ext); +} qfv_device_t; + +struct vulkan_ctx_s; +qfv_device_t *QFV_CreateDevice (struct vulkan_ctx_s *ctx, + const char **extensions); +void QFV_DestroyDevice (qfv_device_t *device); +int QFV_DeviceWaitIdle (qfv_device_t *device); + +VkFormat QFV_FindSupportedFormat (qfv_device_t *device, VkImageTiling tiling, + VkFormatFeatureFlags features, + int numCandidates, + const VkFormat *candidates); + +#endif//__QF_Vulkan_device_h diff --git a/include/QF/Vulkan/draw.h b/include/QF/Vulkan/draw.h new file mode 100644 index 000000000..8f6b78889 --- /dev/null +++ b/include/QF/Vulkan/draw.h @@ -0,0 +1,237 @@ +/* + draw.h + + Video buffer handling definitions and prototypes + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_draw_h +#define __QF_draw_h + +/** \defgroup video Video Sub-sytem */ + +/** \defgroup video_renderer Renderer Sub-system + \ingroup video +*/ + +/** \defgroup video_renderer_draw Generic draw functions + \ingroup video_renderer +*/ +///@{ + +#include "QF/wad.h" + +extern byte *draw_chars; + +/** Initialize the draw stuff. +*/ +void Draw_Init (void); + +/** Draws one 8*8 graphics character with 0 being transparent. + It can be clipped to the top of the screen to allow the console to be + smoothly scrolled off. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param ch 8 bit character to draw. + \note The character drawn is from the quake character set, which is + (by default) standard ascii for 0x20-0x7e (white). 0xa0-0xfe is + also standard ascii (brown). 0x01-0x1f and 0x80-0x9f are + various drawing characters, and 0x7f is a backwards arrow. +*/ +void Draw_Character (int x, int y, unsigned ch); + +/** Draws a character string to the screen. + No line wrapping is performed. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param str 8 bit character string to draw. + \note See Draw_Character() for character set description. + String is normal nul terminated C string. +*/ +void Draw_String (int x, int y, const char *str); + +/** Draws a character sub-string to the screen. + No line wrapping is performed. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param str 8 bit character string to draw. + \param count Maximum characters of the string to draw. + \note See Draw_Character() for character set description. + Draws up to \p count characters, or stops at the first nul + character. +*/ +void Draw_nString (int x, int y, const char *str, int count); + +/** Draws a character string to the screen. + No line wrapping is performed. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param str 8 bit character string to draw. + \note See Draw_Character() for character set description. + String is normal nul terminated C string. + Characters of the string are forced to have their high bit set + (ie, they will be in the range 0x80-0xff). +*/ +void Draw_AltString (int x, int y, const char *str); + +/** Draw the console background with various optional effects. + \param lines Vertical size in pixels of the console. + \param alpha Console transparency level (255 = opaque). + \note \p alpha is effective only in the OpenGL renderer. Effectively + 255 (opaque) for the software renderer. + + \c gl_conspin causes the background to spin. + + \c gl_constretch causes the background to stretch rather than slide. +*/ +void Draw_ConsoleBackground (int lines, byte alpha); + +/** Draw a crosshair at the center of the screen. + \c crosshair specifies which crosshair (1 = '+', 2 = large 'x' shape, + 3 = fancy '+' shape) + \c cl_crossx and \c cl_crossy offset the crosshair from the center of the + screen. +*/ +void Draw_Crosshair (void); + +/** Draw the specified crosshair on the screen. + \param ch crosshair to draw + \param x horizontal position of the center of the crosshair. + \param y vertical position of the center of the crosshair. + + See Draw_Crosshair() for description of crosshair values. +*/ +void Draw_CrosshairAt (int ch, int x, int y); + +/** Clear a rectangle with a tiled background. + \param x horizontal position of the upper left corner of the rectangle + \param y horizontal position of the upper left corner of the rectangle + \param w width of the rectangle + \param h height of the rectangle + + The background used is the "backtile" WAD lump. +*/ +void Draw_TileClear (int x, int y, int w, int h); + +/** Clear a rectangle with a solid color. + \param x horizontal position of the upper left corner of the rectangle + \param y horizontal position of the upper left corner of the rectangle + \param w width of the rectangle + \param h height of the rectangle + \param c 8 bit color index. + + The color comes from the quake palette. +*/ +void Draw_Fill (int x, int y, int w, int h, int c); + +/** Draw a text box on the screen + \param x horizontal location of the upper left corner of the box + \param y vertical location of the upper left corner of the box + \param width horizontal size in character cells of the region + \param lines vertical size in character cells of the region + \param alpha transparency of the box +*/ +void Draw_TextBox (int x, int y, int width, int lines, byte alpha); + +/** Darken the screen. +*/ +void Draw_FadeScreen (void); + +/** Shift the screen colors. +*/ +void Draw_BlendScreen (quat_t color); +///@} + +/** \defgroup video_renderer_draw_qpic QPic functions + \ingroup video_renderer_draw +*/ +///@{ +/** Load a qpic from the filesystem. + \param path path of the file within the quake filesystem + \param alpha transparency level of the pic. + \return pointer qpic data. + \note Up to MAX_CACHED_PICS qpics can be loaded at a time this way +*/ +qpic_t *Draw_CachePic (const char *path, qboolean alpha); + +/** Remove a qpic from the qpic cache. + + This affects only those qpics that were loaded via Draw_CachePic. + + \param path path of the file within the quake filesystem +*/ +void Draw_UncachePic (const char *path); + +/** Create a qpic from raw data. + + \param width The width of the pic. + \param height The height of the pic. + \param data The raw data bytes. The system palette will be used for + colors. + \return pointer qpic data. +*/ +qpic_t *Draw_MakePic (int width, int height, const byte *data); + +/** Destroy a qpic created by Draw_MakePic. + + \param pic The qpic to destory. +*/ +void Draw_DestroyPic (qpic_t *pic); + +/** Load a qpic from gfx.wad. + \param name name of the was lump to load + \return pointer qpic data. +*/ +qpic_t *Draw_PicFromWad (const char *name); + +/** Draw a qpic to the screen + \param x horizontal location of the upper left corner of the qpic + \param y vertical location of the upper left corner of the qpic + \param pic qpic to draw +*/ +void Draw_Pic (int x, int y, qpic_t *pic); + +/** Draw a qpic to the screen + \param x horizontal location of the upper left corner of the qpic + \param y vertical location of the upper left corner of the qpic + \param pic qpic to draw +*/ +void Draw_Picf (float x, float y, qpic_t *pic); + +/** Draw a sub-region of a qpic to the screan + \param x horizontal screen location of the upper left corner of the + sub-region + \param y vertical screen location of the upper left corner of the + sub-region + \param pic qpic to draw + \param srcx horizontal qpic location of the upper left corner of the + sub-region + \param srcy vertical qpic location of the upper left corner of the + sub-region + \param width horizontal size of the sub-region to be drawn + \param height vertical size of the sub-region to be drawn +*/ +void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); +///@} + +#endif//__QF_draw_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h new file mode 100644 index 000000000..9e5af1ef1 --- /dev/null +++ b/include/QF/Vulkan/funclist.h @@ -0,0 +1,220 @@ +#ifndef EXPORTED_VULKAN_FUNCTION +#define EXPORTED_VULKAN_FUNCTION(function) +#endif + +EXPORTED_VULKAN_FUNCTION (vkGetInstanceProcAddr) + +#undef EXPORTED_VULKAN_FUNCTION + +#ifndef GLOBAL_LEVEL_VULKAN_FUNCTION +#define GLOBAL_LEVEL_VULKAN_FUNCTION(function) +#endif + +GLOBAL_LEVEL_VULKAN_FUNCTION (vkEnumerateInstanceVersion) +GLOBAL_LEVEL_VULKAN_FUNCTION (vkEnumerateInstanceExtensionProperties) +GLOBAL_LEVEL_VULKAN_FUNCTION (vkEnumerateInstanceLayerProperties) +GLOBAL_LEVEL_VULKAN_FUNCTION (vkCreateInstance) + +#undef GLOBAL_LEVEL_VULKAN_FUNCTION + +#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION +#define INSTANCE_LEVEL_VULKAN_FUNCTION(function) +#endif + +INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumeratePhysicalDevices) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFeatures) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceQueueFamilyProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateDevice) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetDeviceProcAddr) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceLayerProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceExtensionProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFormatProperties) + +#undef INSTANCE_LEVEL_VULKAN_FUNCTION + +#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) +#endif + +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkDestroyDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkSubmitDebugUtilsMessageEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfaceSupportKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfacePresentModesKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkDestroySurfaceKHR, VK_KHR_SURFACE_EXTENSION_NAME) + +#undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + +#ifndef PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION +#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) +#endif + +#if defined(VK_USE_PLATFORM_XLIB_KHR) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceXlibPresentationSupportKHR, + VK_KHR_XLIB_SURFACE_EXTENSION_NAME) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateXlibSurfaceKHR, + VK_KHR_XLIB_SURFACE_EXTENSION_NAME) +#elif defined(VK_USE_PLATFORM_WIN32_KHR) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceWin32PresentationSupportKHR, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateWin32SurfaceKHR, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME) +#elif defined(VK_USE_PLATFORM_XCB_KHR) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceXcbPresentationSupportKHR, + VK_KHR_XCB_SURFACE_EXTENSION_NAME) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateXcbSurfaceKHR, + VK_KHR_XCB_SURFACE_EXTENSION_NAME) +#endif + +#undef PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + +#ifndef DEVICE_LEVEL_VULKAN_FUNCTION +#define DEVICE_LEVEL_VULKAN_FUNCTION(function) +#endif + +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDevice) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateCommandPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetCommandPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateCommandBuffers) +DEVICE_LEVEL_VULKAN_FUNCTION (vkBeginCommandBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkEndCommandBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetCommandBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateSemaphore) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateFence) +DEVICE_LEVEL_VULKAN_FUNCTION (vkWaitForFences) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetFences) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetFenceStatus) +DEVICE_LEVEL_VULKAN_FUNCTION (vkQueueSubmit) +DEVICE_LEVEL_VULKAN_FUNCTION (vkQueueWaitIdle) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDeviceWaitIdle) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyFence) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroySemaphore) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeCommandBuffers) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyCommandPool) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetBufferMemoryRequirements) +DEVICE_LEVEL_VULKAN_FUNCTION (vkBindBufferMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBufferView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyBufferView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyBuffer) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetImageMemoryRequirements) +DEVICE_LEVEL_VULKAN_FUNCTION (vkBindImageMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateImageView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyImageView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyImage) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkMapMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkUnmapMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFlushMappedMemoryRanges) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateSampler) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateDescriptorSetLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateDescriptorPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkUpdateDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetDescriptorPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDescriptorPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDescriptorSetLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroySampler) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateFramebuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyFramebuffer) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateShaderModule) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyShaderModule) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreatePipelineCache) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetPipelineCacheData) +DEVICE_LEVEL_VULKAN_FUNCTION (vkMergePipelineCaches) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyPipelineCache) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreatePipelineLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyPipelineLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateGraphicsPipelines) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateComputePipelines) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyPipeline) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBufferToImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyImageToBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBlitImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBeginRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdNextSubpass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdEndRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindPipeline) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdClearColorImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdExecuteCommands) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPushConstants) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPushDescriptorSetKHR) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetViewport) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetScissor) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindVertexBuffers) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindIndexBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdDraw) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdDrawIndexed) + +#undef DEVICE_LEVEL_VULKAN_FUNCTION + +#ifndef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) +#endif + +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateSwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkDestroySwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetSwapchainImagesKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkAcquireNextImageKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueuePresentKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) + +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCmdBeginDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCmdEndDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCmdInsertDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueueBeginDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueueEndDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueueInsertDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkSetDebugUtilsObjectNameEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkSetDebugUtilsObjectTagEXT, 0) + +#undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h new file mode 100644 index 000000000..5e4866952 --- /dev/null +++ b/include/QF/Vulkan/image.h @@ -0,0 +1,98 @@ +#ifndef __QF_Vulkan_image_h +#define __QF_Vulkan_image_h + +#include "QF/darray.h" + +typedef struct qfv_imageset_s + DARRAY_TYPE (VkImage) qfv_imageset_t; + +#define QFV_AllocImages(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_imageset_t, num, allocator) + +typedef struct qfv_imageviewset_s + DARRAY_TYPE (VkImageView) qfv_imageviewset_t; + +#define QFV_AllocImageViews(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_imageviewset_t, num, allocator) + +typedef struct qfv_imageresource_s { + struct qfv_device_s *device; + VkImage image; + VkDeviceMemory object; + VkImageView view; +} qfv_imageresource_t; + +typedef struct qfv_imagetransition_s { + VkImage image; + VkAccessFlags srcAccess; + VkAccessFlags dstAccess; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamily; + uint32_t dstQueueFamily; + VkImageAspectFlags aspect; +} qfv_imagetransition_t; + +typedef struct qfv_imagetransitionset_s + DARRAY_TYPE (qfv_imagetransition_t) qfv_imagetransitionset_t; +typedef struct qfv_imagebarrierset_s + DARRAY_TYPE (VkImageMemoryBarrier) qfv_imagebarrierset_t; +#define QFV_AllocImageBarrierSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_imagebarrierset_t, num, allocator) + +struct qfv_device_s; +VkImage QFV_CreateImage (struct qfv_device_s *device, int cubemap, + VkImageType type, + VkFormat format, + VkExtent3D size, + uint32_t num_mipmaps, + uint32_t num_layers, + VkSampleCountFlags samples, + VkImageUsageFlags usage_scenarios); + +VkDeviceMemory QFV_AllocImageMemory (struct qfv_device_s *device, + VkImage image, + VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset); + +int QFV_BindImageMemory (struct qfv_device_s *device, VkImage image, + VkDeviceMemory object, VkDeviceSize offset); + +qfv_imagebarrierset_t * +QFV_CreateImageTransitionSet (qfv_imagetransition_t *transitions, + int numTransitions); + +VkImageView QFV_CreateImageView (struct qfv_device_s *device, + VkImage image, VkImageViewType type, + VkFormat format, VkImageAspectFlags aspect); + +size_t QFV_GetImageSize (struct qfv_device_s *device, VkImage image); + +/** Generate all mipmaps for a given texture down to a 1x1 pixel. + * + * Uses the GPU blit command from one mip level to the next, thus the base mip + * level data must have already been transfered to the image and the image is + * expected to be in VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. This includes any + * array levels. + * + * \param device The device owning the command buffer. + * \param cmd The command buffer to which the barrier and blit commands + * will be written. + * \param image The image to be processed. All array layers of the base mip + * level must be initialized and in "transfer dst optimal" + * layout. All remaining mip levels must be in "undefined" + * oayout. + * \param mips The total number of mip levels of the processed image. + * \param width The pixel width of the base image. + * \param height The pixel height of the base image. + * \param layers The number of array layers in the mbase image. + * + * \note The processed image will be in "shader read only optimal" layout on + * completion. + */ +void QFV_GenerateMipMaps (struct qfv_device_s *device, VkCommandBuffer cmd, + VkImage image, unsigned mips, + unsigned width, unsigned height, unsigned layers); +int QFV_MipLevels (int width, int height) __attribute__((const)); + +#endif//__QF_Vulkan_image_h diff --git a/include/QF/Vulkan/instance.h b/include/QF/Vulkan/instance.h new file mode 100644 index 000000000..4df1827c5 --- /dev/null +++ b/include/QF/Vulkan/instance.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2019 Bill Currie + + Author: Bill Currie + Date: 2019/6/29 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_instance_h +#define __QF_Vulkan_instance_h + +#include + +#include "QF/qtypes.h" + +typedef struct qfv_instfuncs_s { +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#include "QF/Vulkan/funclist.h" +} qfv_instfuncs_t; + +typedef struct qfv_physdev_s { + struct qfv_instance_s *instance; + VkPhysicalDevice dev; + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceMemoryProperties memory_properties; +} qfv_physdev_t; + +typedef struct qfv_instance_s { + VkInstance instance; + qfv_instfuncs_t *funcs; + struct strset_s *enabled_extensions; + int (*extension_enabled) (struct qfv_instance_s *inst, + const char *ext); + VkDebugUtilsMessengerEXT debug_handle; + uint32_t numDevices; + qfv_physdev_t *devices; +} qfv_instance_t; + +struct vulkan_ctx_s; +qfv_instance_t *QFV_CreateInstance (struct vulkan_ctx_s *ctx, + const char *appName, + uint32_t appVersion, + const char **layers, + const char **extensions); +void QFV_DestroyInstance (qfv_instance_t *instance); + +VkSampleCountFlagBits QFV_GetMaxSampleCount (qfv_physdev_t *physdev); + +#endif // __QF_Vulkan_instance_h diff --git a/include/QF/Vulkan/memory.h b/include/QF/Vulkan/memory.h new file mode 100644 index 000000000..91885d31b --- /dev/null +++ b/include/QF/Vulkan/memory.h @@ -0,0 +1,22 @@ +#ifndef __QF_Vulkan_memory_h +#define __QF_Vulkan_memory_h + +#include "QF/darray.h" + +typedef struct qfv_mappedmemrange_s { + VkDeviceMemory object; + VkDeviceSize offset; + VkDeviceSize size; +} qfv_mappedmemrange_t; + +typedef struct qfv_mappedmemrangeset_s + DARRAY_TYPE (qfv_mappedmemrange_t) qfv_mappedmemrangeset_t; + +struct qfv_device_s; + +void *QFV_MapMemory (struct qfv_device_s *device, VkDeviceMemory object, + VkDeviceSize offset, VkDeviceSize size); +void QFV_FlushMemory (struct qfv_device_s *device, + qfv_mappedmemrangeset_t *ranges); + +#endif//__QF_Vulkan_memory_h diff --git a/include/QF/Vulkan/pipeline.h b/include/QF/Vulkan/pipeline.h new file mode 100644 index 000000000..bd6e292a9 --- /dev/null +++ b/include/QF/Vulkan/pipeline.h @@ -0,0 +1,156 @@ +#ifndef __QF_Vulkan_pipeline_h +#define __QF_Vulkan_pipeline_h + +#include "QF/darray.h" + +typedef struct qfv_pipelineshaderstateset_s + DARRAY_TYPE (VkPipelineShaderStageCreateInfo) qfv_pipelineshaderstateset_s; + +#define QFV_AllocPipelineShaderStageSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_pipelineshaderstateset_s, num, allocator) + +typedef struct qfv_vertexinputbindingset_s + DARRAY_TYPE (VkVertexInputBindingDescription) qfv_vertexinputbindingset_t; + +#define QFV_AllocVertexInputBindingSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_vertexinputbindingset_t, num, allocator) + +typedef struct qfv_vertexinputattributeset_s + DARRAY_TYPE (VkVertexInputAttributeDescription) + qfv_vertexinputattributeset_t; + +#define QFV_AllocVertexInputAttributeSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_vertexinputattributeset_t, num, allocator) + +typedef struct qfv_vertexinputstate_s { + qfv_vertexinputbindingset_t *bindings; + qfv_vertexinputattributeset_t *attributes; +} qfv_vertexinputstate_t; + +typedef struct qfv_pipelineinputassembly_s { + VkPrimitiveTopology topology; + VkBool32 primativeRestartEnable; +} qfv_pipelineinputassembly_t; + +typedef struct qfv_pipelinetessellation_s { + uint32_t patchControlPoints; +} qfv_pipelinetessellation_t; + +typedef struct qfv_viewportset_s DARRAY_TYPE (VkViewport) qfv_viewportset_t; + +#define QFV_AllocViewportSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_viewportset_t, num, allocator) + +typedef struct qfv_scissorsset_s DARRAY_TYPE (VkRect2D) qfv_scissorsset_t; + +#define QFV_AllocScissorsSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_scissorsset_t, num, allocator) + +typedef struct qfv_viewportinfo_s { + qfv_viewportset_t *viewportset; + qfv_scissorsset_t *scissorsset; +} qfv_viewportinfo_t; + +typedef struct qfv_pipelinerasterization_s { + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} qfv_pipelinerasterization_t; + +typedef struct qfv_pipelinemultisample_s { + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask *sampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} qfv_pipelinemultisample_t; + +typedef struct qfv_pipelinedepthandstencil_s { + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} qfv_pipelinedepthandstencil_t; + +typedef struct qfv_blendattachmentset_s + DARRAY_TYPE (VkPipelineColorBlendAttachmentState) qfv_blendattachmentset_t; + +#define QFV_AllocBlendAttachmentSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_blendattachmentset_t, num, allocator) + +typedef struct qfv_dynamicstateset_s + DARRAY_TYPE (VkDynamicState) qfv_dynamicstateset_t; + +#define QFV_AllocDynamicStateSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_dynamicstateset_t, num, allocator) + +typedef struct qfv_pushconstantrangeset_s + DARRAY_TYPE (VkPushConstantRange) qfv_pushconstantrangeset_t; + +#define QFV_AllocPushConstantRangeSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_pushconstantrangeset_t, num, allocator) + +typedef struct qfv_pipelineset_s DARRAY_TYPE (VkPipeline) qfv_pipelineset_t; + +#define QFV_AllocPipelineSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_pipelineset_t, num, allocator) + +typedef struct qfv_graphicspipelinecreateinfoset_s + DARRAY_TYPE (VkGraphicsPipelineCreateInfo) + qfv_graphicspipelinecreateinfoset_t; + +#define QFV_AllocGraphicsPipelineCreateInfoSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_graphicspipelinecreateinfoset_t, num, allocator) + +typedef struct qfv_computepipelinecreateinfoset_s + DARRAY_TYPE (VkComputePipelineCreateInfo) + qfv_computepipelinecreateinfoset_t; + +#define QFV_AllocComputePipelineCreateInfoSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_computepipelinecreateinfoset_t, num, allocator) + +typedef struct qfv_pipelinecacheset_s + DARRAY_TYPE (VkPipelineCache) qfv_pipelinecacheset_t; + +#define QFV_AllocPipelineCacheSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_pipelinecacheset_t, num, allocator) + +struct dstring_s; +VkPipelineCache QFV_CreatePipelineCache (struct qfv_device_s *device, + struct dstring_s *cacheData); +struct dstring_s *QFV_GetPipelineCacheData (struct qfv_device_s *device, + VkPipelineCache cache); +void QFV_MergePipelineCaches (struct qfv_device_s *device, + VkPipelineCache targetCache, + qfv_pipelinecacheset_t *sourceCaches); + +struct qfv_descriptorsetlayoutset_s; +VkPipelineLayout +QFV_CreatePipelineLayout (struct qfv_device_s *device, + struct qfv_descriptorsetlayoutset_s *layouts, + qfv_pushconstantrangeset_t *pushConstants); +qfv_pipelineset_t * +QFV_CreateGraphicsPipelines (struct qfv_device_s *device, + VkPipelineCache cache, + qfv_graphicspipelinecreateinfoset_t *gpciSet); +qfv_pipelineset_t * +QFV_CreateComputePipelines (struct qfv_device_s *device, + VkPipelineCache cache, + qfv_computepipelinecreateinfoset_t *cpciSet); +void +QFV_DestroyPipeline (struct qfv_device_s *device, VkPipeline pipeline); + +#endif//__QF_Vulkan_pipeline_h diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h new file mode 100644 index 000000000..7cd5b5bad --- /dev/null +++ b/include/QF/Vulkan/qf_alias.h @@ -0,0 +1,116 @@ +/* + qf_alias.h + + Vulkan specific alias model stuff + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/18 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_alias_h +#define __QF_Vulkan_qf_alias_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/modelgen.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" + +typedef struct aliasvrt_s { + float vertex[4]; + float normal[4]; +} aliasvrt_t; + +typedef struct aliasuv_s { + float u, v; +} aliasuv_t; + +typedef struct qfv_alias_mesh_s { + VkBuffer vertex_buffer; + VkBuffer uv_buffer; + VkBuffer index_buffer; + VkDeviceMemory memory; +} qfv_alias_mesh_t; + +typedef struct qfv_alias_skin_s { + VkDeviceMemory memory; + VkImage image; + VkImageView view; + byte colora[4]; + byte colorb[4]; +} qfv_alias_skin_t; + +#define ALIAS_BUFFER_INFOS 1 +#define ALIAS_IMAGE_INFOS 1 + +typedef enum { + QFV_aliasDepth, + QFV_aliasGBuffer, + QFV_aliasTranslucent, + + QFV_aliasNumPasses +} QFV_AliasSubpass; + +typedef struct aliasframe_s { + qfv_cmdbufferset_t cmdSet; + VkDescriptorBufferInfo bufferInfo[ALIAS_BUFFER_INFOS]; + VkDescriptorImageInfo imageInfo[ALIAS_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[ALIAS_BUFFER_INFOS + ALIAS_IMAGE_INFOS]; +} aliasframe_t; + +typedef struct aliasframeset_s + DARRAY_TYPE (aliasframe_t) aliasframeset_t; + +typedef struct aliasctx_s { + aliasframeset_t frames; + VkPipeline depth; + VkPipeline gbuf; + VkPipelineLayout layout; + VkSampler sampler; +} aliasctx_t; + +struct vulkan_ctx_s; +struct entity_s; +struct mod_alias_ctx_s; +void *Vulkan_Mod_LoadSkin (struct mod_alias_ctx_s *alias_ctx, byte *skin, + int skinsize, int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_FinalizeAliasModel (struct mod_alias_ctx_s *alias_ctx, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_LoadExternalSkins (struct mod_alias_ctx_s *alias_ctx, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_MakeAliasModelDisplayLists (struct mod_alias_ctx_s *alias_ctx, + void *_m, int _s, int extra, + struct vulkan_ctx_s *ctx); + +void Vulkan_AliasBegin (struct vulkan_ctx_s *ctx); +void Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx); +void Vulkan_AliasEnd (struct vulkan_ctx_s *ctx); + +void Vulkan_Alias_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_alias_h diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h new file mode 100644 index 000000000..6c69f2586 --- /dev/null +++ b/include/QF/Vulkan/qf_bsp.h @@ -0,0 +1,175 @@ +/* + qf_bsp.h + + Vulkan specific brush model stuff + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/18 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_bsp_h +#define __QF_Vulkan_qf_bsp_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" + +typedef struct bspvert_s { + quat_t vertex; + quat_t tlst; +} bspvert_t; + +typedef struct elements_s { + struct elements_s *_next; + struct elements_s *next; + uint32_t first_index; + uint32_t index_count; +} elements_t; + +typedef struct elechain_s { + struct elechain_s *_next; + struct elechain_s *next; + int index; + elements_t *elements; + vec_t *transform; + float *color; +} elechain_t; + +typedef enum { + qfv_bsp_texture, + qfv_bsp_glowmap, + qfv_bsp_lightmap, + qfv_bsp_skysheet, + qfv_bsp_skycube, +} qfv_bsp_tex; +// view matrix +#define BSP_BUFFER_INFOS 1 +// Texture, GlowMap, LightMap, SkySheet, SkyCube +#define BSP_IMAGE_INFOS 5 + +typedef enum { + QFV_bspDepth, + QFV_bspGBuffer, + QFV_bspSky, + QFV_bspTurb, + + QFV_bspNumPasses +} QFV_BspSubpass; + +typedef struct bspframe_s { + uint32_t *index_data; // pointer into mega-buffer for this frame (c) + uint32_t index_offset; // offset of index_data within mega-buffer (c) + uint32_t index_count; // number if indices queued (d) + qfv_cmdbufferset_t cmdSet; + VkDescriptorBufferInfo bufferInfo[BSP_BUFFER_INFOS]; + VkDescriptorImageInfo imageInfo[BSP_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[BSP_BUFFER_INFOS + BSP_IMAGE_INFOS]; +} bspframe_t; + +typedef struct fragconst_s { + quat_t fog; + float time; +} fragconst_t; + +typedef struct bspframeset_s + DARRAY_TYPE (bspframe_t) bspframeset_t; + +typedef struct texchainset_s + DARRAY_TYPE (struct vulktex_s *) texchainset_t; + +typedef struct bspctx_s { + instsurf_t *waterchain; + instsurf_t **waterchain_tail; + instsurf_t *sky_chain; + instsurf_t **sky_chain_tail; + + texchainset_t texture_chains; + + // for world and non-instance models + instsurf_t *static_instsurfs; + instsurf_t **static_instsurfs_tail; + instsurf_t *free_static_instsurfs; + + // for instance models + elechain_t *elechains; + elechain_t **elechains_tail; + elechain_t *free_elechains; + elements_t *elementss; + elements_t **elementss_tail; + elements_t *free_elementss; + instsurf_t *instsurfs; + instsurf_t **instsurfs_tail; + instsurf_t *free_instsurfs; + + struct qfv_tex_s *default_skysheet; + struct qfv_tex_s *skysheet_tex; + + struct qfv_tex_s *default_skybox; + struct qfv_tex_s *skybox_tex; + quat_t sky_rotation[2]; + quat_t sky_velocity; + quat_t sky_fix; + double sky_time; + + quat_t default_color; + quat_t last_color; + + struct scrap_s *light_scrap; + struct qfv_stagebuf_s *light_stage; + + struct bsppoly_s *polys; + + VkSampler sampler; + VkDeviceMemory texture_memory; + VkPipeline depth; + VkPipeline gbuf; + VkPipeline skysheet; + VkPipeline skybox; + VkPipeline turb; + VkPipelineLayout layout; + size_t vertex_buffer_size; + size_t index_buffer_size; + VkBuffer vertex_buffer; + VkDeviceMemory vertex_memory; + VkBuffer index_buffer; + VkDeviceMemory index_memory; + bspframeset_t frames; +} bspctx_t; + +struct vulkan_ctx_s; +void Vulkan_ClearElements (struct vulkan_ctx_s *ctx); +void Vulkan_DrawWorld (struct vulkan_ctx_s *ctx); +void Vulkan_DrawSky (struct vulkan_ctx_s *ctx); +void Vulkan_LoadSkys (const char *sky, struct vulkan_ctx_s *ctx); +void Vulkan_RegisterTextures (model_t **models, int num_models, + struct vulkan_ctx_s *ctx); +void Vulkan_BuildDisplayLists (model_t **models, int num_models, + struct vulkan_ctx_s *ctx); +void Vulkan_Bsp_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx); +void Vulkan_DrawWaterSurfaces (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_bsp_h diff --git a/include/QF/Vulkan/qf_compose.h b/include/QF/Vulkan/qf_compose.h new file mode 100644 index 000000000..f8fd497a1 --- /dev/null +++ b/include/QF/Vulkan/qf_compose.h @@ -0,0 +1,62 @@ +/* + qf_compose.h + + Vulkan compose pass + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/24 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_compose_h +#define __QF_Vulkan_qf_compose_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/modelgen.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" + +#define COMPOSE_IMAGE_INFOS 2 + +typedef struct composeframe_s { + VkCommandBuffer cmd; + VkDescriptorImageInfo imageInfo[COMPOSE_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[COMPOSE_IMAGE_INFOS]; +} composeframe_t; + +typedef struct composeframeset_s + DARRAY_TYPE (composeframe_t) composeframeset_t; + +typedef struct composectx_s { + composeframeset_t frames; + VkPipeline pipeline; + VkPipelineLayout layout; +} composectx_t; + +struct vulkan_ctx_s; + +void Vulkan_Compose_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Compose_Shutdown (struct vulkan_ctx_s *ctx); +void Vulkan_Compose_Draw (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_compose_h diff --git a/include/QF/Vulkan/qf_draw.h b/include/QF/Vulkan/qf_draw.h new file mode 100644 index 000000000..c9e8b20ad --- /dev/null +++ b/include/QF/Vulkan/qf_draw.h @@ -0,0 +1,74 @@ +/* + qf_draw.h + + vulkan specific draw function + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_Vulkan_qf_draw_h +#define __QF_Vulkan_qf_draw_h + +struct vulkan_ctx_s; + +void Vulkan_Draw_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Shutdown (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Character (int x, int y, unsigned ch, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_String (int x, int y, const char *str, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_nString (int x, int y, const char *str, int count, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_AltString (int x, int y, const char *str, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_ConsoleBackground (int lines, byte alpha, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Crosshair (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_CrosshairAt (int ch, int x, int y, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_TileClear (int x, int y, int w, int h, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Fill (int x, int y, int w, int h, int c, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_FadeScreen (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_BlendScreen (quat_t color, struct vulkan_ctx_s *ctx); +qpic_t *Vulkan_Draw_CachePic (const char *path, qboolean alpha, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_UncachePic (const char *path, struct vulkan_ctx_s *ctx); +qpic_t *Vulkan_Draw_MakePic (int width, int height, const byte *data, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_DestroyPic (qpic_t *pic, struct vulkan_ctx_s *ctx); +qpic_t *Vulkan_Draw_PicFromWad (const char *name, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Pic (int x, int y, qpic_t *pic, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Picf (float x, float y, qpic_t *pic, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_SubPic(int x, int y, qpic_t *pic, + int srcx, int srcy, int width, int height, + struct vulkan_ctx_s *ctx); + +void Vulkan_Set2D (struct vulkan_ctx_s *ctx); +void Vulkan_Set2DScaled (struct vulkan_ctx_s *ctx); +void Vulkan_End2D (struct vulkan_ctx_s *ctx); +void Vulkan_DrawReset (struct vulkan_ctx_s *ctx); +void Vulkan_FlushText (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_draw_h diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h new file mode 100644 index 000000000..8541d367e --- /dev/null +++ b/include/QF/Vulkan/qf_lighting.h @@ -0,0 +1,98 @@ +/* + qf_lighting.h + + Vulkan lighting pass + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/23 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_lighting_h +#define __QF_Vulkan_qf_lighting_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/modelgen.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" + +typedef struct qfv_light_s { + vec3_t color; + int data; + vec3_t position; + float radius; + vec3_t direction; + float cone; +} qfv_light_t; + +typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t; +typedef struct qfv_lightleafset_s DARRAY_TYPE (int) qfv_lightleafset_t; +typedef struct qfv_lightvisset_s DARRAY_TYPE (byte) qfv_lightvisset_t; + +#define NUM_LIGHTS 256 +#define NUM_STYLES 64 + +typedef struct qfv_light_buffer_s { + float intensity[NUM_STYLES + 3]; + int lightCount; + qfv_light_t lights[NUM_LIGHTS] __attribute__((aligned(16))); +} qfv_light_buffer_t; + +#define LIGHTING_BUFFER_INFOS 1 +#define LIGHTING_IMAGE_INFOS 5 + +typedef struct lightingframe_s { + VkCommandBuffer cmd; + VkBuffer light_buffer; + VkDescriptorBufferInfo bufferInfo[LIGHTING_BUFFER_INFOS]; + VkDescriptorImageInfo imageInfo[LIGHTING_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[LIGHTING_BUFFER_INFOS + + LIGHTING_IMAGE_INFOS]; + // A fat PVS of leafs visible from visible leafs so hidden lights can + // illuminate the leafs visible to the player + byte pvs[MAP_PVS_BYTES]; + struct mleaf_s *leaf; // the last leaf used to generate the pvs + qfv_lightvisset_t lightvis; +} lightingframe_t; + +typedef struct lightingframeset_s + DARRAY_TYPE (lightingframe_t) lightingframeset_t; + +typedef struct lightingctx_s { + lightingframeset_t frames; + VkPipeline pipeline; + VkPipelineLayout layout; + VkDeviceMemory light_memory; + qfv_lightset_t lights; + qfv_lightleafset_t lightleafs; +} lightingctx_t; + +struct vulkan_ctx_s; + +void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx); +void Vulkan_Lighting_Draw (struct vulkan_ctx_s *ctx); +void Vulkan_LoadLights (model_t *model, const char *entity_data, + struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_lighting_h diff --git a/include/QF/Vulkan/qf_lightmap.h b/include/QF/Vulkan/qf_lightmap.h new file mode 100644 index 000000000..eaca4e35f --- /dev/null +++ b/include/QF/Vulkan/qf_lightmap.h @@ -0,0 +1,49 @@ +/* + qf_lightmap.h + + Vulkan lightmap stuff from the renderer. + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_Vulkan_qf_lightmap_h +#define __QF_Vulkan_qf_lightmap_h + +#define MAX_LIGHTMAPS 1024 +#define BLOCK_WIDTH 64 +#define BLOCK_HEIGHT 64 + +#include "QF/Vulkan/qf_vid.h" + +struct vulkan_ctx_s; +struct model_s; +struct mod_brush_s; +struct msurface_s; + +void Vulkan_lightmap_init (struct vulkan_ctx_s *ctx); +void Vulkan_BuildLightmaps (struct model_s **models, int num_models, struct vulkan_ctx_s *ctx); +void Vulkan_CalcLightmaps (struct vulkan_ctx_s *ctx); +void Vulkan_BuildLightMap (struct mod_brush_s *brush, struct msurface_s *surf, struct vulkan_ctx_s *ctx); +VkImageView Vulkan_LightmapImageView (struct vulkan_ctx_s *ctx) __attribute__((pure)); +void Vulkan_FlushLightmaps (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_lightmap_h diff --git a/include/QF/hl.h b/include/QF/Vulkan/qf_main.h similarity index 60% rename from include/QF/hl.h rename to include/QF/Vulkan/qf_main.h index 286768cc0..4b487da5e 100644 --- a/include/QF/hl.h +++ b/include/QF/Vulkan/qf_main.h @@ -1,9 +1,9 @@ /* - hl_bsp.h + qf_main.h - Half Life file definitions + Vulkan main stuff from the renderer. - Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2021 Bill Currie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -25,16 +25,13 @@ */ +#ifndef __QF_Vulkan_qf_main_h +#define __QF_Vulkan_qf_main_h -#ifndef _HL_BSP_H -#define _HL_BSP_H +struct vulkan_ctx_s; -#include "QF/qtypes.h" +void Vulkan_NewMap (model_t *worldmodel, struct model_s **models, + int num_models, struct vulkan_ctx_s *ctx); +void Vulkan_RenderView (struct vulkan_ctx_s *ctx); -extern void CL_ParseEntityLump(const char *entdata); -extern void HL_Mod_LoadLighting (lump_t *l); -extern void HL_Mod_LoadTextures (lump_t *l); -extern byte *W_GetTexture(const char *name, int matchwidth, int matchheight); -extern void W_LoadTextureWadFile (const char *filename, int complain); - -#endif // _HL_BSP_H +#endif//__QF_Vulkan_qf_main_h diff --git a/include/QF/uint32.h b/include/QF/Vulkan/qf_model.h similarity index 57% rename from include/QF/uint32.h rename to include/QF/Vulkan/qf_model.h index 513117d01..3a42e131d 100644 --- a/include/QF/uint32.h +++ b/include/QF/Vulkan/qf_model.h @@ -1,12 +1,14 @@ /* - uint32.h + qf_model.h - Definitions for portable (?) unsigned int + Vulkan specific model stuff - Copyright (C) 2000 Jeff Teunissen + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie - Author: Jeff Teunissen - Date: 01 Jan 2000 + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/19 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,26 +29,16 @@ Boston, MA 02111-1307, USA */ +#ifndef __QF_Vulkan_qf_model_h +#define __QF_Vulkan_qf_model_h -#ifndef __uint32_h -#define __uint32_h +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/Vulkan/qf_vid.h" -#ifndef int32 -# if (SIZEOF_INT == 4) -# define int32 int -# elif (SIZEOF_LONG == 4) -# define int32 long -# elif (SIZEOF_SHORT == 4) -# define int32 short -# else -/* I hope this works */ -# define int32 int -# define LARGE_INT32 -# endif -#endif +typedef struct modelctx_s { + struct vulkan_ctx_s *ctx; + VkDeviceMemory texture_memory; +} modelctx_t; -#ifndef uint32 -# define uint32 unsigned int32 -#endif - -#endif // __uint32_h +#endif//__QF_Vulkan_qf_model_h diff --git a/include/QF/Vulkan/qf_particles.h b/include/QF/Vulkan/qf_particles.h new file mode 100644 index 000000000..c256a9610 --- /dev/null +++ b/include/QF/Vulkan/qf_particles.h @@ -0,0 +1,16 @@ +#ifndef __QF_Vulkan_qf_particles_h +#define __QF_Vulkan_qf_particles_h + +#include "QF/image.h" + +struct cvar_s; +struct vulkan_ctx_s;; + +void Vulkan_ClearParticles (struct vulkan_ctx_s *ctx); +void Vulkan_InitParticles (struct vulkan_ctx_s *ctx); +void Vulkan_r_easter_eggs_f (struct cvar_s *var, struct vulkan_ctx_s *ctx); +void Vulkan_r_particles_style_f (struct cvar_s *var, struct vulkan_ctx_s *ctx); +void Vulkan_Particles_Init (struct vulkan_ctx_s *ctx); +void Vulkan_DrawParticles (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_particles_h diff --git a/include/QF/Vulkan/qf_texture.h b/include/QF/Vulkan/qf_texture.h new file mode 100644 index 000000000..55a631f62 --- /dev/null +++ b/include/QF/Vulkan/qf_texture.h @@ -0,0 +1,27 @@ +#ifndef __QF_Vulkan_qf_texture_h +#define __QF_Vulkan_qf_texture_h + +#include "QF/image.h" +#include "QF/Vulkan/qf_vid.h" + +typedef struct qfv_tex_s { + VkDeviceMemory memory; + size_t offset; + VkImage image; + VkImageView view; +} qfv_tex_t; + +void Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, + int alpha, int count); +qfv_tex_t *Vulkan_LoadTex (struct vulkan_ctx_s *ctx, tex_t *tex, int mip, + const char *name); +qfv_tex_t *Vulkan_LoadEnvMap (struct vulkan_ctx_s *ctx, tex_t *tex, + const char *name); +qfv_tex_t *Vulkan_LoadEnvSides (struct vulkan_ctx_s *ctx, tex_t **tex, + const char *name); +VkImageView Vulkan_TexImageView (qfv_tex_t *tex) __attribute__((pure)); +void Vulkan_UnloadTex (struct vulkan_ctx_s *ctx, qfv_tex_t *tex); +void Vulkan_Texture_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Texture_Shutdown (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_texture_h diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h new file mode 100644 index 000000000..80f12ca67 --- /dev/null +++ b/include/QF/Vulkan/qf_vid.h @@ -0,0 +1,87 @@ +/* + Vulkan/qf_vid.h + + vulkan vid stuff from the renderer. + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_Vulkan_vid_h +#define __QF_Vulkan_vid_h + +#include "QF/Vulkan/cvars.h" + +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + +//FIXME location +typedef enum { + QFV_passDepth, // geometry + QFV_passTranslucent, // geometry + QFV_passGBuffer, // geometry + QFV_passLighting, // single quad + QFV_passCompose, // single quad + + QFV_NumPasses +} QFV_Subpass; + +enum { + QFV_attachDepth, + QFV_attachColor, + QFV_attachEmission, + QFV_attachNormal, + QFV_attachPosition, + QFV_attachOpaque, + QFV_attachTranslucent, + QFV_attachSwapchain, +}; + +struct vulkan_ctx_s; +void Vulkan_DestroyFrames (struct vulkan_ctx_s *ctx); +void Vulkan_CreateFrames (struct vulkan_ctx_s *ctx); +void Vulkan_CreateCapture (struct vulkan_ctx_s *ctx); +void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); +void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); +void Vulkan_CreateMatrices (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyMatrices (struct vulkan_ctx_s *ctx); +void Vulkan_CalcProjectionMatrices (struct vulkan_ctx_s *ctx, float aspect); +void Vulkan_CalcViewMatrix (struct vulkan_ctx_s *ctx); +void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); +void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); +void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); +void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx); +void Vulkan_CreateStagingBuffers (struct vulkan_ctx_s *ctx); + +VkPipeline Vulkan_CreatePipeline (struct vulkan_ctx_s *ctx, const char *name); +VkDescriptorPool Vulkan_CreateDescriptorPool (struct vulkan_ctx_s *ctx, + const char *name); +VkPipelineLayout Vulkan_CreatePipelineLayout (struct vulkan_ctx_s *ctx, + const char *name); +VkSampler Vulkan_CreateSampler (struct vulkan_ctx_s *ctx, const char *name); +VkDescriptorSetLayout Vulkan_CreateDescriptorSetLayout(struct vulkan_ctx_s*ctx, + const char *name); + +#endif // __QF_Vulkan_vid_h diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h new file mode 100644 index 000000000..a584d476d --- /dev/null +++ b/include/QF/Vulkan/renderpass.h @@ -0,0 +1,50 @@ +#ifndef __QF_Vulkan_renderpass_h +#define __QF_Vulkan_renderpass_h + +#include "QF/darray.h" + +typedef struct qfv_attachmentdescription_s + DARRAY_TYPE (VkAttachmentDescription) qfv_attachmentdescription_t; + +#define QFV_AllocAttachmentDescription(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_attachmentdescription_t, num, allocator) + +typedef struct qfv_attachmentreference_s + DARRAY_TYPE (VkAttachmentReference) qfv_attachmentreference_t; + +#define QFV_AllocAttachmentReference(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_attachmentreference_t, num, allocator) + +typedef struct qfv_subpassparametersset_s + DARRAY_TYPE (VkSubpassDescription) qfv_subpassparametersset_t; + +#define QFV_AllocSubpassParametersSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_subpassparametersset_t, num, allocator) + +typedef struct qfv_subpassdependency_s + DARRAY_TYPE (VkSubpassDependency) qfv_subpassdependency_t; + +#define QFV_AllocSubpassDependencies(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_subpassdependency_t, num, allocator) + +typedef struct qfv_framebufferset_s + DARRAY_TYPE (VkFramebuffer) qfv_framebufferset_t; + +#define QFV_AllocFrameBuffers(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_framebufferset_t, num, allocator) + +struct qfv_device_s; +struct qfv_imageviewset_s; +VkRenderPass +QFV_CreateRenderPass (struct qfv_device_s *device, + qfv_attachmentdescription_t *attachments, + qfv_subpassparametersset_t *subpasses, + qfv_subpassdependency_t *dependencies); + +VkFramebuffer +QFV_CreateFramebuffer (struct qfv_device_s *device, + VkRenderPass renderPass, + struct qfv_imageviewset_s *attachments, + VkExtent2D, uint32_t layers); + +#endif//__QF_Vulkan_renderpass_h diff --git a/include/QF/Vulkan/scrap.h b/include/QF/Vulkan/scrap.h new file mode 100644 index 000000000..31ceba506 --- /dev/null +++ b/include/QF/Vulkan/scrap.h @@ -0,0 +1,25 @@ +#ifndef __QF_Vulkan_scrap_h +#define __QF_Vulkan_scrap_h + +#include "QF/image.h" + +typedef struct scrap_s scrap_t; + +struct qfv_stagebuf_s; +struct qfv_device_s; + +scrap_t *QFV_CreateScrap (struct qfv_device_s *device, const char *name, + int size, QFFormat format, + struct qfv_stagebuf_s *stage); +size_t QFV_ScrapSize (scrap_t *scrap) __attribute__((pure)); +void QFV_ScrapClear (scrap_t *scrap); +void QFV_DestroyScrap (scrap_t *scrap); +VkImageView QFV_ScrapImageView (scrap_t *scrap) __attribute__((pure)); +subpic_t *QFV_ScrapSubpic (scrap_t *scrap, int width, int height); +void QFV_SubpicDelete (subpic_t *subpic); + +void *QFV_SubpicBatch (subpic_t *subpic, struct qfv_stagebuf_s *stage); + +void QFV_ScrapFlush (scrap_t *scrap); + +#endif//__QF_Vulkan_scrap_h diff --git a/include/QF/Vulkan/shader.h b/include/QF/Vulkan/shader.h new file mode 100644 index 000000000..f44189978 --- /dev/null +++ b/include/QF/Vulkan/shader.h @@ -0,0 +1,14 @@ +#ifndef __QF_Vulkan_shader_h +#define __QF_Vulkan_shader_h + +struct qfv_device_s; +struct vulkan_ctx_s; +struct plitem_s; +struct parsectx_s; + +VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, + const char *path); +void QFV_DestroyShaderModule (struct qfv_device_s *device, + VkShaderModule module); + +#endif//__QF_Vulkan_shader_h diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h new file mode 100644 index 000000000..9058e3c9a --- /dev/null +++ b/include/QF/Vulkan/staging.h @@ -0,0 +1,37 @@ +#ifndef __QF_Vulkan_staging_h +#define __QF_Vulkan_staging_h + +#include "QF/ringbuffer.h" + +typedef struct qfv_packet_s { + struct qfv_stagebuf_s *stage; ///< staging buffer that owns this packet + VkCommandBuffer cmd; + VkFence fence; + size_t offset; + size_t length; +} qfv_packet_t; + +typedef struct qfv_stagebuf_s { + struct qfv_device_s *device; + VkBuffer buffer; + VkDeviceMemory memory; + RING_BUFFER(qfv_packet_t, 4) packets; ///< packets for controlling access + size_t atom_mask; ///< for flush size rounding + size_t size; ///< actual size of the buffer + size_t end; ///< effective end of the buffer due to early wrap + size_t space_start;///< beginning of available space + size_t space_end; ///< end of available space + void *data; +} qfv_stagebuf_t; + + +qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device, + const char *name, size_t size, + VkCommandPool cmdPool); +void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage); +void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size); +qfv_packet_t *QFV_PacketAcquire (qfv_stagebuf_t *stage); +void *QFV_PacketExtend (qfv_packet_t *packet, size_t size); +void QFV_PacketSubmit (qfv_packet_t *packet); + +#endif//__QF_Vulkan_staging_h diff --git a/include/QF/Vulkan/swapchain.h b/include/QF/Vulkan/swapchain.h new file mode 100644 index 000000000..5c988f90f --- /dev/null +++ b/include/QF/Vulkan/swapchain.h @@ -0,0 +1,25 @@ +#ifndef __QF_Vulkan_swapchain_h +#define __QF_Vulkan_swapchain_h + +typedef struct qfv_swapchain_s { + struct qfv_device_s *device; + VkSurfaceKHR surface; + VkSwapchainKHR swapchain; + VkFormat format; + VkExtent2D extent; + int32_t numImages; + VkImageUsageFlags usage; + struct qfv_imageset_s *images; + struct qfv_imageviewset_s *imageViews; +} qfv_swapchain_t; + +struct vulkan_ctx_s; +qfv_swapchain_t *QFV_CreateSwapchain (struct vulkan_ctx_s *ctx, + VkSwapchainKHR old_swapchain); +void QFV_DestroySwapchain (qfv_swapchain_t *swapchain); +struct qfv_semaphore_s; +struct qfv_fence_s; +int QFV_AcquireNextImage (qfv_swapchain_t *swapchain, VkSemaphore semaphore, + VkFence fence, uint32_t *imageIndex); + +#endif//__QF_Vulkan_swapchain_h diff --git a/include/QF/alloc.h b/include/QF/alloc.h index 59a57bdf1..f67fe7176 100644 --- a/include/QF/alloc.h +++ b/include/QF/alloc.h @@ -37,7 +37,7 @@ /** \defgroup alloc High-tide allocator. \ingroup utils */ -//@{ +///@{ #ifndef DEBUG_QF_MEMORY /** High-tide structure allocator for use in linked lists. @@ -93,6 +93,6 @@ #define FREE(n, p) do { free (p); } while (0) #endif -//@} +///@} #endif//__QF_alloc_h diff --git a/include/QF/bspfile.h b/include/QF/bspfile.h index b7683849f..27648f297 100644 --- a/include/QF/bspfile.h +++ b/include/QF/bspfile.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __bspfile_h_ -#define __bspfile_h_ +#ifndef __QF_bspfile_h +#define __QF_bspfile_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -42,6 +42,8 @@ #define MAX_MAP_FACES 65535 // format limit (u16) #define MAX_MAP_MARKSURFACES 65535 // format limit (u16) +#define MAP_PVS_BYTES (MAX_MAP_LEAFS / 8) + //============================================================================= #define BSPVERSION 29 @@ -310,4 +312,4 @@ void BSP_AddVisibility (bsp_t *bsp, const byte *visdata, size_t visdatasize); void BSP_AddEntities (bsp_t *bsp, const char *entdata, size_t entdatasize); void BSP_AddTextures (bsp_t *bsp, const byte *texdata, size_t texdatasize); -#endif//__bspfile_h_ +#endif//__QF_bspfile_h diff --git a/include/QF/cbuf.h b/include/QF/cbuf.h index 9018fa6b6..29a89588e 100644 --- a/include/QF/cbuf.h +++ b/include/QF/cbuf.h @@ -34,7 +34,7 @@ /** \defgroup cbuf Command buffer management. \ingroup utils */ -//@{ +///@{ #include @@ -100,6 +100,6 @@ void Cbuf_Execute (cbuf_t *cbuf); void Cbuf_Execute_Stack (cbuf_t *cbuf); void Cbuf_Execute_Sets (cbuf_t *cbuf); -//@} +///@} #endif//__QF_cbuf_h diff --git a/include/QF/cdaudio.h b/include/QF/cdaudio.h index e7596ad78..e265231db 100644 --- a/include/QF/cdaudio.h +++ b/include/QF/cdaudio.h @@ -25,8 +25,8 @@ */ -#ifndef _CDAUDIO_H -#define _CDAUDIO_H +#ifndef __QF_cdaudio_h +#define __QF_cdaudio_h #include "QF/qtypes.h" @@ -35,7 +35,6 @@ void CDAudio_Play(int track, qboolean looping); void CDAudio_Stop(void); void CDAudio_Pause(void); void CDAudio_Resume(void); -void CDAudio_Shutdown(void); void CDAudio_Update(void); -#endif // _CDAUDIO_H +#endif//__QF_cdaudio_h diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h new file mode 100644 index 000000000..9a79690a6 --- /dev/null +++ b/include/QF/cexpr.h @@ -0,0 +1,143 @@ +/* + cexpr.h + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_expr_h +#define __QF_expr_h + +#include + +struct exprval_s; +struct exprctx_s; + +typedef struct binop_s { + int op; + struct exprtype_s *other; + struct exprtype_s *result; + void (*func) (const struct exprval_s *val1, + const struct exprval_s *val2, + struct exprval_s *result, + struct exprctx_s *context); +} binop_t; + +typedef struct unop_s { + int op; + struct exprtype_s *result; + void (*func) (const struct exprval_s *val, struct exprval_s *result, + struct exprctx_s *context); +} unop_t; + +typedef struct exprtype_s { + const char *name; + size_t size; + binop_t *binops; + unop_t *unops; + void *data; +} exprtype_t; + +typedef struct exprval_s { + exprtype_t *type; + void *value; +} exprval_t; + +typedef struct exprlist_s { + struct exprlist_s *next; + exprval_t *value; +} exprlist_t; + +typedef struct exprsym_s { + const char *name; + exprtype_t *type; + void *value; + struct exprsym_s *next; +} exprsym_t; + +typedef struct exprfunc_s { + exprtype_t *result; + int num_params; + exprtype_t **param_types; + void (*func) (const exprval_t **params, exprval_t *result, + struct exprctx_s *context); +} exprfunc_t; + +typedef struct exprtab_s { + exprsym_t *symbols; + struct hashtab_s *tab; +} exprtab_t; + +typedef struct exprctx_s { + exprval_t *result; + exprtab_t *symtab; // directly accessible symbols + exprtab_t *external_variables; // accessible via $id + struct memsuper_s *memsuper; + const struct plitem_s *item; + struct plitem_s *messages; + struct hashlink_s **hashlinks; + int errors; +} exprctx_t; + +typedef struct exprenum_s { + exprtype_t *type; + exprtab_t *symtab; +} exprenum_t; + +int cexpr_parse_enum (exprenum_t *enm, const char *str, + const exprctx_t *context, void *data); +binop_t *cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) __attribute__((pure)); +exprval_t *cexpr_value (exprtype_t *type, exprctx_t *ctx); +exprval_t *cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx); +int cexpr_eval_string (const char *str, exprctx_t *context); +void cexpr_error(exprctx_t *ctx, const char *fmt, ...) __attribute__((format(printf,2,3))); + +void cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, + exprval_t *c, exprctx_t *ctx); +void cexpr_struct_pointer_getfield (const exprval_t *a, const exprval_t *b, + exprval_t *c, exprctx_t *ctx); +exprval_t *cexpr_cvar (const char *name, exprctx_t *ctx); +exprval_t *cexpr_cvar_struct (exprctx_t *ctx); + +void cexpr_cast_plitem (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx); + +void cexpr_init_symtab (exprtab_t *symtab, exprctx_t *ctx); + +char *cexpr_yyget_text (void *scanner); + +extern exprtype_t cexpr_int; +extern exprtype_t cexpr_uint; +extern exprtype_t cexpr_size_t; +extern exprtype_t cexpr_float; +extern exprtype_t cexpr_double; +extern exprtype_t cexpr_vector; +extern exprtype_t cexpr_quaternion; +extern exprtype_t cexpr_exprval; +extern exprtype_t cexpr_field; +extern exprtype_t cexpr_function; +extern exprtype_t cexpr_plitem; + +extern binop_t cexpr_struct_binops[]; +extern binop_t cexpr_struct_pointer_binops[]; + +#endif//__QF_expr_h diff --git a/include/QF/checksum.h b/include/QF/checksum.h index 9a7dfb8e6..12fcaf477 100644 --- a/include/QF/checksum.h +++ b/include/QF/checksum.h @@ -25,12 +25,12 @@ */ -#ifndef __checksum_h -#define __checksum_h +#ifndef __QF_checksum_h +#define __QF_checksum_h /** \addtogroup crc */ -//@{ +///@{ #include "QF/qtypes.h" @@ -38,6 +38,6 @@ unsigned int Com_BlockChecksum (const void *buffer, int length); void Com_BlockFullChecksum (const void *buffer, int len, unsigned char *outbuf); byte COM_BlockSequenceCRCByte (const byte *base, int length, int sequence); -//@} +///@} -#endif // __checksum_h +#endif//__QF_checksum_h diff --git a/include/QF/cmd.h b/include/QF/cmd.h index 85131083e..3cd74432b 100644 --- a/include/QF/cmd.h +++ b/include/QF/cmd.h @@ -31,12 +31,13 @@ /** \defgroup cmd Command management. \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" #include "QF/cbuf.h" typedef void (*xcommand_t) (void); +typedef void (*xdatacmd_t) (void *data); typedef enum { src_client, // came in over a net connection as a clc_stringcmd @@ -48,6 +49,8 @@ typedef struct cmd_function_s { struct cmd_function_s *next; const char *name; xcommand_t function; + xdatacmd_t datafunc; + void *data; const char *description; } cmd_function_t; @@ -56,18 +59,21 @@ extern cmd_source_t cmd_source; void Cmd_Init_Hash (void); void Cmd_Init (void); -int Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *description); +int Cmd_AddCommand (const char *cmd_name, xcommand_t function, + const char *description); +int Cmd_AddDataCommand (const char *cmd_name, xdatacmd_t function, + void *data, const char *description); int Cmd_RemoveCommand (const char *cmd_name); qboolean Cmd_Exists (const char *cmd_name); -const char *Cmd_CompleteCommand (const char *partial); -int Cmd_CompleteCountPossible (const char *partial); +const char *Cmd_CompleteCommand (const char *partial) __attribute__((pure)); +int Cmd_CompleteCountPossible (const char *partial) __attribute__((pure)); const char **Cmd_CompleteBuildList (const char *partial); -int Cmd_Argc (void); -const char *Cmd_Argv (int arg); -const char *Cmd_Args (int start); +int Cmd_Argc (void) __attribute__((pure)); +const char *Cmd_Argv (int arg) __attribute__((pure)); +const char *Cmd_Args (int start) __attribute__((pure)); struct cbuf_args_s; int Cmd_Command (struct cbuf_args_s *args); int Cmd_ExecuteString (const char *text, cmd_source_t src); @@ -81,6 +87,6 @@ struct cbuf_interpreter_s *Cmd_GetProvider(const char *name); extern struct cbuf_args_s *cmd_args; extern struct cvar_s *cmd_warncmd; -//@} +///@} #endif//__QF_cmd_h diff --git a/include/QF/cmem.h b/include/QF/cmem.h new file mode 100644 index 000000000..f9c47d4c1 --- /dev/null +++ b/include/QF/cmem.h @@ -0,0 +1,118 @@ +/* + cmem.h + + Cache-line aligned memory allocator + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_cmem_h +#define __QF_cmem_h + +#include "QF/qtypes.h" + +#define MEM_LINE_SIZE 64 +#define MAX_CACHE_LINES 9 + +typedef struct memline_s { + /* chain of free line blocks for fast allocation + * chain begins in memsuper_t + */ + struct memline_s *free_next; + struct memline_s **free_prev; + /* chain of free line blocks within a membock for merging + * chain begins in memblock_t + */ + struct memline_s *block_next; + struct memline_s **block_prev; + size_t size; + /* owning block + */ + struct memblock_s *block; + size_t pad[2]; +} memline_t; + +typedef struct memsline_s { + struct memsline_s *next; + size_t size:2; + size_t list:4; + size_t prev:58; // memsline_t ** +} memsline_t; + +typedef struct memblock_s { + struct memblock_s *next; + struct memblock_s **prev; + /* The pointer to pass to free() + */ + void *mem; + memline_t *free_lines; + /* Size of memory region before block "header". + * + * Since large blocks are allocated with page-size alignment, odds are + * high that the there will be many cache lines "wasted" in the space + * between the address returned from aligned_alloc (to cache-line + * alignment) and the block itself. Setting them up as a pool makes the + * lines available for smaller allocations, thus reducing waste. + */ + size_t pre_size; + /* Size of memory region after block "header". + * + * Will be 0 for blocks that were allocated exclusively for small + * allocations, otherwise indicates the size of the allocated block. + */ + size_t post_size; + /* True if the post-header block is free to be reused. + */ + int post_free; + int pad; + size_t pre_allocated; +} memblock_t; + +typedef struct memsuper_s { + size_t page_size; + size_t page_mask; + memblock_t *memblocks; + /* Allocated cache lines from which smaller blocks can be allocated. + * + * The index is the base-2 log minus 2 of the size of the elements in the + * cache line from which an element was last freed. Only 4-32 bytes are of + * interest because nothing smaller than 4 bytes (int/float) will be + * allocated, and 64 bytes and up consume entire cache lines. + */ + memsline_t *last_freed[4]; + /* Free chache lines grouped by size. + * + * The index is the base-2 log of the MINIMUM number of cache lines + * available in each block. ie, blocks with 4, 5, 6 and 7 lines will all + * be in the third list (index 2). For 4k page sizes, only 6 lists are + * needed (32-63 lines) because a page can hold only 62 lines (1 for the + * control block and one to avoid a cache-line being on a page boundary). + * Having 9 (MAX_CACHE_LINES) lists allows page sizes up to 16kB. + */ + memline_t *free_lines[MAX_CACHE_LINES]; +} memsuper_t; + +memsuper_t *new_memsuper (void); +void delete_memsuper (memsuper_t *super); +void *cmemalloc (memsuper_t *super, size_t size); +void cmemfree (memsuper_t *super, void *mem); + +#endif//__QF_cmem_h diff --git a/include/QF/console.h b/include/QF/console.h index eeb9010d6..f885404fa 100644 --- a/include/QF/console.h +++ b/include/QF/console.h @@ -25,8 +25,8 @@ */ -#ifndef __console_h -#define __console_h +#ifndef __QF_console_h +#define __QF_console_h #include @@ -92,8 +92,8 @@ extern struct console_data_s con_data; void Con_CheckResize (void); void Con_DrawConsole (void); -void Con_Printf (const char *fmt, ...); -void Con_Print (const char *fmt, va_list args); +void Con_Printf (const char *fmt, ...) __attribute__((format(printf, 1, 2))); +void Con_Print (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); void Con_ToggleConsole_f (void); // wrapper function to attempt to either complete the command line @@ -105,7 +105,7 @@ void Con_BasicCompleteCommandLine (inputline_t *il); // Generic libs/util/console.c function to display a list // formatted in columns on the console void Con_DisplayList(const char **list, int con_linewidth); -extern void (*con_list_print)(const char *fmt, ...); +extern void (*con_list_print)(const char *fmt, ...) __attribute__((format(printf, 1, 2))); inputline_t *Con_CreateInputLine (int lines, int lsize, char prompt); void Con_DestroyInputLine (inputline_t *inputline); @@ -119,7 +119,6 @@ void Con_BufferAddText (con_buffer_t *buf, const char *text); // init/shutdown functions void Con_Init (const char *plugin_name); -void Con_Shutdown (void); void Con_ExecLine (const char *line); void Con_ProcessInput (void); @@ -151,4 +150,4 @@ void Menu_Leave_f (void); void Menu_Prev_f (void); void Menu_Next_f (void); -#endif // __console_h +#endif//__QF_console_h diff --git a/include/QF/crc.h b/include/QF/crc.h index 8c3154137..ad26bacb8 100644 --- a/include/QF/crc.h +++ b/include/QF/crc.h @@ -25,22 +25,22 @@ */ -#ifndef __crc_h -#define __crc_h +#ifndef __QF_crc_h +#define __QF_crc_h /** \defgroup crc Checksum generation. \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" void CRC_Init(unsigned short *crcvalue); void CRC_ProcessByte(unsigned short *crcvalue, byte data); void CRC_ProcessBlock (const byte *start, unsigned short *crcvalue, int count); -unsigned short CRC_Value(unsigned short crcvalue); -unsigned short CRC_Block (const byte *start, int count); +unsigned short CRC_Value(unsigned short crcvalue) __attribute__((const)); +unsigned short CRC_Block (const byte *start, int count) __attribute__((pure)); -//@} +///@} -#endif // __crc_h +#endif//__QF_crc_h diff --git a/include/QF/cvar.h b/include/QF/cvar.h index 4f182d285..946a20f13 100644 --- a/include/QF/cvar.h +++ b/include/QF/cvar.h @@ -25,13 +25,13 @@ */ -#ifndef __cvar_h -#define __cvar_h +#ifndef __QF_cvar_h +#define __QF_cvar_h /** \defgroup cvar Configuration variables \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -72,7 +72,7 @@ typedef struct cvar_alias_s { code goes "look, the user made fs_basepath already", uses the users value, but sets CVAR_ROM as per the call. */ -//@{ +///@{ #define CVAR_NONE 0 ///< normal cvar #define CVAR_ARCHIVE 1 ///< set to cause it to be saved to ///< config.cfg @@ -85,7 +85,7 @@ typedef struct cvar_alias_s { #define CVAR_LATCH 2048 ///< will change only when C code next does ///< a Cvar_Get(), so it can't be changed ///< (not implemented) -//@} +///@} // Returns the Cvar if found, creates it with value if not. Description and @@ -122,12 +122,12 @@ void Cvar_WriteVariables (QFile *f); // attempts to match a partial variable name for command line completion // returns NULL if nothing fits -const char *Cvar_CompleteVariable (const char *partial); +const char *Cvar_CompleteVariable (const char *partial) __attribute__((pure)); // Added by EvilTypeGuy - functions for tab completion system // Thanks to Fett erich@heintz.com // Thanks to taniwha -int Cvar_CompleteCountPossible (const char *partial); +int Cvar_CompleteCountPossible (const char *partial) __attribute__((pure)); const char **Cvar_CompleteBuildList (const char *partial); // Returns a pointer to the Cvar, NULL if not found @@ -138,6 +138,6 @@ void Cvar_Init (void); extern cvar_t *cvar_vars; -//@} +///@} -#endif // __cvar_h +#endif//__QF_cvar_h diff --git a/include/QF/darray.h b/include/QF/darray.h new file mode 100644 index 000000000..e41cd5edb --- /dev/null +++ b/include/QF/darray.h @@ -0,0 +1,370 @@ +/* + darray.h + + Dynamic arrays + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/02/17 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_darray_h +#define __QF_darray_h + +#include "QF/sys.h" + +/** \defgroup darray Dynamic Arrays + \ingroup utils + + Dynamic array container object +*/ +///@{ + +/** The structure defs for a dynamic array with elements of the given type. + + This is just the defs of a struct delcaration: it is useless on its own. + The intended usage is something like: + + typedef struct dynamic_array_s DARRAY_TYPE(int) dynamic_array_t; + + This allows full flexibility in just how the actual type is used. + + The \a size field is the number of elements currently in the array, and + the \a maxSize field is the number of elements the array can hold without + being resized. + + The \a grow field specifies the number of elements by which \a maxSize is + to grow when the array needs to be resized. Setting this to 0 prevents + resizing and any attempt to do so is a fatal error. + + \param ele_type The type to use for the element array, which is accessed + by the \a a field. + \hideinitializer +*/ +#define DARRAY_TYPE(ele_type) \ + { \ + size_t size; \ + size_t maxSize; \ + size_t grow; \ + ele_type *a; \ + } + +#define DARRAY_STATIC_INIT(g) { .grow = g } + +/** Allocate a fixed-size array using the given allocator + + The allocated array is initilized to be ungrowable, and with both size + and maxSize set to the given size. + + \param array_type Expression acceptable by typeof for determining the + type of the array. + \param array_size The size of the array. + \param alloc Allocator compatible with malloc (eg, alloca). +*/ +#define DARRAY_ALLOCFIXED(array_type, array_size, alloc) \ + ({ \ + __auto_type s = (array_size); \ + typeof (array_type) *ar = alloc (sizeof(*ar) \ + + s * sizeof (*ar->a)); \ + ar->size = ar->maxSize = s; \ + ar->grow = 0; \ + ar->a = (typeof (ar->a)) (ar + 1); \ + ar; \ + }) + +/** Allocate a fixed-size array using the given allocator + + The allocated array is initilized to be ungrowable, and with both size + and maxSize set to the given size. + + \param array_type Expression acceptable by typeof for determining the + type of the array. + \param array_size The size of the array. + \param alloc Allocator taking (obj, size) where obj is allocator + specific data (eg, a memory pool). + \param obj Additional data for the allocator. +*/ +#define DARRAY_ALLOCFIXED_OBJ(array_type, array_size, alloc, obj) \ + ({ \ + __auto_type s = (array_size); \ + typeof (array_type) *ar = alloc ((obj), \ + sizeof(*ar) \ + + s * sizeof (*ar->a)); \ + ar->size = ar->maxSize = s; \ + ar->grow = 0; \ + ar->a = (typeof (ar->a)) (ar + 1); \ + ar; \ + }) + +/** Initialized the array. + + The array will be initialized to be empty but with grow set to the + specifed value. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param growSize Number of elements by which the array is to grow when + required. + \hideinitializer +*/ +#define DARRAY_INIT(array, growSize) \ + do { \ + __auto_type ar = (array); \ + ar->size = ar->maxSize = 0; \ + ar->grow = (growSize); \ + ar->a = 0; \ + } while (0) + +/** Clear the array. + + If the array can grow, its backing will be freed and maxSize and a reset, + otherwise maxSize and a are left untouched. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \hideinitializer +*/ +#define DARRAY_CLEAR(array) \ + do { \ + __auto_type ar = (array); \ + ar->size = 0; \ + if (ar->grow) { \ + free (ar->a); \ + ar->maxSize = 0; \ + ar->a = 0; \ + } \ + } while (0) + +/** Set the size of the array. + + If the new size is greater than maxSize, and the array can grow (grow is + non-zero), then maxSize will be increased to the smallest multiple of grow + greater than or equal to size (ie, maxSize >= size, maxSize % grow == 0). + + Attempting to increase maxSize on an array that cannot grow is an error: + it is assumed that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param newSize The new size of the array: newly opened slots are + uninitialized, but old slots retain their values. + \hideinitializer +*/ +#define DARRAY_RESIZE(array, newSize) \ + do { \ + __auto_type ar = (array); \ + size_t ns = (newSize); \ + if (__builtin_expect (ns > ar->maxSize, 0)) { \ + if (__builtin_expect (!ar->grow, 0)) { \ + Sys_Error ("Attempt to grow fixed-size darray: %s:%d", \ + __FILE__, __LINE__); \ + } \ + ar->maxSize = ar->grow * ((ns + ar->grow - 1) / ar->grow); \ + ar->a = realloc (ar->a, ar->maxSize * sizeof (*ar->a)); \ + if (__builtin_expect (!ar->a, 0)) { \ + Sys_Error ("failed to realloc darray: %s:%d", \ + __FILE__, __LINE__); \ + } \ + } \ + ar->size = ns; \ + } while (0) + +/** Append a value to the end of the array. + + The array is grown by one and the value written to the newly opened slot. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param value The value to be appended to the array. Must be of a type + compatible with that used for creating the array struct. + \return The appended value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_APPEND(array, value) \ + ({ \ + __auto_type ar = (array); \ + typeof(ar->a[0]) ob = (value); \ + size_t sz = ar->size; \ + DARRAY_RESIZE (ar, ar->size + 1); \ + ar->a[sz] = ob; \ + }) + +/** Open a hole in the array for bulk copying of data. + + The array is grown by the requested size, opening a hole at the specified + index. Values beyond the index are copied to just after the newly opened + hole. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index at which the hole will begin. + \param space The sized of the hole to be opened, in array elements. + \return The *address* of the newly opened hole: can be passed to + memcpy and friends. + + memcpy (DARRAY_OPEN_AT(array, index, size), data, + size * sizeof (*data)); + \hideinitializer +*/ +#define DARRAY_OPEN_AT(array, index, space) \ + ({ \ + __auto_type ar = (array); \ + size_t po = (index); \ + size_t sp = (space); \ + if (__builtin_expect (po > ar->size, 0)) { \ + Sys_Error ("Attempt to insert elements outside darray: " \ + "%s:%d", __FILE__, __LINE__); \ + } \ + DARRAY_RESIZE (ar, ar->size + sp); \ + memmove (&ar->a[po + sp], &ar->a[po], \ + (ar->size - po - sp) * sizeof (*ar->a)); \ + &ar->a[po]; \ + }) + +/** Insert a value into the array at the specified index. + + The array is grown by one at the specified index and the value written + to the newly opened slot. Values beyond the index are copied to just + after the newly opened slot. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + Attempting to insert a value beyond one past the end of the array is an + error (inserting at index = size is valid). + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param value The value to be inserted into the array. Must be of a type + compatible with that used for creating the array struct. + \param index The index at which the value will be inserted + \return The inserted value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_INSERT_AT(array, value, index) \ + ({ \ + __auto_type ar = (array); \ + typeof(ar->a[0]) ob = (value); \ + *DARRAY_OPEN_AT (ar, index, 1) = ob; \ + }) + +/** Close a segment of an array. + + The values beyond the segment are copied to the beginning of the segment + and the array size reduced by the size of the segment. All but the first + one of the values previously in the segment are lost and gone forever. + + Attempting to close a segment that extends outside the array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index of the beginning of the segment. + \param count The number of values in the segment. + \return The single value at the beginning of the segment: can be + assigned to another compatible value. + \hideinitializer +*/ +#define DARRAY_CLOSE_AT(array, index, count) \ + ({ \ + __auto_type ar = (array); \ + size_t po = (index); \ + size_t co = (count); \ + if (__builtin_expect (po + co > ar->size \ + || po >= ar->size, 0)) { \ + Sys_Error ("Attempt to remove elements outside darray: " \ + "%s:%d", __FILE__, __LINE__); \ + } \ + __auto_type ob = ar->a[po]; \ + memmove (&ar->a[po], &ar->a[po + co], \ + (ar->size - po - co) * sizeof (ob)); \ + ar->size -= co; \ + ob; \ + }) + +/** Remove a value from an array at the specified index. + + The values beyond the index are moved down to fill the hole left by the + single value and the array size reduced by one. + + Attempting to remove a value from beyond the array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index of the value to be removed. + \return The removed value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_REMOVE_AT(array, index) \ + ({ \ + __auto_type ar = (array); \ + DARRAY_CLOSE_AT (ar, index, 1); \ + }) + +/** Remove (pop) a value from the end of an array. + + The size of the array size reduced by one. + + Attempting to remove a value from an empty array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \return The removed value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_REMOVE(array) \ + ({ \ + __auto_type ar = (array); \ + DARRAY_CLOSE_AT (ar, ar->size - 1, 1); \ + }) + +///@} + +#endif//__QF_darray_h diff --git a/include/QF/draw.h b/include/QF/draw.h index d8067a4c7..8f6b78889 100644 --- a/include/QF/draw.h +++ b/include/QF/draw.h @@ -25,8 +25,8 @@ */ -#ifndef _DRAW_H -#define _DRAW_H +#ifndef __QF_draw_h +#define __QF_draw_h /** \defgroup video Video Sub-sytem */ @@ -37,7 +37,7 @@ /** \defgroup video_renderer_draw Generic draw functions \ingroup video_renderer */ -//@{ +///@{ #include "QF/wad.h" @@ -160,12 +160,12 @@ void Draw_FadeScreen (void); /** Shift the screen colors. */ void Draw_BlendScreen (quat_t color); -//@} +///@} /** \defgroup video_renderer_draw_qpic QPic functions \ingroup video_renderer_draw */ -//@{ +///@{ /** Load a qpic from the filesystem. \param path path of the file within the quake filesystem \param alpha transparency level of the pic. @@ -232,6 +232,6 @@ void Draw_Picf (float x, float y, qpic_t *pic); \param height vertical size of the sub-region to be drawn */ void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); -//@} +///@} -#endif // _DRAW_H +#endif//__QF_draw_h diff --git a/include/QF/dstring.h b/include/QF/dstring.h index 85ea7d61f..937e9be54 100644 --- a/include/QF/dstring.h +++ b/include/QF/dstring.h @@ -25,13 +25,13 @@ */ -#ifndef __dstring_h -#define __dstring_h +#ifndef __QF_dstring_h +#define __QF_dstring_h /** \defgroup dstring Dynamic Strings \ingroup utils */ -//@{ +///@{ #include #include @@ -52,13 +52,13 @@ typedef struct dstring_s { extern dstring_mem_t dstring_default_mem; // General buffer functions -//@{ +///@{ /** Create a new dstring. size and truesize start at 0 and no string buffer is allocated. */ dstring_t *_dstring_new (dstring_mem_t *mem); dstring_t *dstring_new (void); -//@} +///@} /** Delete a dstring. Both the string buffer and dstring object are freed. */ void dstring_delete (dstring_t *dstr); @@ -103,13 +103,13 @@ void dstring_replace (dstring_t *dstr, unsigned int pos, unsigned int rlen, char *dstring_freeze (dstring_t *dstr); // String-specific functions -//@{ +///@{ /** Allocate a new dstring pre-initialized as a null terminated string. size will be 1 and the first byte 0. */ dstring_t *_dstring_newstr (dstring_mem_t *mem); dstring_t *dstring_newstr (void); -//@} +///@} /** Create a new dstring from a string. Similar to strdup(). \param str the string to copy \return inititialized dstring @@ -160,21 +160,21 @@ void dstring_insertsubstr (dstring_t *dstr, unsigned int pos, const char *str, */ void dstring_clearstr (dstring_t *dstr); -//@{ +///@{ /** Formatted printing to dstrings. Existing data is replaced by the formatted string. */ -int dvsprintf (dstring_t *dstr, const char *fmt, va_list args); -int dsprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); -//@} -//@{ +char *dvsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); +char *dsprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); +///@} +///@{ /** Formatted printing to dstrings. Formatted string is appened to the dstring. Embedded nulls in the dstring are ignored. */ -int davsprintf (dstring_t *dstr, const char *fmt, va_list args); -int dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); -//@} +char *davsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); +char *dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); +///@} -//@} +///@} -#endif // __dstring_h +#endif//__QF_dstring_h diff --git a/include/QF/entity.h b/include/QF/entity.h new file mode 100644 index 000000000..032db67a2 --- /dev/null +++ b/include/QF/entity.h @@ -0,0 +1,124 @@ +/* + entity.h + + Entity management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/02/26 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_entity_h +#define __QF_entity_h + +#include "QF/darray.h" +#include "QF/mathlib.h" +#include "QF/simd/vec4f.h" +#include "QF/simd/mat4f.h" + +/** \defgroup entity Entity management + \ingroup utils +*/ +///@{ + +typedef struct mat4fset_s DARRAY_TYPE (mat4f_t) mat4fset_t; +typedef struct vec4fset_s DARRAY_TYPE (vec4f_t) vec4fset_t; +typedef struct uint32set_s DARRAY_TYPE (uint32_t) uint32set_t; +typedef struct byteset_s DARRAY_TYPE (byte) byteset_t; +typedef struct stringset_s DARRAY_TYPE (char *) stringset_t; +typedef struct xformset_s DARRAY_TYPE (struct transform_s *) xformset_t; +typedef struct entityset_s DARRAY_TYPE (struct entity_s *) entityset_t; + +#define null_transform (~0u) + +typedef struct hierarchy_s { + xformset_t transform; + entityset_t entity; + uint32set_t childCount; + uint32set_t childIndex; + uint32set_t parentIndex; + stringset_t name; + uint32set_t tag; + byteset_t modified; + mat4fset_t localMatrix; + mat4fset_t localInverse; + mat4fset_t worldMatrix; + mat4fset_t worldInverse; + vec4fset_t localRotation; + vec4fset_t localScale; + vec4fset_t worldRotation; + vec4fset_t worldScale; +} hierarchy_t; + +typedef struct transform_s { + hierarchy_t *hierarchy; + uint32_t index; +} transform_t; + +transform_t *Transform_New (transform_t *parent); +void Transform_Delete (transform_t *transform); +transform_t *Transform_NewNamed (transform_t *parent, const char *name); +uint32_t Transform_ChildCount (const transform_t *transform) __attribute__((pure)); +transform_t *Transform_GetChild (const transform_t *transform, + uint32_t childIndex) __attribute__((pure)); +void Transform_SetParent (transform_t *transform, transform_t *parent); +transform_t *Transform_GetParent (const transform_t *transform) __attribute__((pure)); +void Transform_SetName (transform_t *transform, const char *name); +const char *Transform_GetName (const transform_t *transform) __attribute__((pure)); +void Transform_SetTag (transform_t *transform, uint32_t tag); +uint32_t Transform_GetTag (const transform_t *transform) __attribute__((pure)); +void Transform_GetLocalMatrix (const transform_t *transform, mat4f_t mat); +void Transform_GetLocalInverse (const transform_t *transform, mat4f_t mat); +void Transform_GetWorldMatrix (const transform_t *transform, mat4f_t mat); +void Transform_GetWorldInverse (const transform_t *transform, mat4f_t mat); +vec4f_t Transform_GetLocalPosition (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalPosition (transform_t *transform, vec4f_t position); +vec4f_t Transform_GetLocalRotation (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalRotation (transform_t *transform, vec4f_t rotation); +vec4f_t Transform_GetLocalScale (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalScale (transform_t *transform, vec4f_t scale); +vec4f_t Transform_GetWorldPosition (const transform_t *transform) __attribute__((pure)); +void Transform_SetWorldPosition (transform_t *transform, vec4f_t position); +vec4f_t Transform_GetWorldRotation (const transform_t *transform) __attribute__((pure)); +void Transform_SetWorldRotation (transform_t *transform, vec4f_t rotation); +vec4f_t Transform_GetWorldScale (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalTransform (transform_t *transform, vec4f_t scale, + vec4f_t rotation, vec4f_t position); +// NOTE: these use X: right, Y: forward, Z:up +// aslo, not guaranteed to be normalized or even orthogonal +vec4f_t Transform_Forward (const transform_t *transform) __attribute__((pure)); +vec4f_t Transform_Right (const transform_t *transform) __attribute__((pure)); +vec4f_t Transform_Up (const transform_t *transform) __attribute__((pure)); +// no SetWorldScale because after rotations, non uniform scale becomes shear + +hierarchy_t *Hierarchy_New (size_t grow, int createRoot); +hierarchy_t *Hierarchy_Copy (hierarchy_t *src); +void Hierarchy_Delete (hierarchy_t *hierarchy); + +void Hierarchy_UpdateMatrices (hierarchy_t *hierarchy); +uint32_t Hierarchy_InsertHierarchy (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot); +void Hierarchy_RemoveHierarchy (hierarchy_t *hierarchy, uint32_t index); +///@} + +#endif//__QF_entity_h diff --git a/include/QF/gib.h b/include/QF/gib.h index aa97e3b05..09bcf01ad 100644 --- a/include/QF/gib.h +++ b/include/QF/gib.h @@ -28,8 +28,8 @@ */ -#ifndef __gib_h -#define __gib_h +#ifndef __QF_gib_h +#define __QF_gib_h // Dependencies @@ -182,7 +182,7 @@ extern char * const gib_null_string; #define GIB_CanReturn() (GIB_DATA(cbuf_active)->waitret) dstring_t *GIB_Return (const char *str); -void GIB_Error (const char *type, const char *fmt, ...); +void GIB_Error (const char *type, const char *fmt, ...) __attribute__((format(printf, 2, 3))); void GIB_Builtin_Add (const char *name, void (*func) (void)); void GIB_Builtin_Remove (const char *name); qboolean GIB_Builtin_Exists (const char *name); @@ -199,12 +199,12 @@ void GIB_Event_Callback (gib_event_t *event, unsigned int argc, ...); // Interpreter interface (for creating GIB cbufs) -cbuf_interpreter_t *GIB_Interpreter (void); +cbuf_interpreter_t *GIB_Interpreter (void) __attribute__((const)); // Thread interface void GIB_Thread_Execute (void); -unsigned int GIB_Thread_Count (void); +unsigned int GIB_Thread_Count (void) __attribute__((pure)); // Init interface @@ -214,6 +214,6 @@ void GIB_Init (qboolean sandbox); unsigned long int GIB_Handle_New (gib_object_t *data); void GIB_Handle_Free (unsigned long int num); -gib_object_t *GIB_Handle_Get (unsigned long int num); +gib_object_t *GIB_Handle_Get (unsigned long int num) __attribute__((pure)); -#endif +#endif//__QF_gib_h diff --git a/include/QF/hash.h b/include/QF/hash.h index 5cff9d115..f96682fd9 100644 --- a/include/QF/hash.h +++ b/include/QF/hash.h @@ -25,8 +25,8 @@ */ -#ifndef __hash_h -#define __hash_h +#ifndef __QF_hash_h +#define __QF_hash_h #include #include @@ -34,9 +34,10 @@ /** \defgroup hash Hash tables \ingroup utils */ -//@{ +///@{ typedef struct hashtab_s hashtab_t; +typedef struct hashlink_s hashlink_t; /** create a new hash table. \param tsize table size. larger values will give better distribution, but @@ -45,11 +46,18 @@ typedef struct hashtab_s hashtab_t; inserting or finding the element. First parameter is a pointer to the element from which to extract the key, the second is the user data pointer. - \param f a function to free the element. Only ever called from + \param f a function to free the element. Called from only Hash_FlushTable and Hash_DelTable. The first parameter is the element to be freed and the second is the user data pointer. \param ud user data pointer. set to whatever you want, it will be passed to the get key and free functions as the second parameter. + \param hlfl Address of opaque pointer used for per-thread allocation of + internal memory. If null, a local static pointer will be used, + but the hash table will not be thread-safe unless all tables + created with a null \a hlfl (hashlink freelist) are used in + only the one thread. However, this applys only to updating a + hash table; hash tables that are not updated can be safely + shared between threads. \return pointer to the hash table (to be passed to the other functions) or 0 on error. @@ -59,7 +67,8 @@ typedef struct hashtab_s hashtab_t; previous ones until the later one is removed (Hash_Del). */ hashtab_t *Hash_NewTable (int tsize, const char *(*gk)(const void*,void*), - void (*f)(void*,void*), void *ud); + void (*f)(void*,void*), void *ud, + hashlink_t **hlfl); /** change the hash and compare functions used by the Hash_*Element functions. the default hash function just returns the address of the element, and the @@ -177,20 +186,20 @@ void Hash_Free (hashtab_t *tab, void *ele); this is the same function as used internally. */ -unsigned long Hash_String (const char *str); +unsigned long Hash_String (const char *str) __attribute__((pure)); /** hash a buffer. \param buf the buffer to hash \param len the size of the buffer \return the hash value of the string. */ -unsigned long Hash_Buffer (const void *buf, int len); +unsigned long Hash_Buffer (const void *buf, int len) __attribute__((pure)); /** get the size of the table \param tab the table in question \return the number of elements in the table. */ -size_t Hash_NumElements (hashtab_t *tab); +size_t Hash_NumElements (hashtab_t *tab) __attribute__((pure)); /** list of all elements in the table. \param tab the table to list @@ -209,6 +218,6 @@ void **Hash_GetList (hashtab_t *tab); */ void Hash_Stats (hashtab_t *tab); -//@} +///@} -#endif // __hash_h +#endif//__QF_hash_h diff --git a/include/QF/idparse.h b/include/QF/idparse.h index 07b5c322e..e48cf30e6 100644 --- a/include/QF/idparse.h +++ b/include/QF/idparse.h @@ -33,7 +33,7 @@ /** \addtogroup cbuf */ -//@{ +///@{ extern const char *com_token; @@ -44,6 +44,6 @@ void COM_TokenizeString (const char *str, struct cbuf_args_s *args); extern struct cbuf_interpreter_s id_interp; -//@} +///@} #endif//__QF_idparse_h diff --git a/include/QF/image.h b/include/QF/image.h index 47820c856..7ec7d00dc 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -30,24 +30,34 @@ #define __QF_image_h #include "QF/qtypes.h" -#include "QF/quakeio.h" + +typedef enum QFFormat { + tex_palette = 0, + tex_l = 0x1909, //GL_LUMINANCE + tex_a = 0x1906, //GL_ALPHA + tex_la = 2, + tex_rgb = 3, + tex_rgba = 4, + tex_frgba = 5, +} QFFormat; // could not use texture_t as that is used for models. typedef struct tex_s { int width; int height; - int format; - const byte *palette; // 0 = 32 bit, otherwise 8 - byte data[4]; // variable length + QFFormat format; + int loaded; // 0 if size info only, otherwise data loaded + const byte *palette; // 0 = 32 bit, otherwise 8 + byte *data; } tex_t; -#define tex_palette 0 -#define tex_l 0x1909 //GL_LUMINANCE -#define tex_a 0x1906 //GL_ALPHA -#define tex_la 2 -#define tex_rgb 3 -#define tex_rgba 4 +tex_t *LoadImage (const char *imageFile, int load); -tex_t *LoadImage (const char *imageFile); +typedef struct colcache_s colcache_t; -#endif //__QF_image_h +colcache_t *ColorCache_New (void); +void ColorCache_Delete (colcache_t *cache); +byte ConvertColor (const byte *rgb, const byte *pal, colcache_t *cache); +tex_t *ConvertImage (const tex_t *tex, const byte *pal); + +#endif//__QF_image_h diff --git a/include/QF/info.h b/include/QF/info.h index 518a35c23..7bf16b0ab 100644 --- a/include/QF/info.h +++ b/include/QF/info.h @@ -25,13 +25,13 @@ */ -#ifndef _INFO_H -#define _INFO_H +#ifndef __QF_info_h +#define __QF_info_h /** \defgroup info Info Keys \ingroup utils */ -//@{ +///@{ #include // for size_t. sys/types.h SHOULD be used, but can't :(bc) #include @@ -47,10 +47,10 @@ typedef struct info_key_s { const char *value; } info_key_t; -qboolean Info_FilterForKey (const char *key, const char **filter_list); +qboolean Info_FilterForKey (const char *key, const char **filter_list) __attribute__((pure)); void Info_Print (info_t *info); -int Info_CurrentSize (info_t *info); +int Info_CurrentSize (info_t *info) __attribute__((pure)); info_key_t *Info_Key (info_t *info, const char *key); info_key_t **Info_KeyList (info_t *info); void Info_RemoveKey (info_t *info, const char *key); @@ -63,6 +63,6 @@ void Info_Destroy (info_t *info); char *Info_MakeString (info_t *info, int (*filter)(const char *)); void Info_AddKeys (info_t *info, info_t *keys); -//@} +///@} -#endif // _INFO_H +#endif//__QF_info_h diff --git a/include/QF/input.h b/include/QF/input.h index 8f0438071..7644af8cf 100644 --- a/include/QF/input.h +++ b/include/QF/input.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_input_h_ -#define __QF_input_h_ +#ifndef __QF_input_h +#define __QF_input_h #include "QF/keys.h" @@ -44,8 +44,6 @@ struct cvar_s; void IN_Init (struct cbuf_s *cbuf); void IN_Init_Cvars (void); -void IN_Shutdown (void); - void IN_ProcessEvents (void); void IN_UpdateGrab (struct cvar_s *); @@ -75,4 +73,4 @@ void IN_LL_Grab_Input (int grab); extern kbutton_t in_strafe, in_klook, in_speed, in_mlook; -#endif // __QF_input_h_ +#endif//__QF_input_h diff --git a/include/QF/iqm.h b/include/QF/iqm.h index fb6517c76..adc5a3313 100644 --- a/include/QF/iqm.h +++ b/include/QF/iqm.h @@ -1,5 +1,5 @@ -#ifndef __QF_iqm_h__ -#define __QF_iqm_h__ +#ifndef __QF_iqm_h +#define __QF_iqm_h #include "QF/qtypes.h" @@ -149,4 +149,4 @@ typedef struct { void *extra_data; } iqm_t; -#endif//__QF_iqm_h__ +#endif//__QF_iqm_h diff --git a/include/QF/joystick.h b/include/QF/joystick.h index 781f783a9..4b8163f7e 100644 --- a/include/QF/joystick.h +++ b/include/QF/joystick.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_joystick_h_ -#define __QF_joystick_h_ +#ifndef __QF_joystick_h +#define __QF_joystick_h #include #include "QF/quakeio.h" @@ -144,14 +144,14 @@ void JOY_Close (void); void JOY_Read (void); -const char *JOY_GetOption_c (int i); -int JOY_GetOption_i (const char *c); +const char *JOY_GetOption_c (int i) __attribute__((pure)); +int JOY_GetOption_i (const char *c) __attribute__((pure)); -const char *JOY_GetDest_c (int i); -int JOY_GetDest_i (const char *c); +const char *JOY_GetDest_c (int i) __attribute__((pure)); +int JOY_GetDest_i (const char *c) __attribute__((pure)); int JOY_GetAxis_i (int dest, const char *c); void Joy_WriteBindings (QFile *f); -#endif // __QF_joystick_h_ +#endif//__QF_joystick_h diff --git a/include/QF/keys.h b/include/QF/keys.h index f79291dc0..c8fe1cbe2 100644 --- a/include/QF/keys.h +++ b/include/QF/keys.h @@ -26,8 +26,8 @@ */ -#ifndef _KEYS_H -#define _KEYS_H +#ifndef __QF_keys_h +#define __QF_keys_h #ifndef __QFCC__ # include "QF/qtypes.h" @@ -39,7 +39,7 @@ /** \defgroup input_keybinding Key Binding Sub-system \ingroup input */ -//@{ +///@{ /// these are the key numbers that should be passed to Key_Event typedef enum { @@ -227,77 +227,110 @@ typedef enum { /* Numeric keypad */ QFK_KP0 = 256, - QFK_KP1 = 257, - QFK_KP2 = 258, - QFK_KP3 = 259, - QFK_KP4 = 260, - QFK_KP5 = 261, - QFK_KP6 = 262, - QFK_KP7 = 263, - QFK_KP8 = 264, - QFK_KP9 = 265, - QFK_KP_PERIOD = 266, - QFK_KP_DIVIDE = 267, - QFK_KP_MULTIPLY = 268, - QFK_KP_MINUS = 269, - QFK_KP_PLUS = 270, - QFK_KP_ENTER = 271, - QFK_KP_EQUALS = 272, + QFK_KP1, + QFK_KP2, + QFK_KP3, + QFK_KP4, + QFK_KP5, + QFK_KP6, + QFK_KP7, + QFK_KP8, + QFK_KP9, + QFK_KP_PERIOD, + QFK_KP_DIVIDE, + QFK_KP_MULTIPLY, + QFK_KP_MINUS, + QFK_KP_PLUS, + QFK_KP_ENTER, + QFK_KP_EQUALS, /* Arrows + Home/End pad */ - QFK_UP = 273, - QFK_DOWN = 274, - QFK_RIGHT = 275, - QFK_LEFT = 276, - QFK_INSERT = 277, - QFK_HOME = 278, - QFK_END = 279, - QFK_PAGEUP = 280, - QFK_PAGEDOWN = 281, + QFK_UP, + QFK_DOWN, + QFK_RIGHT, + QFK_LEFT, + QFK_INSERT, + QFK_HOME, + QFK_END, + QFK_PAGEUP, + QFK_PAGEDOWN, /* Function keys */ - QFK_F1 = 282, - QFK_F2 = 283, - QFK_F3 = 284, - QFK_F4 = 285, - QFK_F5 = 286, - QFK_F6 = 287, - QFK_F7 = 288, - QFK_F8 = 289, - QFK_F9 = 290, - QFK_F10 = 291, - QFK_F11 = 292, - QFK_F12 = 293, - QFK_F13 = 294, - QFK_F14 = 295, - QFK_F15 = 296, + QFK_F1, + QFK_F2, + QFK_F3, + QFK_F4, + QFK_F5, + QFK_F6, + QFK_F7, + QFK_F8, + QFK_F9, + QFK_F10, + QFK_F11, + QFK_F12, + QFK_F13, + QFK_F14, + QFK_F15, + QFK_F16, + QFK_F17, + QFK_F18, + QFK_F19, + QFK_F20, + QFK_F21, + QFK_F22, + QFK_F23, + QFK_F24, + QFK_F25, + QFK_F26, + QFK_F27, + QFK_F28, + QFK_F29, + QFK_F30, + QFK_F31, + QFK_F32, + QFK_F33, + QFK_F34, + QFK_F35, + QFK_F36, + QFK_F37, + QFK_F38, + QFK_F39, + QFK_F40, + QFK_F41, + QFK_F42, + QFK_F43, + QFK_F44, + QFK_F45, + QFK_F46, + QFK_F47, + QFK_F48, /* Key state modifier keys */ - QFK_NUMLOCK = 300, - QFK_CAPSLOCK = 301, - QFK_SCROLLOCK = 302, - QFK_RSHIFT = 303, - QFK_LSHIFT = 304, - QFK_RCTRL = 305, - QFK_LCTRL = 306, - QFK_RALT = 307, - QFK_LALT = 308, - QFK_RMETA = 309, - QFK_LMETA = 310, - QFK_LSUPER = 311, /* Left "Windows" key */ - QFK_RSUPER = 312, /* Right "Windows" key */ - QFK_MODE = 313, /* "Alt Gr" key */ - QFK_COMPOSE = 314, /* Multi-key compose key */ + QFK_NUMLOCK, + QFK_CAPSLOCK, + QFK_SCROLLOCK, + QFK_RSHIFT, + QFK_LSHIFT, + QFK_RCTRL, + QFK_LCTRL, + QFK_RALT, + QFK_LALT, + QFK_RMETA, + QFK_LMETA, + QFK_LSUPER, /* Left "Windows" key */ + QFK_RSUPER, /* Right "Windows" key */ + QFK_MODE, /* "Alt Gr" key */ + QFK_COMPOSE, /* Multi-key compose key */ /* Miscellaneous function keys */ - QFK_HELP = 315, - QFK_PRINT = 316, - QFK_SYSREQ = 317, - QFK_BREAK = 318, - QFK_MENU = 319, - QFK_POWER = 320, /* Power Macintosh power key */ - QFK_EURO = 321, /* Some european keyboards */ - QFK_UNDO = 322, + QFK_HELP, + QFK_PRINT, + QFK_SYSREQ, + QFK_BREAK, + QFK_MENU, + QFK_POWER, /* Power Macintosh power key */ + QFK_EURO, /* Some european keyboards */ + QFK_UNDO, /* Japanese keys */ QFK_KANJI, /* Kanji, Kanji convert */ @@ -544,7 +577,7 @@ void Key_Init_Cvars (void); \param imt_name The name of the imt to find. Case insensitive. \return The named imt, or null if not found. */ -imt_t *Key_FindIMT (const char *imt_name); +imt_t *Key_FindIMT (const char *imt_name) __attribute__((pure)); /** Create a new imt and attach it to the specified keydest target. @@ -599,7 +632,7 @@ void Key_ClearStates (void); \param key The key for which to get the binding. \return The command string bound to the key, or null if unbound. */ -const char *Key_GetBinding (imt_t *imt, knum_t key); +const char *Key_GetBinding (imt_t *imt, knum_t key) __attribute__((pure)); /** Bind a command string to a key in the specified input mapping table. @@ -639,7 +672,7 @@ void Key_KeydestCallback (keydest_callback_t *callback); \param keynum The key for which to get the string. \return The string representation of the key. */ -const char *Key_KeynumToString (knum_t keynum); +const char *Key_KeynumToString (knum_t keynum) __attribute__((pure)); /** Get the keynum for the named key. @@ -650,7 +683,7 @@ const char *Key_KeynumToString (knum_t keynum); \param str The name of the key. \return The named key if valid, otherwise -1 */ -int Key_StringToKeynum (const char *str); +int Key_StringToKeynum (const char *str) __attribute__((pure)); struct progs_s; @@ -659,6 +692,6 @@ struct progs_s; void Key_Progs_Init (struct progs_s *pr); #endif -//@} +///@} -#endif // _KEYS_H +#endif//__QF_keys_h diff --git a/include/QF/link.h b/include/QF/link.h index de29bb454..5b6fdcf8c 100644 --- a/include/QF/link.h +++ b/include/QF/link.h @@ -25,8 +25,8 @@ */ -#ifndef _LINK_H -#define _LINK_H +#ifndef __QF_link_h +#define __QF_link_h // (type *)STRUCT_FROM_LINK(link_t *link, type, member) // ent = STRUCT_FROM_LINK(link,entity_t,order) @@ -43,4 +43,4 @@ void RemoveLink (link_t *l); void InsertLinkBefore (link_t *l, link_t *before); void InsertLinkAfter (link_t *l, link_t *after); -#endif // _LINK_H +#endif//__QF_link_h diff --git a/include/QF/llist.h b/include/QF/llist.h index 7253618b2..e555c6bd6 100644 --- a/include/QF/llist.h +++ b/include/QF/llist.h @@ -25,21 +25,33 @@ */ -#ifndef _LLIST_H -#define _LLIST_H +#ifndef __QF_llist_h +#define __QF_llist_h #include "QF/qtypes.h" +/** \defgroup llist Linked lists + \ingroup utils +*/ +//@{ + typedef struct llist_node_s { - struct llist_s *parent; - struct llist_node_s *prev, *next; - void *data; + struct llist_s *parent; ///< The list owning this node. + struct llist_node_s *prev; ///< The previous node in the list, or null. + struct llist_node_s *next; ///< The flowing node in the list, or null. + void *data; ///< The actual list item. } llist_node_t; typedef struct llist_s { - struct llist_node_s *start, *end, *iter; + struct llist_node_s *start; ///< The first node in the list, or null. + struct llist_node_s *end; ///< The last node in the list, or null. + struct llist_node_s *iter; + /// Function called when deleting a list item. + /// \param element The item being deleted. + /// \param userdata Pointer to user data supplied to llist_new(). void (*freedata)(void *element, void *userdata); - qboolean (*cmpdata)(const void *element, const void *comparison, void *userdata); + qboolean (*cmpdata)(const void *element, const void *comparison, + void *userdata); void *userdata; } llist_t; @@ -48,18 +60,56 @@ typedef qboolean (*llist_iterator_t)(void *element, llist_node_t *node); #define LLIST_ICAST(x) (llist_iterator_t)(x) #define LLIST_DATA(node, type) ((type *)((node)->data)) -llist_t *llist_new (void (*freedata)(void *element, void *userdata), qboolean (*cmpdata)(const void *element, const void *comparison, void *userdata), void *userdata); +/** Create a new, empty, linked list. + + \param freedata Function to call when deleting a list item. + \param cmpdata Function to call to compare two list items. It must + return true when the items are the same and false when + they differ. + \param userdata User data pointer. Set to whatever you want, it will be + passed to the \a freedata and \a cmpdata functions as + their final parameter. + \return Pointer to the list's control structure, which is to be + passed to the other functions accessing the list. +*/ +llist_t *llist_new (void (*freedata)(void *element, void *userdata), + qboolean (*cmpdata)(const void *element, + const void *comparison, + void *userdata), + void *userdata); + +/** Empty a linked list. + All of the items in the list will be deleted via the list's \a freedata + function and the list will become empty. + + \param list Pointer to the list's control structure created by + llist_new(). May be null, in which case no operation is + performed. +*/ void llist_flush (llist_t *list); + +/** Delete a linked list. + All of the items in the list will be deleted via the list's \a freedata + function and the list will be destroyed. Do not attempt to use the list + pointer after destroying the list. + + \param list Pointer to the list's control structure created by + llist_new(). May be null, in which case no operation is + performed. +*/ void llist_delete (llist_t *list); llist_node_t *llist_append (llist_t *list, void *element); llist_node_t *llist_prefix (llist_t *list, void *element); -llist_node_t *llist_getnode (llist_t *list, void *element); +llist_node_t *llist_getnode (llist_t *list, void *element) __attribute__((pure)); llist_node_t *llist_insertafter (llist_node_t *ref, void *element); llist_node_t *llist_insertbefore (llist_node_t *ref, void *element); void *llist_remove (llist_node_t *ref); -unsigned int llist_size (llist_t *llist); +unsigned int llist_size (llist_t *llist) __attribute__((pure)); void llist_iterate (llist_t *list, llist_iterator_t iterate); void *llist_find (llist_t *list, void *comparison); llist_node_t *llist_findnode (llist_t *list, void *comparison); void *llist_createarray (llist_t *list, size_t esize); -#endif + +//@} + +#endif//__QF_llist_h diff --git a/include/QF/math/dual.h b/include/QF/math/dual.h index eba9b8bf0..34c58a984 100644 --- a/include/QF/math/dual.h +++ b/include/QF/math/dual.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_dual Dual and dual quaternion functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -189,6 +189,6 @@ } while (0) #define DualQuatExpand(dq) QuatExpand ((dq).q0.q), QuatExpand ((dq).qe.q) -//@} +///@} #endif // __QF_math_dual_h diff --git a/include/QF/math/half.h b/include/QF/math/half.h index 61baf8f09..bc9133fc6 100644 --- a/include/QF/math/half.h +++ b/include/QF/math/half.h @@ -34,14 +34,14 @@ /** \defgroup mathlib_half Half-float functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" -int16_t FloatToHalf (float x); -float HalfToFloat (int16_t x); +int16_t FloatToHalf (float x) __attribute__((const)); +float HalfToFloat (int16_t x) __attribute__((const)); -//@} +///@} #endif // __QF_math_half_h diff --git a/include/QF/math/matrix3.h b/include/QF/math/matrix3.h index 7a54938dd..dfe9b530f 100644 --- a/include/QF/math/matrix3.h +++ b/include/QF/math/matrix3.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_matrix3 3x3 matrix functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -101,7 +101,7 @@ void Mat3Init (const quat_t rot, const vec3_t scale, mat3_t mat); void Mat3Transpose (const mat3_t a, mat3_t b); -vec_t Mat3Determinant (const mat3_t m); +vec_t Mat3Determinant (const mat3_t m) __attribute__((pure)); int Mat3Inverse (const mat3_t a, mat3_t b); void Mat3Mult (const mat3_t a, const mat3_t b, mat3_t c); void Mat3MultVec (const mat3_t a, const vec3_t b, vec3_t c); @@ -118,6 +118,6 @@ void Mat3SymEigen (const mat3_t m, vec3_t e); */ int Mat3Decompose (const mat4_t mat, quat_t rot, vec3_t shear, vec3_t scale); -//@} +///@} #endif // __QF_math_matrix3_h diff --git a/include/QF/math/matrix4.h b/include/QF/math/matrix4.h index 4f0e0dfb5..a55c8ed94 100644 --- a/include/QF/math/matrix4.h +++ b/include/QF/math/matrix4.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_matrix4 4x4 matrix functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -130,6 +130,6 @@ void Mat4as3MultVec (const mat4_t a, const vec3_t b, vec3_t c); int Mat4Decompose (const mat4_t mat, quat_t rot, vec3_t shear, vec3_t scale, vec3_t trans); -//@} +///@} #endif // __QF_math_matrix4_h diff --git a/include/QF/math/quaternion.h b/include/QF/math/quaternion.h index c6bec188b..da39b7734 100644 --- a/include/QF/math/quaternion.h +++ b/include/QF/math/quaternion.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_quaternion Quaternion functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -58,10 +58,10 @@ extern const vec_t *const quat_origin; } while (0) #define QuatConj(a,b) \ do { \ - (b)[0] = (a)[0]; \ + (b)[0] = -(a)[0]; \ (b)[1] = -(a)[1]; \ (b)[2] = -(a)[2]; \ - (b)[3] = -(a)[3]; \ + (b)[3] = (a)[3]; \ } while (0) #define QuatAdd(a,b,c) \ do { \ @@ -164,10 +164,11 @@ extern const vec_t *const quat_origin; void QuatMult (const quat_t q1, const quat_t q2, quat_t out); void QuatMultVec (const quat_t q, const vec3_t v, vec3_t out); +void QuatRotation (const vec3_t a, const vec3_t b, quat_t out); void QuatInverse (const quat_t in, quat_t out); void QuatExp (const quat_t a, quat_t b); void QuatToMatrix (const quat_t q, vec_t *m, int homogenous, int vertical); -//@} +///@} #endif // __QF_math_quaternion_h diff --git a/include/QF/math/vector.h b/include/QF/math/vector.h index 994ffee62..6189d002c 100644 --- a/include/QF/math/vector.h +++ b/include/QF/math/vector.h @@ -31,7 +31,7 @@ /** \defgroup mathlib_vector Vector functions \ingroup mathlib */ -//@{ +///@{ #include "QF/qtypes.h" @@ -74,6 +74,18 @@ extern const vec_t *const vec3_origin; (c)[1] = (a)[1] - (s) * (b)[1]; \ (c)[2] = (a)[2] - (s) * (b)[2]; \ } while (0) +#define VectorCompMultAdd(a,b,c,d) \ + do { \ + (d)[0] = (a)[0] + (b)[0] * (c)[0]; \ + (d)[1] = (a)[1] + (b)[1] * (c)[1]; \ + (d)[2] = (a)[2] + (b)[2] * (c)[2]; \ + } while (0) +#define VectorCompMultSub(a,b,c,d) \ + do { \ + (d)[0] = (a)[0] - (b)[0] * (c)[0]; \ + (d)[1] = (a)[1] - (b)[1] * (c)[1]; \ + (d)[2] = (a)[2] - (b)[2] * (c)[2]; \ + } while (0) #define VectorLength(a) sqrt(DotProduct(a, a)) #define VectorScale(a,b,c) \ @@ -142,7 +154,12 @@ extern const vec_t *const vec3_origin; } while (0) #define VectorIsZero(a) (!(a)[0] && !(a)[1] && !(a)[2]) -#define VectorZero(a) ((a)[2] = (a)[1] = (a)[0] = 0); +#define VectorZero(a) \ + do { \ + (a)[0] = 0; \ + (a)[1] = 0; \ + (a)[2] = 0; \ + } while (0) #define VectorSet(a,b,c,d) \ do { \ (d)[0] = a; \ @@ -159,6 +176,8 @@ extern const vec_t *const vec3_origin; //For printf etc #define VectorExpand(v) (v)[0], (v)[1], (v)[2] +//For scanf etc +#define VectorExpandAddr(v) &(v)[0], &(v)[1], &(v)[2] /* * VectorDistance, the distance between two points. @@ -171,11 +190,11 @@ extern const vec_t *const vec3_origin; (((a)[2] - (b)[2]) * ((a)[2] - (b)[2]))) #define VectorDistance(a, b) sqrt(VectorDistance_fast(a, b)) -vec_t _DotProduct (const vec3_t v1, const vec3_t v2); +vec_t _DotProduct (const vec3_t v1, const vec3_t v2) __attribute__((pure)); void _VectorAdd (const vec3_t veca, const vec3_t vecb, vec3_t out); void _VectorCopy (const vec3_t in, vec3_t out); -int _VectorCompare (const vec3_t v1, const vec3_t v2); // uses EQUAL_EPSILON -vec_t _VectorLength (const vec3_t v); +int _VectorCompare (const vec3_t v1, const vec3_t v2) __attribute__((pure)); // uses EQUAL_EPSILON +vec_t _VectorLength (const vec3_t v) __attribute__((pure)); void _VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc); void _VectorScale (const vec3_t in, vec_t scale, vec3_t out); @@ -209,6 +228,6 @@ VectorNormalize (vec3_t v) return length; } -//@} +///@} #endif // __QF_math_vector_h diff --git a/include/QF/mathlib.h b/include/QF/mathlib.h index 498dbd2d0..851b841eb 100644 --- a/include/QF/mathlib.h +++ b/include/QF/mathlib.h @@ -25,13 +25,13 @@ */ -#ifndef __mathlib_h -#define __mathlib_h +#ifndef __QF_mathlib_h +#define __QF_mathlib_h /** \defgroup mathlib Vector and matrix functions \ingroup utils */ -//@{ +///@{ #include #include "QF/qtypes.h" @@ -73,15 +73,15 @@ extern int nanmask; // fall over #define ROLL 2 -int Q_log2(int val); +int Q_log2(int val) __attribute__((const)); void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); void FloorDivMod (double numer, double denom, int *quotient, int *rem); -fixed16_t Invert24To16(fixed16_t val); +fixed16_t Invert24To16(fixed16_t val) __attribute__((const)); fixed16_t Mul16_30(fixed16_t multiplier, fixed16_t multiplicand); -int GreatestCommonDivisor (int i1, int i2); +int GreatestCommonDivisor (int i1, int i2) __attribute__((const)); /** Convert quake angles to basis vectors. @@ -139,8 +139,8 @@ void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, void AngleQuat (const vec3_t angles, quat_t q); void VectorVectors (const vec3_t forward, vec3_t right, vec3_t up); int BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, - struct plane_s *plane); -float anglemod (float a); + struct plane_s *plane) __attribute__((pure)); +float anglemod (float a) __attribute__((const)); void RotatePointAroundVector (vec3_t dst, const vec3_t axis, const vec3_t point, float degrees); @@ -174,7 +174,7 @@ void RotatePointAroundVector (vec3_t dst, const vec3_t axis, } while (0) extern plane_t * const frustum; -GNU89INLINE inline qboolean R_CullBox (const vec3_t mins, const vec3_t maxs); +GNU89INLINE inline qboolean R_CullBox (const vec3_t mins, const vec3_t maxs) __attribute__((pure)); GNU89INLINE inline qboolean R_CullSphere (const vec3_t origin, const float radius); #ifndef IMPLEMENT_R_Cull @@ -218,6 +218,6 @@ int CircumSphere (const vec3_t points[], int num_points, sphere_t *sphere); void BarycentricCoords (const vec_t **points, int num_points, const vec3_t p, vec_t *lambda); -//@} +///@} -#endif // __mathlib_h +#endif//__QF_mathlib_h diff --git a/include/QF/mdfour.h b/include/QF/mdfour.h index 94fe99da0..ec8648cd2 100644 --- a/include/QF/mdfour.h +++ b/include/QF/mdfour.h @@ -26,20 +26,20 @@ */ -#ifndef __mdfour_h -#define __mdfour_h +#ifndef __QF_mdfour_h +#define __QF_mdfour_h + +#include "QF/qtypes.h" /** \addtogroup crc */ -//@{ - -#include "QF/uint32.h" +///@{ #define MDFOUR_DIGEST_BYTES 16 struct mdfour { - uint32 A, B, C, D; - uint32 totalN; + uint32_t A, B, C, D; + uint32_t totalN; }; void mdfour_begin(struct mdfour *md); // old: MD4Init @@ -47,6 +47,6 @@ void mdfour_update(struct mdfour *md, const unsigned char *in, int n); //old: MD void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final void mdfour(unsigned char *out, const unsigned char *in, int n); -//@} +///@} -#endif // __mdfour_h +#endif//__QF_mdfour_h diff --git a/include/QF/model.h b/include/QF/model.h index b4d7791cd..1c5969820 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -25,8 +25,8 @@ */ -#ifndef _MODEL_H -#define _MODEL_H +#ifndef __QF_model_h +#define __QF_model_h #include "QF/qtypes.h" #include "QF/bspfile.h" @@ -61,7 +61,6 @@ typedef struct efrag_s { struct efrag_s *entnext; } efrag_t; - // in memory representation =================================================== // !!! if this is changed, it must be changed in asm_draw.h too !!! @@ -90,20 +89,14 @@ typedef struct instsurf_s { } instsurf_t; typedef struct texture_s { - char name[16]; - unsigned int width, height; - int gl_texturenum; - int gl_fb_texturenum; - int sky_tex[2]; - instsurf_t *tex_chain; // for gl_texsort drawing - instsurf_t **tex_chain_tail; - struct elechain_s *elechain; - struct elechain_s **elechain_tail; + char *name; + unsigned width, height; + void *render; // renderer specific data int anim_total; // total tenths in sequence ( 0 = no) int anim_min, anim_max; // time for this frame min <=time< max struct texture_s *anim_next; // in the animation sequence struct texture_s *alternate_anims; // bmodels in frmae 1 use these - unsigned int offsets[MIPLEVELS]; // four mip maps stored + unsigned offsets[MIPLEVELS]; // four mip maps stored } texture_t; @@ -159,7 +152,7 @@ typedef struct msurface_s { int light_s, light_t; // gl lightmap coordinates - glpoly_t *polys; // multiple if warped + glpoly_t *polys; // multiple if warped instsurf_t *instsurf; ///< null if not part of world model/sub-model instsurf_t *tinst; ///< for instance models @@ -186,8 +179,6 @@ typedef struct mnode_s { float minmaxs[6]; // for bounding box culling - struct mnode_s *parent; - // node specific plane_t *plane; struct mnode_s *children[2]; @@ -205,8 +196,6 @@ typedef struct mleaf_s { float mins[3]; float maxs[3]; - struct mnode_s *parent; - // leaf specific byte *compressed_vis; efrag_t *efrags; @@ -233,6 +222,61 @@ typedef struct hull_s { int depth; ///< maximum depth of the tree } hull_t; +typedef struct mod_brush_s { + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + plane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + int depth; ///< maximum depth of the tree + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + mclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + hull_t *hull_list[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + texture_t *skytexture; + + byte *visdata; + byte *lightdata; + char *entities; //FIXME should not be here + + mnode_t **node_parents; + mnode_t **leaf_parents; + + unsigned int checksum; + unsigned int checksum2; +} mod_brush_t; + // SPRITE MODELS ============================================================== // FIXME: shorten these? @@ -282,10 +326,10 @@ typedef struct { } maliasframedesc_t; typedef struct { - aliasskintype_t type; - int skin; - int texnum; - int fb_texnum; + aliasskintype_t type; + int skin; + int texnum; + int fb_texnum; } maliasskindesc_t; typedef struct { @@ -326,14 +370,6 @@ typedef struct { maliasframedesc_t frames[1]; } aliashdr_t; -#define MAXALIASFRAMES 256 -extern aliashdr_t *pheader; -extern stvert_t *stverts; -extern mtriangle_t *triangles; -extern trivertx_t *poseverts[MAXALIASFRAMES]; -extern int aliasbboxmins[3]; -extern int aliasbboxmaxs[3]; - // Whole model ================================================================ typedef enum {mod_brush, mod_sprite, mod_alias, mod_iqm} modtype_t; @@ -349,6 +385,8 @@ typedef enum {mod_brush, mod_sprite, mod_alias, mod_iqm} modtype_t; #define EF_GLOWTRAIL 4096 // glowcolor particle trail typedef struct model_s { + //FIXME use pointers. needs care in bsp submodel loading + char path[MAX_QPATH]; char name[MAX_QPATH]; const struct vpath_s *vpath;// virtual path where this model was found qboolean needload; // bmodels and sprites don't cache normally @@ -376,96 +414,38 @@ typedef struct model_s { vec3_t clipmins, clipmaxs; // brush model - int firstmodelsurface, nummodelsurfaces; - - int numsubmodels; - dmodel_t *submodels; - - int numplanes; - plane_t *planes; - - int numleafs; // number of visible leafs, not counting 0 - mleaf_t *leafs; - - int numvertexes; - mvertex_t *vertexes; - - int numedges; - medge_t *edges; - - int numnodes; - mnode_t *nodes; - int depth; ///< maximum depth of the tree - - int numtexinfo; - mtexinfo_t *texinfo; - - int numsurfaces; - msurface_t *surfaces; - - int numsurfedges; - int *surfedges; - - int numclipnodes; - mclipnode_t *clipnodes; - - int nummarksurfaces; - msurface_t **marksurfaces; - - hull_t hulls[MAX_MAP_HULLS]; - hull_t *hull_list[MAX_MAP_HULLS]; - - int numtextures; - texture_t **textures; - texture_t *skytexture; - - byte *visdata; - byte *lightdata; - char *entities; - - unsigned int checksum; - unsigned int checksum2; + //FIXME should be a pointer (submodels make things tricky) + mod_brush_t brush; // additional model data cache_user_t cache; - void (*clear) (struct model_s *m); + void (*clear) (struct model_s *m, void *data); + void *data; } model_t; // ============================================================================ -extern float RadiusFromBounds (const vec3_t mins, const vec3_t maxs); -void Mod_Init (void); -void Mod_Init_Cvars (void); -void Mod_ClearAll (void); +void Mod_Init (void); +void Mod_Init_Cvars (void); +void Mod_ClearAll (void); model_t *Mod_ForName (const char *name, qboolean crash); -void *Mod_Extradata (model_t *mod); // handles caching -void Mod_TouchModel (const char *name); +void Mod_TouchModel (const char *name); +// brush specific +mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure)); +byte *Mod_LeafPVS (const mleaf_t *leaf, const model_t *model); -mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model); -byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); -model_t *Mod_FindName (const char *name); -int Mod_CalcFullbright (byte *in, byte *out, int pixels); -int Mod_Fullbright (byte * skin, int width, int height, char *name); +// NOTE: the buffer pointed to by out must be at least MAP_PVS_BYTES in size +void Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out); +void Mod_LeafPVS_mix (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out); -void *Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, - int extra); -void *Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, - int extra); - -void Mod_FindClipDepth (hull_t *hull); -void Mod_LoadBrushModel (model_t *mod, void *buffer); -void Mod_FloodFillSkin (byte * skin, int skinwidth, int skinheight); - -void Mod_Print (void); +void Mod_Print (void); extern struct cvar_s *gl_mesh_cache; extern struct cvar_s *gl_subdivide_size; extern struct cvar_s *gl_alias_render_tri; extern struct cvar_s *gl_textures_external; -extern model_t *loadmodel; -extern char *loadname; -extern byte *mod_base; -extern byte mod_novis[MAX_MAP_LEAFS / 8]; extern int mod_lightmap_bytes; -#endif // _MODEL_H +#endif//__QF_model_h diff --git a/include/QF/modelgen.h b/include/QF/modelgen.h index 447a8c864..66cdd1308 100644 --- a/include/QF/modelgen.h +++ b/include/QF/modelgen.h @@ -31,8 +31,8 @@ // * pass data from one to the other via model files. * // ********************************************************* -#ifndef _MODELGEN_H -#define _MODELGEN_H +#ifndef __QF_modelgen_h +#define __QF_modelgen_h #include "QF/mathlib.h" @@ -142,4 +142,4 @@ typedef struct { // little-endian "IDP2" #define IDHEADER_MD2 (('2'<<24)+('P'<<16)+('D'<<8)+'I') -#endif // _MODELGEN_H +#endif//__QF_modelgen_h diff --git a/include/QF/msg.h b/include/QF/msg.h index 63da220e9..4f696f896 100644 --- a/include/QF/msg.h +++ b/include/QF/msg.h @@ -24,13 +24,13 @@ Boston, MA 02111-1307, USA */ -#ifndef _MSG_H -#define _MSG_H +#ifndef __QF_msg_h +#define __QF_msg_h /** \defgroup msg Message reading and writing \ingroup utils */ -//@{ +///@{ #include "QF/sizebuf.h" @@ -73,7 +73,7 @@ void MSG_BeginReading (qmsg_t *msg); \param msg The message to check. \return The number of bytes that have been read. */ -int MSG_GetReadCount(qmsg_t *msg); +int MSG_GetReadCount(qmsg_t *msg) __attribute__((pure)); /** Read a single byte from the message. @@ -249,6 +249,6 @@ void MSG_ReadAngle16V (qmsg_t *msg, vec3_t angles); */ int MSG_ReadUTF8 (qmsg_t *msg); -//@} +///@} -#endif +#endif//__QF_msg_h diff --git a/include/QF/object.h b/include/QF/object.h index 39f06210b..f5c4f97f8 100644 --- a/include/QF/object.h +++ b/include/QF/object.h @@ -32,8 +32,8 @@ */ -#ifndef __object_h -#define __object_h +#ifndef __QF_object_h +#define __QF_object_h #include "QF/qtypes.h" @@ -115,4 +115,4 @@ void Object_Garbage_Collect (void); #include "QF/classes/String.h" -#endif +#endif//__QF_object_h diff --git a/include/QF/pak.h b/include/QF/pak.h index f176e5733..e331fca6e 100644 --- a/include/QF/pak.h +++ b/include/QF/pak.h @@ -28,12 +28,12 @@ */ -#ifndef __qf_pak_h -#define __qf_pak_h +#ifndef __QF_pak_h +#define __QF_pak_h /** \addtogroup pak */ -//@{ +///@{ // little-endian PACK #define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') @@ -51,6 +51,6 @@ typedef struct { int dirlen; } dpackheader_t; -//@} +///@} -#endif//__qf_pak_h +#endif//__QF_pak_h diff --git a/include/QF/pakfile.h b/include/QF/pakfile.h index ecb6738f0..7bb4f3a0e 100644 --- a/include/QF/pakfile.h +++ b/include/QF/pakfile.h @@ -33,7 +33,7 @@ /** \defgroup pak pakfile proccessing \ingroup utils */ -//@{ +///@{ #include "QF/hash.h" #include "QF/pak.h" @@ -64,6 +64,6 @@ int pack_add (pack_t *pack, const char *filename); int pack_extract (pack_t *pack, dpackfile_t *pf); dpackfile_t *pack_find_file (pack_t *pack, const char *filename); -//@} +///@} #endif//__QF_pakfile_h diff --git a/include/QF/pcx.h b/include/QF/pcx.h index 641df359c..b140dde8f 100644 --- a/include/QF/pcx.h +++ b/include/QF/pcx.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __pcx_h -#define __pcx_h +#ifndef __QF_pcx_h +#define __QF_pcx_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -71,10 +71,11 @@ pcx_t *EncodePCX (const byte *data, int width, int height, int rowbytes, \param f The file to read the texture from \param convert If true, the texture is converted to RGB on load \param pal The palette to apply during conversion + \param load If false, only the format and size info is loaded \return A pointer to the texture. \warning Uses Hunk_TempAlloc() to allocate the texture. */ -struct tex_s *LoadPCX (QFile *f, qboolean convert, const byte *pal); +struct tex_s *LoadPCX (QFile *f, qboolean convert, const byte *pal, int load); -#endif // __pcx_h +#endif//__QF_pcx_h diff --git a/include/QF/plist.h b/include/QF/plist.h new file mode 100644 index 000000000..b14b5e4aa --- /dev/null +++ b/include/QF/plist.h @@ -0,0 +1,508 @@ +/* + plist.h + + Property list management types and prototypes + + Copyright (C) 2000 Jeff Teunissen + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_plist_h +#define __QF_plist_h + +struct hashlink_s; + +/** \defgroup plist Property lists + \ingroup utils +*/ +///@{ + +#include "QF/qtypes.h" + +/** The type of the property list item. + + For further details, see \ref property-list. +*/ +typedef enum { + QFDictionary, ///< The property list item represents a dictionary. + QFArray, ///< The property list item represents an array. + QFBinary, ///< The property list item represents arbitrary binary + ///< data. + QFString, ///< The property list item represents a C string. + + QFMultiType = (1 << 31) ///< if bit 31 is set, the type indicates a mask + ///< of allowed types for plfield_t +} pltype_t; + +/** Generic property list item. + + All inspection and manipulation is to be done via the accessor functions. +*/ +typedef struct plitem_s plitem_t; + +struct plfield_s; +/** Custom parser for the field. + + With this, custom parsing of any property list object type is + supported. For example, parsing of strings into numeric values, + converting binary objects to images, and deeper parsing of array and + dictionary objects. + + If null, then the default parser for the object type is used: + * QFString: the point to the actual string. The string continues + to be owned by the string object. + * QFBinary: pointer to fixed-size DARRAY_TYPE(byte) (so size isn't + lost) + * QFArray: pointer to fixed-size DARRAY_TYPE(plitem_t *) with the + indivisual objects. The individual objects continue to be owned + by the array object. + * QFDictionary: pointer to the hashtab_t hash table used for the + dictionary object. The hash table continues to be owned by the + dictionary object. + + \param field Pointer to this field item. + \param item The property list item being parsed into the field. + \param data Pointer to the field in the structure being parsed. + \param messages An array object the parser can use to store any + error messages. Messages should be strings, but no + checking is done: it is up to the top-level caller to + parse out the messages. + \param context Additional context data passed to the parser. + \return 0 for error, 1 for success. See \a PL_ParseDictionary. +*/ +typedef int (*plparser_t) (const struct plfield_s *field, + const struct plitem_s *item, + void *data, + struct plitem_s *messages, + void *context); + +/** A field to be parsed from a dictionary item. + + something +*/ +typedef struct plfield_s { + const char *name; ///< matched by dictionary key + size_t offset; ///< the offset of the field within the structure + pltype_t type; ///< the required type of the dictionary object + plparser_t parser; ///< custom parser function + void *data; ///< additional data for \a parser +} plfield_t; + +typedef struct plelement_s { + pltype_t type; ///< the required type of the array elements + size_t stride; ///< the size of each element + void *(*alloc) (void *ctx, size_t size);///< allocator for array memory + plparser_t parser; ///< custom parser function + void *data; ///< additional data for \a parser +} plelement_t; + +/** Create an in-memory representation of the contents of a property list. + + \param string the saved plist, as read from a file. + \param hashlinks Hashlink chain to use when creating dictionaries (see + Hash_NewTable()). May be null. + + \return Returns an object equivalent to the passed-in string. + \note You are responsible for freeing the returned object. +*/ +plitem_t *PL_GetPropertyList (const char *string, + struct hashlink_s **hashlinks); + +/** Create a property list string from the in-memory representation. + + \param pl the in-memory representation + \return the text representation of the property list + \note You are responsible for freeing the returned string. +*/ +char *PL_WritePropertyList (const plitem_t *pl); + +/** Retrieve the type of an object. + + \param item The object. Must not be null. + \return the type of the object +*/ +pltype_t PL_Type (const plitem_t *item) __attribute__((pure)); + +/** Retrieve the line number of an object. + + \param item The object. Must not be null. + \return the line number on which the object began, or 0 if not from a + string +*/ +int PL_Line (const plitem_t *item) __attribute__((pure)); + +/** Retrieve the data size from a binary object. + + \param binary The binary object + \return the size in bytes of the binary object 0 if \a binary isn't a + binary object (includes if \a binary is null). +*/ +size_t PL_BinarySize (const plitem_t *binary) __attribute__((pure)); + +/** Retrieve the data from a binary object. + + \param binary The binary object + \return pointer to the actual data or NULL if \b binary isn't a binary + object (includes if \a binary is null). + \note You are NOT responsible for freeing the returned object. It will + be destroyed when its container is. +*/ +const void *PL_BinaryData (const plitem_t *binary) __attribute__((pure)); + +/** Retrieve a string from a string object. + + \param string The string object + \return pointer to the actual string value or NULL if string isn't a + string (includes if \a string is null). + \note You are NOT responsible for freeing the returned object. It will + be destroyed when its container is. +*/ +const char *PL_String (const plitem_t *string) __attribute__((pure)); + +/** Retrieve a value from a dictionary object. + + \param dict The dictionary to retrieve a value from + \param key The unique key associated with the value + \return the value associated with the key, or NULL if not found or \a dict + isn't a dictionary (includes if \a dict is null). + \note You are NOT responsible for freeing the returned object. It will + be destroyed when its container is. +*/ +plitem_t *PL_ObjectForKey (const plitem_t *dict, const char *key); + +/** Remove a value from a dictionary object. + + \param dict The Dictionary to remove the value from + \param key The unique key associated with the value to be removed + \return the value associated with the key, or NULL if not found or \a dict + isn't a dictionary (includes if \a dict is null). + \note You are responsible for freeing the returned object. +*/ +plitem_t *PL_RemoveObjectForKey (const plitem_t *dict, const char *key); + +/** Retrieve a key from a dictionary object. + + \param dict The dictionary to get the key from + \param index The index of the key + \return the key at the specified index, or NULL if index is out of range or + dict is not a dictionary (includes if \a dict is null). + \note You are NOT responsible for freeing the returned object. It will + be destroyed when its container is. +*/ +const char *PL_KeyAtIndex (const plitem_t *dict, int index) __attribute__((pure)); + +/** Retrieve a value from an array object. + + \param array The array to get the value from + \param index The index within the array to retrieve + \return the value at the specified index, or NULL if \a index is out of + range or \a array is not an array (includes in \a array is null). + \note You are NOT responsible for freeing the returned object. It will + be destroyed when its container is. +*/ +plitem_t *PL_ObjectAtIndex (const plitem_t *array, int index) __attribute__((pure)); + +/** Retrieve a list of all keys in a dictionary. + + \param dict The dictionary to list + \return an Array containing Strings or NULL if \a dict isn't a dictionary + (includes if \a dict is null). + \note You are responsible for freeing this array. +*/ +plitem_t *PL_D_AllKeys (const plitem_t *dict); + +/** Retrieve the number of keys in a dictionary. + + \param dict The dictionary to get the number of keys of. + + \return Returns the number of keys in the dictionary or 0 if \a dict isn't + a dictionary (includes if \a dict is null). +*/ +int PL_D_NumKeys (const plitem_t *dict) __attribute__((pure)); + +/** Add a key/value pair to a dictionary. + + \param dict The dictionary to which the key/value pair will be added + \param key The key of the key/value pair to be added to the dictionary + \param value The value of the key/value pair to be added to the dictionary + + \return true on success, false on failure (\a dict is null or not a + dictionary) + + \note the dictionary becomes the owner of the value. +*/ +qboolean PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value); + +/** Add an item to an array. + + \param array The array to which the item will be added + \param item The item to be added to the array + + \return true on success, false on failure (\a array is null or not an + array) + + \note the array becomes the owner of the added item. +*/ +qboolean PL_A_AddObject (plitem_t *array, plitem_t *item); + +/** Retrieve the number of items in an array. + + \param array The array from which to get the number of objects + + \return number of objects in the array or 0 if \a array is null or not + an array. +*/ +int PL_A_NumObjects (const plitem_t *array) __attribute__((pure)); + +/** Insert an item into an array before the specified location. + + \param array The array to which the item will be added + \param item The item to be added to the array + \param index The location at which to insert the item into the array + + \return true on success, false on failure (\a array is null or not an + array). + + \note the array becomes the owner of the added item. +*/ +qboolean PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index); + +/** Remove a value from an array object. + The array items will be shuffled to fill the resulting hole. + + \param array The array from which to remove the value + \param index The index within the array to remove + \return the value associated with the index, or NULL if not found or array + is noll or an array. + \note You are responsible for freeing the returned object. +*/ +plitem_t *PL_RemoveObjectAtIndex (plitem_t *array, int index); + +/** Create a new dictionary object. + The dictionary will be empty. + \param hashlinks Hashlink chain to use when creating dictionaries (see + Hash_NewTable()). May be null. + \return the new dictionary object +*/ +plitem_t *PL_NewDictionary (struct hashlink_s **hashlinks); + +/** Create a new array object. + The array will be empty. + \return the new array object +*/ +plitem_t *PL_NewArray (void); + +/** Create a new data object from the given data. + Takes ownership of the given data. + \param data pointer to data buffer + \param size number of bytes in the buffer + \return the new dictionary object + \note The data will be freed via free() when the item is freed. +*/ +plitem_t *PL_NewData (void *data, size_t size); + +/** Create a new string object. + Makes a copy of the given string. + \param str C string to copy + \return the new dictionary object +*/ +plitem_t *PL_NewString (const char *str); + +/** Free a property list object. + + This function takes care of freeing any referenced property list data, so + call it only on top-level objects. Safe to call with a null argument. + + \param item the property list object to be freed +*/ +void PL_Free (plitem_t *item); + +int PL_CheckType (pltype_t field_type, pltype_t item_type) __attribute__((const)); +void PL_TypeMismatch (plitem_t *messages, const plitem_t *item, + const char *name, pltype_t field_type, + pltype_t item_type); + +/** Parse a dictionary object into a structure. + + For each key in the dictionary, the corresponding field item is used to + determine how to parse the object associated with that key. Duplicate + field items are ignored: only the first item is used, and no checking is + done. Fields for which there is no key in the dictionary are also ignored, + and the destination is left unmodified. However, keys that have no + corresponding field are treated as errors and a suitable message is added + to the \a messages object. + + When an error occurs (unknown key, incorrect item type (item type does not + match the type specified in the field item) or the field item's \a parser + returns 0), processing continues but the error result is returned. + + Can be used recursively to parse deep hierarchies. + + \param fields Array of field items describing the structure. Terminated + by a field item with a null \a name pointer. + \param dict The dictionary object to parse + \param data Pointer to the structure into which the data will be + parsed. + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \param context Additional context data passed to the parser. + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, + void *data, plitem_t *messages, void *context); + +/** Parse an array object into a dynamic array (see darray.h). + + For each object in the array, the field item is used to determine how to + parse the object. If the array is empty, the destination will be + initialized to an empty array. + + When an error occurs (incorrect item type (item type does not match the + type specified in the element object) or the element object's \a parser + returns 0), processing continues but the error result is returned. + + Can be used recursively to parse deep hierarchies. + + \param field Pointer to a single field that has the field data pointer + set to reference a plelement_t object used to describe + the contents of the array. + \param array The array object to parse + \param data Pointer to the pointer to which the dynamic array will + be written. The dynamic array is allocated using + DARRAY_ALLOCFIXED_OBJ(). + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \param context Additional context data passed to the parser and allocator. + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseArray (const plfield_t *field, const plitem_t *array, + void *data, plitem_t *messages, void *context); + +/** Parse a dictionary object into a dynamic array (see darray.h). + + This is useful when the dictionary object is meant to be a labeled list + rather than a representation of a structure. + + For each object in the array, the field item is used to determine how to + parse the object. If the array is empty, the destination will be + initialized to an empty array. + + When an error occurs (incorrect item type (item type does not match the + type specified in the element object) or the element object's \a parser + returns 0), processing continues but the error result is returned. + + Can be used recursively to parse deep hierarchies. + + \param field Pointer to a single field that has the field data pointer + set to reference a plelement_t object used to describe + the contents of the array. + \param dict The dict object to parse + \param data Pointer to the pointer to which the dynamic array will + be written. The dynamic array is allocated using + DARRAY_ALLOCFIXED_OBJ(). + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \param context Additional context data passed to the parser and allocator. + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict, + void *data, plitem_t *messages, void *context); + +/** Parse a dictionary object into a hash table. + + For each key in the dictionary, the element object is used to determine + how to parse the object associated with that key. Duplicate keys are an + error: they must be unique. A suitable message is added to the + \a messages object. If the dictionary object is empty, the destination + table is left unmodified. + + When an error occurs (duplicate keys, incorrect type, or the element + object's \a parser returns 0), processing continues but the error + result is returned. + + Can be used recursively to parse deep hierarchies. + + Hash_Add() is used to add objects to the hash table, and Hash_Find() is + used to check for duplicates. Hash_Free() is used to free unused + objects. The means that the hash table is expected to use standard + objects with embedded keys (the parser is expected to put the key in the + object) and to have a free function. + + The parser's data paramenter points to a pre-allocated block of memory + of the sized indicated by the element object's size field, using the + element object's alloc callback. The name field in the field paramenter + is set to the object's key and remains owned by the dictionary. + + \param field Pointer to a single field that has the field data pointer + set to reference a plelement_t object used to describe + the contents of the dictionary. + \param dict The dictionary object to parse + \param data Pointer to the structure into which the data will be + parsed. + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \param context Additional context data passed to the parser and allocator. + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, + void *data, plitem_t *messages, void *context); +void __attribute__((format(printf,3,4))) +PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...); + +///@} + +#endif//__QF_plist_h diff --git a/include/QF/plugin.h b/include/QF/plugin.h index 995b72750..f1ff974a3 100644 --- a/include/QF/plugin.h +++ b/include/QF/plugin.h @@ -25,22 +25,22 @@ */ -#ifndef __QF_plugin_h_ -#define __QF_plugin_h_ +#ifndef __QF_plugin_h +#define __QF_plugin_h /** \defgroup plugin Plugins \ingroup utils */ -//@{ +///@{ #define QFPLUGIN_VERSION "1.0" #include #ifdef STATIC_PLUGINS -#define PLUGIN_INFO(type,name) plugin_t *type##_##name##_PluginInfo (void); plugin_t * type##_##name##_PluginInfo (void) +#define PLUGIN_INFO(type,name) plugin_t *type##_##name##_PluginInfo (void); __attribute__((const)) plugin_t * type##_##name##_PluginInfo (void) #else -#define PLUGIN_INFO(type,name) plugin_t *PluginInfo (void); __attribute__((visibility ("default"))) plugin_t *PluginInfo (void) +#define PLUGIN_INFO(type,name) plugin_t *PluginInfo (void); __attribute__((visibility ("default"),const)) plugin_t *PluginInfo (void) #endif typedef enum { @@ -111,6 +111,6 @@ void PI_Shutdown (void); // FIXME: we need a generic function to initialize unused fields -//@} +///@} -#endif // __QF_plugin_h_ +#endif//__QF_plugin_h diff --git a/include/QF/plugin/console.h b/include/QF/plugin/console.h index e743d20e7..b404728e3 100644 --- a/include/QF/plugin/console.h +++ b/include/QF/plugin/console.h @@ -34,7 +34,7 @@ #include #include -typedef void (*P_C_Print) (const char *fmt, va_list args); +typedef void (*P_C_Print) (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); typedef void (*P_C_ProcessInput) (void); typedef void (*P_C_KeyEvent) (knum_t key, short unicode, qboolean down); typedef void (*P_C_DrawConsole) (void); diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 90b34eec8..43f4f064b 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -37,6 +37,8 @@ struct plitem_s; struct cvar_s; struct skin_s; +struct mod_alias_ctx_s; + /* All video plugins must export these functions */ @@ -80,23 +82,25 @@ typedef struct vid_particle_funcs_s { } vid_particle_funcs_t; typedef struct vid_model_funcs_s { - void (*Mod_LoadExternalTextures) (model_t *mod); - void (*Mod_LoadLighting) (bsp_t *bsp); - void (*Mod_SubdivideSurface) (msurface_t *fa); - void (*Mod_ProcessTexture) (texture_t *tx); + size_t texture_render_size;// size of renderer specific texture data + void (*Mod_LoadLighting) (model_t *mod, bsp_t *bsp); + void (*Mod_SubdivideSurface) (model_t *mod, msurface_t *fa); + void (*Mod_ProcessTexture) (model_t *mod, texture_t *tx); void (*Mod_LoadIQM) (model_t *mod, void *buffer); void (*Mod_LoadAliasModel) (model_t *mod, void *buffer, cache_allocator_t allocator); void (*Mod_LoadSpriteModel) (model_t *mod, void *buffer); - void (*Mod_MakeAliasModelDisplayLists) (model_t *m, aliashdr_t *hdr, + void (*Mod_MakeAliasModelDisplayLists) (struct mod_alias_ctx_s *alias_ctx, void *_m, int _s, int extra); - void *(*Mod_LoadSkin) (byte *skin, int skinsize, int snum, int gnum, + void *(*Mod_LoadSkin) (struct mod_alias_ctx_s *alias_ctx, byte *skin, + int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc); - void (*Mod_FinalizeAliasModel) (model_t *m, aliashdr_t *hdr); - void (*Mod_LoadExternalSkins) (model_t *mod); + void (*Mod_FinalizeAliasModel) (struct mod_alias_ctx_s *alias_ctx); + void (*Mod_LoadExternalSkins) (struct mod_alias_ctx_s *alias_ctx); void (*Mod_IQMFinish) (model_t *mod); int alias_cache; - void (*Mod_SpriteLoadTexture) (mspriteframe_t *pspriteframe, int framenum); + void (*Mod_SpriteLoadTexture) (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); struct skin_s *(*Skin_SetColormap) (struct skin_s *skin, int cmap); struct skin_s *(*Skin_SetSkin) (struct skin_s *skin, int cmap, @@ -108,7 +112,6 @@ typedef struct vid_model_funcs_s { } vid_model_funcs_t; typedef struct vid_render_funcs_s { - void (*Draw_Init) (void); void (*Draw_Character) (int x, int y, unsigned ch); void (*Draw_String) (int x, int y, const char *str); void (*Draw_nString) (int x, int y, const char *str, int count); @@ -130,10 +133,7 @@ typedef struct vid_render_funcs_s { void (*Draw_Picf) (float x, float y, qpic_t *pic); void (*Draw_SubPic) (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); - - // scr_funcs is a null terminated array - void (*SCR_UpdateScreen) (double realtime, SCR_Func scr_3dfunc, - SCR_Func *scr_funcs); + void (*SCR_SetFOV) (float fov); void (*SCR_DrawRam) (void); void (*SCR_DrawTurtle) (void); void (*SCR_DrawPause) (void); @@ -147,15 +147,17 @@ typedef struct vid_render_funcs_s { void (*Fog_ParseWorldspawn) (struct plitem_s *worldspawn); void (*R_Init) (void); + void (*R_RenderFrame) (SCR_Func scr_3dfunc, SCR_Func *scr_funcs); void (*R_ClearState) (void); void (*R_LoadSkys) (const char *); void (*R_NewMap) (model_t *worldmodel, model_t **models, int num_models); - void (*R_AddEfrags) (entity_t *ent); + void (*R_AddEfrags) (mod_brush_t *brush, entity_t *ent); void (*R_RemoveEfrags) (entity_t *ent); void (*R_EnqueueEntity) (struct entity_s *ent); //FIXME should not be here void (*R_LineGraph) (int x, int y, int *h_vals, int count); dlight_t *(*R_AllocDlight) (int key); entity_t *(*R_AllocEntity) (void); + void (*R_MaxDlightsCheck) (struct cvar_s *var); void (*R_RenderView) (void); void (*R_DecayLights) (double frametime); diff --git a/include/QF/png.h b/include/QF/png.h index c3e2ed562..b322a93f0 100644 --- a/include/QF/png.h +++ b/include/QF/png.h @@ -33,7 +33,7 @@ #include "QF/quakefs.h" -struct tex_s *LoadPNG (QFile *infile); +struct tex_s *LoadPNG (QFile *infile, int load); void WritePNG (const char *fileName, const byte *data, int width, int height); void WritePNGqfs (const char *fileName, const byte *data, int width, int height); diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 4cc274f98..0cd65d7e5 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -18,8 +18,8 @@ */ // this file is shared by QuakeForge and qfcc -#ifndef __pr_comp_h -#define __pr_comp_h +#ifndef __QF_pr_comp_h +#define __QF_pr_comp_h #include "QF/qtypes.h" @@ -27,7 +27,7 @@ typedef int16_t pr_short_t; typedef uint16_t pr_ushort_t; typedef int32_t pr_int_t; typedef uint32_t pr_uint_t; -typedef pr_int_t func_t; +typedef pr_uint_t func_t; typedef pr_int_t string_t; typedef pr_uint_t pointer_t; @@ -44,13 +44,14 @@ typedef enum { ev_integer, ev_uinteger, ev_short, // value is embedded in the opcode + ev_double, ev_invalid, // invalid type. used for instruction checking ev_type_count // not a type, gives number of types } etype_t; -extern int pr_type_size[ev_type_count]; -extern const char *pr_type_name[ev_type_count]; +extern const pr_ushort_t pr_type_size[ev_type_count]; +extern const char * const pr_type_name[ev_type_count]; #define OFS_NULL 0 #define OFS_RETURN 1 @@ -140,7 +141,7 @@ typedef enum { OP_OR, OP_BITAND, - OP_BITOR, + OP_BITOR, // end of v6 opcodes OP_ADD_S, OP_LE_S, @@ -180,8 +181,8 @@ typedef enum { OP_SHL_I, OP_SHR_I, - OP_MOD_F, - OP_MOD_I, + OP_REM_F, + OP_REM_I, OP_LOADB_F, OP_LOADB_V, @@ -295,7 +296,111 @@ typedef enum { OP_RCALL8, OP_RETURN_V, + + OP_PUSH_S, + OP_PUSH_F, + OP_PUSH_V, + OP_PUSH_ENT, + OP_PUSH_FLD, + OP_PUSH_FN, + OP_PUSH_P, + OP_PUSH_Q, + OP_PUSH_I, + OP_PUSH_D, + + OP_PUSHB_S, + OP_PUSHB_F, + OP_PUSHB_V, + OP_PUSHB_ENT, + OP_PUSHB_FLD, + OP_PUSHB_FN, + OP_PUSHB_P, + OP_PUSHB_Q, + OP_PUSHB_I, + OP_PUSHB_D, + + OP_PUSHBI_S, + OP_PUSHBI_F, + OP_PUSHBI_V, + OP_PUSHBI_ENT, + OP_PUSHBI_FLD, + OP_PUSHBI_FN, + OP_PUSHBI_P, + OP_PUSHBI_Q, + OP_PUSHBI_I, + OP_PUSHBI_D, + + OP_POP_S, + OP_POP_F, + OP_POP_V, + OP_POP_ENT, + OP_POP_FLD, + OP_POP_FN, + OP_POP_P, + OP_POP_Q, + OP_POP_I, + OP_POP_D, + + OP_POPB_S, + OP_POPB_F, + OP_POPB_V, + OP_POPB_ENT, + OP_POPB_FLD, + OP_POPB_FN, + OP_POPB_P, + OP_POPB_Q, + OP_POPB_I, + OP_POPB_D, + + OP_POPBI_S, + OP_POPBI_F, + OP_POPBI_V, + OP_POPBI_ENT, + OP_POPBI_FLD, + OP_POPBI_FN, + OP_POPBI_P, + OP_POPBI_Q, + OP_POPBI_I, + OP_POPBI_D, + + OP_ADD_D, + OP_SUB_D, + OP_MUL_D, + OP_MUL_QD, + OP_MUL_DQ, + OP_MUL_VD, + OP_MUL_DV, + OP_DIV_D, + OP_REM_D, + OP_GE_D, + OP_LE_D, + OP_GT_D, + OP_LT_D, + OP_NOT_D, + OP_EQ_D, + OP_NE_D, + OP_CONV_FD, + OP_CONV_DF, + OP_CONV_ID, + OP_CONV_DI, + OP_STORE_D, + OP_STOREB_D, + OP_STOREBI_D, + OP_STOREP_D, + OP_LOAD_D, + OP_LOADB_D, + OP_LOADBI_D, + OP_ADDRESS_D, + + OP_MOD_I, + OP_MOD_F, + OP_MOD_D, + + OP_MEMSETI, + OP_MEMSETP, + OP_MEMSETPI, } pr_opcode_e; +#define OP_BREAK 0x8000 typedef struct opcode_s { const char *name; @@ -307,9 +412,9 @@ typedef struct opcode_s { const char *fmt; } opcode_t; -extern opcode_t pr_opcodes[]; +extern const opcode_t pr_opcodes[]; opcode_t *PR_Opcode (pr_short_t opcode); -void PR_Opcode_Init (void); +void PR_Opcode_Init (void); // idempotent typedef struct dstatement_s { pr_opcode_e op:16; @@ -317,28 +422,51 @@ typedef struct dstatement_s { } GCC_STRUCT dstatement_t; typedef struct ddef_s { - pr_ushort_t type; // if DEF_SAVEGLOBGAL bit is set + pr_ushort_t type; // if DEF_SAVEGLOBAL bit is set // the variable needs to be saved in savegames pr_ushort_t ofs; - pr_int_t s_name; + string_t s_name; } ddef_t; +typedef struct xdef_s { + pointer_t type; ///< pointer to type definition + pointer_t ofs; ///< 32-bit version of ddef_t.ofs +} xdef_t; + +typedef struct pr_xdefs_s { + pointer_t xdefs; + pr_int_t num_xdefs; +} pr_xdefs_t; + +typedef struct pr_def_s { + pr_ushort_t type; + pr_ushort_t size; ///< may not be correct + pointer_t ofs; + string_t name; + pointer_t type_encoding; +} pr_def_t; + +typedef struct dparmsize_s { + uint8_t size:5; + uint8_t alignment:3; +} dparmsize_t; + #define DEF_SAVEGLOBAL (1<<15) #define MAX_PARMS 8 typedef struct dfunction_s { pr_int_t first_statement; // negative numbers are builtins - pr_int_t parm_start; - pr_int_t locals; // total ints of parms + locals + pr_uint_t parm_start; + pr_uint_t locals; // total ints of parms + locals - pr_int_t profile; // runtime + pr_uint_t profile; // runtime - pr_int_t s_name; - pr_int_t s_file; // source file defined in + string_t s_name; + string_t s_file; // source file defined in pr_int_t numparms; - uint8_t parm_size[MAX_PARMS]; + dparmsize_t parm_size[MAX_PARMS]; } dfunction_t; typedef union pr_type_u { @@ -346,8 +474,8 @@ typedef union pr_type_u { string_t string_var; func_t func_var; pr_int_t entity_var; - float vector_var[1]; // really 3, but this structure must be 32 bits - float quat_var[1]; // really 4, but this structure must be 32 bits + float vector_var; // really [3], but this structure must be 32 bits + float quat_var; // really [4], but this structure must be 32 bits pr_int_t integer_var; pointer_t pointer_var; pr_uint_t uinteger_var; @@ -363,7 +491,7 @@ typedef struct pr_va_list_s { |(((0x##b) & 0xfff) << 12) \ |(((0x##c) & 0xfff) << 0) ) #define PROG_ID_VERSION 6 -#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,009) +#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,00a) typedef struct dprograms_s { pr_uint_t version; @@ -379,10 +507,10 @@ typedef struct dprograms_s { pr_uint_t numfielddefs; pr_uint_t ofs_functions; - pr_int_t numfunctions; // function 0 is an empty + pr_uint_t numfunctions; // function 0 is an empty pr_uint_t ofs_strings; - pr_int_t numstrings; // first string is a null string + pr_uint_t numstrings; // first string is a null string pr_uint_t ofs_globals; pr_uint_t numglobals; @@ -390,4 +518,4 @@ typedef struct dprograms_s { pr_uint_t entityfields; } dprograms_t; -#endif // __pr_comp_h +#endif//__QF_pr_comp_h diff --git a/include/QF/pr_debug.h b/include/QF/pr_debug.h index 65b953381..4015f6f65 100644 --- a/include/QF/pr_debug.h +++ b/include/QF/pr_debug.h @@ -28,19 +28,26 @@ */ -#ifndef __pr_debug_h -#define __pr_debug_h +#ifndef __QF_pr_debug_h +#define __QF_pr_debug_h +#ifndef __QFCC__ #include "QF/pr_comp.h" +typedef struct pr_compunit_s { + pr_uint_t unit_name; + pr_uint_t basedir; + pr_uint_t num_files; + pr_uint_t files[1]; +} pr_compunit_t; + typedef struct pr_auxfunction_s { pr_uint_t function; // function def this aux info is for pr_uint_t source_line; // first source line for this function pr_uint_t line_info; // index to first lineno entry pr_uint_t local_defs; // index to the first local def pr_uint_t num_locals; // number of local defs - pr_short_t return_type; // return type of this function - pr_short_t reserved; + pr_uint_t return_type; // return type of this function } pr_auxfunction_t; typedef struct pr_lineno_s { @@ -51,7 +58,7 @@ typedef struct pr_lineno_s { pr_uint_t line; } pr_lineno_t; -#define PROG_DEBUG_VERSION 0x00001002 // MMmmmRRR 0.001.002 (hex) +#define PROG_DEBUG_VERSION 0x00001004 // MMmmmRRR 0.001.004 (hex) typedef struct pr_debug_header_s { pr_int_t version; @@ -63,6 +70,24 @@ typedef struct pr_debug_header_s { pr_uint_t num_linenos; pr_uint_t locals; pr_uint_t num_locals; + pr_uint_t debug_defs; + pr_uint_t num_debug_defs; + pr_uint_t debug_data; + pr_uint_t debug_data_size; } pr_debug_header_t; +#endif -#endif//__pr_debug_h +typedef enum prdebug_e { + prd_none, + prd_trace, + prd_breakpoint, + prd_watchpoint, + prd_subenter, + prd_subexit, // current invocation of PR_ExecuteProgram finished + prd_begin, // not sent by VM + prd_terminate, // not sent by VM + prd_runerror, + prd_error, // lower level error thann prd_runerror +} prdebug_t; + +#endif//__QF_pr_debug_h diff --git a/include/QF/pr_obj.h b/include/QF/pr_obj.h index 5e4f8463c..52f05aa16 100644 --- a/include/QF/pr_obj.h +++ b/include/QF/pr_obj.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_obj_h -#define __pr_obj_h +#ifndef __QF_pr_obj_h +#define __QF_pr_obj_h #include "QF/pr_comp.h" @@ -94,7 +94,7 @@ typedef struct pr_class_s { pr_int_t instance_size; pointer_t ivars; // pr_ivar_list_t pointer_t methods; // pr_method_list_t - pointer_t dtable; + pointer_t dtable; // resource index pointer_t subclass_list; // pr_class_t pointer_t sibling_class; // pr_class_t pointer_t protocols; // pr_protocol_list_t @@ -185,4 +185,4 @@ typedef struct pr_super_s { pointer_t class; } pr_super_t; -#endif//__pr_obj_h +#endif//__QF_pr_obj_h diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h new file mode 100644 index 000000000..56915724b --- /dev/null +++ b/include/QF/pr_type.h @@ -0,0 +1,125 @@ +/* + pr_type.h + + object file type encoding support + + Copyright (C) 2011 Bill Currie + + Author: Bill Currie + Date: 2011/02/18 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_pr_type_h +#define __QF_pr_type_h + +/** \defgroup qfcc_qfo_type Object file type encoding + \ingroup progs + + All \c pointer_t \c type fields are pointers within the type qfo_space. +*/ +///@{ + +#include "QF/pr_comp.h" + +typedef enum { + ty_basic, ///< VM type (float, int, pointer, field, etc) + ty_struct, + ty_union, + ty_enum, + ty_array, + ty_class, + ty_alias, +} ty_meta_e; + +typedef struct qfot_alias_s { + etype_t type; ///< type at end of alias chain + pointer_t aux_type; ///< referenced type: stripped of aliases + pointer_t full_type; ///< includes full alias info + string_t name; ///< alias name, may be null +} qfot_alias_t; + +typedef struct qfot_fldptr_s { + etype_t type; ///< ev_field or ev_pointer + pointer_t aux_type; ///< referenced type +} qfot_fldptr_t; + +typedef struct qfot_func_s { + etype_t type; ///< always ev_func + pointer_t return_type; ///< return type of the function + pr_int_t num_params; ///< ones compliment count of the + ///< parameters. -ve values indicate the + ///< number of real parameters before the + ///< ellipsis + pointer_t param_types[1]; ///< variable length list of parameter + ///< types +} qfot_func_t; + +typedef struct qfot_var_s { + pointer_t type; ///< type of field or self reference for + ///< enum + string_t name; ///< name of field/enumerator + pr_int_t offset; ///< value for enum, 0 for union +} qfot_var_t; + +typedef struct qfot_struct_s { + string_t tag; ///< struct/union/enum tag + pr_int_t num_fields; ///< number of fields/enumerators + qfot_var_t fields[1]; ///< variable length list of + ///< fields/enumerators +} qfot_struct_t; + +typedef struct qfot_array_s { + pointer_t type; ///< element type + pr_int_t base; ///< start index of array + pr_int_t size; ///< number of elements in array +} qfot_array_t; + +/** QFO type encoding. + + \note As this holds a union of all type representations, and those + representations may contain variable arrays, sizeof() will return only + one, rather useless, value. It is also not suitable for direct use in + arrays. +*/ +typedef struct qfot_type_s { + ty_meta_e meta; ///< meta type + pr_uint_t size; ///< total word size of this encoding + string_t encoding; ///< Objective-QC encoding + union { + etype_t type; ///< ty_basic: etype_t + qfot_fldptr_t fldptr; ///< ty_basic, ev_pointer/ev_field + qfot_func_t func; ///< ty_basic, ev_func + qfot_struct_t strct; ///< ty_struct/ty_union/ty_enum + qfot_array_t array; ///< ty_array + string_t class; ///< ty_class + qfot_alias_t alias; ///< ty_alias + }; +} qfot_type_t; + +typedef struct qfot_type_encodings_s { + pointer_t types; + pr_uint_t size; +} qfot_type_encodings_t; + +///@} + +#endif//__QF_pr_type_h diff --git a/include/QF/progs.h b/include/QF/progs.h index 7c8bb3341..b6ced5935 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -39,22 +39,26 @@ struct QFile_s; /** \ingroup progs */ -//@{ +///@{ typedef struct progs_s progs_t; typedef struct pr_resource_s pr_resource_t; typedef struct edict_s edict_t; -//@} +///@} //============================================================================ /** \defgroup progs_misc Miscelaneous functions \ingroup progs */ -//@{ +///@{ /** Initialize the progs engine. + + The first call will initialize subsystems common to all progs instances. + + \param pr The progs engine instance to initialize. */ -void PR_Init (void); +void PR_Init (progs_t *pr); /** Initialize the Cvars for the progs engine. Call before calling PR_Init(). */ @@ -63,12 +67,12 @@ void PR_Init_Cvars (void); void PR_Error (progs_t *pr, const char *error, ...) __attribute__((format(printf,2,3), noreturn)); void PR_RunError (progs_t *pr, const char *error, ...) __attribute__((format(printf,2,3), noreturn)); -//@} +///@} /** \defgroup progs_execution Execution \ingroup progs */ -//@{ +///@{ /** Ensure P_* macros point to the right place for passing parameters to progs functions. @@ -87,15 +91,63 @@ void PR_RunError (progs_t *pr, const char *error, ...) __attribute__((format(pri (pr)->pr_params[1] = (pr)->pr_real_params[1]; \ } while (0) -/** Save the current parameters. - \param pr pointer to ::progs_t VM struct +/** \name Detouring Function Calls + + These functions allow a builtin function that uses PR_CallFunction() to + safely insert a call to another VM function. The +initialize diversion + required by Objective-QuakeC uses this. + + PR_PushFrame (pr); + __auto_type params = PR_SaveParams (pr); + ... set up parameters to detour_function + PR_ExecuteProgram (pr, detour_function) + PR_RestoreParams (pr, params); + PR_PopFrame (pr); + */ -void PR_SaveParams (progs_t *pr); +///@{ +typedef struct pr_stashed_params_s { + pr_type_t *param_ptrs[2]; + int argc; + pr_type_t params[1]; +} pr_stashed_params_t; + +/** Save the current parameters to the provided stash. + + \warning The memory for the parameter stash is allocated using + alloca(). + + \param pr pointer to ::progs_t VM struct + \return Pointer to a newly allocated and initialized parameter + stash that has the current parameters saved to it. + \hideinitializer +*/ +#define PR_SaveParams(pr) \ + _PR_SaveParams((pr), \ + alloca (field_offset (pr_stashed_params_t, \ + params[(pr)->pr_argc \ + * (pr)->pr_param_size]))) + +/** [INTERNAL] Save the current parameters to the provided stash. + + \warning Requires \a params to be correctly allocated. Use + PR_SaveParams instead as it will create a suitable stash for + saving the parameters. + + \param pr pointer to ::progs_t VM struct + \param params location to save the parameters, must be of adequade size + to hold \a pr_argc * \a pr_param_size words in \a params + \return \a params Allows the likes of: + __auto_type params = PR_SaveParams (pr); +*/ +pr_stashed_params_t *_PR_SaveParams (progs_t *pr, pr_stashed_params_t *params); /** Restore the parameters saved by PR_SaveParams(). \param pr pointer to ::progs_t VM struct + \param params pointer to stash created by PR_SaveParams() */ -void PR_RestoreParams (progs_t *pr); +void PR_RestoreParams (progs_t *pr, pr_stashed_params_t *params); +///@} /** Push an execution frame onto the VM stack. Saves current execution state. \param pr pointer to ::progs_t VM struct @@ -128,12 +180,12 @@ void PR_ExecuteProgram (progs_t *pr, func_t fnum); */ int PR_CallFunction (progs_t *pr, func_t fnum); -//@} +///@} /** \defgroup progs_load Loading \ingroup progs */ -//@{ +///@{ /** Type of functions that are called at progs load. \param pr pointer to ::progs_t VM struct @@ -145,27 +197,22 @@ typedef int pr_load_func_t (progs_t *pr); \param pr pointer to ::progs_t VM struct \param file handle of file to read progs data from \param size bytes of \p file to read - \param max_edicts \e number of entities to allocate space for - \param zone minimum size of dynamic memory to allocate space for - dynamic memory (bytes). \note \e All runtime strings (permanent or temporary) are allocated from - the VM's dynamic memory space, so be sure \p zone is of sufficient size. - So far, 1MB has proven more than sufficient for Quakeword, even when using - Ruamoko objects. + the VM's dynamic memory space, so be sure \p zone is of sufficient size + (by setting pr->zone_size prior to calling). So far, 1MB has proven more + than sufficient for Quakeword, even when using Ruamoko objects. + \note If entities are used, ensure pr->max_edicts is set appropriately + prior to calling. */ -void PR_LoadProgsFile (progs_t *pr, struct QFile_s *file, int size, - int max_edicts, int zone); +void PR_LoadProgsFile (progs_t *pr, struct QFile_s *file, int size); /** Convenience wrapper for PR_LoadProgsFile() and PR_RunLoadFuncs(). Searches for the specified file in the Quake filesystem. \param pr pointer to ::progs_t VM struct \param progsname name of the file to load as progs data - \param max_edicts \e number of entities to allocate space for - \param zone minimum size of dynamic memory to allocate space for */ -void PR_LoadProgs (progs_t *pr, const char *progsname, int max_edicts, - int zone); +void PR_LoadProgs (progs_t *pr, const char *progsname); /** Register a primary function to be called after the progs code has been loaded. These functions are remembered across progs loads. They will be @@ -189,14 +236,24 @@ void PR_AddLoadFinishFunc (progs_t *pr, pr_load_func_t *func); \return true for success, false for failure Calls the first set of internal load functions followed by the supplied - symbol resolution function, if any (progs_t::resolve), the second set of - internal load functions. After that, any primary load functions are called - in order of registration followed by any \c .ctor functions in the progs, - then any secondary load functions the primary load functions registered - in \e reverse order of registration. + symbol resolution function, if any (progs_t::resolve), then the second set + of internal load functions. After that, any primary load functions are + called in order of registration, and if there is no debug handler, + PR_RunPostLoadFuncs() is called. */ int PR_RunLoadFuncs (progs_t *pr); +/** Run any progs-dependent load functions. + \param pr pointer to ::progs_t VM struct + \return true for success, false for failure + This means any \c .ctor functions in the progs, followed by any secondary + load functions registered by either the primary load functions or the + \.c ctor functions in \e reverse order of registration. This is called + automatically by PR_RunLoadFuncs() if there is no debug handler, otherwise + it is up to the host to call this function. +*/ +int PR_RunPostLoadFuncs (progs_t *pr); + /** Validate the opcodes and statement addresses in the progs. This is an internal load function. \param pr pointer to ::progs_t VM struct @@ -209,29 +266,30 @@ int PR_Check_Opcodes (progs_t *pr); void PR_BoundsCheckSize (progs_t *pr, pointer_t addr, unsigned size); void PR_BoundsCheck (progs_t *pr, int addr, etype_t type); -//@} +///@} /** \defgroup progs_edict Edict management \ingroup progs */ -//@{ +///@{ struct edict_s { qboolean free; + progs_t *pr; ///< progs owning this edict int entnum; ///< number of this entity + int edict; ///< offset of this entity in pr_edict_area float freetime; ///< sv.time when the object was freed void *edata; ///< external per-edict data - pr_type_t v[1]; ///< fields from progs }; // pr_edict.c void ED_ClearEdict (progs_t *pr, edict_t *e, int val); edict_t *ED_Alloc (progs_t *pr); void ED_Free (progs_t *pr, edict_t *ed); -edict_t *ED_EdictNum(progs_t *pr, pr_int_t n); -pr_int_t ED_NumForEdict(progs_t *pr, edict_t *e); +edict_t *ED_EdictNum(progs_t *pr, pr_int_t n) __attribute__((pure)); +pr_int_t ED_NumForEdict(progs_t *pr, edict_t *e) __attribute__((pure)); void ED_Count (progs_t *pr); -qboolean PR_EdictValid (progs_t *pr, pr_int_t e); +qboolean PR_EdictValid (progs_t *pr, pr_int_t e) __attribute__((pure)); // pr_debug.c void ED_Print (progs_t *pr, edict_t *ed); @@ -241,44 +299,48 @@ void ED_PrintNum (progs_t *pr, pr_int_t ent); // pr_parse.c struct script_s; struct plitem_s; -qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, +struct hashlink_s; +qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s); struct plitem_s *ED_EntityDict (progs_t *pr, edict_t *ed); struct plitem_s *ED_GlobalsDict (progs_t *pr); void ED_InitGlobals (progs_t *pr, struct plitem_s *globals); void ED_InitEntity (progs_t *pr, struct plitem_s *entity, edict_t *ent); -struct plitem_s *ED_ConvertToPlist (struct script_s *script, int nohack); +struct plitem_s *ED_ConvertToPlist (struct script_s *script, int nohack, + struct hashlink_s **hashlinks); struct plitem_s *ED_Parse (progs_t *pr, const char *data); void ED_LoadFromFile (progs_t *pr, const char *data); void ED_EntityParseFunction (progs_t *pr); -#define PR_edicts(p) ((byte *) *(p)->edicts) +#define PR_edicts(p) (*(p)->pr_edicts) -#define NEXT_EDICT(p,e) ((edict_t *) ((byte *) e + (p)->pr_edict_size)) -#define EDICT_TO_PROG(p,e) ((pr_int_t)(intptr_t)((byte *)(e) - PR_edicts (p))) -#define PROG_TO_EDICT(p,e) ((edict_t *) (PR_edicts (p) + (e))) +#define NEXT_EDICT(p,e) ((e) + 1) +#define EDICT_TO_PROG(p,e) ((e)->entnum * (p)->pr_edict_size) +#define PROG_TO_EDICT(p,e) (&PR_edicts(p)[(e) / (p)->pr_edict_size]) #define NUM_FOR_BAD_EDICT(p,e) ((e)->entnum) #ifndef PR_PARANOID_PROGS -# define EDICT_NUM(p,n) (PROG_TO_EDICT (p, (n) * (p)->pr_edict_size)) -# define NUM_FOR_EDICT(p,e) NUM_FOR_BAD_EDICT (p, e) +# define EDICT_NUM(p,n) (PR_edicts (p) + (n)) +# define NUM_FOR_EDICT(p,e) NUM_FOR_BAD_EDICT ((p), (e)) #else -# define EDICT_NUM(p,n) ED_EdictNum (p, n) -# define NUM_FOR_EDICT(p,e) ED_NumForEdict (p, e) +# define EDICT_NUM(p,n) ED_EdictNum ((p), (n)) +# define NUM_FOR_EDICT(p,e) ED_NumForEdict ((p), (e)) #endif -//@} +///@} /** \defgroup pr_symbols Symbol Management \ingroup progs Lookup functions for symbol name resolution. */ -//@{ +///@{ -ddef_t *PR_FieldAtOfs (progs_t *pr, pr_int_t ofs); -ddef_t *PR_GlobalAtOfs (progs_t *pr, pr_int_t ofs); +pr_def_t *PR_SearchDefs (pr_def_t *defs, unsigned num_defs, pointer_t offset) + __attribute__((pure)); +pr_def_t *PR_FieldAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); +pr_def_t *PR_GlobalAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); -ddef_t *PR_FindField (progs_t *pr, const char *name); -ddef_t *PR_FindGlobal (progs_t *pr, const char *name); +pr_def_t *PR_FindField (progs_t *pr, const char *name); +pr_def_t *PR_FindGlobal (progs_t *pr, const char *name); dfunction_t *PR_FindFunction (progs_t *pr, const char *name); int PR_ResolveGlobals (progs_t *pr); @@ -287,7 +349,7 @@ int PR_AccessField (progs_t *pr, const char *name, etype_t type, const char *file, int line); void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute__((noreturn)); -//@} +///@} //============================================================================ @@ -301,7 +363,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ Typed global access macros. No checking is done against the QC type, but the appropriate C type will be used. */ -//@{ +///@{ /** \internal \param p pointer to ::progs_t VM struct @@ -313,6 +375,21 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define G_var(p,o,t) ((p)->pr_globals[o].t##_var) +/** Access a global as an arbitray type. + + More direct than G_STRUCT + \par QC type: + \c struct etc small enough to fit in a single parameter + \param p pointer to ::progs_t VM struct + \param t C type of the structure + \param o offset into global data space + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define G_PACKED(p,t,o) (*(t *) &(p)->pr_globals[o]) + /** Access a float global. Can be assigned to. \par QC type: @@ -325,6 +402,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define G_FLOAT(p,o) G_var (p, o, float) +/** Access a double global. Can be assigned to. + + \par QC type: + \c double + \param p pointer to ::progs_t VM struct + \param o offset into global data space + \return double lvalue + + \hideinitializer +*/ +#define G_DOUBLE(p,o) (*(double *) ((p)->pr_globals + o)) + /** Access an integer global. Can be assigned to. \par QC type: @@ -359,7 +448,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_VECTOR(p,o) G_var (p, o, vector) +#define G_VECTOR(p,o) (&G_var (p, o, vector)) /** Access a quaternion global. Can be assigned to. @@ -371,7 +460,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_QUAT(p,o) G_var (p, o, quat) +#define G_QUAT(p,o) (&G_var (p, o, quat)) /** Access a string index global. Can be assigned to. @@ -420,7 +509,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_EDICT(p,o) ((edict_t *)(PR_edicts (p) + G_INT (p, o))) +#define G_EDICT(p,o) PROG_TO_EDICT ((p), G_INT (p, o)) /** Access an entity global. @@ -484,14 +573,14 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define G_STRUCT(p,t,o) (*(t *)G_GPOINTER (p, o)) -//@} +///@} /** \defgroup prda_parameters Parameters \ingroup progs_data_access Typed parameter access macros. No checking is done against the QC type, but the appropriate C type will be used. */ -//@{ +///@{ /** \internal \param p pointer to ::progs_t VM struct @@ -503,6 +592,20 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_var(p,n,t) ((p)->pr_params[n]->t##_var) +/** Access a parameter as an arbitray type. + + \par QC type: + \c struct etc small enough to fit in a single parameter + \param p pointer to ::progs_t VM struct + \param t C type of the structure + \param n parameter number (0-7) + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define P_PACKED(p,t,n) (*(t *) (p)->pr_params[n]) + /** Access a float parameter. Can be assigned to. \par QC type: @@ -515,6 +618,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_FLOAT(p,n) P_var (p, n, float) +/** Access a double parameter. Can be assigned to. + + \par QC type: + \c double + \param p pointer to ::progs_t VM struct + \param n parameter number (0-7) + \return double lvalue + + \hideinitializer +*/ +#define P_DOUBLE(p,n) P_PACKED(p, double, n) + /** Access an integer parameter. Can be assigned to. \par QC type: @@ -549,7 +664,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_VECTOR(p,n) P_var (p, n, vector) +#define P_VECTOR(p,n) (&P_var (p, n, vector)) /** Access a quaterion parameter. Can be used any way a quat_t variable can. @@ -561,7 +676,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_QUAT(p,n) P_var (p, n, quat) +#define P_QUAT(p,n) (&P_var (p, n, quat)) /** Access a string index parameter. Can be assigned to. @@ -599,7 +714,6 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_POINTER(p,n) P_var (p, n, pointer) - /** Access an entity parameter. \par QC type: @@ -610,7 +724,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_EDICT(p,n) ((edict_t *)(PR_edicts (p) + P_INT (p, n))) +#define P_EDICT(p,n) PROG_TO_EDICT ((p), P_INT (p, n)) /** Access an entity parameter. @@ -674,7 +788,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define P_STRUCT(p,t,n) (*(t *)P_GPOINTER (p, n)) -//@} +///@} /** \defgroup prda_return Return Values \ingroup progs_data_access @@ -685,7 +799,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ ask for an \c int from a function that returned a \c float, you're asking for trouble. */ -//@{ +///@{ /** \internal \param p pointer to ::progs_t VM struct @@ -696,6 +810,19 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define R_var(p,t) ((p)->pr_return->t##_var) +/** Access the VM function return value parameter as an arbitray type. + + \par QC type: + \c struct etc small enough to fit in the return slot + \param p pointer to ::progs_t VM struct + \param t C type of the structure + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define R_PACKED(p,t) (*(t *) (p)->pr_return) + /** Access the VM function return value as a \c float \par QC type: @@ -707,6 +834,17 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define R_FLOAT(p) R_var (p, float) +/** Access the VM function return value as a \c double + + \par QC type: + \c double + \param p pointer to ::progs_t VM struct + \return double lvalue + + \hideinitializer +*/ +#define R_DOUBLE(p) R_PACKED (p, double) + /** Access the VM function return value as a \c ::pr_int_t (AKA int32_t) \par QC type: @@ -738,7 +876,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_VECTOR(p) R_var (p, vector) +#define R_VECTOR(p) (&R_var (p, vector)) /** Access the VM function return value as a \c ::quat_t quaternion. @@ -749,7 +887,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_QUAT(p) R_var (p, quat) +#define R_QUAT(p) (&R_var (p, quat)) /** Access the VM function return value as a ::string_t (a VM string reference). @@ -807,7 +945,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define RETURN_EDICT(p,e) (R_STRING (p) = EDICT_TO_PROG(p, e)) +#define RETURN_EDICT(p,e) (R_INT (p) = EDICT_TO_PROG(p, e)) /** Set the return value to the given C pointer. NULL is converted to 0. @@ -841,14 +979,14 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define RETURN_QUAT(p,q) VectorCopy (q, R_QUAT (p)) -//@} +///@} /** \defgroup prda_entity_fields Entity Fields \ingroup progs_data_access Typed entity field access macros. No checking is done against the QC type, but the appropriate C type will be used. */ -//@{ +///@{ /** \internal \param e pointer to the entity @@ -858,7 +996,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_var(e,o,t) ((e)->v[o].t##_var) +#define E_fld(e,o) ((e)->pr->pr_edict_area[(e)->edict + (o)]) + + +/** \internal + \param e pointer to the entity + \param o field offset into entity data space + \param t typename prefix (see pr_type_u) + \return lvalue of the appropriate type + + \hideinitializer +*/ +#define E_var(e,o,t) (E_fld (e,o).t##_var) /** Access a float entity field. Can be assigned to. @@ -873,6 +1022,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define E_FLOAT(e,o) E_var (e, o, float) +/** Access a double entity field. Can be assigned to. + + \par QC type: + \c double + \param e pointer to the entity + \param o field offset into entity data space + \return double lvalue + + \hideinitializer +*/ +#define E_DOUBLE(e,o) (*(double *) ((e)->v + o)) + /** Access an integer entity field. Can be assigned to. \par QC type: @@ -907,7 +1068,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_VECTOR(e,o) E_var (e, o, vector) +#define E_VECTOR(e,o) (&E_var (e, o, vector)) /** Access a quaternion entity field. Can be used any way a quat_t variable can. @@ -985,7 +1146,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define E_DSTRING(p,e,o) (PR_GetMutableString (p, E_STRING (e, o))) -//@} +///@} /** \defgroup pr_builtins VM Builtin functions \ingroup progs @@ -998,7 +1159,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ 0x8000000 to 0xffffffff is unavailable due to the builtin number being a negative statement address. */ -//@{ +///@{ #define PR_RANGE_SHIFT 16 #define PR_RANGE_MASK 0xffff0000 @@ -1037,7 +1198,7 @@ typedef struct { pr_int_t locals; pr_int_t profile; pr_int_t numparms; - uint8_t parm_size[MAX_PARMS]; + dparmsize_t parm_size[MAX_PARMS]; dfunction_t *descriptor; builtin_proc func; } bfunction_t; @@ -1072,7 +1233,7 @@ builtin_t *PR_FindBuiltinNum (progs_t *pr, pr_int_t num); */ int PR_RelocateBuiltins (progs_t *pr); -//@} +///@} /** \defgroup pr_strings String Management \ingroup progs @@ -1098,9 +1259,16 @@ int PR_RelocateBuiltins (progs_t *pr); They can be created, altered, and destroyed at any time by the main program (or the progs code via an appropriate builtin function). */ -//@{ +///@{ -/** Initialize the string tables using the strings supplied by the progs. +/** Initialize the string management subsystem. + + \param pr The VM of which the string management subsystem will be + initialized; +*/ +void PR_Strings_Init (progs_t *pr); + +/** Initialize the string tables using the strings supplied by the progs. Called automatically during progs load. \param pr pointer to ::progs_t VM struct \return true for success, false for failure @@ -1112,21 +1280,28 @@ int PR_LoadStrings (progs_t *pr); \param num string index to be validated \return true if the index is valid, false otherwise */ -qboolean PR_StringValid (progs_t *pr, string_t num); +qboolean PR_StringValid (progs_t *pr, string_t num) __attribute__((pure)); + +/** Check if a string is valid and mutable. + \param pr pointer to ::progs_t VM struct + \param num string index to be checked + \return true if the string is valid and mutable, false otherwise +*/ +qboolean PR_StringMutable (progs_t *pr, string_t num) __attribute__((pure)); /** Convert a string index to a C string. \param pr pointer to ::progs_t VM struct \param num string index to be converted \return C pointer to the string. */ -const char *PR_GetString(progs_t *pr, string_t num); +const char *PR_GetString(progs_t *pr, string_t num) __attribute__((pure)); /** Retrieve the dstring_t associated with a mutable string. \param pr pointer to ::progs_t VM struct \param num string index of the mutable string \return the dstring implementing the mutable string */ -struct dstring_s *PR_GetMutableString(progs_t *pr, string_t num); +struct dstring_s *PR_GetMutableString(progs_t *pr, string_t num) __attribute__((pure)); /** Make a permanent progs string from the given C string. Will not create a duplicate permanent string (temporary and mutable strings are not checked). @@ -1136,6 +1311,15 @@ struct dstring_s *PR_GetMutableString(progs_t *pr, string_t num); */ string_t PR_SetString(progs_t *pr, const char *s); +/** Get the progs string if it exists. + Only static strings are searched. + \param pr pointer to ::progs_t VM struct + \param s C string to be found + \return string index of the progs string if it exists, otherwise + 0 (ambiguous with ""). +*/ +string_t PR_FindString(progs_t *pr, const char *s); + /** Make a temporary progs string that will survive across function returns. Will not duplicate a permanent string. If a new progs string is created, it will be freed after ::PR_RS_SLOTS calls to this function. ie, up to @@ -1154,6 +1338,29 @@ string_t PR_SetReturnString(progs_t *pr, const char *s); */ string_t PR_SetTempString(progs_t *pr, const char *s); +/** Make a temporary memory block that will be freed when the current progs + stack frame is exited. The contents may be anything and a new block is + returned every time, and the block is in VM addressible space. To access + the contents of the block (for reading, writing, etc), use PR_GetString() + and cast the pointer as necessary. + + \param pr pointer to ::progs_t VM struct + \param size size of block in bytes + \return string index of the block +*/ +string_t PR_AllocTempBlock (progs_t *pr, size_t size); + +/** Push a temporary string to the callee stack frame + + This is for when the temp string needs to be freed when the called function + returns rather than the calling function. It is an error to push a non-temp + string. + + \param pr pointer to ::progs_t VM struct + \param num string index of the temp string +*/ +void PR_PushTempString (progs_t *pr, string_t num); + /** Make a temporary progs string that is the concatenation of two C strings. \param pr pointer to ::progs_t VM struct \param a C string @@ -1184,10 +1391,17 @@ string_t PR_NewMutableString (progs_t *pr); */ string_t PR_SetDynamicString (progs_t *pr, const char *s); -/** Clear all of the return string slots. Called at progs load. +/** Convert an ephemeral string to a dynamic string. + + Valid strings that are not ephemeral (static, dynamic, mutable) will not + be affected, but temp and return strings will be marked dynamic, requiring + a call to PR_FreeString to return their memory. + \param pr pointer to ::progs_t VM struct + \param str The string to be "held" (made non-ephemeral). Safe to call + on any valid string, but affects only ephemeral strings. */ -void PR_ClearReturnStrings (progs_t *pr); +void PR_HoldString (progs_t *pr, string_t str); /** Destroy a mutable, dynamic or temporary string. \param pr pointer to ::progs_t VM struct @@ -1259,13 +1473,13 @@ void PR_FreeTempStrings (progs_t *pr); void PR_Sprintf (progs_t *pr, struct dstring_s *result, const char *name, const char *format, int count, pr_type_t **args); -//@} +///@} /** \defgroup pr_resources Resource Management \ingroup progs Builtin module private data management. */ -//@{ +///@{ /** Initialize the resource management fields. @@ -1319,7 +1533,7 @@ void *PR_Resources_Find (progs_t *pr, const char *name); \note \p map is the resource map itself, not a pointer to the resource map. */ -//@{ +///@{ /** Type delcaration for the resource map. @@ -1330,68 +1544,85 @@ void *PR_Resources_Find (progs_t *pr, const char *name); /** Allocate a new resource from the resource map. - \param type The type of the resource. Must match the \c type parameter - used for PR_RESMAP. \param map The resource map. \return A pointer to the new resource, or null if no more could be allocated. */ -#define PR_RESNEW(type,map) \ - type *t; \ - \ - if (!map._free) { \ - int i, size; \ - map._size++; \ - size = map._size * sizeof (type *); \ - map._map = realloc (map._map, size); \ - if (!map._map) \ - return 0; \ - map._free = calloc (1024, sizeof (type)); \ - if (!map._free) \ - return 0; \ - map._map[map._size - 1] = map._free; \ - for (i = 0; i < 1023; i++) \ - *(type **) &map._free[i] = &map._free[i + 1]; \ - *(type **) &map._free[i] = 0; \ - } \ - t = map._free; \ - map._free = *(type **) t; \ - memset (t, 0, sizeof (type)); \ - return t +#define PR_RESNEW_NC(map) \ + ({ \ + if (!(map)._free) { \ + int i, size; \ + (map)._size++; \ + size = (map)._size * sizeof ((map)._free); \ + (map)._map = realloc ((map)._map, size); \ + if (!(map)._map) { \ + return 0; \ + } \ + (map)._free = malloc (1024 * sizeof (*(map)._free)); \ + if (!(map)._free) { \ + return 0; \ + } \ + (map)._map[(map)._size - 1] = (map)._free; \ + for (i = 0; i < 1023; i++) { \ + *(typeof ((map)._free) *) &(map)._free[i] \ + = &(map)._free[i + 1]; \ + } \ + *(typeof ((map)._free) *) &(map)._free[i] = 0; \ + } \ + __auto_type t = (map)._free; \ + (map)._free = *(typeof ((map)._free) *) t; \ + t; \ + }) + +#define PR_RESNEW(map) \ + ({ \ + __auto_type t = PR_RESNEW_NC (map); \ + memset (t, 0, sizeof (*(map)._free)); \ + t; \ + }) /** Free a resource returning it to the resource map. - \param type The type of the resource. Must match the \c type parameter - used for PR_RESMAP. \param map The resource map. \param t Pointer to the resource to be freed. */ -#define PR_RESFREE(type,map,t) \ - memset (t, 0, sizeof (type)); \ - *(type **) t = map._free; \ - map._free = t +#define PR_RESFREE(map,t) \ + do { \ + memset (t, 0, sizeof (*(map)._free)); \ + *(typeof ((map)._free) *) t = (map)._free; \ + (map)._free = t; \ + } while (0) /** Free all resources in the resource map. Any memory allocated to the resource must be freed before freeing the resource. - \param type The type of the resource. Must match the \c type parameter - used for PR_RESMAP. + A reset resource map is guaranteed to allocate elements sequentially. + \param map The resource map. */ -#define PR_RESRESET(type,map) \ - unsigned i, j; \ - if (!map._size) \ - return; \ - for (i = 0; i < map._size; i++) { \ - map._free = map._map[i]; \ - for (j = 0; j < 1023; j++) \ - *(type **) &map._free[j] = &map._free[j + 1]; \ - if (i < map._size - 1) \ - *(type **) &map._free[j] = &map._map[i + 1][0]; \ - } \ - map._free = map._map[0]; +#define PR_RESRESET(map) \ + do { \ + unsigned i, j; \ + if (!(map)._size) { \ + return; \ + } \ + for (i = 0; i < (map)._size; i++) { \ + (map)._free = (map)._map[i]; \ + for (j = 0; j < 1023; j++) { \ + *(typeof ((map)._free) *) &(map)._free[j] \ + = &(map)._free[j + 1]; \ + } \ + if (i < (map)._size - 1) { \ + *(typeof ((map)._free) *) &(map)._free[j] \ + = &(map)._map[i + 1][0]; \ + } else { \ + *(typeof ((map)._free) *) &(map)._free[j] = 0; \ + } \ + } \ + (map)._free = (map)._map[0]; \ + } while (0) /** Retrieve a resource from the resource map using a handle. @@ -1400,12 +1631,14 @@ void *PR_Resources_Find (progs_t *pr, const char *name); \return A pointer to the resource, or NULL if the handle is invalid. */ -#define PR_RESGET(map,col) \ - unsigned row = ~col / 1024; \ - col = ~col % 1024; \ - if (row >= map._size) \ - return 0; \ - return &map._map[row][col] +#define PR_RESGET(map,col) \ + ({ \ + unsigned row = ~col / 1024; \ + col = ~col % 1024; \ + if (row >= (map)._size) \ + return 0; \ + &(map)._map[row][col]; \ + }) /** Convert a resource pointer to a handle. @@ -1413,51 +1646,106 @@ void *PR_Resources_Find (progs_t *pr, const char *name); \param ptr The resource pointer. \return The handle or 0 if the pointer is invalid. */ -#define PR_RESINDEX(map,ptr) \ - unsigned i; \ - for (i = 0; i < map._size; i++) { \ - long d = ptr - map._map[i]; \ - if (d >= 0 && d < 1024) \ - return ~(i * 1024 + d); \ - } \ - return 0 -//@} +#define PR_RESINDEX(map,ptr) \ + ({ \ + unsigned i; \ + unsigned index = 0; \ + for (i = 0; i < (map)._size; i++) { \ + long d = ptr - (map)._map[i]; \ + if (d >= 0 && d < 1024) { \ + index = ~(i * 1024 + d); \ + break; \ + } \ + } \ + index; \ + }) +///@} -//@} +///@} /** \defgroup pr_zone VM memory management. \ingroup progs Used to allocate and free memory in the VM address space. */ -//@{ +///@{ void PR_Zone_Init (progs_t *pr); void PR_Zone_Free (progs_t *pr, void *ptr); void *PR_Zone_Malloc (progs_t *pr, pr_int_t size); void *PR_Zone_Realloc (progs_t *pr, void *ptr, pr_int_t size); +void *PR_Zone_TagMalloc (progs_t *pr, int size, int tag); -//@} +///@} /** \defgroup debug VM Debugging \ingroup progs Progs debugging support. */ -//@{ +/// \addtogroup debug +///@{ -void PR_Debug_Init (void); +struct qfot_type_s; + +/** Callback for viewing progs data + + \param type C pointer to the type definition by which to view the + data. + \param value C pointer to the data to be viewed. + \param data User data. +*/ +typedef void (*type_view_func) (struct qfot_type_s *type, pr_type_t *value, + void *data); + +/** Set of callbacks for viewing progs data + + Each possible type has its own callback. Basic types (those for which the + VM has specific instructions) all have separate callbacks, one for each + type, but the callbacks for compound types are expected to some + interpretation on their own, such as displaying a simple identifier or + the entire contents of the data. +*/ +typedef struct type_view_s { + type_view_func void_view; + type_view_func string_view; + type_view_func float_view; + type_view_func vector_view; + type_view_func entity_view; + type_view_func field_view; + type_view_func func_view; + type_view_func pointer_view; + type_view_func quat_view; + type_view_func integer_view; + type_view_func uinteger_view; + type_view_func short_view; + type_view_func double_view; + + type_view_func struct_view; + type_view_func union_view; + type_view_func enum_view; + type_view_func array_view; + type_view_func class_view; +} type_view_t; + +void PR_Debug_Init (progs_t *pr); void PR_Debug_Init_Cvars (void); int PR_LoadDebug (progs_t *pr); +const char *PR_Debug_GetBaseDirectory (progs_t *pr, const char *file); void PR_Debug_Watch (progs_t *pr, const char *expr); void PR_Debug_Print (progs_t *pr, const char *expr); -pr_auxfunction_t *PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno); -pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno); -pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno); -pr_lineno_t *PR_Find_Lineno (progs_t *pr, pr_uint_t addr); -const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno); +pr_auxfunction_t *PR_Debug_AuxFunction (progs_t *pr, pr_uint_t func) __attribute__((pure)); +pr_auxfunction_t *PR_Debug_MappedAuxFunction (progs_t *pr, pr_uint_t func) __attribute__((pure)); +pr_def_t *PR_Debug_LocalDefs (progs_t *pr, pr_auxfunction_t *aux_function) __attribute__((pure)); +pr_lineno_t *PR_Debug_Linenos (progs_t *pr, pr_auxfunction_t *aux_function, + pr_uint_t *num_linenos); +pr_auxfunction_t *PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); +pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); +pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); +pr_lineno_t *PR_Find_Lineno (progs_t *pr, pr_uint_t addr) __attribute__((pure)); +const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); const char *PR_Get_Source_Line (progs_t *pr, pr_uint_t addr); -ddef_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm); -ddef_t *PR_Get_Local_Def (progs_t *pr, pr_int_t offs); +pr_def_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure)); +pr_def_t *PR_Get_Local_Def (progs_t *pr, pointer_t *offs) __attribute__((pure)); void PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents); void PR_DumpState (progs_t *pr); void PR_StackTrace (progs_t *pr); @@ -1469,20 +1757,20 @@ extern struct cvar_s *pr_deadbeef_locals; extern struct cvar_s *pr_boundscheck; extern struct cvar_s *pr_faultchecks; -//@} +///@} /** \defgroup pr_cmds Quake and Quakeworld common builtins \ingroup progs \todo This really doesn't belong in progs. */ -//@{ +///@{ char *PF_VarString (progs_t *pr, int first); void PR_Cmds_Init (progs_t *pr); extern const char *pr_gametype; -//@} +///@} //============================================================================ @@ -1493,21 +1781,20 @@ extern const char *pr_gametype; typedef struct strref_s strref_t; typedef struct { - pr_int_t s; ///< Return statement. - bfunction_t *f; ///< Calling function. + pr_int_t staddr; ///< Return statement. + bfunction_t *func; ///< Calling function. strref_t *tstr; ///< Linked list of temporary strings. } prstack_t; -struct obj_list_s; - struct progs_s { int (*parse_field) (progs_t *pr, const char *key, const char *value); int null_bad; int no_exec_limit; + struct hashlink_s **hashlink_freelist; void (*file_error) (progs_t *pr, const char *path); - void *(*load_file) (progs_t *pr, const char *path); + void *(*load_file) (progs_t *pr, const char *path, off_t *size); void *(*allocate_progs_mem) (progs_t *pr, int size); void (*free_progs_mem) (progs_t *pr, void *mem); @@ -1521,93 +1808,88 @@ struct progs_s { int denorm_found; struct memzone_s *zone; - int zone_size; + int zone_size; ///< set by user /// \name builtin functions - //@{ + ///@{ struct hashtab_s *builtin_hash; struct hashtab_s *builtin_num_hash; + struct biblock_s *builtin_blocks; unsigned bi_next; unsigned (*bi_map) (progs_t *pr, unsigned binum); - //@} + ///@} /// \name symbol management - //@{ + ///@{ struct hashtab_s *function_hash; struct hashtab_s *global_hash; struct hashtab_s *field_hash; - //@} + ///@} /// \name load hooks - //@{ + ///@{ int num_load_funcs; int max_load_funcs; pr_load_func_t **load_funcs; /// cleared each load - //@{ + ///@{ int num_load_finish_funcs; int max_load_finish_funcs; pr_load_func_t **load_finish_funcs; - //@} - //@} + ///@} + ///@} /// \name string management - //@{ - struct dstring_mem_s *ds_mem; - strref_t *free_string_refs; - strref_t *static_strings; - strref_t **string_map; - strref_t *return_strings[PR_RS_SLOTS]; - int rs_slot; - unsigned dyn_str_size; - struct hashtab_s *strref_hash; - int num_strings; + ///@{ + struct prstr_resources_s *pr_string_resources; strref_t *pr_xtstr; - //@} + strref_t *pr_pushtstr; + int float_promoted; ///< for PR_Sprintf + ///@} /// \name memory map - //@{ + ///@{ dfunction_t *pr_functions; bfunction_t *function_table; char *pr_strings; int pr_stringsize; - ddef_t *pr_globaldefs; - ddef_t *pr_fielddefs; + pr_def_t *pr_globaldefs; + pr_def_t *pr_fielddefs; dstatement_t *pr_statements; pr_type_t *pr_globals; unsigned globals_size; - //@} + ///@} /// \name parameter block - //@{ + ///@{ pr_type_t *pr_return; pr_type_t *pr_params[MAX_PARMS]; pr_type_t *pr_real_params[MAX_PARMS]; - pr_type_t *pr_param_ptrs[2]; - pr_type_t *pr_saved_params; - int pr_saved_argc; int pr_param_size; ///< covers both params and return - //@} + int pr_param_alignment; ///< covers both params and return + ///@} /// \name edicts - //@{ - edict_t **edicts; - int max_edicts; + /// \todo FIXME should this be outside the VM? + ///@{ + edict_t **pr_edicts; + int max_edicts; ///< set by user int *num_edicts; int *reserved_edicts; ///< alloc will start at reserved_edicts+1 void (*unlink) (edict_t *ent); void (*flush) (void); int (*prune_edict) (progs_t *pr, edict_t *ent); void (*free_edict) (progs_t *pr, edict_t *ent); - int pr_edict_size; ///< in bytes - int pr_edictareasize; ///< for bounds checking, starts at 0 + pr_type_t *pr_edict_area; + int pr_edict_size; ///< # of pr_type_t slots + int pr_edict_area_size; ///< for bounds checking, starts at 0 func_t edict_parse; - //@} + ///@} /// \name execution state - //@{ - int pr_argc; + ///@{ + int pr_argc; //FIXME need a good way to ensure it is correct qboolean pr_trace; int pr_trace_depth; @@ -1617,50 +1899,50 @@ struct progs_s { prstack_t pr_stack[MAX_STACK_DEPTH]; int pr_depth; + /// \name progs visible stack + /// Usable by the progs for any purpose. Will not be accessible unless + /// a .stack global is found. Space is allocated from the top of the stack + /// (as is common for hardware). The push and pop instructions will not + /// be considered valid if there is no .stack global. + /// \note The return address and saved locals will not ever be on this + /// stack. + ///@{ + pr_type_t *stack; + pointer_t stack_bottom; + int stack_size; ///< set by user + ///@} + int localstack[LOCALSTACK_SIZE]; int localstack_used; - //@} + ///@} /// \name resources - //@{ + ///@{ pr_resource_t *resources; struct hashtab_s *resource_hash; - //@} + ///@} /// \name obj info - //@{ - unsigned selector_index; - unsigned selector_index_max; - struct obj_list_s **selector_sels; - string_t *selector_names; - struct hashtab_s *selector_hash; - struct hashtab_s *classes; - struct hashtab_s *load_methods; - struct obj_list_s *unresolved_classes; - struct obj_list_s *unclaimed_categories; - struct obj_list_s *unclaimed_proto_list; - struct obj_list_s *module_list; - struct obj_list_s *class_tree_list; - //@} + ///@{ + struct probj_resources_s *pr_objective_resources; + ///@} - /// \name debug info - //@{ - const char *debugfile; - struct pr_debug_header_s *debug; - struct pr_auxfunction_s *auxfunctions; - struct pr_auxfunction_s **auxfunction_map; - struct pr_lineno_s *linenos; - ddef_t *local_defs; + /// \name debugging + ///@{ + struct prdeb_resources_s *pr_debug_resources; + void (*debug_handler) (prdebug_t event, void *param, void *data); + void *debug_data; pr_type_t *watch; int wp_conditional; pr_type_t wp_val; - //@} + ///@} /// \name globals and fields needed by the VM - //@{ + ///@{ struct { float *time; ///< required for OP_STATE pr_int_t *self; ///< required for OP_STATE + pointer_t *stack; ///< required for OP_(PUSH|POP)* } globals; struct { pr_int_t nextthink; ///< required for OP_STATE @@ -1668,12 +1950,12 @@ struct progs_s { pr_int_t think; ///< required for OP_STATE pr_int_t this; ///< optional for entity<->object linking } fields; - //@} + ///@} }; /** \addtogroup progs_data_access */ -//@{ +///@{ /** Convert a progs offset/pointer to a C pointer. \param pr pointer to ::progs_t VM struct @@ -1681,7 +1963,7 @@ struct progs_s { \return C pointer represented by the parameter. 0 offset -> NULL */ static inline pr_type_t * -PR_GetPointer (progs_t *pr, pointer_t o) +PR_GetPointer (const progs_t *pr, pointer_t o) { return o ? pr->pr_globals + o : 0; } @@ -1692,12 +1974,12 @@ PR_GetPointer (progs_t *pr, pointer_t o) \return Progs offset/pointer represented by \c p. NULL -> 0 offset */ static inline pointer_t -PR_SetPointer (progs_t *pr, void *p) +PR_SetPointer (const progs_t *pr, const void *p) { - return p ? (pr_type_t *) p - pr->pr_globals : 0; + return p ? (const pr_type_t *) p - pr->pr_globals : 0; } -//@} +///@} /** \example vm-exec.c */ diff --git a/include/QF/qargs.h b/include/QF/qargs.h index 5b4252075..bf49495a4 100644 --- a/include/QF/qargs.h +++ b/include/QF/qargs.h @@ -27,12 +27,12 @@ */ -#ifndef __qargs_h -#define __qargs_h +#ifndef __QF_qargs_h +#define __QF_qargs_h /** \addtogroup misc */ -//@{ +///@{ #include "QF/qtypes.h" @@ -42,7 +42,7 @@ extern const char *com_cmdline; extern struct cvar_s *fs_globalcfg; extern struct cvar_s *fs_usercfg; -int COM_CheckParm (const char *parm); +int COM_CheckParm (const char *parm) __attribute__((pure)); void COM_AddParm (const char *parm); void COM_Init (void); @@ -50,6 +50,6 @@ void COM_Init_Cvars (void); void COM_InitArgv (int argc, const char **argv); void COM_ParseConfig (void); -//@} +///@} -#endif // __qargs_h +#endif//__QF_qargs_h diff --git a/include/QF/qdefs.h b/include/QF/qdefs.h index 1d00abee0..a0dbbfe5c 100644 --- a/include/QF/qdefs.h +++ b/include/QF/qdefs.h @@ -27,8 +27,8 @@ */ -#ifndef __qdefs_h -#define __qdefs_h +#ifndef __QF_qdefs_h +#define __QF_qdefs_h #define MAX_QPATH 64 #define MAX_CL_STATS 32 @@ -40,4 +40,4 @@ #define clc_stringcmd 4 -#endif // __qdefs_h +#endif//__QF_qdefs_h diff --git a/include/QF/qendian.h b/include/QF/qendian.h index 49e60c2aa..7c418be53 100644 --- a/include/QF/qendian.h +++ b/include/QF/qendian.h @@ -27,13 +27,13 @@ */ -#ifndef __qendian_h -#define __qendian_h +#ifndef __QF_qendian_h +#define __QF_qendian_h /** \defgroup qendian Endian handling functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -75,12 +75,12 @@ extern qboolean bigendien; -uint16_t _ShortSwap (uint16_t l); -uint16_t _ShortNoSwap (uint16_t l); -uint32_t _LongSwap (uint32_t l); -uint32_t _LongNoSwap (uint32_t l); -float _FloatSwap (float f); -float _FloatNoSwap (float f); +uint16_t _ShortSwap (uint16_t l) __attribute__((const)); +uint16_t _ShortNoSwap (uint16_t l) __attribute__((const)); +uint32_t _LongSwap (uint32_t l) __attribute__((const)); +uint32_t _LongNoSwap (uint32_t l) __attribute__((const)); +float _FloatSwap (float f) __attribute__((const)); +float _FloatNoSwap (float f) __attribute__((const)); #ifdef __GNUC__ @@ -118,6 +118,6 @@ byte ReadByte (struct QFile_s *file); unsigned short ReadShort (struct QFile_s *file); unsigned int ReadLong (struct QFile_s *file); -//@} +///@} -#endif // __qendian_h +#endif//__QF_qendian_h diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h deleted file mode 100644 index 713eb6dbb..000000000 --- a/include/QF/qfplist.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - qfplist.h - - Property list management types and prototypes - - Copyright (C) 2000 Jeff Teunissen - - 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: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ - -#ifndef __QF_qfplist_h_ -#define __QF_qfplist_h_ - -/** \defgroup qfplist Property lists - \ingroup utils -*/ -//@{ - -#include "QF/qtypes.h" - -/** The type of the property list item. - - For further details, see \ref property-list. -*/ -typedef enum { - QFDictionary, ///< The property list item represents a dictionary. - QFArray, ///< The property list item represents an array. - QFBinary, ///< The property list item represents arbitrary binary - ///< data. - QFString ///< The property list item represents a C string. -} pltype_t; - -/** Generic property list item. - - All inspection and manipulation is to be done via the accessor functions. -*/ -typedef struct plitem_s plitem_t; - -/** Create an in-memory representation of the contents of a property list. - - \param string the saved plist, as read from a file. - - \return Returns an object equivalent to the passed-in string. - \note You are responsible for freeing the returned object. -*/ -plitem_t *PL_GetPropertyList (const char *string); - -/** Create a property list string from the in-memory representation. - - \param pl the in-memory representation - \return the text representation of the property list - \note You are responsible for freeing the returned string. -*/ -char *PL_WritePropertyList (plitem_t *pl); - -/** Retrieve the type of an object. - - \param item The object - \return the type of the object -*/ -pltype_t PL_Type (plitem_t *item); - -/** Retrieve a string from a string object. - - \param string The string object - \return pointer to the actual string value or NULL if string isn't a - string. - \note You are NOT responsible for freeing the returned object. It will - be destroyed when its container is. -*/ -const char *PL_String (plitem_t *string); - -/** Retrieve a value from a dictionary object. - - \param dict The dictionary to retrieve a value from - \param key The unique key associated with the value - \return the value associated with the key, or NULL if not found or dict - isn't a dictionary. - \note You are NOT responsible for freeing the returned object. It will - be destroyed when its container is. -*/ -plitem_t *PL_ObjectForKey (plitem_t *dict, const char *key); - -/** Remove a value from a dictionary object. - - \param dict The Dictionary to remove the value from - \param key The unique key associated with the value to be removed - \return the value associated with the key, or NULL if not found or dict - isn't a dictionary. - \note You are responsible for freeing the returned object. -*/ -plitem_t *PL_RemoveObjectForKey (plitem_t *dict, const char *key); - -/** Retrieve a value from an array object. - - \param array The array to get the value from - \param index The index within the array to retrieve - \return the value associated with the key, or NULL if not found or array - isn't an array. - \note You are NOT responsible for freeing the returned object. It will - be destroyed when its container is. -*/ -plitem_t *PL_ObjectAtIndex (plitem_t *array, int index); - -/** Retrieve a list of all keys in a dictionary. - - \param dict The dictionary to list - \return an Array containing Strings or NULL if dict isn't a dictionary - \note You are responsible for freeing this array. -*/ -plitem_t *PL_D_AllKeys (plitem_t *dict); - -/** Retrieve the number of keys in a dictionary. - - \param dict The dictionary to get the number of keys of. - - \return Returns the number of keys in the dictionary. -*/ -int PL_D_NumKeys (plitem_t *dict); - -/** Add a key/value pair to a dictionary. - - \param dict The dictionary to which the key/value pair will be added - \param key The key of the key/value pair to be added to the dictionary - \param value The value of the key/value pair to be added to the dictionary - - \return true on success, false on failure - - \note the dictionary becomes the owner of the value. -*/ -qboolean PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value); - -/** Add an item to an array. - - \param array The array to which the item will be added - \param item The item to be added to the array - - \return true on success, false on failure - - \note the array becomes the owner of the added item. -*/ -qboolean PL_A_AddObject (plitem_t *array, plitem_t *item); - -/** Retrieve the number of items in an array. - - \param array The array from which to get the number of objects - - \return number of objects in the array -*/ -int PL_A_NumObjects (plitem_t *array); - -/** Insert an item into an array before the specified location. - - \param array The array to which the item will be added - \param item The item to be added to the array - \param index The location at which to insert the item into the array - - \return true on success, false on failure - - \note the array becomes the owner of the added item. -*/ -qboolean PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index); - -/** Remove a value from an array object. - The array items will be shuffled to fill the resulting hole. - - \param array The array from which to remove the value - \param index The index within the array to remove - \return the value associated with the index, or NULL if not found or array - isn't an array. - \note You are responsible for freeing the returned object. -*/ -plitem_t *PL_RemoveObjectAtIndex (plitem_t *array, int index); - -/** Create a new dictionary object. - The dictionary will be empty. - \return the new dictionary object -*/ -plitem_t *PL_NewDictionary (void); - -/** Create a new array object. - The array will be empty. - \return the new array object -*/ -plitem_t *PL_NewArray (void); - -/** Create a new data object from the given data. - Takes ownership of the given data. - \param data pointer to data buffer - \param size number of bytes in the buffer - \return the new dictionary object - \note The data will be freed via free() when the item is freed. -*/ -plitem_t *PL_NewData (void *data, size_t size); - -/** Create a new string object. - Makes a copy of the given string. - \param str C string to copy - \return the new dictionary object -*/ -plitem_t *PL_NewString (const char *str); - -/** Free a property list object. - - This function takes care of freeing any referenced property list data, so - call it only on top-level objects. - - \param item the property list object to be freed -*/ -void PL_Free (plitem_t *item); - -//@} - -#endif // __QF_qfplist_h_ diff --git a/include/QF/qtypes.h b/include/QF/qtypes.h index 05c93af59..ea3a4df6c 100644 --- a/include/QF/qtypes.h +++ b/include/QF/qtypes.h @@ -27,8 +27,8 @@ */ -#ifndef __qtypes_h -#define __qtypes_h +#ifndef __QF_qtypes_h +#define __QF_qtypes_h #include #include @@ -76,8 +76,8 @@ typedef vec_t quat_t[4]; ///< A quaternion. typedef vec_t vec5_t[5]; typedef union { struct { - vec_t s; vec3_t v; + vec_t s; } sv; quat_t q; } Quat_t; @@ -115,4 +115,4 @@ typedef struct sphere_s { vec_t radius; } sphere_t; -#endif // __qtypes_h +#endif//__QF_qtypes_h diff --git a/include/QF/quakefs.h b/include/QF/quakefs.h index aab034381..761997eea 100644 --- a/include/QF/quakefs.h +++ b/include/QF/quakefs.h @@ -27,13 +27,13 @@ */ -#ifndef __quakefs_h -#define __quakefs_h +#ifndef __QF_quakefs_h +#define __QF_quakefs_h /** \defgroup quakefs Quake Filesystem \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -356,7 +356,7 @@ char *QFS_CompressPath (const char *pth); \return Pointer to the beginning of the filename. This points inside \a pathname. */ -const char *QFS_SkipPath (const char *pathname); +const char *QFS_SkipPath (const char *pathname) __attribute__((pure)); /** Return a pointer to the start of the extention part of the path. @@ -366,7 +366,7 @@ const char *QFS_SkipPath (const char *pathname); the returned pointer will point to the terminating nul of the path. */ -const char *QFS_FileExtension (const char *in); +const char *QFS_FileExtension (const char *in) __attribute__((pure)); /** Register a callback function for when the gamedir changes. @@ -418,6 +418,6 @@ void QFS_FilelistFill (filelist_t *list, const char *path, const char *ext, */ void QFS_FilelistFree (filelist_t *list); -//@} +///@} -#endif // __quakefs_h +#endif//__QF_quakefs_h diff --git a/include/QF/quakeio.h b/include/QF/quakeio.h index 0664bd0b6..1fd7205a0 100644 --- a/include/QF/quakeio.h +++ b/include/QF/quakeio.h @@ -26,21 +26,21 @@ Boston, MA 02111-1307, USA */ -#ifndef __quakeio_h -#define __quakeio_h +#ifndef __QF_quakeio_h +#define __QF_quakeio_h #include /** \defgroup quakeio File IO \ingroup utils */ -//@{ +///@{ typedef struct QFile_s QFile; int Qrename(const char *old_path, const char *new_path); int Qremove(const char *path); -int Qfilesize (QFile *file); +int Qfilesize (QFile *file) __attribute__((pure)); QFile *Qopen(const char *path, const char *mode); QFile *Qdopen(int fd, const char *mode); QFile *Qfopen (FILE *file, const char *mode); @@ -60,6 +60,6 @@ int Qflush(QFile *file); int Qeof(QFile *file); const char *Qgetline(QFile *file); -//@} +///@} -#endif /*__quakeio_h*/ +#endif//__QF_quakeio_h diff --git a/include/QF/render.h b/include/QF/render.h index cc08c3800..adc5e141e 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -25,13 +25,14 @@ */ -#ifndef __render_h -#define __render_h +#ifndef __QF_render_h +#define __QF_render_h #include "QF/mathlib.h" #include "QF/model.h" #include "QF/qdefs.h" // FIXME #include "QF/vid.h" +#include "QF/simd/types.h" typedef enum { pt_static, @@ -55,6 +56,15 @@ typedef enum { extern struct vid_render_funcs_s *r_funcs; extern struct vid_render_data_s *r_data; +typedef struct subpic_s { + const struct subpic_s *const next; + const struct scrap_s *const scrap; ///< renderer specific type + const struct vrect_s *const rect; + const int width; ///< requested width + const int height; ///< requested height + const float size; ///< size factor for tex coords (mult) +} subpic_t; + // dynamic lights =========================================================== typedef struct dlight_s @@ -81,47 +91,52 @@ typedef struct //=============== +typedef struct animation_s { + int frame; + float syncbase; // randomize time base for local animations + float frame_start_time; + float frame_interval; + int pose1; + int pose2; + float blend; + int nolerp; // don't lerp this frame (pose data invalid) +} animation_t; + +typedef struct visibility_s { + struct entity_s *entity; // owning entity + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // bmodels, first world node that + // splits bmodel, or NULL if not split + // applies to other models, too + int visframe; // last frame this entity was + // found in an active leaf + int trivial_accept; // view clipping (frustum and depth) +} visibility_t; + +typedef struct renderer_s { + struct model_s *model; // NULL = no model + struct skin_s *skin; + float colormod[4]; // color tint and alpha for model + int skinnum; // for Alias models + int fullbright; + float min_light; + mat4_t full_transform; +} renderer_t; + typedef struct entity_s { struct entity_s *next; - struct entity_s *unext; //FIXME this shouldn't be here. for qw demos - vec3_t origin; - vec3_t old_origin; - vec3_t angles; - vec_t transform[4 * 4]; - vec_t full_transform[4 * 4]; - struct model_s *model; // NULL = no model - int frame; - int skinnum; // for Alias models - struct skin_s *skin; - - float syncbase; // for client-side animations - - struct efrag_s *efrag; // linked list of efrags - int visframe; // last frame this entity was - // found in an active leaf - float colormod[4]; // color tint and alpha for model - float scale; // size scaler of the model - - int fullbright; - float min_light; - - // FIXME: could turn these into a union - int trivial_accept; - struct mnode_s *topnode; // for bmodels, first world node that - // splits bmodel, or NULL if not split - - // Animation interpolation - float frame_start_time; - float frame_interval; - int pose1; - int pose2; - struct model_s *pose_model; // no lerp if not the same as model + struct transform_s *transform; + animation_t animation; + visibility_t visibility; + renderer_t renderer; + int active; + //XXX FIXME XXX should not be here + vec4f_t old_origin; } entity_t; // !!! if this is changed, it must be changed in asm_draw.h too !!! -typedef struct -{ +typedef struct { vrect_t vrect; // subwindow in video for refresh // FIXME: not need vrect next field here? vrect_t aliasvrect; // scaled Alias version @@ -142,8 +157,9 @@ typedef struct float xOrigin; // should probably always be 0.5 float yOrigin; // between be around 0.3 to 0.5 - vec3_t vieworg; - vec3_t viewangles; + //FIXME was vec3_t, need to deal with asm (maybe? is it worth it?) + vec4f_t viewposition; + vec4f_t viewrotation; float fov_x, fov_y; @@ -172,9 +188,9 @@ extern struct texture_s *r_notexture_mip; extern entity_t r_worldentity; void R_Init (void); -void R_LoadModule (void (*load_gl)(void), - void (*set_palette) (const byte *palette)); +struct vid_internal_s; +void R_LoadModule (struct vid_internal_s *vid_internal); struct progs_s; void R_Progs_Init (struct progs_s *pr); -#endif // __render_h +#endif//__QF_render_h diff --git a/include/QF/ringbuffer.h b/include/QF/ringbuffer.h new file mode 100644 index 000000000..ac339ea70 --- /dev/null +++ b/include/QF/ringbuffer.h @@ -0,0 +1,212 @@ +/* + ringbuffer.h + + ring buffer + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_ringbuffer_h +#define __QF_ringbuffer_h + +/** Type declaration for a type-safe ring buffer. + * + * While not in itself thread-safe, the buffer is designed (and tested) to be + * used in a threaded environment using sutable locking mechanisms. + * + * \param type The type of data element stored in the ring buffer. + * \param size The number of objects in the ring buffer. Note that the + * actual capacity of the buffer is `size - 1` due to the + * way ring buffers work. + */ +#define RING_BUFFER(type, size) \ + struct { \ + type buffer[size]; \ + unsigned head; \ + unsigned tail; \ + } + +#define RB_buffer_size(ring_buffer) \ + ({ __auto_type rb = (ring_buffer); \ + sizeof (rb->buffer) / sizeof (rb->buffer[0]); \ + }) + +/** Return the amount of space available for writing in the ring buffer. + * + * Use this to know how much data can be written (RB_WRITE_DATA()) or acquired + * (RB_ACQUIRE()), or just to see if any space is available. + * + * \note Does NOT affect buffer state. + * + * \param ring_buffer The ring buffer to check for available space. + */ +#define RB_SPACE_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->tail + RB_buffer_size(rb) - rb->head - 1) % RB_buffer_size(rb);\ + }) + +/** Return the number of objects available in the ring buffer. + * + * Use this to know how much data can be read (RB_READ_DATA()) or discarded + * (RB_RELEASE()), or just to see if any data is available. + * + * \note Does NOT affect buffer state. + * + * \param ring_buffer The ring buffer to check for available data. + */ +#define RB_DATA_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->head + RB_buffer_size (rb) - rb->tail) % RB_buffer_size (rb); \ + }) + +/** Write \a count objects from \a data to the buffer, wrapping if necessary. + * + * \note Affects buffer state (advances the head). + * + * \note Does NOT check that the space is available. It is the caller's + * responsitiblity to do so using RB_SPACE_AVAILABLE(). + * + * \param ring_buffer The ring buffer to which the data will be written. + * \param data Pointer to the data to be copied into the ring buffer. + * \param count unsigned int. The number of objects to copy from + * \a data + */ +#define RB_WRITE_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + const typeof (rb->buffer[0]) *d = (data); \ + unsigned c = (count); \ + unsigned h = rb->head; \ + rb->head = (h + c) % RB_buffer_size (rb); \ + if (c > RB_buffer_size (rb) - h) { \ + memcpy (rb->buffer + h, d, \ + (RB_buffer_size (rb) - h) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - h; \ + d += RB_buffer_size (rb) - h; \ + h = 0; \ + } \ + memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \ + }) + +/** Acquire \a count objects from the buffer, wrapping if necessary. + * + * \note Affects buffer state (advances the head). + * + * \note Does NOT check that the space is available. It is the caller's + * responsitiblity to do so using RB_SPACE_AVAILABLE(). + * + * \param ring_buffer The ring buffer to which the data will be written. + * \param count unsigned int. The number of objects to copy from + * \a data. + * \return Address of the first object acquired. + */ +#define RB_ACQUIRE(ring_buffer, count) \ + ({ __auto_type rb = &(ring_buffer); \ + unsigned c = (count); \ + unsigned h = rb->head; \ + rb->head = (h + c) % RB_buffer_size (rb); \ + &rb->buffer[h]; \ + }) + +/** Read \a count objects from the buffer to \a data, wrapping if necessary. + * + * \note Affects buffer state (advances the tail). + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which the data will be read. + * \param data Pointer to the location into which data will be copied + * from the ring buffer. + * \param count unsigned int. The number of objects to copy from + * the buffer into \a data + */ +#define RB_READ_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + typeof (&rb->buffer[0]) d = (data); \ + unsigned c = (count); \ + unsigned oc = c; \ + unsigned t = rb->tail; \ + if (c > RB_buffer_size (rb) - t) { \ + memcpy (d, rb->buffer + t, \ + (RB_buffer_size (rb) - t) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - t; \ + d += RB_buffer_size (rb) - t; \ + t = 0; \ + } \ + memcpy (d, rb->buffer + t, c * sizeof (rb->buffer[0])); \ + rb->tail = (t + oc) % RB_buffer_size (rb); \ + }) + +/** Discard \a count objects from the ring buffer. + * + * \note Affects buffer state (advances the tail). + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which the objects will be + * discarded. + * \param count The number of objects to discard. + */ +#define RB_RELEASE(ring_buffer, count) \ + ({ __auto_type rb = &(ring_buffer); \ + unsigned c = (count); \ + unsigned t = rb->tail; \ + rb->tail = (t + c) % RB_buffer_size (rb); \ + }) + +/** Access a single item from the buffer without affecting buffer state. + * + * \note Does NOT affect buffer state. + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which to access the object. + * \param ahead The tail-relative index of the object to access from + * the buffer. Valid range is 0 to + * `RB_DATA_AVAILABLE() - 1` + * \return Address of the accessed element + */ +#define RB_PEEK_DATA(ring_buffer, ahead) \ + ({ __auto_type rb = &(ring_buffer); \ + &rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ + }) + +/** WRite a single item to the buffer without affecting buffer state. + * + * \note Does NOT affect buffer state. + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which to read the object. + * \param ahead The tail-relative index of the buffer object to write. + * Valid range is 0 to `RB_DATA_AVAILABLE() - 1` + * \param data The data to write to the buffer. + */ +#define RB_POKE_DATA(ring_buffer, ahead, data) \ + ({ __auto_type rb = &(ring_buffer); \ + rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)] = (data); \ + }) + +#endif//__QF_ringbuffer_h diff --git a/include/QF/ruamoko.h b/include/QF/ruamoko.h index a2dcd6366..956465268 100644 --- a/include/QF/ruamoko.h +++ b/include/QF/ruamoko.h @@ -31,7 +31,7 @@ #ifndef __QF_ruamoko_h #define __QF_ruamoko_h -#include "QF/pr_comp.h" +#include "QF/pr_obj.h" struct progs_s; struct cbuf_s; @@ -40,4 +40,9 @@ void RUA_Init (struct progs_s *pr, int secure); void RUA_Cbuf_SetCbuf (struct progs_s *pr, struct cbuf_s *cbuf); func_t RUA_Obj_msg_lookup (struct progs_s *pr, pointer_t _self, pointer_t __cmd); +// self is expected in param 0 +int RUA_obj_increment_retaincount (struct progs_s *pr); +// self is expected in param 0 +int RUA_obj_decrement_retaincount (struct progs_s *pr); + #endif//__QF_ruamoko_h diff --git a/include/QF/screen.h b/include/QF/screen.h index 9586e20a1..b904f1c7c 100644 --- a/include/QF/screen.h +++ b/include/QF/screen.h @@ -26,8 +26,8 @@ */ // screen.h -#ifndef __screen_h -#define __screen_h +#ifndef __QF_screen_h +#define __QF_screen_h #include "QF/qtypes.h" @@ -35,6 +35,9 @@ void SCR_Init_Cvars (void); void SCR_Init (void); typedef void (*SCR_Func)(void); +// scr_funcs is a null terminated array +void SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, + SCR_Func *scr_funcs); void SCR_SizeUp (void); void SCR_SizeDown (void); @@ -67,4 +70,4 @@ extern struct qpic_s *scr_turtle; extern struct cvar_s *hud_fps, *hud_time; -#endif // __screen_h +#endif//__QF_screen_h diff --git a/include/QF/script.h b/include/QF/script.h index bc11b0e2a..34e6f269a 100644 --- a/include/QF/script.h +++ b/include/QF/script.h @@ -25,7 +25,7 @@ Line oriented script parsing. Multiple scripts being parsed at the same time is supported. */ -//@{ +///@{ #include "QF/qtypes.h" @@ -41,8 +41,9 @@ typedef struct script_s { /// line number of the file being processed. used only for error reporting /// but updated internally. int line; - /// if set, will be called instead of the internal error handler - void (*error)(struct script_s *script, const char *msg); + /// contains last error message or null if no error + /// if set, no tokens will be parsed. + const char *error; /// if set, multi line quoted tokens will be treated as errors int no_quote_lines; /// if set, characters in this string will always be lexed as single @@ -65,6 +66,7 @@ void Script_Delete (script_t *script); /** Prepare a script_t object for parsing. The caller is responsible for freeing the memory associated with file and data when parsing is complete. + Resets \a script->error \param script The script_t object being parsed \param file Name of the file being parsed. used only for error reporting \param data The script to be parsed @@ -95,8 +97,8 @@ void Script_UngetToken (script_t *script); /** Return a pointer to the current token. \param script The script_t object being parsed */ -const char *Script_Token (script_t *script); +const char *Script_Token (script_t *script) __attribute__((pure)); -//@} +///@} #endif//__QF_script_h diff --git a/include/QF/segtext.h b/include/QF/segtext.h index 1c781fcb9..79020356c 100644 --- a/include/QF/segtext.h +++ b/include/QF/segtext.h @@ -31,28 +31,110 @@ #ifndef __QF_segtext_h #define __QF_segtext_h -/** \defgroup segtext Segmented text files. +/** \defgroup segtext Segmented text files \ingroup utils - Based on The OpenGL Shader Wrangler: http://prideout.net/blog/?p=11 + Based on The OpenGL Shader Wrangler: + https://prideout.net/blog/old/blog/index.html@p=11.html + However, nothing is assumed about any of the segments: they are all nothing + more than chunks of mostly random (lines cannot start with --) text with + identifying tags. Also, the identifying tag represents only the shader_key + of OpenGL Shader Wrangler's Effect.shader_key identifier. */ +///@{ +/** Represent a single text segment + + Segments are separated by lines beginning with "--" (without the quotes). + + The first word ([A-Za-z0-9_.]+) following the double-hyphen is used as an + identifying tag for the segment. Whitespace and any additional characters + are ignored. + + The segment itself starts on the following line. +*/ typedef struct segchunk_s { struct segchunk_s *next; - const char *tag; - const char *text; - int start_line; + const char *tag; ///< identifying tag or null if no tag + const char *text; ///< nul-terminated string holding the segment + int start_line; ///< line number for first line of the segment } segchunk_t; +/** Container for all the segments extracted from the provided text + + The first segment has no tag and may or may not be empty. + Segments are stored sequentially in \a chunk_list are indexed by + identifying tag (if present) in \a tab. + Segments that have no identifying tag are not in \a tab, but can + be accessed by walking \a chunk_list its \a next field. +*/ typedef struct segtext_s { struct segtext_s *next; segchunk_t *chunk_list; struct hashtab_s *tab; } segtext_t; +/** Parse a nul-terminated string into (optionally) tagged segments + + The segments are separated by lines beginning with a double-hyphen ("--"), + with an optional tag following the double-hyphen on the same line. Valid + tag characters are ASCII alpha-numerics, "." and "_". Whitespace is ignored + and invalid characters are treated as whitespace. Only the first tag on the + line is significant. + + \param src nul-terminated string to be parsed into segments + \return Pointer to container of parsed segments. Can be freed using + Segtext_delete(). +*/ segtext_t *Segtext_new (const char *src); +/** Free a segmented text container created by Segtext_new() + + \param st Pointer to segmented text container to be freed. Must have been + created by Segtext_new(). +*/ void Segtext_delete (segtext_t *st); +/** Find a text segment via its identifying tag + + Like OpenGL Shader Wrangler, the segment tag does not have to be a perfect + match with the specified tag: the segment with the longest string of + sub-tags matching the leading subtags of the specified tag is selected. + Tags are logically broken into sub-tag by the "." character. Thus in a + collection of segments with tags "foo" and "foo.b", "foo.bar" will find the + segment tagged "foo". However, if a segment tagged "foo.bar" is present, it + will be returned. A segment tagged "foo.bar.baz" will not. + + \param st Pointer to segmented text container + \param tag String specifying the tag identifying the segment to be + returned. Valid tag characters are alphanumerics, "_" and "." + (ie, [A-Za-z0-9._]). "." is used as a sub-tag separator for + partial matches. + \return Pointer to segment data block with the best matching tag, + providing access to the segment's tag and starting line number, + as well as the segment contents. Null if no matching tag was + found. +*/ const segchunk_t *Segtext_FindChunk (const segtext_t *st, const char *tag); + +/** Find a text segment via its identifying tag + + Like OpenGL Shader Wrangler, the segment tag does not have to be a perfect + match with the specified tag: the segment with the longest string of + sub-tags matching the leading subtags of the specified tag is selected. + Tags are logically broken into sub-tag by the "." character. Thus in a + collection of segments with tags "foo" and "foo.b", "foo.bar" will find the + segment tagged "foo". However, if a segment tagged "foo.bar" is present, it + will be returned. A segment tagged "foo.bar.baz" will not. + + \param st Pointer to segmented text container + \param tag String specifying the tag identifying the segment to be + returned. Valid tag characters are alphanumerics, "_" and "." + (ie, [A-Za-z0-9._]). "." is used as a sub-tag separator for + partial matches. + \return Contents of the segment with the best matching tag, or null if + no matching tag was found. +*/ const char *Segtext_Find (const segtext_t *st, const char *tag); +///@} + #endif//__QF_segtext_h diff --git a/include/QF/set.h b/include/QF/set.h index a30840b18..1261bdb40 100644 --- a/include/QF/set.h +++ b/include/QF/set.h @@ -36,7 +36,7 @@ /** \defgroup set Set handling \ingroup utils */ -//@{ +///@{ //FIXME other archs #ifdef __x86_64__ @@ -251,19 +251,19 @@ set_t *set_empty (set_t *set); */ set_t *set_everything (set_t *set); -/** Test if a set is the set of everything. +/** Test if a set is the empty set. \param set The set to test. \return 1 if \a set is empty (non-inverted). */ -int set_is_empty (const set_t *set); +int set_is_empty (const set_t *set) __attribute__((pure)); /** Test if a set is the set of everything. \param set The set to test. \return 1 if \a set is the set of everything (empty inverted set). */ -int set_is_everything (const set_t *set); +int set_is_everything (const set_t *set) __attribute__((pure)); /** Test if two sets are disjoint. @@ -273,7 +273,7 @@ int set_is_everything (const set_t *set); \note The emtpy set is disjoint with itself. */ -int set_is_disjoint (const set_t *s1, const set_t *s2); +int set_is_disjoint (const set_t *s1, const set_t *s2) __attribute__((pure)); /** Test if two sets intersect. @@ -283,7 +283,7 @@ int set_is_disjoint (const set_t *s1, const set_t *s2); \note Equivalent non-empty sets are treated as intersecting. */ -int set_is_intersecting (const set_t *s1, const set_t *s2); +int set_is_intersecting (const set_t *s1, const set_t *s2) __attribute__((pure)); /** Test if two sets are equivalent. @@ -291,7 +291,7 @@ int set_is_intersecting (const set_t *s1, const set_t *s2); \param s2 The second set to test. \return 1 if \a s2 is equivalent to \a s1, 0 if not. */ -int set_is_equivalent (const set_t *s1, const set_t *s2); +int set_is_equivalent (const set_t *s1, const set_t *s2) __attribute__((pure)); /** Test if a set is a subset of another set. @@ -302,7 +302,7 @@ int set_is_equivalent (const set_t *s1, const set_t *s2); \return 1 if \a sub is a subset of \a set, or if the sets are equivalent. */ -int set_is_subset (const set_t *set, const set_t *sub); +int set_is_subset (const set_t *set, const set_t *sub) __attribute__((pure)); /** Test an element for membership in a set. @@ -310,7 +310,7 @@ int set_is_subset (const set_t *set, const set_t *sub); \param x The element to test. \return 1 if the element is a member of the set, otherwise 0. */ -int set_is_member (const set_t *set, unsigned x); +int set_is_member (const set_t *set, unsigned x) __attribute__((pure)); /** Obtain the number of members (or non-members) of a set. @@ -322,7 +322,7 @@ int set_is_member (const set_t *set, unsigned x); \return The number of (non-)members. Both empty sets and sets of evertything will return 0. */ -unsigned set_size (const set_t *set); +unsigned set_size (const set_t *set) __attribute__((pure)); /** Find the first "member" of the set. @@ -358,8 +358,8 @@ set_iter_t *set_next_r (set_pool_t *set_pool, set_iter_t *set_iter); /** Return a human-readable string representing the set. - Empty sets will be represented by the string "[empty]". Sets of everything - will be represented by the string "[everything]". Inverted sets will have + Empty sets will be represented by the string "{}". Sets of everything + will be represented by the string "{...}". Inverted sets will have the first implicit member followed by "..." (eg, "256 ..."). \param set The set to be converted to a string. @@ -370,5 +370,5 @@ set_iter_t *set_next_r (set_pool_t *set_pool, set_iter_t *set_iter); */ const char *set_as_string (const set_t *set); -//@} +///@} #endif//__QF_set_h diff --git a/include/QF/simd/mat4f.h b/include/QF/simd/mat4f.h new file mode 100644 index 000000000..658cf582b --- /dev/null +++ b/include/QF/simd/mat4f.h @@ -0,0 +1,192 @@ +/* + QF/simd/mat4f.h + + Matrix functions for mat4f_t (ie, float precision) + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_mat4f_h +#define __QF_simd_mat4f_h + +#include + +#include "QF/simd/types.h" + +GNU89INLINE inline void maddf (mat4f_t c, const mat4f_t a, const mat4f_t b); +GNU89INLINE inline void msubf (mat4f_t c, const mat4f_t a, const mat4f_t b); +GNU89INLINE inline void mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b); +GNU89INLINE inline vec4f_t mvmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t m3vmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); +GNU89INLINE inline void mat4fidentity (mat4f_t m); +GNU89INLINE inline void mat4ftranspose (mat4f_t t, const mat4f_t m); +GNU89INLINE inline void mat4fquat (mat4f_t m, vec4f_t q); + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +maddf (mat4f_t c, const mat4f_t a, const mat4f_t b) +{ + c[0] = a[0] + b[0]; + c[1] = a[1] + b[1]; + c[2] = a[2] + b[2]; + c[3] = a[3] + b[3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +msubf (mat4f_t c, const mat4f_t a, const mat4f_t b) +{ + c[0] = a[0] - b[0]; + c[1] = a[1] - b[1]; + c[2] = a[2] - b[2]; + c[3] = a[3] - b[3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b) +{ + c[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2] + a[3] * b[0][3]; + c[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2] + a[3] * b[1][3]; + c[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2] + a[3] * b[2][3]; + c[3] = a[0] * b[3][0] + a[1] * b[3][1] + a[2] * b[3][2] + a[3] * b[3][3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +mvmulf (const mat4f_t m, vec4f_t v) +{ + return m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * v[3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +m3vmulf (const mat4f_t m, vec4f_t v) +{ + vec4f_t w; + w = m[0] * v[0] + m[1] * v[1] + m[2] * v[2]; + w[3] = v[3]; + return w; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mat4fidentity (mat4f_t m) +{ + m[0] = (vec4f_t) { 1, 0, 0, 0 }; + m[1] = (vec4f_t) { 0, 1, 0, 0 }; + m[2] = (vec4f_t) { 0, 0, 1, 0 }; + m[3] = (vec4f_t) { 0, 0, 0, 1 }; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mat4ftranspose (mat4f_t t, const mat4f_t m) +{ + vec4f_t a = m[0]; + vec4f_t b = m[1]; + vec4f_t c = m[2]; + vec4f_t d = m[3]; + t[0] = (vec4f_t) { a[0], b[0], c[0], d[0] }; + t[1] = (vec4f_t) { a[1], b[1], c[1], d[1] }; + t[2] = (vec4f_t) { a[2], b[2], c[2], d[2] }; + t[3] = (vec4f_t) { a[3], b[3], c[3], d[3] }; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mat4fquat (mat4f_t m, vec4f_t q) +{ + vec4f_t xq = q[0] * q; + vec4f_t yq = q[1] * q; + vec4f_t zq = q[2] * q; + vec4f_t wq = q[3] * q; + + static const vec4i_t shuff103 = { 1, 0, 3, 2 }; + static const vec4i_t shuff230 = { 2, 3, 0, 1 }; + static const vec4i_t shuff321 = { 3, 2, 1, 0 }; +#define p (0) +#define m (1u << 31) + static const vec4i_t mpm = { m, p, m, 0 }; + static const vec4i_t pmm = { p, m, m, 0 }; + static const vec4i_t mmp = { m, m, p, 0 }; + static const vec4i_t mask = { ~0u, ~0u, ~0u, 0 }; +#undef p +#undef m + { + vec4f_t a = xq; + vec4f_t b = _mm_xor_ps (__builtin_shuffle (yq, shuff103), (__m128) mpm); + vec4f_t c = _mm_xor_ps (__builtin_shuffle (zq, shuff230), (__m128) pmm); + vec4f_t d = _mm_xor_ps (__builtin_shuffle (wq, shuff321), (__m128) mmp); + + m[0] = _mm_and_ps (a + b - c - d, (__m128) mask); + } + { + vec4f_t a = _mm_xor_ps (__builtin_shuffle (xq, shuff103), (__m128) mpm); + vec4f_t b = yq; + vec4f_t c = _mm_xor_ps (__builtin_shuffle (zq, shuff321), (__m128) mmp); + vec4f_t d = _mm_xor_ps (__builtin_shuffle (wq, shuff230), (__m128) pmm); + m[1] = _mm_and_ps (b + c - a - d, (__m128) mask); + } + { + vec4f_t a = _mm_xor_ps (__builtin_shuffle (xq, shuff230), (__m128) pmm); + vec4f_t b = _mm_xor_ps (__builtin_shuffle (yq, shuff321), (__m128) mmp); + vec4f_t c = zq; + vec4f_t d = _mm_xor_ps (__builtin_shuffle (wq, shuff103), (__m128) mpm); + m[2] = _mm_and_ps (a - b + c - d, (__m128) mask); + } + m[3] = (vec4f_t) { 0, 0, 0, 1 }; +} + +#endif//__QF_simd_mat4f_h diff --git a/include/QF/simd/types.h b/include/QF/simd/types.h new file mode 100644 index 000000000..e056abfac --- /dev/null +++ b/include/QF/simd/types.h @@ -0,0 +1,89 @@ +/* + QF/simd/types.h + + Type definitions for QF SIMD values + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_types_h +#define __QF_simd_types_h + +#define VEC_TYPE(t,n) typedef t n __attribute__ ((vector_size (4*sizeof (t)))) + +/** Three element vector type for interfacing with compact data. + * + * This cannot be used directly by SIMD code and must be loaded and stored + * using load_vec3d() and store_vec3d() respectively. + */ +typedef double vec3d_t[3]; + +#ifdef __AVX__ +/** Four element vector type for horizontal (AOS) vector data. + * + * This is used for both vectors (3D and 4D) and quaternions. 3D vectors + * are simply vec4d_t values with 0 in the 4th element. + * + * Also usable with vertical (SOA) code, in which case each vec4d_t represents + * a single component from four vectors, or a single row/column (depending on + * context) of an Nx4 or 4xN matrix. + */ +VEC_TYPE (double, vec4d_t); + +/** Used mostly for __builtin_shuffle. + */ +VEC_TYPE (long, vec4l_t); +#endif + +/** Three element vector type for interfacing with compact data. + * + * This cannot be used directly by SIMD code and must be loaded and stored + * using load_vec3f() and store_vec3f() respectively. + */ +typedef float vec3f_t[3]; + +/** Four element vector type for horizontal (AOS) vector data. + * + * This is used for both vectors (3D and 4D) and quaternions. 3D vectors + * are simply vec4f_t values with 0 in the 4th element. + * + * Also usable with vertical (SOA) code, in which case each vec4f_t represents + * a single component from four vectors, or a single row/column (depending on + * context) of an Nx4 or 4xN matrix. + */ +VEC_TYPE (float, vec4f_t); + +/** Used mostly for __builtin_shuffle. + */ +VEC_TYPE (int, vec4i_t); + +#define VEC4D_FMT "[%.17g, %.17g, %.17g, %.17g]" +#define VEC4L_FMT "[%ld, %ld, %ld, %ld]" +#define VEC4F_FMT "[%.9g, %.9g, %.9g, %.9g]" +#define VEC4I_FMT "[%d, %d, %d, %d]" +#define VEC4_EXP(v) (v)[0], (v)[1], (v)[2], (v)[3] + +#define MAT4_ROW(m, r) (m)[0][r], (m)[1][r], (m)[2][r], (m)[3][r] + +typedef vec4f_t mat4f_t[4]; +typedef vec4i_t mat4i_t[4]; +#endif//__QF_simd_types_h diff --git a/include/QF/simd/vec4d.h b/include/QF/simd/vec4d.h new file mode 100644 index 000000000..e73873bc0 --- /dev/null +++ b/include/QF/simd/vec4d.h @@ -0,0 +1,294 @@ +/* + QF/simd/vec4d.h + + Vector functions for vec4d_t (ie, double precision) + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_vec4d_h +#define __QF_simd_vec4d_h + +#include + +#include "QF/simd/types.h" + +GNU89INLINE inline vec4d_t vsqrtd (vec4d_t v) __attribute__((const)); +GNU89INLINE inline vec4d_t vceild (vec4d_t v) __attribute__((const)); +GNU89INLINE inline vec4d_t vfloord (vec4d_t v) __attribute__((const)); +GNU89INLINE inline vec4d_t vtruncd (vec4d_t v) __attribute__((const)); +/** 3D vector cross product. + * + * The w (4th) component can be any value on input, and is guaranteed to be 0 + * in the result. The result is not affected in any way by either vector's w + * componemnt + */ +GNU89INLINE inline vec4d_t crossd (vec4d_t a, vec4d_t b) __attribute__((const)); +/** 4D vector dot product. + * + * The w component *IS* significant, but if it is 0 in either vector, then + * the result will be as for a 3D dot product. + * + * Note that the dot product is in all 4 of the return value's elements. This + * helps optimize vector math as the scalar is already pre-spread. If just the + * scalar is required, use result[0]. + */ +GNU89INLINE inline vec4d_t dotd (vec4d_t a, vec4d_t b) __attribute__((const)); +/** Quaternion product. + * + * The vector is interpreted as a quaternion instead of a regular 4D vector. + * The quaternion may be of any magnitude, so this is more generally useful. + * than if the quaternion was required to be unit length. + */ +GNU89INLINE inline vec4d_t qmuld (vec4d_t a, vec4d_t b) __attribute__((const)); +/** Optimized quaterion-vector multiplication for vector rotation. + * + * \note This is the inverse of vqmulf + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. If the quaternion is not unit, the + * vector will be scaled by the square of the quaternion's magnitude. + */ +GNU89INLINE inline vec4d_t qvmuld (vec4d_t q, vec4d_t v) __attribute__((const)); +/** Optimized vector-quaterion multiplication for vector rotation. + * + * \note This is the inverse of qvmulf + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. If the quaternion is not unit, the + * vector will be scaled by the square of the quaternion's magnitude. + */ +GNU89INLINE inline vec4d_t vqmuld (vec4d_t v, vec4d_t q) __attribute__((const)); +/** Create the quaternion representing the shortest rotation from a to b. + * + * Both a and b are assumed to be 3D vectors (w components 0), but a resonable + * (but incorrect) result will still be produced if either a or b is a 4D + * vector. The rotation axis will be the same as if both vectors were 3D, but + * the magnitude of the rotation will be different. + */ +GNU89INLINE inline vec4d_t qrotd (vec4d_t a, vec4d_t b) __attribute__((const)); +/** Return the conjugate of the quaternion. + * + * That is, [-x, -y, -z, w]. + */ +GNU89INLINE inline vec4d_t qconjd (vec4d_t q) __attribute__((const)); +GNU89INLINE inline vec4d_t loadvec3d (const double v3[]) __attribute__((pure, access(read_only, 1))); +GNU89INLINE inline void storevec3d (double v3[3], vec4d_t v4) __attribute__((access (write_only, 1))); + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vsqrtd (vec4d_t v) +{ + return _mm256_sqrt_pd (v); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vceild (vec4d_t v) +{ + return _mm256_ceil_pd (v); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vfloord (vec4d_t v) +{ + return _mm256_floor_pd (v); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vtruncd (vec4d_t v) +{ + return _mm256_round_pd (v, _MM_FROUND_TRUNC); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +crossd (vec4d_t a, vec4d_t b) +{ + static const vec4l_t A = {1, 2, 0, 3}; + vec4d_t c = a * __builtin_shuffle (b, A); + vec4d_t d = __builtin_shuffle (a, A) * b; + c = c - d; + return __builtin_shuffle(c, A); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +dotd (vec4d_t a, vec4d_t b) +{ + vec4d_t c = a * b; + c = _mm256_hadd_pd (c, c); + static const vec4l_t A = {2, 3, 0, 1}; + c += __builtin_shuffle(c, A); + return c; +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +qmuld (vec4d_t a, vec4d_t b) +{ + // results in [2*as*bs, as*b + bs*a + a x b] ([scalar, vector] notation) + // doesn't seem to adversly affect precision + vec4d_t c = crossd (a, b) + a * b[3] + a[3] * b; + vec4d_t d = dotd (a, b); + // zero out the vector component of dot product so only the scalar remains + d = _mm256_permute2f128_pd (d, d, 0x18); + d = _mm256_permute4x64_pd (d, 0xc0); + return c - d; +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +qvmuld (vec4d_t q, vec4d_t v) +// ^^^ ^^^ +{ + double s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + vec4d_t z = {}; + q = _mm256_blend_pd (q, z, 0x08); + vec4d_t c = crossd (q, v); + vec4d_t qv = dotd (q, v); // q.w is 0 so v.w is irrelevant + vec4d_t qq = dotd (q, q); + + // vvv + return (s * s - qq) * v + 2 * (qv * q + s * c); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vqmuld (vec4d_t v, vec4d_t q) +// ^^^ ^^^ +{ + double s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + vec4d_t z = {}; + q = _mm256_blend_pd (q, z, 0x08); + vec4d_t c = crossd (q, v); + vec4d_t qv = dotd (q, v); // q.w is 0 so v.w is irrelevant + vec4d_t qq = dotd (q, q); + + // vvv + return (s * s - qq) * v + 2 * (qv * q - s * c); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +qrotd (vec4d_t a, vec4d_t b) +{ + vec4d_t ma = vsqrtd (dotd (a, a)); + vec4d_t mb = vsqrtd (dotd (b, b)); + vec4d_t den = 2 * ma * mb; + vec4d_t t = mb * a + ma * b; + vec4d_t mba_mab = vsqrtd (dotd (t, t)); + vec4d_t q = crossd (a, b) / mba_mab; + q[3] = (mba_mab / den)[0]; + return q; +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +qconjd (vec4d_t q) +{ + const vec4l_t neg = { 1lu << 63, 1lu << 63, 1lu << 63, 0 }; + return _mm256_xor_pd (q, (__m256d) neg); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +loadvec3d (const double v3[]) +{ + vec4d_t v4 = {}; + + v4[0] = v3[0]; + v4[1] = v3[1]; + v4[2] = v3[2]; + return v4; +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +storevec3d (double v3[3], vec4d_t v4) +{ + v3[0] = v4[0]; + v3[1] = v4[1]; + v3[2] = v4[2]; +} + +#endif//__QF_simd_vec4d_h diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h new file mode 100644 index 000000000..8fe207b74 --- /dev/null +++ b/include/QF/simd/vec4f.h @@ -0,0 +1,328 @@ +/* + QF/simd/vec4f.h + + Vector functions for vec4f_t (ie, float precision) + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_vec4f_h +#define __QF_simd_vec4f_h + +#include + +#include "QF/simd/types.h" + +GNU89INLINE inline vec4f_t vsqrtf (vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t vceilf (vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t vfloorf (vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t vtruncf (vec4f_t v) __attribute__((const)); +/** 3D vector cross product. + * + * The w (4th) component can be any value on input, and is guaranteed to be 0 + * in the result. The result is not affected in any way by either vector's w + * componemnt + */ +GNU89INLINE inline vec4f_t crossf (vec4f_t a, vec4f_t b) __attribute__((const)); +/** 4D vector dot product. + * + * The w component *IS* significant, but if it is 0 in either vector, then + * the result will be as for a 3D dot product. + * + * Note that the dot product is in all 4 of the return value's elements. This + * helps optimize vector math as the scalar is already pre-spread. If just the + * scalar is required, use result[0]. + */ +GNU89INLINE inline vec4f_t dotf (vec4f_t a, vec4f_t b) __attribute__((const)); +/** Quaternion product. + * + * The vector is interpreted as a quaternion instead of a regular 4D vector. + * The quaternion may be of any magnitude, so this is more generally useful. + * than if the quaternion was required to be unit length. + */ +GNU89INLINE inline vec4f_t qmulf (vec4f_t a, vec4f_t b) __attribute__((const)); +/** Optimized quaterion-vector multiplication for vector rotation. + * + * \note This is the inverse of vqmulf + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. + */ +GNU89INLINE inline vec4f_t qvmulf (vec4f_t q, vec4f_t v) __attribute__((const)); +/** Optimized vector-quaterion multiplication for vector rotation. + * + * \note This is the inverse of qvmulf + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. + */ +GNU89INLINE inline vec4f_t vqmulf (vec4f_t v, vec4f_t q) __attribute__((const)); +/** Create the quaternion representing the shortest rotation from a to b. + * + * Both a and b are assumed to be 3D vectors (w components 0), but a resonable + * (but incorrect) result will still be produced if either a or b is a 4D + * vector. The rotation axis will be the same as if both vectors were 3D, but + * the magnitude of the rotation will be different. + */ +GNU89INLINE inline vec4f_t qrotf (vec4f_t a, vec4f_t b) __attribute__((const)); +/** Return the conjugate of the quaternion. + * + * That is, [-x, -y, -z, w]. + */ +GNU89INLINE inline vec4f_t qconjf (vec4f_t q) __attribute__((const)); +GNU89INLINE inline vec4f_t loadvec3f (const float v3[3]) __attribute__((pure, access(read_only, 1))); +GNU89INLINE inline void storevec3f (float v3[3], vec4f_t v4) __attribute__((access (write_only, 1))); +GNU89INLINE inline vec4f_t normalf (vec4f_t v) __attribute__((pure)); +GNU89INLINE inline vec4f_t magnitudef (vec4f_t v) __attribute__((pure)); +GNU89INLINE inline vec4f_t magnitude3f (vec4f_t v) __attribute__((pure)); + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vsqrtf (vec4f_t v) +{ + return _mm_sqrt_ps (v); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vceilf (vec4f_t v) +{ + return _mm_ceil_ps (v); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vfloorf (vec4f_t v) +{ + return _mm_floor_ps (v); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vtruncf (vec4f_t v) +{ + return _mm_round_ps (v, _MM_FROUND_TRUNC); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +crossf (vec4f_t a, vec4f_t b) +{ + static const vec4i_t A = {1, 2, 0, 3}; + vec4f_t c = a * __builtin_shuffle (b, A) - __builtin_shuffle (a, A) * b; + return __builtin_shuffle(c, A); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +dotf (vec4f_t a, vec4f_t b) +{ + vec4f_t c = a * b; + c = _mm_hadd_ps (c, c); + c = _mm_hadd_ps (c, c); + return c; +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +qmulf (vec4f_t a, vec4f_t b) +{ + // results in [2*as*bs, as*b + bs*a + a x b] ([scalar, vector] notation) + // doesn't seem to adversly affect precision + vec4f_t c = crossf (a, b) + a * b[3] + a[3] * b; + vec4f_t d = dotf (a, b); + // zero out the vector component of dot product so only the scalar remains + d = _mm_insert_ps (d, d, 0xf7); + return c - d; +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +qvmulf (vec4f_t q, vec4f_t v) +{ + float s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + q = _mm_insert_ps (q, q, 0xf8); + vec4f_t c = crossf (q, v); + vec4f_t qv = dotf (q, v); // q.w is 0 so v.w is irrelevant + vec4f_t qq = dotf (q, q); + + return (s * s - qq) * v + 2 * (qv * q + s * c); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vqmulf (vec4f_t v, vec4f_t q) +{ + float s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + q = _mm_insert_ps (q, q, 0xf8); + vec4f_t c = crossf (q, v); + vec4f_t qv = dotf (q, v); // q.w is 0 so v.w is irrelevant + vec4f_t qq = dotf (q, q); + + return (s * s - qq) * v + 2 * (qv * q - s * c); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +qrotf (vec4f_t a, vec4f_t b) +{ + vec4f_t ma = vsqrtf (dotf (a, a)); + vec4f_t mb = vsqrtf (dotf (b, b)); + vec4f_t den = 2 * ma * mb; + vec4f_t t = mb * a + ma * b; + vec4f_t mba_mab = vsqrtf (dotf (t, t)); + vec4f_t q = crossf (a, b) / mba_mab; + q[3] = (mba_mab / den)[0]; + return q; +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +qconjf (vec4f_t q) +{ + const vec4i_t neg = { 1u << 31, 1u << 31, 1u << 31, 0 }; + return _mm_xor_ps (q, (__m128) neg); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +loadvec3f (const float v3[3]) +{ + vec4f_t v4; + + // this had to be in asm otherwise gcc thinks v4 is only partially + // initialized, and gcc 10 does not use the zero flags when generating + // the code, resulting in a memory access to load a 0 into v4[3] + // + // The first instruction zeros v4[3] while loading v4[0] + asm ("\n\ + vinsertps $0x08, %1, %0, %0 \n\ + vinsertps $0x10, %2, %0, %0 \n\ + vinsertps $0x20, %3, %0, %0 \n\ + " + : "=v"(v4) + : "m"(v3[0]), "m"(v3[1]), "m"(v3[2])); + return v4; +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +storevec3f (float v3[3], vec4f_t v4) +{ + v3[0] = v4[0]; + v3[1] = v4[1]; + v3[2] = v4[2]; +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +normalf (vec4f_t v) +{ + return v / vsqrtf (dotf (v, v)); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +magnitudef (vec4f_t v) +{ + return vsqrtf (dotf (v, v)); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +magnitude3f (vec4f_t v) +{ + v[3] = 0; + return vsqrtf (dotf (v, v)); +} + +#endif//__QF_simd_vec4f_h diff --git a/include/QF/sizebuf.h b/include/QF/sizebuf.h index 8605f803d..a6fc39411 100644 --- a/include/QF/sizebuf.h +++ b/include/QF/sizebuf.h @@ -24,14 +24,14 @@ Boston, MA 02111-1307, USA */ -#ifndef __sizebuf_h -#define __sizebuf_h +#ifndef __QF_sizebuf_h +#define __QF_sizebuf_h /** \defgroup sizebuf Fixed Size Buffers \ingroup utils Fixed size buffer management */ -//@{ +///@{ #include "QF/qtypes.h" @@ -50,7 +50,8 @@ void SZ_Clear (sizebuf_t *buf); void *SZ_GetSpace (sizebuf_t *buf, int length); void SZ_Write (sizebuf_t *buf, const void *data, int length); void SZ_Print (sizebuf_t *buf, const char *data); // strcats onto the sizebuf +void SZ_Dump (sizebuf_t *buf); -//@} +///@} -#endif // __sizebuf_h +#endif//__QF_sizebuf_h diff --git a/include/QF/skin.h b/include/QF/skin.h index b9c8a3dcb..7f520e1d6 100644 --- a/include/QF/skin.h +++ b/include/QF/skin.h @@ -25,8 +25,8 @@ */ -#ifndef _SKIN_H -#define _SKIN_H +#ifndef __QF_skin_h +#define __QF_skin_h #include "QF/qtypes.h" #include "QF/vid.h" @@ -57,4 +57,4 @@ typedef struct skin_s { int auxtex; } skin_t; -#endif +#endif//__QF_skin_h diff --git a/include/QF/sound.h b/include/QF/sound.h index 874469ea4..9fba9b158 100644 --- a/include/QF/sound.h +++ b/include/QF/sound.h @@ -26,8 +26,8 @@ */ // sound.h -- client sound i/o functions -#ifndef _SOUND_H -#define _SOUND_H +#ifndef __QF_sound_h +#define __QF_sound_h /** \defgroup sound QuakeForge sound engine */ @@ -37,7 +37,7 @@ /** \ingroup sound */ -//@{ +///@{ typedef struct sfx_s sfx_t; struct sfx_s { @@ -62,14 +62,14 @@ struct sfx_s sfx_t *(*open) (sfx_t *sfx); void (*close) (sfx_t *sfx); }; -//@} +///@} struct model_s; /** \defgroup sound_init Initialization functions \ingroup sound */ -//@{ +///@{ /** Initialize the sound engine. \param viewentity pointer to view entity index @@ -85,12 +85,12 @@ void S_Init_Cvars (void); gracefully. */ void S_Shutdown (void); -//@} +///@} /** \defgroup sound_stuff Unclassified \ingroup sound */ -//@{ +///@{ /** Start a sound playing. \param entnum index of entity the sound is associated with. @@ -193,6 +193,6 @@ void S_AmbientOn (void); struct progs_s; void S_Progs_Init (struct progs_s *pr); -//@} +///@} -#endif // _SOUND_H +#endif//__QF_sound_h diff --git a/include/QF/spritegn.h b/include/QF/spritegn.h index 4505ad59f..de490f28d 100644 --- a/include/QF/spritegn.h +++ b/include/QF/spritegn.h @@ -45,8 +45,8 @@ // //------------------------------------------------------- -#ifndef _SPRITEGN_H -#define _SPRITEGN_H +#ifndef __QF_sprintgn_h +#define __QF_sprintgn_h #define SPR_VERSION 1 #define SP2_VERSION 2 @@ -102,4 +102,4 @@ typedef struct { // little-endian "IDS2" #define IDHEADER_SP2 (('2'<<24)+('S'<<16)+('D'<<8)+'I') -#endif // _SPRITEGN_H +#endif//__QF_sprintgn_h diff --git a/include/QF/sys.h b/include/QF/sys.h index 8bbb08781..e54031af2 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -25,14 +25,14 @@ */ -#ifndef __sys_h -#define __sys_h +#ifndef __QF_sys_h +#define __QF_sys_h -/** \defgroup sys Portability +/** \defgroup sys System Portability \ingroup utils Non-portable functions */ -//@{ +///@{ #include #include @@ -62,41 +62,44 @@ int Sys_FileExists (const char *path); int Sys_isdir (const char *path); int Sys_mkdir (const char *path); -typedef void (*sys_printf_t) (const char *fmt, va_list args); +typedef void (*sys_printf_t) (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); typedef void (*sys_error_t) (void *data); -void Sys_SetStdPrintf (sys_printf_t func); -void Sys_SetErrPrintf (sys_printf_t func); +sys_printf_t Sys_SetStdPrintf (sys_printf_t func); +sys_printf_t Sys_SetErrPrintf (sys_printf_t func); void Sys_PushErrorHandler (sys_error_t func, void *data); void Sys_PopErrorHandler (void); -void Sys_Print (FILE *stream, const char *fmt, va_list args); +void Sys_Print (FILE *stream, const char *fmt, va_list args) __attribute__((format(printf, 2, 0))); void Sys_Printf (const char *fmt, ...) __attribute__((format(printf,1,2))); void Sys_Error (const char *error, ...) __attribute__((format(printf,1,2), noreturn)); void Sys_FatalError (const char *error, ...) __attribute__((format(printf,1,2), noreturn)); void Sys_Quit (void) __attribute__((noreturn)); void Sys_Shutdown (void); -void Sys_RegisterShutdown (void (*func) (void)); +void Sys_RegisterShutdown (void (*func) (void *), void *data); int64_t Sys_LongTime (void); double Sys_DoubleTime (void); void Sys_TimeOfDay(date_t *date); void Sys_MaskPrintf (int mask, const char *fmt, ...) __attribute__((format(printf,2,3))); -#define SYS_DEV (1|0) -#define SYS_WARN (1|2) // bit 0 so developer 1 will pick it up -#define SYS_VID (1|4) -#define SYS_FS_NF (1|8) -#define SYS_FS_F (1|16) -#define SYS_FS (1|32) -#define SYS_NET (1|64) -#define SYS_RUA_OBJ (1|128) -#define SYS_RUA_MSG (1|256) -#define SYS_SND (1|512) -#define SYS_GLT (1|1024) -#define SYS_GLSL (1|2048) -#define SYS_SKIN (1|4096) -#define SYS_MODEL (1|8192) +// remember to update developer_flags in cvar.c +#define SYS_DEV (1|0) +#define SYS_WARN (1|2) // bit 0 so developer 1 will pick it up +#define SYS_VID (1|4) +#define SYS_FS_NF (1|8) +#define SYS_FS_F (1|16) +#define SYS_FS (1|32) +#define SYS_NET (1|64) +#define SYS_RUA_OBJ (1|128) +#define SYS_RUA_MSG (1|256) +#define SYS_SND (1|512) +#define SYS_GLT (1|1024) +#define SYS_GLSL (1|2048) +#define SYS_SKIN (1|4096) +#define SYS_MODEL (1|8192) +#define SYS_VULKAN (1|16384) +#define SYS_VULKAN_PARSE (1|32768) int Sys_CheckInput (int idle, int net_socket); const char *Sys_ConsoleInput (void); @@ -120,7 +123,8 @@ void Sys_Init_Cvars (void); // memory protection // void Sys_MakeCodeWriteable (uintptr_t startaddr, size_t length); -void Sys_PageIn (void *ptr, int size); +void Sys_PageIn (void *ptr, size_t size); +void *Sys_Alloc (size_t size); // // system IO @@ -157,6 +161,6 @@ int Sys_CreatePath (const char *path); */ char *Sys_ExpandSquiggle (const char *path); -//@} +///@} -#endif // __sys_h +#endif//__QF_sys_h diff --git a/include/QF/teamplay.h b/include/QF/teamplay.h index b0b1c01da..91b2a6f65 100644 --- a/include/QF/teamplay.h +++ b/include/QF/teamplay.h @@ -25,8 +25,8 @@ */ -#ifndef __teamplay_h -#define __teamplay_h +#ifndef __QF_teamplay_h +#define __QF_teamplay_h extern struct cvar_s *cl_parsesay; extern struct cvar_s *cl_nofake; @@ -43,8 +43,8 @@ void Team_Init_Cvars (void); void Team_BestWeaponImpulse (void); void Team_Dead (void); void Team_NewMap (void); -const char *Team_ParseSay (const char *); +const char *Team_ParseSay (struct dstring_s *buf, const char *); void Locs_Init (void); void Team_ParseChat (const char *string); void Team_ResetTimers (void); -#endif // __teamplay_h +#endif//__QF_teamplay_h diff --git a/include/QF/tga.h b/include/QF/tga.h index 1d0bc8c25..08d610d95 100644 --- a/include/QF/tga.h +++ b/include/QF/tga.h @@ -25,8 +25,8 @@ */ -#ifndef __tga_h -#define __tga_h +#ifndef __QF_tga_h +#define __QF_tga_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -67,7 +67,7 @@ typedef struct _TargaHeader { # endif #endif -struct tex_s *LoadTGA (QFile *fin); +struct tex_s *LoadTGA (QFile *fin, int load); void WriteTGAfile (const char *tganame, byte *data, int width, int height); -#endif // __tga_h +#endif//__QF_tga_h diff --git a/include/QF/txtbuffer.h b/include/QF/txtbuffer.h new file mode 100644 index 000000000..8e4723fb9 --- /dev/null +++ b/include/QF/txtbuffer.h @@ -0,0 +1,112 @@ +/* + txtbuffer.h + + Text buffer for edit or scrollback + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_txtbuffer_h +#define __QF_txtbuffer_h + +#include +#include + +/** \defgroup txtbuffer Text buffers + \ingroup utils +*/ +///@{ + +/// must be a power of 2 +#define TXTBUFFER_GROW 0x4000 + +/** Text buffer implementing efficient editing. +*/ +typedef struct txtbuffer_s { + struct txtbuffer_s *next; + char *text; + size_t textSize; ///< amount of text in the buffer + size_t bufferSize; ///< current capacity of the buffer + size_t gapOffset; ///< beginning of the gap + size_t gapSize; ///< size of gap. gapSize + textSize == bufferSize +} txtbuffer_t; + +/** Create a new, empty buffer. +*/ +txtbuffer_t *TextBuffer_Create (void); + +/** Destroy a buffer, freeing all resources connected to it. + \param buffer The buffer to destroy. +*/ +void TextBuffer_Destroy (txtbuffer_t *buffer); + +/** Open a gap for writing at the specified offset. + + Text after the offset is moved to be after the opened gap. + The buffer is resized as necessary. + + \param buffer The buffer to be updated + \param offset The offset in the buffer at which to insert the text block + \param text_len The size of the gap to be opened + \return Pointr to beginning of gap if successful, 0 if failure + (offset not valid or out of memory) +*/ +char *TextBuffer_OpenGap (txtbuffer_t *buffer, size_t offset, + size_t text_len); + +/** Insert a block of text at the specified offset. + + Text after the offset is moved to be after the inserted block of text. + The buffer is resized as necessary. + nul characters are not significant in that they do not mark the end of + the text to be inserted. + + \param buffer The buffer to be updated + \param offset The offset in the buffer at which to insert the text block + \param text The text block to be inserted. May contain nul ('\0') + characters. + \param text_len The number of characters to insert. + \return 1 for success, 0 for failure (offset not valid or out + of memory) +*/ +int TextBuffer_InsertAt (txtbuffer_t *buffer, size_t offset, + const char *text, size_t text_len); + +/** Delete a block of text from the buffer. + + The buffer is not resized. Rather, its capacity before resizing is require + is increased. + + \param buffer The buffer to be updated + \param offset The offset of the beginning of the text block to be deleted + \param len The amount of characters to be deleted. Values larger than + the amount of text in the buffer beyond the beginning of + block are truncated to the amount of remaining text. Thus + using excessivly large values sets the offset to be the + end of the buffer. + \return 1 for success, 0 for failure (offset not valid) +*/ +int TextBuffer_DeleteAt (txtbuffer_t *buffer, size_t offset, size_t len); + +///@} + +#endif//__QF_txtbuffer_h diff --git a/include/QF/va.h b/include/QF/va.h index 6a5e54465..74a28aba7 100644 --- a/include/QF/va.h +++ b/include/QF/va.h @@ -26,19 +26,70 @@ */ -#ifndef __va_h -#define __va_h +#ifndef __QF_va_h +#define __QF_va_h /** \addtogroup misc Formatted printing. */ -//@{ +///@{ -// does a varargs printf into a temp buffer -char *va(const char *format, ...) __attribute__((format(printf,1,2))); -// does a varargs printf into a malloced buffer +/** Opaque context for va so it can have per-thread data. + */ +typedef struct va_ctx_s va_ctx_t; + +/** Create a va context with the specified number of buffers. + * + * Having multiple buffers allows va to be used in short chains. + * + * \param buffers The number of buffers to create in the context. va() will + * cycle through the buffers for each call. + * \return Pointer to the context. Pass to va() for thread-safe usage. + */ +va_ctx_t *va_create_context (int buffers); + +/** Destroy a va context. + * + * \param ctx The context to be destroyed. Must have been created by + * va_create_context(). + * \note Any pointers to strings returned by va() using the context + * referenced by \a ctx will become invalid as the backing + * memory for the strings will have been freed. + */ +void va_destroy_context (va_ctx_t *ctx); + +/** Does a varargs printf into a private buffer. + * + * \param ctx Context used for storing the private buffer such that va + * can be used in a multi-threaded environment. If null then + * a static context is used, in which case va is NOT + * thread-safe. + * \param format Standard printf() format string. + * \return Pointer to the beginning of the output string. The memory + * for the returned string is owned by the context pointed to + * by \a ctx. + * \note The static context is created with 4 buffers, so va (0,...) + * can be used to produce mildly complex output (eg, 3 calls + * to va sent to a 4th) with a reduced risk of strings being + * trampled. + */ +char *va(va_ctx_t *ctx, const char *format, ...) __attribute__((format(printf,2,3))); + +/** Does a varargs printf into a malloced buffer. + * + * Combines the effect of strdup and sprintf, but in a safe manner. Essentially + * the equivalent of strdup (va (ctx, format, ...)); + * + * \param format Standard printf() format string. + * \return Pointer to the beginning of the output string. The caller + * is responsible for freeing the memory holding the string. + * \note As nva() creates a new buffer every time it is called, it + * is thread-safe and there is no risk of the string being + * trampled. In addition, it does not use va(), so combining + * nva() with va() is safe. + */ char *nva(const char *format, ...) __attribute__((format(printf,1,2))); -//@} +///@} -#endif // __va_h +#endif//__QF_va_h diff --git a/include/QF/ver_check.h b/include/QF/ver_check.h index 5d8c1061c..eaa4d9391 100644 --- a/include/QF/ver_check.h +++ b/include/QF/ver_check.h @@ -25,8 +25,8 @@ */ -#ifndef __ver_check_h_ -#define __ver_check_h_ +#ifndef __QF_ver_check_h +#define __QF_ver_check_h /** \defgroup utils Utils */ @@ -34,7 +34,7 @@ /** \defgroup misc Miscellaneous functions \ingroup utils */ -//@{ +///@{ /* ver_compare @@ -45,6 +45,6 @@ */ int ver_compare (const char *, const char *); -//@} +///@} -#endif // __ver_check_h_ +#endif//__QF_ver_check_h diff --git a/include/QF/vid.h b/include/QF/vid.h index 8fd82165c..4a78fa46d 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -25,8 +25,8 @@ */ -#ifndef __vid_h_ -#define __vid_h_ +#ifndef __QF_vid_h +#define __QF_vid_h #include "QF/qtypes.h" #include "QF/vrect.h" @@ -43,6 +43,7 @@ typedef struct { byte *gammatable; // 256 const byte *basepal; // 256 * 3 byte *palette; // 256 * 3 + byte *palette32; // 256 * 4 includes alpha byte *colormap8; // 256 * VID_GRADES size unsigned short *colormap16; // 256 * VID_GRADES size unsigned int *colormap32; // 256 * VID_GRADES size @@ -61,17 +62,7 @@ typedef struct { int conheight; byte *direct; // direct drawing to framebuffer, if not // NULL - int (*surf_cache_size)(int width, int height); - void (*flush_caches)(void); - void (*init_caches)(void *cache, int size); - void (*do_screen_buffer)(void); - void (*set_palette)(const byte *palette); - - // gl stuff - void (*load_gl)(void); - void (*init_gl)(void); - void *(*get_proc_address)(const char *name, qboolean crit); - void (*end_rendering)(void); + struct vid_internal_s *vid_internal; } viddef_t; #define viddef (*r_data->vid) @@ -86,7 +77,7 @@ void VID_Init_Cvars (void); // the palette data will go away after the call, so it must be copied off if // the video driver will need it again void VID_Init (byte *palette, byte *colormap); -void VID_Shutdown (void); void VID_SetCaption (const char *text); +void VID_ClearMemory (void); -#endif // __vid_h_ +#endif//__QF_vid_h diff --git a/include/QF/view.h b/include/QF/view.h index ecb2ea920..5a6ae339f 100644 --- a/include/QF/view.h +++ b/include/QF/view.h @@ -28,13 +28,13 @@ */ -#ifndef __qf_view_h -#define __qf_view_h +#ifndef __QF_view_h +#define __QF_view_h /** \defgroup console_view Console View Objects \ingroup console */ -//@{ +///@{ /** Control the positioning of a view within its parent. The directions are the standard compass rose (north, east, south, west in clockwise order) @@ -215,6 +215,6 @@ void view_resize (view_t *view, int xl, int yl); */ void view_move (view_t *view, int xp, int yp); -//@} +///@} -#endif//__qf_view_h +#endif//__QF_view_h diff --git a/include/QF/vrect.h b/include/QF/vrect.h index 4c0cba107..bb0f99061 100644 --- a/include/QF/vrect.h +++ b/include/QF/vrect.h @@ -100,7 +100,7 @@ vrect_t *VRect_Intersect (const vrect_t *r1, const vrect_t *r2); vrect_t *VRect_HSplit (const vrect_t *r, int y); /** Return two rectangles representing the portions of \a r to the left and - right of \a y. + right of \a x. One of the returned rectangles may be empty. Use VRect_IsEmpty to check. The first rectangle represents the portion of \a r that is to the left of @@ -111,7 +111,7 @@ vrect_t *VRect_HSplit (const vrect_t *r, int y); \param r The rectangle to split. \param x The vertical line by which \a r will be split. \return The two linked rectangles representing the portions to the - left and right of \a y. The returned pointer points to the + left and right of \a x. The returned pointer points to the first (left) rectangle, which links to the second (right) rectangle. \note It is the caller's responsibility to delete the returned diff --git a/include/QF/wad.h b/include/QF/wad.h index 805a69925..2e6bb9c67 100644 --- a/include/QF/wad.h +++ b/include/QF/wad.h @@ -26,13 +26,13 @@ */ // wad.h -#ifndef _WAD_H -#define _WAD_H +#ifndef __QF_wad_h +#define __QF_wad_h /** \addtogroup wad Wad Files */ -//@{ +///@{ #include "QF/wadfile.h" @@ -46,6 +46,6 @@ void *W_GetLumpName (const char *name); void SwapPic (qpic_t *pic); -//@} +///@} -#endif // _WAD_H +#endif//__QF_wad_h diff --git a/include/QF/wadfile.h b/include/QF/wadfile.h index 79e5e2055..9e6c220f6 100644 --- a/include/QF/wadfile.h +++ b/include/QF/wadfile.h @@ -29,7 +29,7 @@ \ingroup utils Wadfile processing */ -//@{ +///@{ #ifndef __QF_wadfile_h #define __QF_wadfile_h @@ -102,6 +102,6 @@ int wad_add_data (wad_t *wad, const char *lumpname, byte type, const void *data, int bytes); lumpinfo_t *wad_find_lump (wad_t *wad, const char *filename); -//@} +///@} #endif//__QF_wadfile_h diff --git a/include/QF/winding.h b/include/QF/winding.h index 5ef3d8094..5815ac793 100644 --- a/include/QF/winding.h +++ b/include/QF/winding.h @@ -26,7 +26,7 @@ /** \defgroup winding Winding Manipulation */ -//@{ +///@{ struct plane_s; @@ -138,6 +138,6 @@ winding_t *ClipWinding (winding_t *in, struct plane_s *split, qboolean keepon); void DivideWinding (winding_t *in, struct plane_s *split, winding_t **front, winding_t **back); -//@} +///@} #endif//__QF_winding_h diff --git a/include/QF/zone.h b/include/QF/zone.h index 22c7bc19f..023ff07d6 100644 --- a/include/QF/zone.h +++ b/include/QF/zone.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __zone_h -#define __zone_h +#ifndef __QF_zone_h +#define __QF_zone_h /** \defgroup zone Memory Management \ingroup utils @@ -88,7 +88,7 @@ ----- Bottom of Memory ----- */ -//@{ +///@{ typedef struct memzone_s memzone_t; @@ -105,9 +105,10 @@ void Z_SetError (memzone_t *zone, void (*err) (void *data, const char *msg), void *data); void Z_CheckPointer (const memzone_t *zone, const void *ptr, int size); +void Hunk_Print (qboolean all); void *Hunk_Alloc (int size); // returns 0 filled memory void *Hunk_AllocName (int size, const char *name); -int Hunk_LowMark (void); +int Hunk_LowMark (void) __attribute__((pure)); void Hunk_FreeToLowMark (int mark); void *Hunk_TempAlloc (int size); void Hunk_Check (void); @@ -138,8 +139,8 @@ void Cache_Remove (cache_user_t *c); void *Cache_TryGet (cache_user_t *c); void *Cache_Get (cache_user_t *c); void Cache_Release (cache_user_t *c); -int Cache_ReadLock (cache_user_t *c); +int Cache_ReadLock (cache_user_t *c) __attribute__((pure)); -//@} +///@} -#endif // __zone_h +#endif//__QF_zone_h diff --git a/include/client/effects.h b/include/client/effects.h new file mode 100644 index 000000000..dbec75769 --- /dev/null +++ b/include/client/effects.h @@ -0,0 +1,47 @@ +/* + effects.h + + Effect management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/11 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __client_effects_h +#define __client_effects_h + +#include "QF/simd/types.h" + +struct entity_s; +struct entity_state_s; + +void CL_NewDlight (int key, vec4f_t org, int effects, byte glow_size, + byte glow_color, double time); +void CL_ModelEffects (struct entity_s *ent, int num, int glow_color, + double time); +void CL_EntityEffects (int num, struct entity_s *ent, + struct entity_state_s *state, double time); +void CL_MuzzleFlash (vec4f_t position, vec4f_t fv, float zoffset, int num, + double time); + +#endif//__client_effects_h diff --git a/include/client/entities.h b/include/client/entities.h index ae046b8c4..5981d1c9d 100644 --- a/include/client/entities.h +++ b/include/client/entities.h @@ -32,6 +32,7 @@ #define __client_entities_h #include "QF/qtypes.h" +#include "QF/simd/types.h" // entity_state_t is the information conveyed from the server // in an update message @@ -39,10 +40,12 @@ typedef struct entity_state_s { int number; // edict index unsigned flags; // nolerp, etc - vec3_t origin; + vec4f_t origin; + vec4f_t velocity; vec3_t angles; - unsigned short modelindex; - unsigned short frame; + uint16_t modelindex; + uint16_t frame; + int weaponframe; int effects; byte colormap; byte skinnum; @@ -67,4 +70,8 @@ extern entstates_t qw_entstates; extern vec3_t ent_colormod[256]; +struct entity_s; +void CL_TransformEntity (struct entity_s *ent, float scale, + const vec3_t angles, vec4f_t position); + #endif//__client_entities_h diff --git a/include/QF/locs.h b/include/client/locs.h similarity index 69% rename from include/QF/locs.h rename to include/client/locs.h index 32cb4ea0d..06817ef5a 100644 --- a/include/QF/locs.h +++ b/include/client/locs.h @@ -25,26 +25,28 @@ */ -#ifndef __locs_h -#define __locs_h +#ifndef __QF_locs_h +#define __QF_locs_h #include "QF/qtypes.h" +#include "QF/simd/types.h" typedef struct { - vec3_t loc; - char *name; + vec4f_t loc; + char *name; } location_t; -location_t *locs_find(const vec3_t target); -void locs_add (const vec3_t location, const char *name); -void locs_del (const vec3_t loc); -void locs_edit (const vec3_t loc, const char *desc); +location_t *locs_find(vec4f_t target) __attribute__((pure)); +void locs_add (vec4f_t location, const char *name); +void locs_del (vec4f_t loc); +void locs_edit (vec4f_t loc, const char *desc); void locs_load(const char *filename); -void locs_mark (const vec3_t loc, const char *desc); -int locs_nearest (const vec3_t loc); +void locs_mark (vec4f_t loc, const char *desc); +int locs_nearest (vec4f_t loc) __attribute__((pure)); void locs_reset (void); void locs_save (const char *filename, qboolean gz); void map_to_loc (const char *mapname, char *filename); +void locs_draw (vec4f_t simorg); -#endif // __locs_h +#endif//__QF_locs_h diff --git a/include/client/state.h b/include/client/state.h new file mode 100644 index 000000000..a06890822 --- /dev/null +++ b/include/client/state.h @@ -0,0 +1,58 @@ +/* + state.h + + client state + + Copyright (C) 2013 Bill Currie + + Author: Bill Currie + Date: 2013/01/31 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __client_state_h +#define __client_state_h + +typedef struct player_info_s { + int userid; + struct info_s *userinfo; + + // scoreboard information + struct info_key_s *name; + struct info_key_s *team; + struct info_key_s *chat; + float entertime; + int frags; + int ping; + byte pl; + + // skin information + int topcolor; + int bottomcolor; + struct info_key_s *skinname; + struct skin_s *skin; + + int spectator; + int stats[MAX_CL_STATS]; // health, etc + int prevcount; +} player_info_t; + +#endif//__client_state_h diff --git a/include/client/temp_entities.h b/include/client/temp_entities.h new file mode 100644 index 000000000..c4dbc0868 --- /dev/null +++ b/include/client/temp_entities.h @@ -0,0 +1,119 @@ +/* + temp_entities.h + + Temporary entity management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/10 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __client_temp_entities_h +#define __client_temp_entities_h + +#include "QF/simd/vec4f.h" + +typedef enum TE_Effect { + TE_NoEffect, // for invalid nq/qw -> qf mapping + TE_Beam, // grappling hook beam + TE_Blood, // bullet hitting body + TE_Explosion, // rocket explosion + TE_Explosion2, // color mapped explosion + TE_Explosion3, // Nehahra colored light explosion + TE_Gunshot1, // NQ gunshot (20 particles) + TE_Gunshot2, // QW gunshot (has particle count) + TE_KnightSpike, // spike hitting wall + TE_LavaSplash, + TE_Lightning1, // lightning bolts + TE_Lightning2, // lightning bolts + TE_Lightning3, // lightning bolts + TE_Lightning4, // Nehahra lightning + TE_LightningBlood, // lightning hitting body + TE_Spike, // spike hitting wall + TE_SuperSpike, // super spike hitting wall + TE_TarExplosion, // tarbaby explosion + TE_Teleport, + TE_WizSpike, // spike hitting wall +} TE_Effect; + +typedef enum TE_nqEffect { + TE_nqSpike, + TE_nqSuperSpike, + TE_nqGunshot, + TE_nqExplosion, + TE_nqTarExplosion, + TE_nqLightning1, + TE_nqLightning2, + TE_nqWizSpike, + TE_nqKnightSpike, + TE_nqLightning3, + TE_nqLavaSplash, + TE_nqTeleport, + TE_nqExplosion2, + TE_nqBeam, + TE_nqExplosion3 = 16, + TE_nqLightning4, +} TE_nqEffect; + +typedef enum TE_qwEffect { + TE_qwSpike, + TE_qwSuperSpike, + TE_qwGunshot, + TE_qwExplosion, + TE_qwTarExplosion, + TE_qwLightning1, + TE_qwLightning2, + TE_qwWizSpike, + TE_qwKnightSpike, + TE_qwLightning3, + TE_qwLavaSplash, + TE_qwTeleport, + TE_qwBlood, + TE_qwLightningBlood, + TE_qwExplosion2 = 16, + TE_qwBeam, +} TE_qwEffect; + +//FIXME find a better way to get this info from the parser +typedef struct TEntContext_s { + vec4f_t simorg; + struct model_s *worldModel; + int playerEntity; +} TEntContext_t; + +struct msg_s; +struct entity_s; + +void CL_TEnts_Init (void); +void CL_Init_Entity (struct entity_s *ent); +void CL_ClearTEnts (void); +void CL_UpdateTEnts (double time, TEntContext_t *ctx); +void CL_ParseTEnt_nq (struct msg_s *net_message, double time, + TEntContext_t *ctx); +void CL_ParseTEnt_qw (struct msg_s *net_message, double time, + TEntContext_t *ctx); +void CL_ParseParticleEffect (struct msg_s *net_message); +void CL_ClearProjectiles (void); +void CL_ParseProjectiles (struct msg_s *net_message, qboolean nail2, + TEntContext_t *ctx); + +#endif//__client_temp_entities_h diff --git a/include/clview.h b/include/client/view.h similarity index 70% rename from include/clview.h rename to include/client/view.h index 7568ab23b..7a7f8e005 100644 --- a/include/clview.h +++ b/include/client/view.h @@ -1,5 +1,5 @@ /* - clview.h + view.h (description) @@ -26,28 +26,39 @@ */ // view.h -#ifndef __clview_h_ -#define __clview_h_ +#ifndef __client_view_h_ +#define __client_view_h_ #include "QF/mathlib.h" +#include "QF/simd/types.h" #define INFO_CSHIFT_BONUS (1 << 0) #define INFO_CSHIFT_CONTENTS (1 << 1) #define INFO_CSHIFT_DAMAGE (1 << 2) #define INFO_CSHIFT_POWERUP (1 << 3) +typedef struct viewstate_s { + vec4f_t movecmd; + vec4f_t velocity; + vec4f_t origin; + vec3_t angles; + int weaponframe; + int onground; // -1 when in air + uint32_t flags; + float frametime; + vec4f_t punchangle; +} viewstate_t; + +#define VF_DEAD 1 +#define VF_GIB 2 + void V_Init (void); void V_Init_Cvars (void); void V_RenderView (void); -float V_CalcRoll (const vec3_t angles, const vec3_t velocity); -void V_UpdatePalette (void); +float V_CalcRoll (const vec3_t angles, vec4f_t velocity); void V_StartPitchDrift (void); void V_StopPitchDrift (void); -void V_RenderView (void); -void V_UpdatePalette (void); -void V_Register (void); void V_SetContentsColor (int contents); -void V_CalcBlend (void); -#endif // __clview_h_ +#endif // __client_view_h_ diff --git a/include/context_sdl.h b/include/context_sdl.h index b097587f1..f6f1dbbe7 100644 --- a/include/context_sdl.h +++ b/include/context_sdl.h @@ -30,7 +30,19 @@ #ifndef __context_sdl_h_ #define __context_sdl_h_ +#include + +extern SDL_Surface *sdl_screen; + void VID_SDL_GammaCheck (void); void SDL_Init_Cvars (void); +struct gl_ctx_s *SDL_GL_Context (void); +void SDL_GL_Init_Cvars (void); + +struct sw_ctx_s *SDL_SW_Context (void); +void SDL_SW_Init_Cvars (void); + +extern uint32_t sdl_flags; + #endif // __context_sdl_h_ diff --git a/include/context_x11.h b/include/context_x11.h index b513e587a..884fafe9e 100644 --- a/include/context_x11.h +++ b/include/context_x11.h @@ -77,4 +77,13 @@ void X11_SaveMouseAcceleration (void); void X11_RemoveMouseAcceleration (void); void X11_RestoreMouseAcceleration (void); +struct gl_ctx_s *X11_GL_Context (void); +void X11_GL_Init_Cvars (void); + +struct sw_ctx_s *X11_SW_Context (void); +void X11_SW_Init_Cvars (void); + +struct vulkan_ctx_s *X11_Vulkan_Context (void); +void X11_Vulkan_Init_Cvars (void); + #endif // __context_x11_h_ diff --git a/include/d_iface.h b/include/d_iface.h index f7d6a72a2..4f45aa4fa 100644 --- a/include/d_iface.h +++ b/include/d_iface.h @@ -65,7 +65,7 @@ typedef enum { typedef struct particle_s particle_t; typedef void (*pt_phys_func)(particle_t *); -pt_phys_func R_ParticlePhysics (ptype_t type); +pt_phys_func R_ParticlePhysics (ptype_t type) __attribute__((pure)); // !!! if this is changed, it must be changed in d_ifacea.h too !!! struct particle_s diff --git a/include/d_local.h b/include/d_local.h index cc7c4591c..7143277b1 100644 --- a/include/d_local.h +++ b/include/d_local.h @@ -94,11 +94,11 @@ void R_ShowSubDiv (void); extern void (*prealspandrawer)(void); surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel); -extern int D_MipLevelForScale (float scale); +int D_MipLevelForScale (float scale) __attribute__((pure)); #ifdef USE_INTEL_ASM -extern void D_PolysetAff8Start (void); -extern void D_PolysetAff8End (void); +void D_PolysetAff8Start (void); +void D_PolysetAff8End (void); #endif extern short *d_pzbuffer; diff --git a/include/exp.h b/include/exp.h index a3c40a7ca..f4a46514e 100644 --- a/include/exp.h +++ b/include/exp.h @@ -80,7 +80,7 @@ typedef union token_u extern exp_error_t EXP_ERROR; -const char *EXP_GetErrorMsg (void); +const char *EXP_GetErrorMsg (void) __attribute__((pure)); token *EXP_ParseString (char *str); exp_error_t EXP_SimplifyTokens (token *chain); void EXP_RemoveToken (token *tok); diff --git a/include/gib_buffer.h b/include/gib_buffer.h index e3944287e..b0e9219d2 100644 --- a/include/gib_buffer.h +++ b/include/gib_buffer.h @@ -40,7 +40,7 @@ void GIB_Buffer_Push_Sstack (struct cbuf_s *cbuf); void GIB_Buffer_Pop_Sstack (struct cbuf_s *cbuf); dstring_t *GIB_Buffer_Dsarray_Get (struct cbuf_s *cbuf); void GIB_Buffer_Reply_Callback (int argc, const char **argv, void *data); -void GIB_Buffer_Error (cbuf_t *cbuf, const char *type, const char *fmt, va_list args); +void GIB_Buffer_Error (cbuf_t *cbuf, const char *type, const char *fmt, va_list args) __attribute__((format(printf, 3, 0))); extern struct cbuf_interpreter_s gib_interp; diff --git a/include/gib_parse.h b/include/gib_parse.h index a6dae25c0..6c6ee06e4 100644 --- a/include/gib_parse.h +++ b/include/gib_parse.h @@ -43,5 +43,5 @@ gib_tree_t *GIB_Parse_Embedded (gib_tree_t *token); extern qboolean gib_parse_error; void GIB_Parse_Error (const char *msg, unsigned int pos); -const char *GIB_Parse_ErrorMsg (void); -unsigned int GIB_Parse_ErrorPos (void); +const char *GIB_Parse_ErrorMsg (void) __attribute__((pure)); +unsigned int GIB_Parse_ErrorPos (void) __attribute__((pure)); diff --git a/include/gib_regex.h b/include/gib_regex.h index 2970a21c1..aeccd78a1 100644 --- a/include/gib_regex.h +++ b/include/gib_regex.h @@ -39,7 +39,7 @@ typedef struct gib_regex_s { void GIB_Regex_Init (void); regex_t *GIB_Regex_Compile (const char *regex, int cflags); -const char *GIB_Regex_Error (void); -int GIB_Regex_Translate_Options (const char *opstr); -int GIB_Regex_Translate_Runtime_Options (const char *opstr); +const char *GIB_Regex_Error (void) __attribute__((const)); +int GIB_Regex_Translate_Options (const char *opstr) __attribute__((pure)); +int GIB_Regex_Translate_Runtime_Options (const char *opstr) __attribute__((pure)); unsigned int GIB_Regex_Apply_Match (regmatch_t match[10], dstring_t *dstr, unsigned int ofs, const char *replace); diff --git a/include/mod_internal.h b/include/mod_internal.h index 7f6be3e4e..d498ee9ce 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -1,55 +1,90 @@ #ifndef __mod_internal_h #define __mod_internal_h +#include "QF/darray.h" #include "QF/iqm.h" #include "QF/model.h" #include "QF/skin.h" #include "QF/plugin/vid_render.h" +typedef struct stvertset_s DARRAY_TYPE (stvert_t) stvertset_t; +typedef struct mtriangleset_s DARRAY_TYPE (mtriangle_t) mtriangleset_t; +typedef struct trivertxset_s DARRAY_TYPE (trivertx_t *) trivertxset_t; + +typedef struct mod_alias_ctx_s { + aliashdr_t *header; + model_t *mod; + stvertset_t stverts; + mtriangleset_t triangles; + trivertxset_t poseverts; + int aliasbboxmins[3]; + int aliasbboxmaxs[3]; + +} mod_alias_ctx_t; + +int Mod_CalcFullbright (const byte *in, byte *out, int pixels); +void Mod_ClearFullbright (const byte *in, byte *out, int pixels); +void Mod_FloodFillSkin (byte *skin, int skinwidth, int skinheight); +//FIXME gl specific. rewrite to use above +int Mod_Fullbright (byte * skin, int width, int height, const char *name); + +void Mod_LoadBrushModel (model_t *mod, void *buffer); +void Mod_FindClipDepth (hull_t *hull); + +model_t *Mod_FindName (const char *name); +float RadiusFromBounds (const vec3_t mins, const vec3_t maxs) __attribute__((pure)); + +struct vulkan_ctx_s; + extern vid_model_funcs_t *m_funcs; -void gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +void gl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *gl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc); -void gl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); -void gl_Mod_LoadExternalSkins (model_t *mod); +void *gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc); +void gl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx); +void gl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx); void gl_Mod_IQMFinish (model_t *mod); -void glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, +void glsl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *glsl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc); -void glsl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); -void glsl_Mod_LoadExternalSkins (model_t *mod); +void *glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc); +void glsl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx); +void glsl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx); void glsl_Mod_IQMFinish (model_t *mod); -void sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +void sw_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *sw_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc); -void sw_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); -void sw_Mod_LoadExternalSkins (model_t *mod); +void *sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc); void sw_Mod_IQMFinish (model_t *mod); -void gl_Mod_LoadExternalTextures (model_t *mod); -void gl_Mod_LoadLighting (bsp_t *bsp); -void gl_Mod_SubdivideSurface (msurface_t *fa); -void gl_Mod_ProcessTexture(texture_t *tx); +void gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp); +void gl_Mod_SubdivideSurface (model_t *mod, msurface_t *fa); +void gl_Mod_ProcessTexture (model_t *mod, texture_t *tx); -void glsl_Mod_LoadExternalTextures (model_t *mod); -void glsl_Mod_LoadLighting (bsp_t *bsp); -void glsl_Mod_SubdivideSurface (msurface_t *fa); -void glsl_Mod_ProcessTexture(texture_t *tx); +void glsl_Mod_LoadLighting (model_t *mod, bsp_t *bsp); +void glsl_Mod_ProcessTexture (model_t *mod, texture_t *tx); -void sw_Mod_LoadExternalTextures (model_t *mod); -void sw_Mod_LoadLighting (bsp_t *bsp); -void sw_Mod_SubdivideSurface (msurface_t *fa); -void sw_Mod_ProcessTexture(texture_t *tx); +void sw_Mod_LoadLighting (model_t *mod, bsp_t *bsp); -void gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); -void glsl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); -void sw_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); +void Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_SubdivideSurface (model_t *mod, msurface_t *fa, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, + struct vulkan_ctx_s *ctx); + +void gl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); +void glsl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); +void sw_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); void Mod_LoadIQM (model_t *mod, void *buffer); void Mod_FreeIQM (iqm_t *iqm); @@ -62,6 +97,10 @@ void Skin_Init (void); skin_t *Skin_SetColormap (skin_t *skin, int cmap); skin_t *Skin_SetSkin (skin_t *skin, int cmap, const char *skinname); void Skin_SetTranslation (int cmap, int top, int bottom); +int Skin_CalcTopColors (const byte *in, byte *out, int pixels); +int Skin_CalcBottomColors (const byte *in, byte *out, int pixels); +void Skin_ClearTopColors (const byte *in, byte *out, int pixels); +void Skin_ClearBottomColors (const byte *in, byte *out, int pixels); void sw_Skin_SetupSkin (skin_t *skin, int cmap); void sw_Skin_ProcessTranslation (int cmap, const byte *translation); diff --git a/include/net_dgrm.h b/include/net_dgrm.h index 712864dd3..38c2f7e19 100644 --- a/include/net_dgrm.h +++ b/include/net_dgrm.h @@ -29,7 +29,7 @@ /** \defgroup nq-dgrm NetQuake Datagram network driver. \ingroup nq-nd */ -//@{ +///@{ /** Initialize the Datagram net driver. @@ -125,4 +125,4 @@ void Datagram_Close (qsocket_t *sock); */ void Datagram_Shutdown (void); -//@} +///@} diff --git a/include/net_loop.h b/include/net_loop.h index a0f58a34a..9247f949e 100644 --- a/include/net_loop.h +++ b/include/net_loop.h @@ -34,7 +34,7 @@ /** \defgroup nq-loop NetQuake loopback network driver. \ingroup nq-nd */ -//@{ +///@{ int Loop_Init (void); void Loop_Listen (qboolean state); @@ -49,6 +49,6 @@ qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock); void Loop_Close (qsocket_t *sock); void Loop_Shutdown (void); -//@} +///@} #endif//__net_loop_h diff --git a/include/net_udp.h b/include/net_udp.h index 78f26a6ec..bd414513d 100644 --- a/include/net_udp.h +++ b/include/net_udp.h @@ -33,7 +33,7 @@ /** \defgroup nq-udp NetQuake UDP lan driver. \ingroup nq-ld */ -//@{ +///@{ /** Initialize the UDP network interface. @@ -193,6 +193,6 @@ int UDP_GetSocketPort (netadr_t *addr); */ int UDP_SetSocketPort (netadr_t *addr, int port); -//@} +///@} #endif // __net_udp_h diff --git a/include/net_vcr.h b/include/net_vcr.h index f5383b572..9f5446453 100644 --- a/include/net_vcr.h +++ b/include/net_vcr.h @@ -29,7 +29,7 @@ /** \defgroup nq-vcr NetQuake VCR network driver. \ingroup nq-nd */ -//@{ +///@{ #define VCR_OP_CONNECT 1 #define VCR_OP_GETMESSAGE 2 @@ -48,4 +48,4 @@ qboolean VCR_CanSendMessage (qsocket_t *sock); void VCR_Close (qsocket_t *sock); void VCR_Shutdown (void); -//@} +///@} diff --git a/include/net_wins.h b/include/net_wins.h index fe4133f50..c4954f9ac 100644 --- a/include/net_wins.h +++ b/include/net_wins.h @@ -35,7 +35,7 @@ /** \defgroup nq-wins NetQuake Winsock lan driver. \ingroup nq-ld */ -//@{ +///@{ extern int winsock_initialized; extern WSADATA winsockdata; @@ -58,6 +58,6 @@ int WINS_AddrCompare (netadr_t *addr1, netadr_t *addr2); int WINS_GetSocketPort (netadr_t *addr); int WINS_SetSocketPort (netadr_t *addr, int port); -//@} +///@} #endif//__net_wins_h diff --git a/include/netchan.h b/include/netchan.h index 5b361009e..207ed78fe 100644 --- a/include/netchan.h +++ b/include/netchan.h @@ -39,7 +39,7 @@ /** \defgroup qw-net QuakeWorld network support. \ingroup network */ -//{ +///@{ #define MAX_MSGLEN 1450 ///< max length of a reliable message #define MAX_DATAGRAM 1450 ///< max length of unreliable message @@ -70,17 +70,17 @@ void Log_Incoming_Packet (const byte *p, int len, int has_sequence, int is_server); void Log_Outgoing_Packet (const byte *p, int len, int has_sequence, int is_server); -void Net_LogStop (void); +void Net_LogStop (void *data); void Analyze_Client_Packet (const byte * data, int len, int has_sequence); void Analyze_Server_Packet (const byte * data, int len, int has_sequence); extern struct cvar_s *net_packetlog; -//@} +///@} /** \defgroup qw-udp QuakeWorld udp support. \ingroup qw-net */ -//@{ +///@{ /** Initialize the UDP network interface. @@ -90,10 +90,6 @@ extern struct cvar_s *net_packetlog; */ void NET_Init (int port); -/** Shutdown the UDP network interface. -*/ -void NET_Shutdown (void); - /** Read a single packet from the network into net_message. \return True if successfully read, otherwise false. @@ -116,7 +112,7 @@ void NET_SendPacket (int length, const void *data, netadr_t to); \param b The second address to compare. \return True of the addresses match, otherwise false. */ -qboolean NET_CompareAdr (netadr_t a, netadr_t b); +qboolean NET_CompareAdr (netadr_t a, netadr_t b) __attribute__((pure)); /** Compare two network addresses. @@ -126,7 +122,7 @@ qboolean NET_CompareAdr (netadr_t a, netadr_t b); \param b The second address to compare. \return True of the addresses match, otherwise false. */ -qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b); +qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) __attribute__((pure)); /** Convert an address to a string. @@ -165,7 +161,7 @@ const char *NET_BaseAdrToString (netadr_t a); */ qboolean NET_StringToAdr (const char *s, netadr_t *a); -//@} +///@} /** \defgroup netchan Netchan \ingroup qw-net @@ -220,7 +216,7 @@ qboolean NET_StringToAdr (const char *s, netadr_t *a); the channel matches even if the IP port differs. The IP port should be updated to the new value before sending out any replies. */ -//@{ +///@{ #define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG) #define MAX_LATENT 32 @@ -362,7 +358,7 @@ void Netchan_Setup (netchan_t *chan, netadr_t adr, int qport, ncqport_e flags); \param chan The netchan representing the connection. \return True if the connection isn't chocked. */ -qboolean Netchan_CanPacket (netchan_t *chan); +qboolean Netchan_CanPacket (netchan_t *chan) __attribute__((pure)); /** Check if a reliable packet can be sent to the connection. @@ -370,7 +366,7 @@ qboolean Netchan_CanPacket (netchan_t *chan); \return True if there is no outstanding reliable packet and the connection isn't chocked. */ -qboolean Netchan_CanReliable (netchan_t *chan); +qboolean Netchan_CanReliable (netchan_t *chan) __attribute__((pure)); /** Send a packet. @@ -381,6 +377,6 @@ qboolean Netchan_CanReliable (netchan_t *chan); */ void Netchan_SendPacket (int length, const void *data, netadr_t to); -//@} +///@} #endif // _NET_H diff --git a/include/netmain.h b/include/netmain.h index a35171415..351e615ba 100644 --- a/include/netmain.h +++ b/include/netmain.h @@ -34,7 +34,7 @@ /** \defgroup nq-net NetQuake network support. \ingroup network */ -//@{ +///@{ typedef struct { @@ -56,7 +56,7 @@ typedef struct /** \name NetHeader flags */ -//@{ +///@{ #define NETFLAG_LENGTH_MASK 0x0000ffff #define NETFLAG_DATA 0x00010000 #define NETFLAG_ACK 0x00020000 @@ -64,7 +64,7 @@ typedef struct #define NETFLAG_EOM 0x00080000 #define NETFLAG_UNRELIABLE 0x00100000 #define NETFLAG_CTL 0x80000000 -//@} +///@} #define NET_PROTOCOL_VERSION 3 @@ -86,7 +86,7 @@ typedef struct a full address and port in a string. It is used for returning the address of a server that is not running locally. */ -//@{ +///@{ /** Connect Request: \arg \b string \c game_name \em "QUAKE" @@ -153,7 +153,7 @@ typedef struct \arg \b string \c value */ #define CCREP_RULE_INFO 0x85 -//@} +///@} typedef struct qsocket_s { struct qsocket_s *next; @@ -205,11 +205,11 @@ typedef struct qsocket_s { /** \name socket management */ -//@{ +///@{ extern qsocket_t *net_activeSockets; extern qsocket_t *net_freeSockets; extern int net_numsockets; -//@} +///@} #define MAX_NET_DRIVERS 8 @@ -220,12 +220,12 @@ extern int net_driverlevel; /** \name message statistics */ -//@{ +///@{ extern int messagesSent; extern int messagesReceived; extern int unreliableMessagesSent; extern int unreliableMessagesReceived; -//@} +///@} /** Create and initialize a new qsocket. @@ -273,10 +273,6 @@ extern int net_activeconnections; */ void NET_Init (void); -/** Shutdown the networking sub-system. -*/ -void NET_Shutdown (void); - /** Check for new connections. \return Pointer to the qsocket for the new connection if there @@ -390,12 +386,12 @@ extern struct cvar_s *hostname; extern QFile *vcrFile; -//@} +///@} /** \defgroup nq-ld NetQuake lan drivers. \ingroup nq-net */ -//@{ +///@{ typedef struct { const char *name; @@ -423,12 +419,12 @@ typedef struct { extern int net_numlandrivers; extern net_landriver_t net_landrivers[MAX_NET_DRIVERS]; -//@} +///@} /** \defgroup nq-nd NetQuake network drivers. \ingroup nq-net */ -//@{ +///@{ typedef struct { const char *name; @@ -451,6 +447,6 @@ typedef struct { extern int net_numdrivers; extern net_driver_t net_drivers[MAX_NET_DRIVERS]; -//@} +///@} #endif // __net_h diff --git a/include/ops.h b/include/ops.h index cc988e56a..8793d5663 100644 --- a/include/ops.h +++ b/include/ops.h @@ -22,34 +22,34 @@ #ifndef __ops_h #define __ops_h -double OP_Not (double op1, double op2); -double OP_Negate (double op1, double op2); -double OP_Add (double op1, double op2); -double OP_Sub (double op1, double op2); -double OP_Mult (double op1, double op2); -double OP_Div (double op1, double op2); -double OP_Exp (double op1, double op2); -double OP_Eq (double op1, double op2); -double OP_Neq (double op1, double op2); -double OP_Or (double op1, double op2); -double OP_And (double op1, double op2); -double OP_GreaterThan (double op1, double op2); -double OP_LessThan (double op1, double op2); -double OP_GreaterThanEqual (double op1, double op2); -double OP_LessThanEqual (double op1, double op2); -double OP_BitAnd (double op1, double op2); -double OP_BitOr (double op1, double op2); -double OP_BitXor (double op1, double op2); -double OP_BitInv (double op1, double op2); +double OP_Not (double op1, double op2) __attribute__((const)); +double OP_Negate (double op1, double op2) __attribute__((const)); +double OP_Add (double op1, double op2) __attribute__((const)); +double OP_Sub (double op1, double op2) __attribute__((const)); +double OP_Mult (double op1, double op2) __attribute__((const)); +double OP_Div (double op1, double op2) __attribute__((const)); +double OP_Exp (double op1, double op2) __attribute__((const)); +double OP_Eq (double op1, double op2) __attribute__((const)); +double OP_Neq (double op1, double op2) __attribute__((const)); +double OP_Or (double op1, double op2) __attribute__((const)); +double OP_And (double op1, double op2) __attribute__((const)); +double OP_GreaterThan (double op1, double op2) __attribute__((const)); +double OP_LessThan (double op1, double op2) __attribute__((const)); +double OP_GreaterThanEqual (double op1, double op2) __attribute__((const)); +double OP_LessThanEqual (double op1, double op2) __attribute__((const)); +double OP_BitAnd (double op1, double op2) __attribute__((const)); +double OP_BitOr (double op1, double op2) __attribute__((const)); +double OP_BitXor (double op1, double op2) __attribute__((const)); +double OP_BitInv (double op1, double op2) __attribute__((const)); -double Func_Sin (double *oplist, unsigned int numops); -double Func_Cos (double *oplist, unsigned int numops); -double Func_Tan (double *oplist, unsigned int numops); -double Func_Asin (double *oplist, unsigned int numops); -double Func_Acos (double *oplist, unsigned int numops); -double Func_Atan (double *oplist, unsigned int numops); -double Func_Sqrt (double *oplist, unsigned int numops); -double Func_Abs (double *oplist, unsigned int numops); +double Func_Sin (double *oplist, unsigned int numops) __attribute__((pure)); +double Func_Cos (double *oplist, unsigned int numops) __attribute__((pure)); +double Func_Tan (double *oplist, unsigned int numops) __attribute__((pure)); +double Func_Asin (double *oplist, unsigned int numops) __attribute__((pure)); +double Func_Acos (double *oplist, unsigned int numops) __attribute__((pure)); +double Func_Atan (double *oplist, unsigned int numops) __attribute__((pure)); +double Func_Sqrt (double *oplist, unsigned int numops) __attribute__((pure)); +double Func_Abs (double *oplist, unsigned int numops) __attribute__((pure)); double Func_Rand (double *oplist, unsigned int numops); -double Func_Trunc (double *oplist, unsigned int numops); +double Func_Trunc (double *oplist, unsigned int numops) __attribute__((pure)); #endif // __ops_h diff --git a/include/qstring.h b/include/qstring.h index acea2f2e2..55b7ff30d 100644 --- a/include/qstring.h +++ b/include/qstring.h @@ -31,8 +31,8 @@ #include #include -const char * Q_strcasestr (const char *haystack, const char *needle); -size_t Q_strnlen (const char *s, size_t maxlen); +const char * Q_strcasestr (const char *haystack, const char *needle) __attribute__((pure)); +size_t Q_strnlen (const char *s, size_t maxlen) __attribute__((pure)); size_t Q_snprintfz (char *dest, size_t size, const char *fmt, ...) __attribute__((format(printf,3,4))); size_t Q_vsnprintfz (char *dest, size_t size, const char *fmt, va_list argptr); diff --git a/include/qw/msg_backbuf.h b/include/qw/msg_backbuf.h index 787612d38..12cbb0b06 100644 --- a/include/qw/msg_backbuf.h +++ b/include/qw/msg_backbuf.h @@ -43,7 +43,7 @@ typedef struct backbuf_s { const char *name; } backbuf_t; -int MSG_ReliableCheckSize (backbuf_t *rel, int maxsize, int minsize); +int MSG_ReliableCheckSize (backbuf_t *rel, int maxsize, int minsize) __attribute__((pure)); sizebuf_t *MSG_ReliableCheckBlock(backbuf_t *rel, int maxsize); void MSG_Reliable_FinishWrite(backbuf_t *rel); sizebuf_t *MSG_ReliableWrite_Begin(backbuf_t *rel, int c, int maxsize); diff --git a/include/qw/pmove.h b/include/qw/pmove.h index 285513a75..b8c436e56 100644 --- a/include/qw/pmove.h +++ b/include/qw/pmove.h @@ -106,9 +106,9 @@ void PlayerMove (void); void Pmove_Init (void); void Pmove_Init_Cvars (void); -int PM_HullPointContents (hull_t *hull, int num, const vec3_t p); +int PM_HullPointContents (hull_t *hull, int num, const vec3_t p) __attribute__((pure)); -int PM_PointContents (const vec3_t point); +int PM_PointContents (const vec3_t point) __attribute__((pure)); qboolean PM_TestPlayerPosition (const vec3_t point); trace_t PM_PlayerMove (const vec3_t start, const vec3_t stop); diff --git a/include/qw/protocol.h b/include/qw/protocol.h index 76f2c625d..9fb818d37 100644 --- a/include/qw/protocol.h +++ b/include/qw/protocol.h @@ -320,26 +320,9 @@ typedef struct usercmd_s { } usercmd_t; typedef struct plent_state_s { - int number; - - unsigned int flags; - vec3_t origin; + entity_state_t es; usercmd_t cmd; - vec3_t velocity; - int modelindex; - int frame; - int skinnum; - int effects; - int weaponframe; - byte msec; - - // QSG 2 - byte alpha; - byte scale; - byte glow_size; - byte glow_color; - byte colormod; } plent_state_t; typedef struct { diff --git a/include/r_cvar.h b/include/r_cvar.h index 8383f4705..e8a85a679 100644 --- a/include/r_cvar.h +++ b/include/r_cvar.h @@ -16,7 +16,6 @@ extern quat_t crosshair_color; extern struct cvar_s *d_mipcap; extern struct cvar_s *d_mipscale; -extern struct cvar_s *gl_driver; extern struct cvar_s *gl_affinemodels; extern struct cvar_s *gl_anisotropy; extern struct cvar_s *gl_clear; diff --git a/include/r_dynamic.h b/include/r_dynamic.h index 1dd54fc11..8968cfa1c 100644 --- a/include/r_dynamic.h +++ b/include/r_dynamic.h @@ -49,12 +49,6 @@ void R_PushDlights (const vec3_t entorigin); struct cvar_s; void R_MaxDlightsCheck (struct cvar_s *var); void R_Particles_Init_Cvars (void); -void R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp); -void R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp); void R_InitBubble (void); void R_InitParticles (void); diff --git a/include/r_internal.h b/include/r_internal.h index 3d5e69206..acd201c79 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -9,6 +9,34 @@ #include "r_screen.h" #include "r_shared.h" +typedef struct gltex_s { + texture_t *texture; + int gl_texturenum; + int gl_fb_texturenum; + instsurf_t *tex_chain; // for gl_texsort drawing + instsurf_t **tex_chain_tail; +} gltex_t; + +typedef struct glsltex_s { + texture_t *texture; + int gl_texturenum; + int sky_tex[2]; + instsurf_t *tex_chain; // for gl_texsort drawing + instsurf_t **tex_chain_tail; + struct elechain_s *elechain; + struct elechain_s **elechain_tail; +} glsltex_t; + +typedef struct vulktex_s { + texture_t *texture; + instsurf_t *tex_chain; // for gl_texsort drawing + instsurf_t **tex_chain_tail; + struct elechain_s *elechain; + struct elechain_s **elechain_tail; + struct qfv_tex_s *tex; + struct qfv_tex_s *glow; +} vulktex_t; + extern viddef_t vid; // global video state extern vid_render_data_t vid_render_data; @@ -16,6 +44,7 @@ extern vid_render_funcs_t gl_vid_render_funcs; extern vid_render_funcs_t glsl_vid_render_funcs; extern vid_render_funcs_t sw_vid_render_funcs; extern vid_render_funcs_t sw32_vid_render_funcs; +extern vid_render_funcs_t vulkan_vid_render_funcs; extern vid_render_funcs_t *vid_render_funcs; #define vr_data vid_render_data @@ -31,8 +60,8 @@ void Fog_Update (float density, float red, float green, float blue, struct plitem_s; void Fog_ParseWorldspawn (struct plitem_s *worldspawn); -float *Fog_GetColor (void); -float Fog_GetDensity (void); +void Fog_GetColor (quat_t fogcolor); +float Fog_GetDensity (void) __attribute__((pure)); void Fog_SetupFrame (void); void Fog_EnableGFog (void); void Fog_DisableGFog (void); @@ -44,7 +73,7 @@ void gl_R_Init (void); void glsl_R_Init (void); void sw_R_Init (void); void sw32_R_Init (void); - +void R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs); void R_Init_Cvars (void); void R_InitEfrags (void); void R_ClearState (void); @@ -54,7 +83,7 @@ void R_RenderView (void); // must set r_refdef first void R_ViewChanged (float aspect); // must set r_refdef first // called whenever r_refdef or vid change -void R_AddEfrags (entity_t *ent); +void R_AddEfrags (mod_brush_t *, entity_t *ent); void R_RemoveEfrags (entity_t *ent); void R_NewMap (model_t *worldmodel, model_t **models, int num_models); @@ -63,12 +92,12 @@ void R_NewMap (model_t *worldmodel, model_t **models, int num_models); void R_PushDlights (const vec3_t entorigin); void R_DrawWaterSurfaces (void); -void *D_SurfaceCacheAddress (void); +void *D_SurfaceCacheAddress (void) __attribute__((pure)); int D_SurfaceCacheForRes (int width, int height); void D_FlushCaches (void); void D_DeleteSurfaceCache (void); void D_InitCaches (void *buffer, int size); -void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj); +void R_SetVrect (const vrect_t *pvrect, vrect_t *pvrectin, int lineadj); void R_LoadSkys (const char *); diff --git a/include/r_local.h b/include/r_local.h index 5f9eb2ef0..37d5308c1 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -33,6 +33,8 @@ #include "QF/model.h" #include "QF/render.h" #include "QF/vid.h" +#include "QF/simd/mat4f.h" +#include "QF/simd/vec4f.h" #include "r_shared.h" #define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0) @@ -136,8 +138,8 @@ extern qboolean r_cache_thrash; // set if thrashing the surface cache extern qboolean insubmodel; extern vec3_t r_worldmodelorg; -extern mat4_t glsl_projection; -extern mat4_t glsl_view; +extern mat4f_t glsl_projection; +extern mat4f_t glsl_view; void R_SetFrustum (void); @@ -151,7 +153,7 @@ void R_TransformPlane (plane_t *p, float *normal, float *dist); void R_TransformFrustum (void); void R_SetSkyFrame (void); void R_DrawSurfaceBlock (void); -texture_t *R_TextureAnimation (msurface_t *surf); +texture_t *R_TextureAnimation (msurface_t *surf) __attribute__((pure)); void R_GenSkyTile (void *pdest); void R_SurfPatch (void); @@ -180,8 +182,9 @@ void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist); void R_StepActiveU (edge_t *pedge); void R_RemoveEdges (edge_t *pedge); void R_AddTexture (texture_t *tex); +struct vulkan_ctx_s; void R_ClearTextures (void); -void R_InitSurfaceChains (model_t *model); +void R_InitSurfaceChains (mod_brush_t *brush); extern void R_Surf8Start (void); extern void R_Surf8End (void); @@ -302,17 +305,18 @@ void R_ZGraph (void); void R_PrintAliasStats (void); void R_PrintTimes (void); void R_AnimateLight (void); -int R_LightPoint (const vec3_t p); +int R_LightPoint (mod_brush_t *brush, const vec3_t p); void R_SetupFrame (void); void R_cshift_f (void); void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1); void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip); -void R_RecursiveMarkLights (const vec3_t lightorigin, struct dlight_s *light, - int bit, mnode_t *node); +void R_RecursiveMarkLights (mod_brush_t *brush, const vec3_t lightorigin, + struct dlight_s *light, int bit, mnode_t *node); void R_MarkLights (const vec3_t lightorigin, struct dlight_s *light, int bit, model_t *model); void R_LoadSkys (const char *); +//void Vulkan_R_LoadSkys (const char *, struct vulkan_ctx_s *ctx); void R_LowFPPrecision (void); void R_HighFPPrecision (void); @@ -346,7 +350,12 @@ extern byte crosshair_data[]; #define CROSSHAIR_TILEY 2 #define CROSSHAIR_COUNT (CROSSHAIR_TILEX * CROSSHAIR_TILEY) +//NOTE: This is packed 8x8 bitmap data, one byte per scanline, 8 scanlines +////per character. Also, it is NOT the quake font, but the IBM charset. +extern byte font8x8_data[]; + struct qpic_s *Draw_CrosshairPic (void); +struct qpic_s *Draw_Font8x8Pic (void); struct tex_s *R_DotParticleTexture (void); struct tex_s *R_SparkParticleTexture (void); diff --git a/include/r_scrap.h b/include/r_scrap.h new file mode 100644 index 000000000..5539d7480 --- /dev/null +++ b/include/r_scrap.h @@ -0,0 +1,49 @@ +/* + r_scrap.h + + Renderer agnostic scrap management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/12 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __r_scrap_h +#define __r_scrap_h + +typedef struct rscrap_s { + struct vrect_s *free_rects; ///< linked list of free areas + struct vrect_s *rects; ///< linked list of allocated rects + int width; ///< overall width of scrap + int height; ///< overall height of scrap +} rscrap_t; + +void R_ScrapInit (rscrap_t *scrap, int width, int height); +void R_ScrapDelete (rscrap_t *scrap); +struct vrect_s *R_ScrapAlloc (rscrap_t *scrap, int width, int height); +void R_ScrapFree (rscrap_t *scrap, struct vrect_s *rect); +void R_ScrapClear (rscrap_t *scrap); +size_t R_ScrapArea (rscrap_t *scrap) __attribute__((pure)); +void R_ScrapDump (rscrap_t *scrap); + +#endif//__r_scrap_h diff --git a/include/r_screen.h b/include/r_screen.h index 5f7978e01..996cc3a0f 100644 --- a/include/r_screen.h +++ b/include/r_screen.h @@ -52,7 +52,6 @@ extern float scr_con_current; extern float scr_conlines; // lines of console to display extern int oldscreensize; -extern float oldfov; extern int oldsbar; extern qboolean scr_initialized; // ready to draw @@ -64,14 +63,12 @@ extern struct qpic_s *scr_turtle; extern int clearconsole; extern int clearnotify; -extern viddef_t vid; // global video state - extern vrect_t *pconupdate; extern vrect_t scr_vrect; extern qboolean scr_skipupdate; -float CalcFov (float fov_x, float width, float height); +void SCR_SetFOV (float fov); void SCR_SetUpToDrawConsole (void); void SCR_ScreenShot_f (void); diff --git a/include/rua_internal.h b/include/rua_internal.h index 0b6b34801..7bde98a77 100644 --- a/include/rua_internal.h +++ b/include/rua_internal.h @@ -39,8 +39,6 @@ void RUA_Cmd_Init (struct progs_s *pr, int secure); void RUA_Cvar_Init (struct progs_s *pr, int secure); -void RUA_File_Init (struct progs_s *pr, int secure); - void RUA_Hash_Init (struct progs_s *pr, int secure); void RUA_Math_Init (struct progs_s *pr, int secure); @@ -51,6 +49,8 @@ void RUA_Obj_Init (struct progs_s *pr, int secure); void RUA_Plist_Init (struct progs_s *pr, int secure); +void RUA_Runtime_Init (struct progs_s *pr, int secure); + void RUA_Script_Init (progs_t *pr, int secure); void RUA_Set_Init (progs_t *pr, int secure); diff --git a/include/snd_internal.h b/include/snd_internal.h index 0d8f5ba3e..7978c4307 100644 --- a/include/snd_internal.h +++ b/include/snd_internal.h @@ -35,7 +35,7 @@ /** \defgroup sound_render Sound rendering sub-system. \ingroup sound */ -//@{ +///@{ #include "QF/plugin/general.h" #include "QF/plugin/snd_render.h" @@ -58,7 +58,8 @@ typedef struct sfxstream_s sfxstream_t; \param buffer sound data \param count number of frames to paint */ -typedef void sfxpaint_t (int, channel_t *, float *, unsigned); +typedef void sfxpaint_t (int offset, channel_t *ch, float *buffer, + unsigned count); /** Represent a sound sample in the mixer. */ @@ -234,12 +235,12 @@ extern snd_render_data_t snd_render_data; #define PAINTBUFFER_SIZE 512 extern portable_samplepair_t snd_paintbuffer[PAINTBUFFER_SIZE * 2]; -//@} +///@} /** \defgroup sound_render_sfx Sound sfx \ingroup sound_render_mix */ -//@{ +///@{ /** Cache sound data. Initializes caching fields of sfx. \param sfx \param realname @@ -289,7 +290,7 @@ sfx_t *SND_LoadSound (const char *name); */ void SND_SFX_Init (void); -//@} +///@} /** \defgroup sound_render_mix_channels Sound channels \ingroup sound_render_mix @@ -302,7 +303,7 @@ void SND_SFX_Init (void); - MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels - 1
static sounds */ -//@{ +///@{ #define MAX_CHANNELS 512 //!< number of available mixing channels #define MAX_DYNAMIC_CHANNELS 128 //!< number of dynamic channels #define MAX_STATIC_CHANNELS 256 //!< number of static channels @@ -390,13 +391,13 @@ void SND_StopSound (int entnum, int entchannel); \param s name of sound to play */ void SND_LocalSound (const char *s); -//@} +///@} /** \defgroup sound_render_mix Mixer engine. \ingroup sound_render */ -//@{ +///@{ /** sound clock in samples */ extern unsigned snd_paintedtime; @@ -414,13 +415,13 @@ void SND_InitScaletable (void); \param sc sfxbuffer to set. */ void SND_SetPaint (sfxbuffer_t *sc); -//@} +///@} /** \defgroup sound_render_resample Resampling functions \ingroup sound_render */ -//@{ +///@{ /** Set up the various parameters that depend on the actual sample rate. \param sc buffer to setup \param streamed non-zero if this is for a stream. @@ -448,13 +449,13 @@ void SND_Resample (sfxbuffer_t *sc, float *data, int length); */ void SND_Convert (byte *idata, float *fdata, int frames, int channels, int width); -//@} +///@} /** \defgroup sound_render_load Sound loading functions \ingroup sound_render */ -//@{ +///@{ /** Load the referenced sound. \param sfx sound reference \return 0 if ok, -1 on error @@ -492,23 +493,23 @@ int SND_LoadWav (QFile *file, sfx_t *sfx, char *realname); \return 0 if ok, -1 on error */ int SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname); -//@} +///@} /** \defgroup sound_render_cache_stream Cache/Stream Functions. \ingroup sound_render */ -//@{ +///@{ /** Retrieve wavinfo from a cached sound. \param sfx sound reference \return pointer to sound's wavinfo */ -wavinfo_t *SND_CacheWavinfo (sfx_t *sfx); +wavinfo_t *SND_CacheWavinfo (sfx_t *sfx) __attribute__((pure)); /** Retrieve wavinfo from a streamed sound. \param sfx sound reference \return pointer to sound's wavinfo */ -wavinfo_t *SND_StreamWavinfo (sfx_t *sfx); +wavinfo_t *SND_StreamWavinfo (sfx_t *sfx) __attribute__((pure)); /** Ensure a cached sound is in memory. \param sfx sound reference @@ -522,7 +523,7 @@ sfxbuffer_t *SND_CacheTouch (sfx_t *sfx); \note The sound must be retained with SND_CacheRetain() for the returned buffer to be valid. */ -sfxbuffer_t *SND_CacheGetBuffer (sfx_t *sfx); +sfxbuffer_t *SND_CacheGetBuffer (sfx_t *sfx) __attribute__((pure)); /** Lock a cached sound into memory. After calling this, SND_CacheGetBffer() will return a valid buffer. @@ -541,14 +542,14 @@ void SND_CacheRelease (sfx_t *sfx); \param sfx sound reference \return poitner to sound buffer */ -sfxbuffer_t *SND_StreamGetBuffer (sfx_t *sfx); +sfxbuffer_t *SND_StreamGetBuffer (sfx_t *sfx) __attribute__((pure)); /** Lock a streamed sound into memory. Doesn't actually do anything other than return a pointer to the buffer. \param sfx sound reference \return poitner to sound buffer */ -sfxbuffer_t *SND_StreamRetain (sfx_t *sfx); +sfxbuffer_t *SND_StreamRetain (sfx_t *sfx) __attribute__((pure)); /** Unlock a streamed sound from memory. Doesn't actually do anything. \param sfx sound reference @@ -579,6 +580,6 @@ void SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos); */ sfxbuffer_t *SND_GetCache (long samples, int rate, int channels, sfxblock_t *block, cache_allocator_t allocator); -//@} +///@} #endif//__snd_internal_h diff --git a/include/vid_gl.h b/include/vid_gl.h new file mode 100644 index 000000000..2561af575 --- /dev/null +++ b/include/vid_gl.h @@ -0,0 +1,20 @@ +#ifndef __vid_gl_h +#define __vid_gl_h + +// GLXContext is a pointer to opaque data +typedef struct __GLXcontextRec *GLXContext; + +typedef struct gl_ctx_s { + GLXContext context; + void (*load_gl) (void); + void (*choose_visual) (struct gl_ctx_s *ctx); + void (*create_context) (struct gl_ctx_s *ctx); + void (*init_gl) (void); + void *(*get_proc_address) (const char *name, qboolean crit); + void (*end_rendering) (void); +} gl_ctx_t; + +extern gl_ctx_t *gl_ctx; +extern gl_ctx_t *glsl_ctx; + +#endif//__vid_gl_h diff --git a/include/vid_internal.h b/include/vid_internal.h index 9cf91bbc0..61ad44fe7 100644 --- a/include/vid_internal.h +++ b/include/vid_internal.h @@ -4,6 +4,21 @@ #include "QF/vid.h" #include "QF/plugin/vid_render.h" +typedef struct vid_internal_s { + int (*surf_cache_size) (int width, int height); + void (*flush_caches) (void); + void (*init_caches) (void *cache, int size); + void (*do_screen_buffer) (void); + void (*set_palette) (const byte *palette); + + void (*choose_visual) (void); + void (*create_context) (void); + + struct gl_ctx_s *(*gl_context) (void); + struct sw_ctx_s *(*sw_context) (void); + struct vulkan_ctx_s *(*vulkan_context) (void); +} vid_internal_t; + extern struct cvar_s *vid_fullscreen; extern struct cvar_s *vid_system_gamma; extern struct cvar_s *vid_gamma; @@ -16,11 +31,9 @@ void VID_InitGamma (const byte *); qboolean VID_SetGamma (double); void VID_UpdateGamma (struct cvar_s *); -void VID_Update (vrect_t *rects); void VID_LockBuffer (void); void VID_UnlockBuffer (void); void VID_InitBuffers (void); void VID_MakeColormaps (void); - #endif//__vid_internal_h diff --git a/include/vid_sw.h b/include/vid_sw.h new file mode 100644 index 000000000..2a5ab20a5 --- /dev/null +++ b/include/vid_sw.h @@ -0,0 +1,18 @@ +#ifndef __vid_sw_h +#define __vid_sw_h + +// GLXContext is a pointer to opaque data +typedef struct __GLXcontextRec *GLXContext; +struct vrect_s; +typedef struct sw_ctx_s { + GLXContext context; + void (*choose_visual) (struct sw_ctx_s *ctx); + void (*create_context) (struct sw_ctx_s *ctx); + void (*set_palette) (const byte *palette); + void (*update) (struct vrect_s *rects); +} sw_ctx_t; + +extern sw_ctx_t *sw_ctx; +extern sw_ctx_t *sw32_ctx; + +#endif//__vid_sw_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h new file mode 100644 index 000000000..2a1f8fd9a --- /dev/null +++ b/include/vid_vulkan.h @@ -0,0 +1,110 @@ +#ifndef __vid_vulkan_h +#define __vid_vulkan_h + +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + +#include "QF/darray.h" + +typedef struct vulkan_frame_s { + VkFramebuffer framebuffer; + VkFence fence; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderDoneSemaphore; + VkCommandBuffer cmdBuffer; + + int cmdSetCount; + struct qfv_cmdbufferset_s *cmdSets; +} vulkan_frame_t; + +typedef struct vulkan_matrices_s { + VkBuffer buffer_2d; + VkBuffer buffer_3d; + VkDeviceMemory memory; + float *projection_2d; + float *projection_3d; + float *view_3d; + float *sky_3d; +} vulkan_matrices_t; + +typedef struct vulkan_frameset_s + DARRAY_TYPE (vulkan_frame_t) vulkan_frameset_t; + +typedef struct clearvalueset_s + DARRAY_TYPE (VkClearValue) clearvalueset_t; + +typedef struct vulkan_ctx_s { + void (*load_vulkan) (struct vulkan_ctx_s *ctx); + void (*unload_vulkan) (struct vulkan_ctx_s *ctx); + + const char **required_extensions; + struct vulkan_presentation_s *presentation; + int (*get_presentation_support) (struct vulkan_ctx_s *ctx, + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex); + void (*choose_visual) (struct vulkan_ctx_s *ctx); + void (*create_window) (struct vulkan_ctx_s *ctx); + VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx); + + struct va_ctx_s *va_ctx; + struct qfv_instance_s *instance; + struct qfv_device_s *device; + struct qfv_swapchain_s *swapchain; + VkSampleCountFlagBits msaaSamples; // FIXME not here? + struct hashlink_s *hashlinks; //FIXME want per thread + VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain + struct plitem_s *pipelineDef; + + struct plitem_s *renderpassDef; + VkRenderPass renderpass; + clearvalueset_t *clearValues; + struct qfv_imageset_s *attachment_images; + struct qfv_imageviewset_s *attachment_views; + VkDeviceMemory attachmentMemory; + + uint32_t swapImageIndex; + struct qfv_framebufferset_s *framebuffers; + + struct hashtab_s *shaderModules; + struct hashtab_s *setLayouts; + struct hashtab_s *pipelineLayouts; + struct hashtab_s *descriptorPools; + struct hashtab_s *samplers; + struct hashtab_s *images; + struct hashtab_s *imageViews; + struct hashtab_s *renderpasses; + + struct aliasctx_s *alias_context; + struct bspctx_s *bsp_context; + struct drawctx_s *draw_context; + struct lightingctx_s *lighting_context; + struct composectx_s *compose_context; + + VkBuffer quad_buffer; + VkDeviceMemory quad_memory; + + VkCommandPool cmdpool; + VkCommandBuffer cmdbuffer; + VkFence fence; // for ctx->cmdbuffer only + struct qfv_stagebuf_s *staging; + size_t curFrame; + vulkan_frameset_t frames; + + struct qfv_capture_s *capture; + void (*capture_callback) (const byte *data, int width, int height); + + struct qfv_tex_s *default_black; + struct qfv_tex_s *default_white; + struct qfv_tex_s *default_magenta; + + // projection and view matrices (model is push constant) + vulkan_matrices_t matrices; + +#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; +#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; +#include "QF/Vulkan/funclist.h" +} vulkan_ctx_t; + +#endif//__vid_vulkan_h diff --git a/include/world.h b/include/world.h index e6ebc90ee..57bc973a6 100644 --- a/include/world.h +++ b/include/world.h @@ -98,8 +98,8 @@ void SV_LinkEdict (struct edict_s *ent, qboolean touch_triggers); // sets ent->v.absmin and ent->v.absmax // if touchtriggers, calls prog functions for the intersected triggers -int SV_PointContents (const vec3_t p); -int SV_TruePointContents (const vec3_t p); +int SV_PointContents (const vec3_t p) __attribute__((pure)); +int SV_TruePointContents (const vec3_t p) __attribute__((pure)); // returns the CONTENTS_* value from the world at the given point. // does not check any entities at all // the non-true version remaps the water current contents to content_water @@ -123,7 +123,7 @@ trace_t SV_Move (const vec3_t start, const vec3_t mins, const vec3_t maxs, struct edict_s *SV_TestPlayerPosition (struct edict_s *ent, const vec3_t origin); -int SV_HullPointContents (hull_t *hull, int num, const vec3_t p); +int SV_HullPointContents (hull_t *hull, int num, const vec3_t p) __attribute__((pure)); hull_t *SV_HullForEntity (struct edict_s *ent, const vec3_t mins, const vec3_t maxs, vec3_t extents, vec3_t offset); void MOD_TraceLine (hull_t *hull, int num, diff --git a/libs/Makefile.am b/libs/Makefile.am deleted file mode 100644 index 5c14c7d00..000000000 --- a/libs/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -# everything depends on util -# ruamoko depends on gamecode -# gib depends on ruamoko -# audio depends on gamecode -# models depends on image -# video depends on models(?), image(?) and ruamoko -# console depends on video, ruamoko and audio -SUBDIRS=@libs_dirs@ -DIST_SUBDIRS=util gamecode ruamoko gib audio image models video console \ - net qw client diff --git a/libs/Makemodule.am b/libs/Makemodule.am new file mode 100644 index 000000000..86fcac7df --- /dev/null +++ b/libs/Makemodule.am @@ -0,0 +1,14 @@ +include libs/util/Makemodule.am +include libs/gamecode/Makemodule.am +include libs/ruamoko/Makemodule.am +include libs/gib/Makemodule.am +include libs/audio/Makemodule.am +include libs/image/Makemodule.am +include libs/models/Makemodule.am +include libs/video/Makemodule.am +include libs/console/Makemodule.am +include libs/entity/Makemodule.am + +include libs/net/Makemodule.am +include libs/client/Makemodule.am +include libs/qw/Makemodule.am diff --git a/libs/audio/Makefile.am b/libs/audio/Makefile.am deleted file mode 100644 index 5521b3e2f..000000000 --- a/libs/audio/Makefile.am +++ /dev/null @@ -1,77 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= targets renderer . test -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include -SDL_LIBS= @SDL_LIBS@ -XMMS_LIBS= @XMMS_LIBS@ -plugin_ldflags= @plugin_ldflags@ -avoid-version -module -rpath $(plugindir) -plugin_libadd= @plugin_libadd@ -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined -EXEEXT= - -plugin_LTLIBRARIES= @cd_plugins@ -noinst_LTLIBRARIES= @cd_static_plugins@ -lib_LTLIBRARIES= @CD_TARGETS@ @SND_TARGETS@ -EXTRA_LTLIBRARIES= libQFsound.la libQFcd.la \ - cd_file.la cd_linux.la cd_sdl.la cd_sgi.la cd_win.la \ - cd_xmms.la - -cd_plug_libs=$(top_builddir)/libs/util/libQFutil.la - -cd_file_libs= \ - libQFsound.la \ - $(cd_plug_libs) - -cd_file_la_LDFLAGS= $(plugin_ldflags) -cd_file_la_LIBADD= $(cd_file_libs) -cd_file_la_DEPENDENCIES= $(cd_file_libs) -cd_file_la_SOURCES= cd_file.c - -cd_linux_la_LDFLAGS= $(plugin_ldflags) -cd_linux_la_LIBADD= $(cd_plug_libs) -cd_linux_la_DEPENDENCIES= $(cd_plug_libs) -cd_linux_la_SOURCES= cd_linux.c - -cd_sdl_la_LDFLAGS= $(plugin_ldflags) -cd_sdl_la_LIBADD= $(cd_plug_libs) $(SDL_LIBS) $(plugin_libadd) -cd_sdl_la_DEPENDENCIES= $(cd_plug_libs) -cd_sdl_la_CFLAGS= $(SDL_CFLAGS) -cd_sdl_la_SOURCES= cd_sdl.c - -cd_sgi_la_LDFLAGS= $(plugin_ldflags) -cd_sgi_la_LIBADD= $(cd_plug_libs) $(SGI_CD_LIBS) -cd_sgi_la_DEPENDENCIES= $(cd_plug_libs) -cd_sgi_la_SOURCES= cd_sgi.c - -cd_win_la_LDFLAGS= $(plugin_ldflags) -cd_win_la_LIBADD= $(cd_plug_libs) $(plugin_libadd) -cd_win_la_DEPENDENCIES= $(cd_plug_libs) -cd_win_la_SOURCES= cd_win.c - -cd_xmms_la_LDFLAGS= $(plugin_ldflags) -cd_xmms_la_LIBADD= $(cd_plug_libs) $(XMMS_LIBS) -cd_xmms_la_DEPENDENCIES= $(cd_plug_libs) -cd_xmms_la_CFLAGS= $(XMMS_CFLAGS) -cd_xmms_la_SOURCES= cd_xmms.c - -sound_libs= \ - @snd_output_static_plugin_libs@ \ - @snd_render_static_plugin_libs@ \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(top_builddir)/libs/util/libQFutil.la - -cd_libs= \ - @cd_static_plugin_libs@ \ - $(top_builddir)/libs/util/libQFutil.la - -libQFsound_la_LDFLAGS= $(lib_ldflags) -libQFsound_la_LIBADD= $(sound_libs) -libQFsound_la_DEPENDENCIES= $(sound_libs) -libQFsound_la_SOURCES= snd.c snd_progs.c - -libQFcd_la_LDFLAGS= $(lib_ldflags) -libQFcd_la_LIBADD= $(cd_libs) -libQFcd_la_DEPENDENCIES= $(cd_libs) -libQFcd_la_SOURCES= cd.c diff --git a/libs/audio/Makemodule.am b/libs/audio/Makemodule.am new file mode 100644 index 000000000..c649c7351 --- /dev/null +++ b/libs/audio/Makemodule.am @@ -0,0 +1,67 @@ +include libs/audio/targets/Makemodule.am +include libs/audio/renderer/Makemodule.am + +plugin_LTLIBRARIES += @cd_plugins@ +noinst_LTLIBRARIES += @cd_static_plugins@ +lib_LTLIBRARIES += @CD_TARGETS@ @SND_TARGETS@ +EXTRA_LTLIBRARIES += \ + libs/audio/libQFsound.la \ + libs/audio/libQFcd.la \ + libs/audio/cd_file.la \ + libs/audio/cd_linux.la \ + libs/audio/cd_sdl.la \ + libs/audio/cd_sgi.la \ + libs/audio/cd_win.la \ + libs/audio/cd_xmms.la + +cd_plug_libs=libs/util/libQFutil.la + +cd_file_libs= \ + libs/audio/libQFsound.la \ + $(cd_plug_libs) + +libs_audio_cd_file_la_LDFLAGS= $(plugin_ldflags) +libs_audio_cd_file_la_LIBADD= $(cd_file_libs) +libs_audio_cd_file_la_SOURCES= libs/audio/cd_file.c + +libs_audio_cd_linux_la_LDFLAGS= $(plugin_ldflags) +libs_audio_cd_linux_la_LIBADD= $(cd_plug_libs) +libs_audio_cd_linux_la_SOURCES= libs/audio/cd_linux.c + +libs_audio_cd_sdl_la_LDFLAGS= $(plugin_ldflags) +libs_audio_cd_sdl_la_LIBADD= $(cd_plug_libs) $(SDL_LIBS) $(plugin_libadd) +libs_audio_cd_sdl_la_CFLAGS= $(SDL_CFLAGS) +libs_audio_cd_sdl_la_SOURCES= libs/audio/cd_sdl.c + +libs_audio_cd_sgi_la_LDFLAGS= $(plugin_ldflags) +libs_audio_cd_sgi_la_LIBADD= $(cd_plug_libs) $(SGI_CD_LIBS) +libs_audio_cd_sgi_la_SOURCES= libs/audio/cd_sgi.c + +libs_audio_cd_win_la_LDFLAGS= $(plugin_ldflags) +libs_audio_cd_win_la_LIBADD= $(cd_plug_libs) $(plugin_libadd) +libs_audio_cd_win_la_SOURCES= libs/audio/cd_win.c + +libs_audio_cd_xmms_la_LDFLAGS= $(plugin_ldflags) +libs_audio_cd_xmms_la_LIBADD= $(cd_plug_libs) $(XMMS_LIBS) +libs_audio_cd_xmms_la_CFLAGS= $(XMMS_CFLAGS) +libs_audio_cd_xmms_la_SOURCES= libs/audio/cd_xmms.c + +sound_libs= \ + @snd_output_static_plugin_libs@ \ + @snd_render_static_plugin_libs@ \ + libs/ruamoko/libQFruamoko.la \ + libs/util/libQFutil.la + +cd_libs= \ + @cd_static_plugin_libs@ \ + libs/util/libQFutil.la + +libs_audio_libQFsound_la_LDFLAGS= $(lib_ldflags) +libs_audio_libQFsound_la_DEPENDENCIES= $(sound_libs) +libs_audio_libQFsound_la_LIBADD= $(sound_libs) +libs_audio_libQFsound_la_SOURCES= libs/audio/snd.c libs/audio/snd_progs.c + +libs_audio_libQFcd_la_LDFLAGS= $(lib_ldflags) +libs_audio_libQFcd_la_DEPENDENCIES= $(cd_libs) +libs_audio_libQFcd_la_LIBADD= $(cd_libs) +libs_audio_libQFcd_la_SOURCES= libs/audio/cd.c diff --git a/libs/audio/cd.c b/libs/audio/cd.c index bf4245ba6..c6a9e8893 100644 --- a/libs/audio/cd.c +++ b/libs/audio/cd.c @@ -69,8 +69,8 @@ CDAudio_Resume (void) cdmodule->functions->cd->pCDAudio_Resume (); } -VISIBLE void -CDAudio_Shutdown (void) +static void +CDAudio_shutdown (void *data) { if (cdmodule) cdmodule->functions->general->p_Shutdown (); @@ -93,6 +93,8 @@ CD_f (void) VISIBLE int CDAudio_Init (void) { + Sys_RegisterShutdown (CDAudio_shutdown, 0); + PI_RegisterPlugins (cd_plugin_list); cd_plugin = Cvar_Get ("cd_plugin", CD_DEFAULT, CVAR_ROM, NULL, "CD Plugin to use"); diff --git a/libs/audio/cd_file.c b/libs/audio/cd_file.c index ce0f2b94f..0e26a803a 100644 --- a/libs/audio/cd_file.c +++ b/libs/audio/cd_file.c @@ -53,8 +53,8 @@ #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/plist.h" #include "QF/qargs.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/quakeio.h" #include "QF/sound.h" @@ -172,7 +172,8 @@ Load_Tracklist (void) buffile = calloc (size+10, sizeof (char)); Qread (oggfile, buffile, size); - tracklist = PL_GetPropertyList (buffile); + PL_Free (tracklist); + tracklist = PL_GetPropertyList (buffile, 0); if (!tracklist || PL_Type (tracklist) != QFDictionary) { Sys_Printf ("Malformed or empty tracklist file. check mus_ogglist\n"); return -1; @@ -189,7 +190,7 @@ Load_Tracklist (void) static void I_OGGMus_SetPlayList (int track) { - const char *trackstring = va ("%i", track); + const char *trackstring = va (0, "%i", track); int i; play_list = PL_ObjectForKey (tracklist, trackstring); @@ -327,7 +328,7 @@ I_OGGMus_Info (void) /* loop, and count up the Highest key number. */ for (iter = 1, count = 0; count < keycount && iter <= 99 ; iter++) { - trackstring = va ("%i", iter); + trackstring = va (0, "%i", iter); if (!(currenttrack = PL_ObjectForKey (tracklist, trackstring))) { continue; } @@ -454,7 +455,7 @@ Mus_VolChange (cvar_t *bgmvolume) static void Mus_gamedir (int phase) { - if (phase); + if (phase) Mus_OggChange (mus_ogglist); } diff --git a/libs/audio/cd_xmms.c b/libs/audio/cd_xmms.c index 6ed35d2cf..47c8a187f 100644 --- a/libs/audio/cd_xmms.c +++ b/libs/audio/cd_xmms.c @@ -43,9 +43,6 @@ #ifdef HAVE_SYS_IOCTL_H # include #endif -#ifdef HAVE_SIGNAL_H -# include -#endif #include #include diff --git a/libs/audio/renderer/Makefile.am b/libs/audio/renderer/Makefile.am deleted file mode 100644 index 0c3bcd719..000000000 --- a/libs/audio/renderer/Makefile.am +++ /dev/null @@ -1,55 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ \ - $(VORBIS_CFLAGS) $(OGG_CFLAGS) $(SAMPLERATE_CFLAGS) $(JACK_CFLAGS) -AM_CPPFLAGS= -I$(top_srcdir)/include -plugin_ldflags= @plugin_ldflags@ -avoid-version -module -rpath $(plugindir) -plugin_libadd= @plugin_libadd@ -EXEEXT= - -plugin_LTLIBRARIES= @snd_render_plugins@ -noinst_LTLIBRARIES= @snd_render_static_plugins@ -EXTRA_LTLIBRARIES= snd_render_default.la snd_render_jack.la - -flac_src=flac.c -midi_src=midi.c -vorbis_src=vorbis.c -wav_src=wav.c - -if HAVE_FLAC -have_flac_src=$(flac_src) -else -have_flac_src= -endif -if HAVE_MIDI -have_midi_src=$(midi_src) -else -have_midi_src= -endif -if HAVE_VORBIS -have_vorbis_src=$(vorbis_src) -else -have_vorbis_src= -endif -have_wav_src=$(wav_src) - -format_src=$(have_flac_src) $(have_midi_src) $(have_vorbis_src) $(have_wav_src) -format_libs= \ - $(SAMPLERATE_LIBS) $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(FLAC_LIBS) \ - $(OGG_LIBS) $(WM_LIBS) -extra_format_src=flac.c midi.c vorbis.c wav.c -snd_common=snd_channels.c snd_mem.c snd_mix.c snd_resample.c snd_sfx.c -snd_libs= \ - $(top_builddir)/libs/util/libQFutil.la - -snd_render_default_la_LDFLAGS= $(plugin_ldflags) -snd_render_default_la_SOURCES= snd_dma.c $(snd_common) $(format_src) -snd_render_default_la_LIBADD= $(snd_libs) $(format_libs) -snd_render_default_la_DEPENDENCIES= $(snd_libs) -EXTRA_snd_render_default_la_SOURCES=$(extra_format_src) - -snd_render_jack_la_LDFLAGS= $(plugin_ldflags) -snd_render_jack_la_SOURCES= snd_jack.c $(snd_common) $(format_src) -snd_render_jack_la_LIBADD= $(snd_libs) $(format_libs) $(JACK_LIBS) -snd_render_jack_la_DEPENDENCIES= $(snd_libs) -EXTRA_snd_render_jack_la_SOURCES= $(extra_format_src) diff --git a/libs/audio/renderer/Makemodule.am b/libs/audio/renderer/Makemodule.am new file mode 100644 index 000000000..0ef8bda4f --- /dev/null +++ b/libs/audio/renderer/Makemodule.am @@ -0,0 +1,46 @@ +plugin_LTLIBRARIES += @snd_render_plugins@ +noinst_LTLIBRARIES += @snd_render_static_plugins@ +EXTRA_LTLIBRARIES += libs/audio/renderer/snd_render_default.la libs/audio/renderer/snd_render_jack.la + +flac_src=libs/audio/renderer/flac.c +midi_src=libs/audio/renderer/midi.c +vorbis_src=libs/audio/renderer/vorbis.c +wav_src=libs/audio/renderer/wav.c + +if HAVE_FLAC +have_flac_src=$(flac_src) +else +have_flac_src= +endif +if HAVE_MIDI +have_midi_src=$(midi_src) +else +have_midi_src= +endif +if HAVE_VORBIS +have_vorbis_src=$(vorbis_src) +else +have_vorbis_src= +endif +have_wav_src=$(wav_src) + +format_src=$(have_flac_src) $(have_midi_src) $(have_vorbis_src) $(have_wav_src) +format_libs= \ + $(SAMPLERATE_LIBS) $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(FLAC_LIBS) \ + $(OGG_LIBS) $(WM_LIBS) +extra_format_src=libs/audio/renderer/flac.c libs/audio/renderer/midi.c libs/audio/renderer/vorbis.c libs/audio/renderer/wav.c +snd_common=libs/audio/renderer/snd_channels.c libs/audio/renderer/snd_mem.c libs/audio/renderer/snd_mix.c libs/audio/renderer/snd_resample.c libs/audio/renderer/snd_sfx.c +snd_libs= \ + libs/util/libQFutil.la + +libs_audio_renderer_snd_render_default_la_LDFLAGS= $(plugin_ldflags) +libs_audio_renderer_snd_render_default_la_SOURCES= libs/audio/renderer/snd_dma.c $(snd_common) $(format_src) +libs_audio_renderer_snd_render_default_la_LIBADD= $(snd_libs) $(format_libs) +libs_audio_renderer_snd_render_default_la_DEPENDENCIES= $(snd_libs) +EXTRA_libs_audio_renderer_snd_render_default_la_SOURCES=$(extra_format_src) + +libs_audio_renderer_snd_render_jack_la_LDFLAGS= $(plugin_ldflags) +libs_audio_renderer_snd_render_jack_la_SOURCES= libs/audio/renderer/snd_jack.c $(snd_common) $(format_src) +libs_audio_renderer_snd_render_jack_la_LIBADD= $(snd_libs) $(format_libs) $(JACK_LIBS) +libs_audio_renderer_snd_render_jack_la_DEPENDENCIES= $(snd_libs) +EXTRA_libs_audio_renderer_snd_render_jack_la_SOURCES= $(extra_format_src) diff --git a/libs/audio/renderer/midi.c b/libs/audio/renderer/midi.c index 86898da65..c4f44a050 100644 --- a/libs/audio/renderer/midi.c +++ b/libs/audio/renderer/midi.c @@ -105,7 +105,7 @@ midi_stream_read (void *file, float **buf) int res; byte *data = alloca (size); - res = WildMidi_GetOutput (mf->handle, (char *)data, size); + res = WildMidi_GetOutput (mf->handle, (int8_t *)data, size); if (res <= 0) { stream->error = 1; return 0; diff --git a/libs/audio/renderer/snd_channels.c b/libs/audio/renderer/snd_channels.c index cbf337496..59c068b2c 100644 --- a/libs/audio/renderer/snd_channels.c +++ b/libs/audio/renderer/snd_channels.c @@ -104,7 +104,8 @@ SND_AllocChannel (void) for (free = &free_channels; *free; free = &(*free)->next) { num_free++; } - Sys_Printf ("SND_AllocChannel: out of channels. %d\n", num_free); + Sys_MaskPrintf (SYS_WARN, "SND_AllocChannel: out of channels. %d\n", + num_free); return 0; } chan = *free; diff --git a/libs/audio/renderer/snd_jack.c b/libs/audio/renderer/snd_jack.c index 36c5d0e6a..e35d61e50 100644 --- a/libs/audio/renderer/snd_jack.c +++ b/libs/audio/renderer/snd_jack.c @@ -306,7 +306,9 @@ snd_jack_error (const char *desc) static int snd_jack_xrun (void *arg) { - fprintf (stderr, "snd_jack: xrun\n"); + if (developer->int_val & SYS_SND) { + fprintf (stderr, "snd_jack: xrun\n"); + } return 0; } @@ -327,7 +329,7 @@ s_jack_connect (void) jack_set_process_callback (jack_handle, snd_jack_process, 0); jack_on_shutdown (jack_handle, snd_jack_shutdown, 0); for (i = 0; i < 2; i++) - jack_out[i] = jack_port_register (jack_handle, va ("out_%d", i + 1), + jack_out[i] = jack_port_register (jack_handle, va (0, "out_%d", i + 1), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); snd_shm->speed = jack_get_sample_rate (jack_handle); diff --git a/libs/audio/renderer/snd_sfx.c b/libs/audio/renderer/snd_sfx.c index 25d023de8..8152213a6 100644 --- a/libs/audio/renderer/snd_sfx.c +++ b/libs/audio/renderer/snd_sfx.c @@ -199,7 +199,7 @@ SND_PrecacheSound (const char *name) if (!name) Sys_Error ("SND_PrecacheSound: NULL"); - sfx = SND_LoadSound (va ("sound/%s", name)); + sfx = SND_LoadSound (va (0, "sound/%s", name)); if (sfx && precache->int_val) { if (sfx->retain (sfx)) sfx->release (sfx); @@ -245,7 +245,7 @@ s_soundlist_f (void) void SND_SFX_Init (void) { - snd_sfx_hash = Hash_NewTable (511, snd_sfx_getkey, snd_sfx_free, 0); + snd_sfx_hash = Hash_NewTable (511, snd_sfx_getkey, snd_sfx_free, 0, 0); precache = Cvar_Get ("precache", "1", CVAR_NONE, NULL, "Toggle the use of a precache"); diff --git a/libs/audio/renderer/vorbis.c b/libs/audio/renderer/vorbis.c index fd14ec965..1c346a146 100644 --- a/libs/audio/renderer/vorbis.c +++ b/libs/audio/renderer/vorbis.c @@ -249,6 +249,7 @@ vorbis_stream_close (sfx_t *sfx) if (vf->data) free (vf->data); ov_clear (vf->vf); + free (vf->vf); free (vf); SND_SFX_StreamClose (sfx); } diff --git a/libs/audio/snd.c b/libs/audio/snd.c index 6f4ecba05..552dfad0e 100644 --- a/libs/audio/snd.c +++ b/libs/audio/snd.c @@ -53,6 +53,19 @@ static plugin_list_t snd_render_list[] = { SND_RENDER_PLUGIN_LIST }; +static void +S_shutdown (void *data) +{ + if (snd_render_module) { + PI_UnloadPlugin (snd_render_module); + snd_render_module = NULL; + snd_render_funcs = NULL; + } + if (snd_output_module) { + PI_UnloadPlugin (snd_output_module); + snd_output_module = NULL; + } +} VISIBLE void S_Init (int *viewentity, double *host_frametime) @@ -65,6 +78,8 @@ S_Init (int *viewentity, double *host_frametime) return; } + Sys_RegisterShutdown (S_shutdown, 0); + PI_RegisterPlugins (snd_output_list); PI_RegisterPlugins (snd_render_list); snd_output_module = PI_LoadPlugin ("snd_output", snd_output->string); @@ -120,20 +135,6 @@ S_AmbientOn (void) snd_render_funcs->pS_AmbientOn (); } -VISIBLE void -S_Shutdown (void) -{ - if (snd_render_module) { - PI_UnloadPlugin (snd_render_module); - snd_render_module = NULL; - snd_render_funcs = NULL; - } - if (snd_output_module) { - PI_UnloadPlugin (snd_output_module); - snd_output_module = NULL; - } -} - VISIBLE void S_StaticSound (sfx_t *sfx, const vec3_t origin, float vol, float attenuation) { diff --git a/libs/audio/targets/Makefile.am b/libs/audio/targets/Makefile.am deleted file mode 100644 index ff0411354..000000000 --- a/libs/audio/targets/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include -SDL_LIBS = @SDL_LIBS@ -plugin_ldflags= @plugin_ldflags@ -avoid-version -module -rpath $(plugindir) -plugin_libadd= @plugin_libadd@ -EXEEXT= -snd_deps=$(top_builddir)/libs/util/libQFutil.la - -plugin_LTLIBRARIES= @snd_output_plugins@ -noinst_LTLIBRARIES= @snd_output_static_plugins@ -EXTRA_LTLIBRARIES= \ - snd_output_sdl.la snd_output_alsa.la snd_output_oss.la snd_output_sgi.la \ - snd_output_sun.la snd_output_win.la snd_output_dx.la snd_output_disk.la - -snd_output_sdl_la_LDFLAGS= $(plugin_ldflags) -snd_output_sdl_la_LIBADD= $(snd_deps) $(SDL_LIBS) $(plugin_libadd) -snd_output_sdl_la_DEPENDENCIES= $(snd_deps) -snd_output_sdl_la_CFLAGS= $(SDL_CFLAGS) -snd_output_sdl_la_SOURCES= snd_sdl.c - -snd_output_alsa_la_LDFLAGS= $(plugin_ldflags) -snd_output_alsa_la_LIBADD= $(snd_deps) -snd_output_alsa_la_DEPENDENCIES=$(snd_deps) -snd_output_alsa_la_CFLAGS= $(ALSA_CFLAGS) -snd_output_alsa_la_SOURCES= snd_alsa.c - -snd_output_oss_la_LDFLAGS= $(plugin_ldflags) -snd_output_oss_la_LIBADD= $(snd_deps) $(OSS_LIBS) -snd_output_oss_la_DEPENDENCIES= $(snd_deps) -snd_output_oss_la_CFLAGS= $(OSS_CFLAGS) -snd_output_oss_la_SOURCES= snd_oss.c - -snd_output_sgi_la_LDFLAGS= $(plugin_ldflags) -snd_output_sgi_la_LIBADD= $(snd_deps) $(SGISND_LIBS) -snd_output_sgi_la_DEPENDENCIES= $(snd_deps) -snd_output_sgi_la_CFLAGS= $(SGISND_CFLAGS) -snd_output_sgi_la_SOURCES= snd_sgi.c - -snd_output_sun_la_LDFLAGS= $(plugin_ldflags) -snd_output_sun_la_DEPENDENCIES= $(snd_deps) -snd_output_sun_la_CFLAGS= $(SUNSND_CFLAGS) -snd_output_sun_la_SOURCES= snd_sun.c - -snd_output_win_la_LDFLAGS= $(plugin_ldflags) -snd_output_win_la_LIBADD= $(snd_deps) $(WINSND_LIBS) $(plugin_libadd) -snd_output_win_la_DEPENDENCIES= $(snd_deps) -snd_output_win_la_CFLAGS= $(WIN32SND_CFLAGS) -snd_output_win_la_SOURCES= snd_win.c - -snd_output_dx_la_LDFLAGS= $(plugin_ldflags) -snd_output_dx_la_LIBADD= $(snd_deps) $(WINSND_LIBS) $(plugin_libadd) -snd_output_dx_la_DEPENDENCIES= $(snd_deps) -snd_output_dx_la_CFLAGS= $(WIN32SND_CFLAGS) -snd_output_dx_la_SOURCES= snd_dx.c - -snd_output_disk_la_LDFLAGS= $(plugin_ldflags) -snd_output_disk_la_LIBADD= $(snd_deps) $(plugin_libadd) -snd_output_disk_la_DEPENDENCIES=$(snd_deps) -snd_output_disk_la_CFLAGS= -snd_output_disk_la_SOURCES= snd_disk.c diff --git a/libs/audio/targets/Makemodule.am b/libs/audio/targets/Makemodule.am new file mode 100644 index 000000000..dfc566f2a --- /dev/null +++ b/libs/audio/targets/Makemodule.am @@ -0,0 +1,54 @@ +plugin_LTLIBRARIES += @snd_output_plugins@ +noinst_LTLIBRARIES += @snd_output_static_plugins@ +EXTRA_LTLIBRARIES += \ + libs/audio/targets/snd_output_sdl.la libs/audio/targets/snd_output_alsa.la libs/audio/targets/snd_output_oss.la libs/audio/targets/snd_output_sgi.la \ + libs/audio/targets/snd_output_sun.la libs/audio/targets/snd_output_win.la libs/audio/targets/snd_output_dx.la libs/audio/targets/snd_output_disk.la + +snd_deps=libs/util/libQFutil.la + +libs_audio_targets_snd_output_sdl_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_sdl_la_LIBADD= $(snd_deps) $(SDL_LIBS) $(plugin_libadd) +libs_audio_targets_snd_output_sdl_la_DEPENDENCIES= $(snd_deps) +libs_audio_targets_snd_output_sdl_la_CFLAGS= $(SDL_CFLAGS) +libs_audio_targets_snd_output_sdl_la_SOURCES= libs/audio/targets/snd_sdl.c + +libs_audio_targets_snd_output_alsa_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_alsa_la_LIBADD= $(snd_deps) +libs_audio_targets_snd_output_alsa_la_DEPENDENCIES=$(snd_deps) +libs_audio_targets_snd_output_alsa_la_CFLAGS= $(ALSA_CFLAGS) +libs_audio_targets_snd_output_alsa_la_SOURCES= libs/audio/targets/snd_alsa.c + +libs_audio_targets_snd_output_oss_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_oss_la_LIBADD= $(snd_deps) $(OSS_LIBS) +libs_audio_targets_snd_output_oss_la_DEPENDENCIES= $(snd_deps) +libs_audio_targets_snd_output_oss_la_CFLAGS= $(OSS_CFLAGS) +libs_audio_targets_snd_output_oss_la_SOURCES= libs/audio/targets/snd_oss.c + +libs_audio_targets_snd_output_sgi_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_sgi_la_LIBADD= $(snd_deps) $(SGISND_LIBS) +libs_audio_targets_snd_output_sgi_la_DEPENDENCIES= $(snd_deps) +libs_audio_targets_snd_output_sgi_la_CFLAGS= $(SGISND_CFLAGS) +libs_audio_targets_snd_output_sgi_la_SOURCES= libs/audio/targets/snd_sgi.c + +libs_audio_targets_snd_output_sun_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_sun_la_DEPENDENCIES= $(snd_deps) +libs_audio_targets_snd_output_sun_la_CFLAGS= $(SUNSND_CFLAGS) +libs_audio_targets_snd_output_sun_la_SOURCES= libs/audio/targets/snd_sun.c + +libs_audio_targets_snd_output_win_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_win_la_LIBADD= $(snd_deps) $(WINSND_LIBS) $(plugin_libadd) +libs_audio_targets_snd_output_win_la_DEPENDENCIES= $(snd_deps) +libs_audio_targets_snd_output_win_la_CFLAGS= $(WIN32SND_CFLAGS) +libs_audio_targets_snd_output_win_la_SOURCES= libs/audio/targets/snd_win.c + +libs_audio_targets_snd_output_dx_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_dx_la_LIBADD= $(snd_deps) $(WINSND_LIBS) $(plugin_libadd) +libs_audio_targets_snd_output_dx_la_DEPENDENCIES= $(snd_deps) +libs_audio_targets_snd_output_dx_la_CFLAGS= $(WIN32SND_CFLAGS) +libs_audio_targets_snd_output_dx_la_SOURCES= libs/audio/targets/snd_dx.c + +libs_audio_targets_snd_output_disk_la_LDFLAGS= $(plugin_ldflags) +libs_audio_targets_snd_output_disk_la_LIBADD= $(snd_deps) $(plugin_libadd) +libs_audio_targets_snd_output_disk_la_DEPENDENCIES=$(snd_deps) +libs_audio_targets_snd_output_disk_la_CFLAGS= +libs_audio_targets_snd_output_disk_la_SOURCES= libs/audio/targets/snd_disk.c diff --git a/libs/audio/targets/snd_alsa.c b/libs/audio/targets/snd_alsa.c index 864055ccc..205153752 100644 --- a/libs/audio/targets/snd_alsa.c +++ b/libs/audio/targets/snd_alsa.c @@ -103,7 +103,7 @@ SNDDMA_Init_Cvars (void) static int SNDDMA_GetDMAPos (void); -static snd_pcm_uframes_t +static __attribute__((const)) snd_pcm_uframes_t round_buffer_size (snd_pcm_uframes_t sz) { snd_pcm_uframes_t mask = ~0; @@ -463,7 +463,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { qfsnd_pcm_close (pcm); @@ -549,7 +549,7 @@ PLUGIN_INFO(snd_output, alsa) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_disk.c b/libs/audio/targets/snd_disk.c index e24bc0e9f..878ca90ca 100644 --- a/libs/audio/targets/snd_disk.c +++ b/libs/audio/targets/snd_disk.c @@ -108,7 +108,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { Qclose (snd_file); @@ -174,7 +174,7 @@ PLUGIN_INFO(snd_output, disk) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_dx.c b/libs/audio/targets/snd_dx.c index 1bae2c3d0..3852a17a5 100644 --- a/libs/audio/targets/snd_dx.c +++ b/libs/audio/targets/snd_dx.c @@ -417,13 +417,8 @@ SNDDMA_Submit (void) DSOUND_LockBuffer (false); } -/* - SNDDMA_Shutdown - - Reset the sound device for exiting -*/ static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { FreeSound (); } @@ -450,7 +445,7 @@ DSOUND_LockBuffer (qboolean lockit) if (hresult != DSERR_BUFFERLOST) { Sys_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n"); - SNDDMA_Shutdown (); + SNDDMA_shutdown (); SNDDMA_Init (); return NULL; } @@ -458,7 +453,7 @@ DSOUND_LockBuffer (qboolean lockit) if (++reps > 10000) { Sys_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n"); - SNDDMA_Shutdown (); + SNDDMA_shutdown (); SNDDMA_Init (); return NULL; } @@ -529,7 +524,7 @@ PLUGIN_INFO(snd_output, dx) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_oss.c b/libs/audio/targets/snd_oss.c index 33349dc98..97383ff82 100644 --- a/libs/audio/targets/snd_oss.c +++ b/libs/audio/targets/snd_oss.c @@ -331,7 +331,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { if (mmaped_io) @@ -413,7 +413,7 @@ PLUGIN_INFO(snd_output, oss) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_sdl.c b/libs/audio/targets/snd_sdl.c index 91d5500f5..5e8dfc409 100644 --- a/libs/audio/targets/snd_sdl.c +++ b/libs/audio/targets/snd_sdl.c @@ -206,7 +206,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { SDL_CloseAudio (); @@ -297,7 +297,7 @@ PLUGIN_INFO(snd_output, sdl) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_sgi.c b/libs/audio/targets/snd_sgi.c index 4b431dbaf..27ae12d64 100644 --- a/libs/audio/targets/snd_sgi.c +++ b/libs/audio/targets/snd_sgi.c @@ -269,7 +269,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { free (write_buffer); @@ -357,7 +357,7 @@ PLUGIN_INFO(snd_output, sgi) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_sun.c b/libs/audio/targets/snd_sun.c index 89c649416..702757a34 100644 --- a/libs/audio/targets/snd_sun.c +++ b/libs/audio/targets/snd_sun.c @@ -189,7 +189,7 @@ SNDDMA_GetSamples (void) } #endif static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { close (audio_fd); @@ -281,7 +281,7 @@ PLUGIN_INFO(snd_output, sun) plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_sound_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_sound_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_sound_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_sound_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_sound_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_sound_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_win.c b/libs/audio/targets/snd_win.c index 91d4ce298..84465516c 100644 --- a/libs/audio/targets/snd_win.c +++ b/libs/audio/targets/snd_win.c @@ -344,13 +344,8 @@ SNDDMA_Submit (void) } } -/* - SNDDMA_Shutdown - - Reset the sound device for exiting -*/ static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { FreeSound (); } @@ -379,7 +374,7 @@ PLUGIN_INFO(snd_output, win) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/test/Makefile.am b/libs/audio/test/Makefile.am index 410be4f4e..ff6d259a4 100644 --- a/libs/audio/test/Makefile.am +++ b/libs/audio/test/Makefile.am @@ -7,9 +7,9 @@ noinst_PROGRAMS= @AUDIO_TARGETS@ EXTRA_PROGRAMS= testsound test_libs= \ - $(top_builddir)/libs/audio/libQFsound.la \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(top_builddir)/libs/util/libQFutil.la + libs/audio/libQFsound.la \ + libs/ruamoko/libQFruamoko.la \ + libs/util/libQFutil.la testsound_SOURCES= testsound.c testsound_LDADD= $(test_libs) diff --git a/libs/audio/test/testsound.c b/libs/audio/test/testsound.c index f4518d7ac..698fc40ec 100644 --- a/libs/audio/test/testsound.c +++ b/libs/audio/test/testsound.c @@ -68,7 +68,7 @@ init (void) COM_ParseConfig (); Cvar_Get ("cmd_warncmd", "1", CVAR_NONE, NULL, NULL); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); QFS_Init ("qw"); PI_Init (); diff --git a/libs/client/Makefile.am b/libs/client/Makefile.am deleted file mode 100644 index d9fc98a77..000000000 --- a/libs/client/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= libQFclient.la - -libQFclient_la_LDFLAGS= @STATIC@ -libQFclient_la_LIBADD= $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la -libQFclient_la_SOURCES= \ - cl_entities.c diff --git a/libs/client/Makemodule.am b/libs/client/Makemodule.am new file mode 100644 index 000000000..074daea58 --- /dev/null +++ b/libs/client/Makemodule.am @@ -0,0 +1,10 @@ +noinst_LTLIBRARIES += libs/client/libQFclient.la + +libs_client_libQFclient_la_LDFLAGS= @STATIC@ +libs_client_libQFclient_la_LIBADD= libs/gamecode/libQFgamecode.la libs/util/libQFutil.la +libs_client_libQFclient_la_SOURCES= \ + libs/client/cl_effects.c \ + libs/client/cl_entities.c \ + libs/client/cl_temp_entities.c \ + libs/client/locs.c \ + $e diff --git a/libs/client/cl_effects.c b/libs/client/cl_effects.c new file mode 100644 index 000000000..707699141 --- /dev/null +++ b/libs/client/cl_effects.c @@ -0,0 +1,181 @@ +/* + cl_effect.c + + Client side effect management + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/11 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/entity.h" +#include "QF/render.h" + +#include "QF/plugin/vid_render.h" //FIXME + +#include "client/entities.h" +#include "client/effects.h" + +void +CL_NewDlight (int key, vec4f_t org, int effects, byte glow_size, + byte glow_color, double time) +{ + float radius; + dlight_t *dl; + static quat_t normal = {0.4, 0.2, 0.05, 0.7}; + static quat_t red = {0.5, 0.05, 0.05, 0.7}; + static quat_t blue = {0.05, 0.05, 0.5, 0.7}; + static quat_t purple = {0.5, 0.05, 0.5, 0.7}; + + effects &= EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT; + if (!effects) { + if (!glow_size) + return; + } + + dl = r_funcs->R_AllocDlight (key); + if (!dl) + return; + VectorCopy (org, dl->origin); + + if (effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT)) { + radius = 200 + (rand () & 31); + if (effects & EF_BRIGHTLIGHT) { + radius += 200; + dl->origin[2] += 16; + } + if (effects & EF_DIMLIGHT) + if (effects & ~EF_DIMLIGHT) + radius -= 100; + dl->radius = radius; + dl->die = time + 0.1; + + switch (effects & (EF_RED | EF_BLUE)) { + case EF_RED | EF_BLUE: + QuatCopy (purple, dl->color); + break; + case EF_RED: + QuatCopy (red, dl->color); + break; + case EF_BLUE: + QuatCopy (blue, dl->color); + break; + default: + QuatCopy (normal, dl->color); + break; + } + } + + if (glow_size) { + dl->radius += glow_size < 128 ? glow_size * 8.0 : + (glow_size - 256) * 8.0; + dl->die = time + 0.1; + if (glow_color) { + if (glow_color == 255) { + dl->color[0] = dl->color[1] = dl->color[2] = 1.0; + } else { + byte *tempcolor; + + tempcolor = (byte *) &d_8to24table[glow_color]; + VectorScale (tempcolor, 1 / 255.0, dl->color); + } + } + } +} + +void +CL_ModelEffects (entity_t *ent, int num, int glow_color, double time) +{ + dlight_t *dl; + model_t *model = ent->renderer.model; + + // add automatic particle trails + if (model->flags & EF_ROCKET) { + dl = r_funcs->R_AllocDlight (num); + if (dl) { + VectorCopy (Transform_GetWorldPosition (ent->transform), + dl->origin); + dl->radius = 200.0; + dl->die = time + 0.1; + //FIXME VectorCopy (r_firecolor->vec, dl->color); + VectorSet (0.9, 0.7, 0.0, dl->color); + dl->color[3] = 0.7; + } + r_funcs->particles->R_RocketTrail (ent); + } else if (model->flags & EF_GRENADE) + r_funcs->particles->R_GrenadeTrail (ent); + else if (model->flags & EF_GIB) + r_funcs->particles->R_BloodTrail (ent); + else if (model->flags & EF_ZOMGIB) + r_funcs->particles->R_SlightBloodTrail (ent); + else if (model->flags & EF_TRACER) + r_funcs->particles->R_WizTrail (ent); + else if (model->flags & EF_TRACER2) + r_funcs->particles->R_FlameTrail (ent); + else if (model->flags & EF_TRACER3) + r_funcs->particles->R_VoorTrail (ent); + else if (model->flags & EF_GLOWTRAIL) + if (r_funcs->particles->R_GlowTrail) + r_funcs->particles->R_GlowTrail (ent, glow_color); +} + +void +CL_MuzzleFlash (vec4f_t position, vec4f_t fv, float zoffset, int num, + double time) +{ + dlight_t *dl = r_funcs->R_AllocDlight (num); + if (dl) { + position += 18 * fv; + VectorCopy (position, dl->origin); + dl->origin[2] += zoffset; + dl->radius = 200 + (rand () & 31); + dl->die = time + 0.1; + dl->minlight = 32; + dl->color[0] = 0.2; + dl->color[1] = 0.1; + dl->color[2] = 0.05; + dl->color[3] = 0.7; + } +} + +void +CL_EntityEffects (int num, entity_t *ent, entity_state_t *state, double time) +{ + if (state->effects & EF_BRIGHTFIELD) + r_funcs->particles->R_EntityParticles (ent); + if (state->effects & EF_MUZZLEFLASH) { + vec4f_t position = Transform_GetWorldPosition (ent->transform); + vec4f_t fv = Transform_Forward (ent->transform); + CL_MuzzleFlash (position, fv, 16, num, time); + } +} diff --git a/libs/client/cl_entities.c b/libs/client/cl_entities.c index 01397321a..599576863 100644 --- a/libs/client/cl_entities.c +++ b/libs/client/cl_entities.c @@ -31,6 +31,10 @@ # include "config.h" #endif +#include "QF/entity.h" +#include "QF/render.h" //FIXME for entity_t +#include "QF/simd/vec4f.h" + #include "client/entities.h" /* QW has a max of 512 entities and wants 64 frames of data per entity, plus @@ -340,3 +344,26 @@ vec3_t ent_colormod[256] = { {1, 1, 0.666667}, {1, 1, 1} }; + +void +CL_TransformEntity (entity_t *ent, float scale, const vec3_t angles, + vec4f_t position) +{ + vec4f_t rotation; + vec4f_t scalevec = { scale, scale, scale, 1}; + + if (VectorIsZero (angles)) { + rotation = (vec4f_t) { 0, 0, 0, 1 }; + } else { + vec3_t ang; + VectorCopy (angles, ang); + if (ent->renderer.model && ent->renderer.model->type == mod_alias) { + // stupid quake bug + // why, oh, why, do alias models pitch in the opposite direction + // to everything else? + ang[PITCH] = -ang[PITCH]; + } + AngleQuat (ang, &rotation[0]);//FIXME + } + Transform_SetLocalTransform (ent->transform, scalevec, rotation, position); +} diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c new file mode 100644 index 000000000..fdffbf985 --- /dev/null +++ b/libs/client/cl_temp_entities.c @@ -0,0 +1,726 @@ +/* + cl_temp_entities.c + + Client side temporary entity management + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/10 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/entity.h" +#include "QF/msg.h" +#include "QF/progs.h" // for PR_RESMAP +#include "QF/quakefs.h" +#include "QF/render.h" +#include "QF/sound.h" + +#include "QF/plugin/vid_render.h" //FIXME + +#include "client/entities.h" +#include "client/temp_entities.h" + +typedef struct tent_s { + struct tent_s *next; + entity_t ent; +} tent_t; + +typedef struct { + int entity; + struct model_s *model; + float endtime; + vec4f_t start, end; + vec4f_t rotation; + tent_t *tents; + int seed; +} beam_t; + +#define BEAM_SEED_INTERVAL 72 +#define BEAM_SEED_PRIME 3191 + +typedef struct { + float start; + tent_t *tent; +} explosion_t; + +typedef struct tent_obj_s { + struct tent_obj_s *next; + union { + beam_t beam; + explosion_t ex; + } to; +} tent_obj_t; + +static PR_RESMAP (tent_t) temp_entities; +static PR_RESMAP (tent_obj_t) tent_objects; +static tent_obj_t *cl_beams; +static tent_obj_t *cl_explosions; + +static tent_t *cl_projectiles; + +static sfx_t *cl_sfx_wizhit; +static sfx_t *cl_sfx_knighthit; +static sfx_t *cl_sfx_tink1; +static sfx_t *cl_sfx_r_exp3; +static sfx_t *cl_sfx_ric[4]; + +static model_t *cl_mod_beam; +static model_t *cl_mod_bolt; +static model_t *cl_mod_bolt2; +static model_t *cl_mod_bolt3; +static model_t *cl_spr_explod; +static model_t *cl_spike; + +static vec4f_t beam_rolls[360]; + +static void +CL_TEnts_Precache (int phase) +{ + if (!phase) { + return; + } + cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); + cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); + cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); + cl_sfx_ric[3] = S_PrecacheSound ("weapons/ric1.wav"); + cl_sfx_ric[2] = S_PrecacheSound ("weapons/ric2.wav"); + cl_sfx_ric[1] = S_PrecacheSound ("weapons/ric3.wav"); + cl_sfx_ric[0] = cl_sfx_ric[1]; + cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); + + cl_mod_bolt = Mod_ForName ("progs/bolt.mdl", true); + cl_mod_bolt2 = Mod_ForName ("progs/bolt2.mdl", true); + cl_mod_bolt3 = Mod_ForName ("progs/bolt3.mdl", true); + cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); + cl_mod_beam = Mod_ForName ("progs/beam.mdl", false); + cl_spike = Mod_ForName ("progs/spike.mdl", false); + + if (!cl_mod_beam) { + cl_mod_beam = cl_mod_bolt; + } +} + +void +CL_TEnts_Init (void) +{ + QFS_GamedirCallback (CL_TEnts_Precache); + CL_TEnts_Precache (1); + for (int i = 0; i < 360; i++) { + float ang = i * M_PI / 360; + beam_rolls[i] = (vec4f_t) { sin (ang), 0, 0, cos (ang) }; + } +} + +void +CL_Init_Entity (entity_t *ent) +{ + if (ent->transform) { + Transform_Delete (ent->transform); + } + memset (ent, 0, sizeof (*ent)); + + ent->transform = Transform_New (0); + ent->renderer.skin = 0; + QuatSet (1.0, 1.0, 1.0, 1.0, ent->renderer.colormod); + ent->animation.pose1 = ent->animation.pose2 = -1; +} + +static tent_t * +new_temp_entity (void) +{ + tent_t *tent = PR_RESNEW_NC (temp_entities); + tent->ent.transform = 0; + tent->next = 0; + CL_Init_Entity (&tent->ent); + return tent; +} + +static void +free_temp_entities (tent_t *tents) +{ + tent_t **t = &tents; + + while (*t) { + Transform_Delete ((*t)->ent.transform);//FIXME reuse? + t = &(*t)->next; + } + *t = temp_entities._free; + temp_entities._free = tents; +} + +static tent_obj_t * +new_tent_object (void) +{ + tent_obj_t *tobj = PR_RESNEW_NC (tent_objects); + tobj->next = 0; + return tobj; +} + +static void +free_tent_object (tent_obj_t *tobj) +{ + tobj->next = tent_objects._free; + tent_objects._free = tobj; +} + +void +CL_ClearTEnts (void) +{ + PR_RESRESET (temp_entities); + PR_RESRESET (tent_objects); + cl_beams = 0; + cl_explosions = 0; +} + +static inline void +beam_clear (beam_t *b) +{ + if (b->tents) { + tent_t *t; + + for (t = b->tents; t; t = t->next) { + r_funcs->R_RemoveEfrags (&t->ent); + t->ent.visibility.efrag = 0; + } + free_temp_entities (b->tents); + b->tents = 0; + } +} + +static inline void +beam_setup (beam_t *b, qboolean transform, double time, TEntContext_t *ctx) +{ + tent_t *tent; + float d; + int ent_count; + vec4f_t dist, org; + vec4f_t rotation; + vec4f_t scale = { 1, 1, 1, 1 }; + unsigned seed; + + // calculate pitch and yaw + dist = b->end - b->start; + + // FIXME interpolation may be off when passing through the -x axis + if (dist[0] < 0 && dist[1] == 0 && dist[2] == 0) { + // anti-parallel with the +x axis, so assome 180 degree rotation around + // the z-axis + rotation = (vec4f_t) { 0, 0, 1, 0 }; + } else { + rotation = qrotf ((vec4f_t) { 1, 0, 0, 0 }, dist); + } + b->rotation = rotation; + + // add new entities for the lightning + org = b->start; + d = magnitudef (dist)[0]; + dist = normalf (dist) * 30; + ent_count = ceil (d / 30); + d = 0; + + seed = b->seed + ((int) (time * BEAM_SEED_INTERVAL) % BEAM_SEED_INTERVAL); + + while (ent_count--) { + tent = new_temp_entity (); + tent->next = b->tents; + b->tents = tent; + + vec4f_t position = org + d * dist; + d += 1.0; + tent->ent.renderer.model = b->model; + if (transform) { + seed = seed * BEAM_SEED_PRIME; + Transform_SetLocalTransform (tent->ent.transform, scale, + qmulf (rotation, + beam_rolls[seed % 360]), + position); + } else { + Transform_SetLocalPosition (tent->ent.transform, position); + } + r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); + } +} + +static void +CL_ParseBeam (qmsg_t *net_message, model_t *m, double time, TEntContext_t *ctx) +{ + tent_obj_t *to; + beam_t *b; + int ent; + vec4f_t start, end; + + ent = MSG_ReadShort (net_message); + + MSG_ReadCoordV (net_message, &start[0]);//FIXME + MSG_ReadCoordV (net_message, &end[0]);//FIXME + start[3] = end[3] = 1;//FIXME + + to = 0; + if (ent) { + for (to = cl_beams; to; to = to->next) { + if (to->to.beam.entity == ent) { + break; + } + } + } + if (!to) { + to = new_tent_object (); + to->next = cl_beams; + cl_beams = to; + to->to.beam.tents = 0; + to->to.beam.entity = ent; + } + b = &to->to.beam; + + beam_clear (b); + b->model = m; + b->endtime = time + 0.2; + b->seed = rand (); + b->end = end; + if (b->entity != ctx->playerEntity) { + // this will be done in CL_UpdateBeams + b->start = start; + beam_setup (b, true, time, ctx); + } +} + +static void +parse_tent (qmsg_t *net_message, double time, TEntContext_t *ctx, + TE_Effect type) +{ + dlight_t *dl; + tent_obj_t *to; + explosion_t *ex; + int colorStart, colorLength; + quat_t color; + vec3_t position; + int count; + const char *name; + + switch (type) { + case TE_NoEffect: + // invalid mapping, can't do anything + break; + case TE_Beam: + CL_ParseBeam (net_message, cl_mod_beam, time, ctx); + break; + case TE_Blood: + count = MSG_ReadByte (net_message) * 20; + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_BloodPuffEffect (position, count); + break; + case TE_Explosion: + MSG_ReadCoordV (net_message, position); + + // particles + r_funcs->particles->R_ParticleExplosion (position); + + // light + dl = r_funcs->R_AllocDlight (0); + if (dl) { + VectorCopy (position, dl->origin); + dl->radius = 350; + dl->die = time + 0.5; + dl->decay = 300; + QuatSet (0.86, 0.31, 0.24, 0.7, dl->color); + //FIXME? nq: QuatSet (1.0, 0.5, 0.25, 0.7, dl->color); + } + + // sound + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); + + // sprite + to = new_tent_object (); + to->next = cl_explosions; + cl_explosions = to; + ex = &to->to.ex; + ex->tent = new_temp_entity (); + + ex->start = time; + //FIXME need better model management + if (!cl_spr_explod->cache.data) { + cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); + } + ex->tent->ent.renderer.model = cl_spr_explod; + Transform_SetLocalPosition (ex->tent->ent.transform,//FIXME + (vec4f_t) {VectorExpand (position), 1}); + break; + case TE_Explosion2: + MSG_ReadCoordV (net_message, position); + colorStart = MSG_ReadByte (net_message); + colorLength = MSG_ReadByte (net_message); + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); + r_funcs->particles->R_ParticleExplosion2 (position, colorStart, + colorLength); + dl = r_funcs->R_AllocDlight (0); + if (!dl) + break; + VectorCopy (position, dl->origin); + dl->radius = 350; + dl->die = time + 0.5; + dl->decay = 300; + colorStart = (colorStart + (rand () % colorLength)) * 3; + VectorScale (&r_data->vid->palette[colorStart], 1.0 / 255.0, + dl->color); + dl->color[3] = 0.7; + break; + case TE_Explosion3: + MSG_ReadCoordV (net_message, position); + MSG_ReadCoordV (net_message, color); // OUCH! + color[3] = 0.7; + r_funcs->particles->R_ParticleExplosion (position); + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); + dl = r_funcs->R_AllocDlight (0); + if (dl) { + VectorCopy (position, dl->origin); + dl->radius = 350; + dl->die = time + 0.5; + dl->decay = 300; + QuatCopy (color, dl->color); + } + break; + case TE_Gunshot1: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_GunshotEffect (position, 20); + break; + case TE_Gunshot2: + count = MSG_ReadByte (net_message) * 20; + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_GunshotEffect (position, count); + break; + case TE_KnightSpike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_KnightSpikeEffect (position); + S_StartSound (-1, 0, cl_sfx_knighthit, position, 1, 1); + break; + case TE_LavaSplash: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_LavaSplash (position); + break; + case TE_Lightning1: + CL_ParseBeam (net_message, cl_mod_bolt, time, ctx); + break; + case TE_Lightning2: + CL_ParseBeam (net_message, cl_mod_bolt2, time, ctx); + break; + case TE_Lightning3: + CL_ParseBeam (net_message, cl_mod_bolt3, time, ctx); + break; + case TE_Lightning4: + name = MSG_ReadString (net_message); + CL_ParseBeam (net_message, Mod_ForName (name, true), time, ctx); + break; + case TE_LightningBlood: + MSG_ReadCoordV (net_message, position); + + // light + dl = r_funcs->R_AllocDlight (0); + if (dl) { + VectorCopy (position, dl->origin); + dl->radius = 150; + dl->die = time + 0.1; + dl->decay = 200; + QuatSet (0.25, 0.40, 0.65, 1, dl->color); + } + + r_funcs->particles->R_LightningBloodEffect (position); + break; + case TE_Spike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_SpikeEffect (position); + { + int i; + sfx_t *sound; + + i = (rand () % 20) - 16; + if (i >= 0) { + sound = cl_sfx_ric[i]; + } else { + sound = cl_sfx_tink1; + } + S_StartSound (-1, 0, sound, position, 1, 1); + } + break; + case TE_SuperSpike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_SuperSpikeEffect (position); + { + int i; + sfx_t *sound; + + i = (rand () % 20) - 16; + if (i >= 0) { + sound = cl_sfx_ric[i]; + } else { + sound = cl_sfx_tink1; + } + S_StartSound (-1, 0, sound, position, 1, 1); + } + break; + case TE_TarExplosion: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_BlobExplosion (position); + + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); + break; + case TE_Teleport: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_TeleportSplash (position); + break; + case TE_WizSpike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_WizSpikeEffect (position); + S_StartSound (-1, 0, cl_sfx_wizhit, position, 1, 1); + break; + } +} + +// the effect type is a byte so a max of 256 values +static const TE_Effect nqEffects[256] = { + [TE_nqSpike] = TE_Spike, + [TE_nqSuperSpike] = TE_SuperSpike, + [TE_nqGunshot] = TE_Gunshot1, + [TE_nqExplosion] = TE_Explosion, + [TE_nqTarExplosion] = TE_TarExplosion, + [TE_nqLightning1] = TE_Lightning1, + [TE_nqLightning2] = TE_Lightning2, + [TE_nqWizSpike] = TE_WizSpike, + [TE_nqKnightSpike] = TE_KnightSpike, + [TE_nqLightning3] = TE_Lightning3, + [TE_nqLavaSplash] = TE_LavaSplash, + [TE_nqTeleport] = TE_Teleport, + [TE_nqExplosion2] = TE_Explosion2, + [TE_nqBeam] = TE_Beam, + [TE_nqExplosion3] = TE_Explosion3, + [TE_nqLightning4] = TE_Lightning4, +}; + +void +CL_ParseTEnt_nq (qmsg_t *net_message, double time, TEntContext_t *ctx) +{ + byte type = MSG_ReadByte (net_message); + parse_tent (net_message, time, ctx, nqEffects[type]); +} + +// the effect type is a byte so a max of 256 values +static const TE_Effect qwEffects[256] = { + [TE_qwSpike] = TE_Spike, + [TE_qwSuperSpike] = TE_SuperSpike, + [TE_qwGunshot] = TE_Gunshot2, + [TE_qwExplosion] = TE_Explosion, + [TE_qwTarExplosion] = TE_TarExplosion, + [TE_qwLightning1] = TE_Lightning1, + [TE_qwLightning2] = TE_Lightning2, + [TE_qwWizSpike] = TE_WizSpike, + [TE_qwKnightSpike] = TE_KnightSpike, + [TE_qwLightning3] = TE_Lightning3, + [TE_qwLavaSplash] = TE_LavaSplash, + [TE_qwTeleport] = TE_Teleport, + [TE_qwBlood] = TE_Blood, + [TE_qwLightningBlood] = TE_LightningBlood, + [TE_qwExplosion2] = TE_Explosion2, + [TE_qwBeam] = TE_Beam, +}; + +void +CL_ParseTEnt_qw (qmsg_t *net_message, double time, TEntContext_t *ctx) +{ + byte type = MSG_ReadByte (net_message); + parse_tent (net_message, time, ctx, qwEffects[type]); +} + +static void +CL_UpdateBeams (double time, TEntContext_t *ctx) +{ + tent_obj_t **to; + beam_t *b; + unsigned seed; + tent_t *t; + + // update lightning + for (to = &cl_beams; *to; ) { + b = &(*to)->to.beam; + if (!b->endtime) + continue; + if (!b->model || b->endtime < time) { + tent_obj_t *_to; + b->endtime = 0; + beam_clear (b); + _to = *to; + *to = _to->next; + free_tent_object (_to); + continue; + } + to = &(*to)->next; + + // if coming from the player, update the start position + if (b->entity == ctx->playerEntity) { + beam_clear (b); + b->start = ctx->simorg; + beam_setup (b, false, time, ctx); + } + + seed = b->seed + ((int) (time * BEAM_SEED_INTERVAL) % + BEAM_SEED_INTERVAL); + + // add new entities for the lightning + for (t = b->tents; t; t = t->next) { + seed = seed * BEAM_SEED_PRIME; + Transform_SetLocalRotation (t->ent.transform, + qmulf (b->rotation, + beam_rolls[seed % 360])); + } + } +} + +static void +CL_UpdateExplosions (double time, TEntContext_t *ctx) +{ + int f; + tent_obj_t **to; + explosion_t *ex; + entity_t *ent; + + for (to = &cl_explosions; *to; ) { + ex = &(*to)->to.ex; + ent = &ex->tent->ent; + f = 10 * (time - ex->start); + if (f >= ent->renderer.model->numframes) { + tent_obj_t *_to; + r_funcs->R_RemoveEfrags (ent); + ent->visibility.efrag = 0; + free_temp_entities (ex->tent); + _to = *to; + *to = _to->next; + free_tent_object (_to); + continue; + } + to = &(*to)->next; + + ent->animation.frame = f; + if (!ent->visibility.efrag) { + r_funcs->R_AddEfrags (&ctx->worldModel->brush, ent); + } + } +} + +void +CL_UpdateTEnts (double time, TEntContext_t *ctx) +{ + CL_UpdateBeams (time, ctx); + CL_UpdateExplosions (time, ctx); +} + +/* + CL_ParseParticleEffect + + Parse an effect out of the server message +*/ +void +CL_ParseParticleEffect (qmsg_t *net_message) +{ + int i, count, color; + vec3_t org, dir; + + MSG_ReadCoordV (net_message, org); + for (i = 0; i < 3; i++) + dir[i] = ((signed char) MSG_ReadByte (net_message)) * (15.0 / 16.0); + count = MSG_ReadByte (net_message); + color = MSG_ReadByte (net_message); + + if (count == 255) + r_funcs->particles->R_ParticleExplosion (org); + else + r_funcs->particles->R_RunParticleEffect (org, dir, color, count); +} + +void +CL_ClearProjectiles (void) +{ + tent_t *tent; + + for (tent = cl_projectiles; tent; tent = tent->next) { + r_funcs->R_RemoveEfrags (&tent->ent); + tent->ent.visibility.efrag = 0; + } + free_temp_entities (cl_projectiles); + cl_projectiles = 0; +} + +/* + Nails are passed as efficient temporary entities +*/ +void +CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx) +{ + tent_t *tent; + tent_t *head = 0, **tail = &head; + byte bits[6]; + int i, c, j, num; + entity_t *pr; + vec4f_t position = { 0, 0, 0, 1 }; + vec3_t angles; + + c = MSG_ReadByte (net_message); + + for (i = 0; i < c; i++) { + if (nail2) + num = MSG_ReadByte (net_message); + else + num = 0; + (void) num; //FIXME + + for (j = 0; j < 6; j++) + bits[j] = MSG_ReadByte (net_message); + + tent = new_temp_entity (); + *tail = tent; + tail = &tent->next; + + pr = &tent->ent; + pr->renderer.model = cl_spike; + pr->renderer.skin = 0; + position[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; + position[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; + position[2] = ((bits[3] + ((bits[4] & 15) << 8)) << 1) - 4096; + angles[0] = (bits[4] >> 4) * (360.0 / 16.0); + angles[1] = bits[5] * (360.0 / 256.0); + angles[2] = 0; + CL_TransformEntity (&tent->ent, 1, angles, position); + + r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); + } + + *tail = cl_projectiles; + cl_projectiles = head; +} diff --git a/qw/source/locs.c b/libs/client/locs.c similarity index 78% rename from qw/source/locs.c rename to libs/client/locs.c index 2f94da0f8..2ab477921 100644 --- a/qw/source/locs.c +++ b/libs/client/locs.c @@ -41,14 +41,21 @@ #include -#include "QF/locs.h" +#include "QF/mathlib.h" +#include "QF/render.h" #include "QF/qtypes.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/va.h" -#include "client.h" +#include "QF/simd/vec4f.h" + +#include "QF/plugin/vid_render.h" //FIXME + #include "compat.h" +#include "d_iface.h" //FIXME part_tex_smoke and part_tex_dot + +#include "client/locs.h" #define LOCATION_BLOCK 128 // 128 locations per block. @@ -58,7 +65,7 @@ int locations_count = 0; int location_blocks = 0; int -locs_nearest (const vec3_t loc) +locs_nearest (vec4f_t loc) { float best_distance = 9999999, distance; int i, j = -1; @@ -66,7 +73,8 @@ locs_nearest (const vec3_t loc) for (i = 0; i < locations_count; i++) { cur = locations[i]; - distance = VectorDistance_fast (loc, cur->loc); + vec4f_t d = loc - cur->loc; + distance = dotf (d, d)[0]; if ((distance < best_distance)) { best_distance = distance; j = i; @@ -76,7 +84,7 @@ locs_nearest (const vec3_t loc) } location_t * -locs_find (const vec3_t target) +locs_find (vec4f_t target) { int i; @@ -105,7 +113,7 @@ locs_more (void) } void -locs_add (const vec3_t location, const char *name) +locs_add (vec4f_t location, const char *name) { int num; @@ -132,10 +140,10 @@ locs_load (const char *filename) const char *tmp; char *t1, *t2; const char *line; - vec3_t loc; + vec4f_t loc = { 0, 0, 0, 1 }; QFile *file; - tmp = va ("maps/%s", filename); + tmp = va (0, "maps/%s", filename); file = QFS_FOpenFile (tmp); if (!file) { Sys_Printf ("Couldn't load %s\n", tmp); @@ -195,7 +203,7 @@ locs_save (const char *filename, qboolean gz) if (gz) { if (strcmp (QFS_FileExtension (filename), ".gz") != 0) - filename = va ("%s.gz", filename); + filename = va (0, "%s.gz", filename); locfd = QFS_Open (filename, "z9w+"); } else locfd = QFS_Open (filename, "w+"); @@ -211,7 +219,7 @@ locs_save (const char *filename, qboolean gz) } void -locs_mark (const vec3_t loc, const char *desc) +locs_mark (vec4f_t loc, const char *desc) { locs_add (loc, desc); Sys_Printf ("Marked current location: %s\n", desc); @@ -224,14 +232,14 @@ locs_mark (const vec3_t loc, const char *desc) call with NULL description to modify location vectors */ void -locs_edit (const vec3_t loc, const char *desc) +locs_edit (vec4f_t loc, const char *desc) { int i; if (locations_count) { i = locs_nearest (loc); if (!desc) { - VectorCopy (loc, locations[i]->loc); + locations[i]->loc = loc; Sys_Printf ("Moving location marker for %s\n", locations[i]->name); } else { @@ -245,7 +253,7 @@ locs_edit (const vec3_t loc, const char *desc) } void -locs_del (const vec3_t loc) +locs_del (vec4f_t loc) { int i; @@ -275,3 +283,37 @@ map_to_loc (const char *mapname, char *filename) t1++; strcpy (t1, "loc"); } + +void +locs_draw (vec4f_t simorg) +{ + //FIXME custom ent rendering code would be nice + dlight_t *dl; + location_t *nearloc; + vec4f_t trueloc; + int i; + + nearloc = locs_find (simorg); + if (nearloc) { + dl = r_funcs->R_AllocDlight (4096); + if (dl) { + VectorCopy (nearloc->loc, dl->origin); + dl->radius = 200; + dl->die = r_data->realtime + 0.1; + dl->color[0] = 0; + dl->color[1] = 1; + dl->color[2] = 0; + dl->color[3] = 0.7; + } + trueloc = nearloc->loc; + r_funcs->particles->R_Particle_New (pt_smokecloud, part_tex_smoke, + &trueloc[0], 2.0,//FIXME + vec3_origin, r_data->realtime + 9.0, 254, + 0.25 + qfrandom (0.125), 0.0); + for (i = 0; i < 15; i++) + r_funcs->particles->R_Particle_NewRandom (pt_fallfade, + part_tex_dot, &trueloc[0], 12,//FIXME + 0.7, 96, r_data->realtime + 5.0, + 104 + (rand () & 7), 1.0, 0.0); + } +} diff --git a/libs/console/Makefile.am b/libs/console/Makefile.am deleted file mode 100644 index d7cce92e7..000000000 --- a/libs/console/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(FNM_FLAGS) -plugin_ldflags= @plugin_ldflags@ -avoid-version -module -rpath $(plugindir) -plugin_libadd= @plugin_libadd@ -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined -EXEEXT= - -lib_LTLIBRARIES= libQFconsole.la -plugin_LTLIBRARIES= @console_plugins@ -noinst_LTLIBRARIES= @client_static_plugins@ @server_static_plugins@ -EXTRA_LTLIBRARIES= console_server.la console_client.la - -common_sources= \ - buffer.c complete.c console.c inputline.c list.c filelist.c view.c -client_sources= bi_inputline.c client.c menu.c -server_sources= server.c - -console_deps=$(top_builddir)/libs/util/libQFutil.la -client_deps= libQFconsole.la \ - $(top_builddir)/libs/audio/libQFsound.la \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(top_builddir)/libs/gib/libQFgib.la \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(console_deps) -server_deps= libQFconsole.la $(console_deps) - -libQFconsole_la_LDFLAGS= $(lib_ldflags) -libQFconsole_la_LIBADD= $(console_deps) $(plugin_libadd) -libQFconsole_la_DEPENDENCIES= $(console_deps) -libQFconsole_la_SOURCES= $(common_sources) - -console_client_la_LDFLAGS= $(plugin_ldflags) -console_client_la_LIBADD= $(client_deps) $(plugin_libadd) -console_client_la_DEPENDENCIES= $(client_deps) -console_client_la_SOURCES= $(client_sources) - -console_server_la_LDFLAGS= $(plugin_ldflags) -console_server_la_LIBADD= $(server_deps) $(CURSES_LIBS) $(plugin_libadd) -console_server_la_DEPENDENCIES= $(server_deps) -console_server_la_SOURCES= $(server_sources) diff --git a/libs/console/Makemodule.am b/libs/console/Makemodule.am new file mode 100644 index 000000000..bd745a2e2 --- /dev/null +++ b/libs/console/Makemodule.am @@ -0,0 +1,33 @@ +lib_LTLIBRARIES += libs/console/libQFconsole.la +plugin_LTLIBRARIES += @console_plugins@ +noinst_LTLIBRARIES += @client_static_plugins@ @server_static_plugins@ +EXTRA_LTLIBRARIES += libs/console/console_server.la libs/console/console_client.la + +console_common_sources= \ + libs/console/buffer.c libs/console/complete.c libs/console/console.c libs/console/inputline.c libs/console/list.c libs/console/filelist.c libs/console/view.c +client_sources= libs/console/bi_inputline.c libs/console/client.c libs/console/menu.c +server_sources= libs/console/server.c + +console_deps=libs/util/libQFutil.la +client_deps= libs/console/libQFconsole.la \ + libs/audio/libQFsound.la \ + libs/ruamoko/libQFruamoko.la \ + libs/gib/libQFgib.la \ + libs/ruamoko/libQFruamoko.la \ + $(console_deps) +server_deps= libs/console/libQFconsole.la $(console_deps) + +libs_console_libQFconsole_la_LDFLAGS= $(lib_ldflags) +libs_console_libQFconsole_la_LIBADD= $(console_deps) $(plugin_libadd) +libs_console_libQFconsole_la_DEPENDENCIES= $(console_deps) +libs_console_libQFconsole_la_SOURCES= $(console_common_sources) + +libs_console_console_client_la_LDFLAGS= $(plugin_ldflags) +libs_console_console_client_la_LIBADD= $(client_deps) $(plugin_libadd) +libs_console_console_client_la_DEPENDENCIES= $(client_deps) +libs_console_console_client_la_SOURCES= $(client_sources) + +libs_console_console_server_la_LDFLAGS= $(plugin_ldflags) +libs_console_console_server_la_LIBADD= $(server_deps) $(CURSES_LIBS) $(plugin_libadd) +libs_console_console_server_la_DEPENDENCIES= $(server_deps) +libs_console_console_server_la_SOURCES= $(server_sources) diff --git a/libs/console/bi_inputline.c b/libs/console/bi_inputline.c index e4a936d6f..b55cfa034 100644 --- a/libs/console/bi_inputline.c +++ b/libs/console/bi_inputline.c @@ -62,31 +62,31 @@ typedef struct { static il_data_t * il_data_new (il_resources_t *res) { - PR_RESNEW (il_data_t, res->line_map); + return PR_RESNEW (res->line_map); } static void il_data_free (il_resources_t *res, il_data_t *line) { - PR_RESFREE (il_data_t, res->line_map, line); + PR_RESFREE (res->line_map, line); } static void il_data_reset (il_resources_t *res) { - PR_RESRESET (il_data_t, res->line_map); + PR_RESRESET (res->line_map); } static inline il_data_t * il_data_get (il_resources_t *res, unsigned index) { - PR_RESGET (res->line_map, index); + return PR_RESGET (res->line_map, index); } -static inline int +static inline int __attribute__((pure)) il_data_index (il_resources_t *res, il_data_t *line) { - PR_RESINDEX (res->line_map, line); + return PR_RESINDEX (res->line_map, line); } static void @@ -130,9 +130,11 @@ bi_inputline_enter (inputline_t *il) P_POINTER (pr, 0) = data->data[0]; P_POINTER (pr, 1) = data->data[1]; P_STRING (pr, 2) = PR_SetTempString (pr, line); + pr->pr_argc = 3; } else { P_STRING (pr, 0) = PR_SetTempString (pr, line); P_POINTER (pr, 1) = data->data[0]; + pr->pr_argc = 2; } PR_ExecuteProgram (pr, data->enter); PR_PopFrame (pr); diff --git a/libs/console/buffer.c b/libs/console/buffer.c index d494c0655..2aa477abc 100644 --- a/libs/console/buffer.c +++ b/libs/console/buffer.c @@ -92,7 +92,7 @@ Con_BufferAddText (con_buffer_t *buf, const char *text) } while (len--) { byte c = *pos++ = *text++; - if ((size_t) (pos - buf->buffer) >= buf->buffer_size) + if (pos >= buf->buffer + buf->buffer_size) pos = buf->buffer; cur_line->len++; if (pos == tail_line->text) { diff --git a/libs/console/client.c b/libs/console/client.c index f31ccada9..3370a7614 100644 --- a/libs/console/client.c +++ b/libs/console/client.c @@ -251,7 +251,7 @@ Condump_f (void) Sys_Printf ("invalid character in filename\n"); return; } - name = va ("%s/%s.txt", qfs_gamedir->dir.def, Cmd_Argv (1)); + name = va (0, "%s/%s.txt", qfs_gamedir->dir.def, Cmd_Argv (1));//FIXME if (!(file = QFS_WOpen (name, 0))) { Sys_Printf ("could not open %s for writing: %s\n", name, @@ -360,7 +360,7 @@ Linefeed (void) All console printing must go through this in order to be logged to disk If no console is visible, the notify window will pop up. */ -static void +static __attribute__((format(printf, 1, 0))) void C_Print (const char *fmt, va_list args) { char *s; @@ -375,7 +375,7 @@ C_Print (const char *fmt, va_list args) // log all messages to file if (con_debuglog) - Sys_DebugLog (va ("%s/%s/qconsole.log", qfs_userpath, + Sys_DebugLog (va (0, "%s/%s/qconsole.log", qfs_userpath,//FIXME qfs_gamedir->dir.def), "%s", buffer->str); if (!con_initialized) @@ -931,13 +931,13 @@ C_Init (void) } static void -C_Shutdown (void) +C_shutdown (void) { } static general_funcs_t plugin_info_general_funcs = { C_Init, - C_Shutdown, + C_shutdown, }; static console_funcs_t plugin_info_console_funcs = { diff --git a/libs/console/complete.c b/libs/console/complete.c index 83dedc7a1..220906473 100644 --- a/libs/console/complete.c +++ b/libs/console/complete.c @@ -157,7 +157,7 @@ Con_BasicCompleteCommandLine (inputline_t *il) && strncmp (s + bound, cmd, strlen (s + bound))) bound++; - overwrite = va("%.*s%.*s", bound, s, cmd_len, cmd); + overwrite = va (0, "%.*s%.*s", bound, s, cmd_len, cmd); il->lines[il->edit_line][1] = '/'; strncpy (il->lines[il->edit_line] + 2, overwrite, il->line_size - 3); diff --git a/libs/console/console.c b/libs/console/console.c index fbfdbd608..cb966a941 100644 --- a/libs/console/console.c +++ b/libs/console/console.c @@ -84,9 +84,20 @@ Con_Interp_f (cvar_t *var) } } +static void +Con_shutdown (void *data) +{ + if (con_module) { + con_module->functions->general->p_Shutdown (); + PI_UnloadPlugin (con_module); + } +} + VISIBLE void Con_Init (const char *plugin_name) { + Sys_RegisterShutdown (Con_shutdown, 0); + con_module = PI_LoadPlugin ("console", plugin_name); if (con_module) { con_module->functions->general->p_Init (); @@ -123,15 +134,6 @@ Con_ExecLine (const char *line) Sys_Printf ("%s\n", line); } -VISIBLE void -Con_Shutdown (void) -{ - if (con_module) { - con_module->functions->general->p_Shutdown (); - PI_UnloadPlugin (con_module); - } -} - VISIBLE void Con_Printf (const char *fmt, ...) { diff --git a/libs/console/filelist.c b/libs/console/filelist.c index 73595de82..b2942c593 100644 --- a/libs/console/filelist.c +++ b/libs/console/filelist.c @@ -102,7 +102,7 @@ filelist_print (filelist_t *filelist) if (filelist->count) { qsort (filelist->list, filelist->count, sizeof (char *), filelist_cmp); - list = malloc ((filelist->count + 1) * sizeof (char **)); + list = malloc ((filelist->count + 1) * sizeof (char *)); list[filelist->count] = 0; for (i = 0; i < filelist->count; i++) list[i] = filelist->list[i]; @@ -167,7 +167,7 @@ Con_Skyboxlist_f (void) for (j = 1; sb_endings[j]; j++) { b = 0; for (k = 0; k < skyboxlist->count; k++) { - if (strcmp(va("%s%s", basename->str, sb_endings[j]), + if (strcmp(va (0, "%s%s", basename->str, sb_endings[j]), skyboxlist->list[k]) == 0) { b = 1; *skyboxlist->list[k] = 0; diff --git a/libs/console/menu.c b/libs/console/menu.c index 48df52b7d..d1a5e9c76 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -117,7 +117,7 @@ static int menu_resolve_globals (progs_t *pr) { const char *sym; - ddef_t *def; + pr_def_t *def; dfunction_t *f; size_t i; @@ -439,6 +439,7 @@ bi_Menu_Enter (progs_t *pr) P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state, item->text); P_INT (&menu_pr_state, 1) = 0; + pr->pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, item->func); PR_PopFrame (&menu_pr_state); run_menu_post (); @@ -510,9 +511,11 @@ menu_free_progs_mem (progs_t *pr, void *mem) } static void * -menu_load_file (progs_t *pr, const char *path) +menu_load_file (progs_t *pr, const char *path, off_t *size) { - return QFS_LoadFile (QFS_FOpenFile (path), 0); + void *data = QFS_LoadFile (QFS_FOpenFile (path), 0); + *size = qfs_filesize; + return data; } static builtin_t builtins[] = { @@ -578,7 +581,12 @@ Menu_Init (void) menu_pr_state.load_file = menu_load_file; menu_pr_state.resolve = menu_resolve_globals; - menu_hash = Hash_NewTable (61, menu_get_key, menu_free, 0); + menu_pr_state.max_edicts = 0; + menu_pr_state.zone_size = 1024 * 1024; + + PR_Init (&menu_pr_state); + + menu_hash = Hash_NewTable (61, menu_get_key, menu_free, 0, 0); PR_RegisterBuiltins (&menu_pr_state, builtins); @@ -617,10 +625,11 @@ Menu_Load (void) menu_pr_state.progs = 0; if ((file = QFS_FOpenFile (menu_pr_state.progs_name))) { size = Qfilesize (file); - PR_LoadProgsFile (&menu_pr_state, file, size, 0, 1024 * 1024); + PR_LoadProgsFile (&menu_pr_state, file, size); Qclose (file); - if (!PR_RunLoadFuncs (&menu_pr_state)) { + if (!PR_RunLoadFuncs (&menu_pr_state) + || !PR_RunPostLoadFuncs (&menu_pr_state)) { free (menu_pr_state.progs); menu_pr_state.progs = 0; } @@ -665,6 +674,7 @@ Menu_Draw (view_t *view) PR_RESET_PARAMS (&menu_pr_state); P_INT (&menu_pr_state, 0) = x; P_INT (&menu_pr_state, 1) = y; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, menu->draw); ret = R_INT (&menu_pr_state); run_menu_post (); @@ -699,6 +709,7 @@ Menu_Draw (view_t *view) PR_RESET_PARAMS (&menu_pr_state); P_INT (&menu_pr_state, 0) = x + item->x; P_INT (&menu_pr_state, 1) = y + item->y; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, menu->cursor); run_menu_post (); } else { @@ -731,6 +742,7 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) P_INT (&menu_pr_state, 0) = key; P_INT (&menu_pr_state, 1) = unicode; P_INT (&menu_pr_state, 2) = down; + menu_pr_state.pr_argc = 3; PR_ExecuteProgram (&menu_pr_state, menu->keyevent); ret = R_INT (&menu_pr_state); run_menu_post (); @@ -745,6 +757,7 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state, item->text); P_INT (&menu_pr_state, 1) = key; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, item->func); PR_PopFrame (&menu_pr_state); ret = R_INT (&menu_pr_state); diff --git a/libs/console/server.c b/libs/console/server.c index 5bf9061ec..3a0d3f035 100644 --- a/libs/console/server.c +++ b/libs/console/server.c @@ -99,7 +99,7 @@ static view_t *output; static view_t *status; static view_t *input; static int screen_x, screen_y; -static int interrupted; +static volatile sig_atomic_t interrupted; static int batch_print; #define MAXCMDLINE 256 @@ -342,13 +342,12 @@ static void sigwinch (int sig) { interrupted = 1; - signal (SIGWINCH, sigwinch); } #endif static void get_size (int *xlen, int *ylen) { -#if 0 +#ifdef SIGWINCH struct winsize size; *xlen = *ylen = 0; @@ -356,8 +355,9 @@ get_size (int *xlen, int *ylen) return; *xlen = size.ws_col; *ylen = size.ws_row; -#endif +#else getmaxyx (stdscr, *ylen, *xlen); +#endif } static void @@ -366,10 +366,11 @@ process_input (void) int ch; int escape = 0; - if (interrupted) { -#ifdef SIGWINCH + if (__builtin_expect (interrupted, 0)) { interrupted = 0; +#ifdef SIGWINCH get_size (&screen_x, &screen_y); + Sys_MaskPrintf (SYS_DEV, "resizing to %d x %d\n", screen_x, screen_y); resizeterm (screen_y, screen_x); con_linewidth = screen_x; view_resize (sv_con_data.view, screen_x, screen_y); @@ -570,7 +571,9 @@ static void init (void) { #ifdef SIGWINCH - signal (SIGWINCH, sigwinch); + struct sigaction action = {}; + action.sa_handler = sigwinch; + sigaction (SIGWINCH, &action, 0); #endif initscr (); @@ -696,7 +699,7 @@ C_Init (void) } static void -C_Shutdown (void) +C_shutdown (void) { if (log_file) { Qclose (log_file); @@ -708,7 +711,7 @@ C_Shutdown (void) #endif } -static void +static __attribute__((format(printf, 1, 0))) void C_Print (const char *fmt, va_list args) { static dstring_t *buffer; @@ -780,7 +783,7 @@ C_NewMap (void) static general_funcs_t plugin_info_general_funcs = { C_Init, - C_Shutdown, + C_shutdown, }; static general_data_t plugin_info_general_data; diff --git a/libs/entity/Makemodule.am b/libs/entity/Makemodule.am new file mode 100644 index 000000000..d8ac9a7e1 --- /dev/null +++ b/libs/entity/Makemodule.am @@ -0,0 +1,13 @@ +include libs/entity/test/Makemodule.am + +entity_deps=libs/util/libQFutil.la + +lib_LTLIBRARIES += libs/entity/libQFentity.la + +libs_entity_libQFentity_la_LDFLAGS= $(lib_ldflags) +libs_entity_libQFentity_la_LIBADD= $(entity_deps) +libs_entity_libQFentity_la_DEPENDENCIES= $(entity_deps) +libs_entity_libQFentity_la_SOURCES= \ + libs/entity/hierarchy.c \ + libs/entity/transform.c \ + $e diff --git a/libs/entity/hierarchy.c b/libs/entity/hierarchy.c new file mode 100644 index 000000000..cadb3771c --- /dev/null +++ b/libs/entity/hierarchy.c @@ -0,0 +1,444 @@ +/* + hierarchy.c + + General hierarchy handling + + Copyright (C) 2021 Bill Currke + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/entity.h" + +static void +hierarchy_UpdateTransformIndices (hierarchy_t *hierarchy, uint32_t start, + int offset) +{ + for (size_t i = start; i < hierarchy->transform.size; i++) { + if (hierarchy->transform.a[i]) { + hierarchy->transform.a[i]->index += offset; + } + } +} + +static void +hierarchy_UpdateChildIndices (hierarchy_t *hierarchy, uint32_t start, + int offset) +{ + for (size_t i = start; i < hierarchy->childIndex.size; i++) { + hierarchy->childIndex.a[i] += offset; + } +} + +static void +hierarchy_UpdateParentIndices (hierarchy_t *hierarchy, uint32_t start, + int offset) +{ + for (size_t i = start; i < hierarchy->parentIndex.size; i++) { + hierarchy->parentIndex.a[i] += offset; + } +} + +static void +hierarchy_calcLocalInverse (hierarchy_t *h, uint32_t index) +{ + // This takes advantage of the fact that localMatrix is a simple + // homogenous scale/rotate/translate matrix with no shear + vec4f_t x = h->localMatrix.a[index][0]; + vec4f_t y = h->localMatrix.a[index][1]; + vec4f_t z = h->localMatrix.a[index][2]; + vec4f_t t = h->localMatrix.a[index][3]; + + // "one" is to ensure both the scalar and translation have 1 in their + // forth components + vec4f_t one = { 0, 0, 0, 1 }; + vec4f_t nx = { x[0], y[0], z[0], 0 }; + vec4f_t ny = { x[1], y[1], z[1], 0 }; + vec4f_t nz = { x[2], y[2], z[2], 0 }; + vec4f_t nt = one - t[0] * nx - t[1] * ny - t[2] * nz; + // vertical dot product!!! + vec4f_t s = 1 / (nx * nx + ny * ny + nz * nz + one); + h->localInverse.a[index][0] = nx * s; + h->localInverse.a[index][1] = ny * s; + h->localInverse.a[index][2] = nz * s; + h->localInverse.a[index][3] = nt * s; +} + +void +Hierarchy_UpdateMatrices (hierarchy_t *h) +{ + for (size_t i = 0; i < h->localInverse.size; i++) { + if (h->modified.a[i]) { + hierarchy_calcLocalInverse (h, i); + } + } + if (h->modified.a[0]) { + memcpy (h->worldMatrix.a[0], + h->localMatrix.a[0], sizeof (mat4_t)); + memcpy (h->worldInverse.a[0], + h->localInverse.a[0], sizeof (mat4_t)); + h->worldRotation.a[0] = h->localRotation.a[0]; + h->worldScale.a[0] = h->localScale.a[0]; + } + for (size_t i = 1; i < h->worldMatrix.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + + if (h->modified.a[i] || h->modified.a[parent]) { + mmulf (h->worldMatrix.a[i], + h->worldMatrix.a[parent], h->localMatrix.a[i]); + h->modified.a[i] = 1; + } + } + for (size_t i = 1; i < h->worldInverse.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + + if (h->modified.a[i] || h->modified.a[parent]) { + mmulf (h->worldInverse.a[i], + h->localInverse.a[i], h->worldInverse.a[parent]); + } + } + for (size_t i = 1; i < h->worldRotation.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + if (h->modified.a[i] || h->modified.a[parent]) { + h->worldRotation.a[i] = qmulf (h->worldRotation.a[parent], + h->localRotation.a[i]); + } + } + for (size_t i = 1; i < h->worldScale.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + if (h->modified.a[i] || h->modified.a[parent]) { + h->worldScale.a[i] = m3vmulf (h->worldMatrix.a[parent], + h->localScale.a[i]); + } + } + memset (h->modified.a, 0, h->modified.size); +} + +static void +hierarchy_open (hierarchy_t *hierarchy, uint32_t index, uint32_t count) +{ + DARRAY_OPEN_AT (&hierarchy->transform, index, count); + DARRAY_OPEN_AT (&hierarchy->entity, index, count); + DARRAY_OPEN_AT (&hierarchy->childCount, index, count); + DARRAY_OPEN_AT (&hierarchy->childIndex, index, count); + DARRAY_OPEN_AT (&hierarchy->parentIndex, index, count); + DARRAY_OPEN_AT (&hierarchy->name, index, count); + DARRAY_OPEN_AT (&hierarchy->tag, index, count); + DARRAY_OPEN_AT (&hierarchy->modified, index, count); + DARRAY_OPEN_AT (&hierarchy->localMatrix, index, count); + DARRAY_OPEN_AT (&hierarchy->localInverse, index, count); + DARRAY_OPEN_AT (&hierarchy->worldMatrix, index, count); + DARRAY_OPEN_AT (&hierarchy->worldInverse, index, count); + DARRAY_OPEN_AT (&hierarchy->localRotation, index, count); + DARRAY_OPEN_AT (&hierarchy->localScale, index, count); + DARRAY_OPEN_AT (&hierarchy->worldRotation, index, count); + DARRAY_OPEN_AT (&hierarchy->worldScale, index, count); +} + +static void +hierarchy_close (hierarchy_t *hierarchy, uint32_t index, uint32_t count) +{ + if (count) { + DARRAY_CLOSE_AT (&hierarchy->transform, index, count); + DARRAY_CLOSE_AT (&hierarchy->entity, index, count); + DARRAY_CLOSE_AT (&hierarchy->childCount, index, count); + DARRAY_CLOSE_AT (&hierarchy->childIndex, index, count); + DARRAY_CLOSE_AT (&hierarchy->parentIndex, index, count); + DARRAY_CLOSE_AT (&hierarchy->name, index, count); + DARRAY_CLOSE_AT (&hierarchy->tag, index, count); + DARRAY_CLOSE_AT (&hierarchy->modified, index, count); + DARRAY_CLOSE_AT (&hierarchy->localMatrix, index, count); + DARRAY_CLOSE_AT (&hierarchy->localInverse, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldMatrix, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldInverse, index, count); + DARRAY_CLOSE_AT (&hierarchy->localRotation, index, count); + DARRAY_CLOSE_AT (&hierarchy->localScale, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldRotation, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldScale, index, count); + } +} + +static void +hierarchy_move (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstIndex, uint32_t srcIndex, uint32_t count) +{ + memcpy (&dst->transform.a[dstIndex], &src->transform.a[srcIndex], + count * sizeof(dst->transform.a[0])); + memset (&src->transform.a[srcIndex], 0, + count * sizeof(dst->transform.a[0])); + memcpy (&dst->entity.a[dstIndex], &src->entity.a[srcIndex], + count * sizeof(dst->entity.a[0])); + memcpy (&dst->name.a[dstIndex], &src->name.a[srcIndex], + count * sizeof(dst->name.a[0])); + memcpy (&dst->tag.a[dstIndex], &src->tag.a[srcIndex], + count * sizeof(dst->tag.a[0])); + memset (&dst->modified.a[dstIndex], 1, count * sizeof(dst->modified.a[0])); + memcpy (&dst->localMatrix.a[dstIndex], &src->localMatrix.a[srcIndex], + count * sizeof(dst->localMatrix.a[0])); + memcpy (&dst->localInverse.a[dstIndex], &src->localInverse.a[srcIndex], + count * sizeof(dst->localInverse.a[0])); + memcpy (&dst->localRotation.a[dstIndex], &src->localRotation.a[srcIndex], + count * sizeof(dst->localRotation.a[0])); + memcpy (&dst->localScale.a[dstIndex], &src->localScale.a[srcIndex], + count * sizeof(dst->localScale.a[0])); + + for (uint32_t i = 0; i < count; i++) { + dst->transform.a[dstIndex + i]->hierarchy = dst; + dst->transform.a[dstIndex + i]->index = dstIndex + i; + } +} + +static void +hierarchy_init (hierarchy_t *dst, uint32_t index, + uint32_t parentIndex, uint32_t childIndex, uint32_t count) +{ + memset (&dst->transform.a[index], 0, + count * sizeof(dst->transform.a[0])); + memset (&dst->entity.a[index], 0, count * sizeof(dst->entity.a[0])); + memset (&dst->name.a[index], 0, count * sizeof(dst->name.a[0])); + memset (&dst->tag.a[index], 0, count * sizeof(dst->tag.a[0])); + memset (&dst->modified.a[index], 1, count * sizeof(dst->modified.a[0])); + + for (uint32_t i = 0; i < count; i++) { + mat4fidentity (dst->localMatrix.a[index]); + mat4fidentity (dst->localInverse.a[index]); + dst->localRotation.a[index] = (vec4f_t) { 0, 0, 0, 1 }; + dst->localScale.a[index] = (vec4f_t) { 1, 1, 1, 1 }; + + dst->parentIndex.a[index + i] = parentIndex; + dst->childCount.a[index + i] = 0; + dst->childIndex.a[index + i] = childIndex; + } +} + +static uint32_t +hierarchy_insert (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot, uint32_t count) +{ + uint32_t insertIndex; // where the transforms will be inserted + uint32_t childIndex; // where the transforms' children will inserted + + // The newly added transforms are always last children of the parent + // transform + insertIndex = dst->childIndex.a[dstParent] + dst->childCount.a[dstParent]; + + // By design, all of a transform's children are in one contiguous block, + // and the blocks of children for each transform are ordered by their + // parents. Thus the child index of each transform increases monotonically + // for each child index in the array, regardless of the level of the owning + // transform (higher levels always come before lower levels). + uint32_t neighbor = insertIndex - 1; // insertIndex never zero + childIndex = dst->childIndex.a[neighbor] + dst->childCount.a[neighbor]; + + // Any transforms that come after the inserted transforms need to have + // thier indices adjusted. + hierarchy_UpdateTransformIndices (dst, insertIndex, count); + // The parent transform's child index is not affected, but the child + // indices of all transforms immediately after the parent transform are. + hierarchy_UpdateChildIndices (dst, dstParent + 1, count); + hierarchy_UpdateParentIndices (dst, childIndex, count); + + // The beginning of the block of children for the new transforms was + // computed from the pre-insert indices of the related transforms, thus + // the index must be updated by the number of transforms being inserted + // (it would have been updated thusly if the insert was done before + // updating the indices of the other transforms). + childIndex += count; + + hierarchy_open (dst, insertIndex, count); + if (src) { + hierarchy_move (dst, src, insertIndex, srcRoot, count); + } else { + hierarchy_init (dst, insertIndex, dstParent, childIndex, count); + } + for (uint32_t i = 0; i < count; i++) { + dst->parentIndex.a[insertIndex + i] = dstParent; + dst->childIndex.a[insertIndex + i] = childIndex; + dst->childCount.a[insertIndex + i] = 0; + } + + dst->childCount.a[dstParent] += count; + return insertIndex; +} + +static void +hierarchy_insert_children (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot) +{ + uint32_t insertIndex; + uint32_t childIndex = src->childIndex.a[srcRoot]; + uint32_t childCount = src->childCount.a[srcRoot]; + + if (childCount) { + insertIndex = hierarchy_insert (dst, src, dstParent, + childIndex, childCount); + for (uint32_t i = 0; i < childCount; i++) { + hierarchy_insert_children (dst, src, insertIndex + i, + childIndex + i); + } + } +} + +uint32_t +Hierarchy_InsertHierarchy (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot) +{ + uint32_t insertIndex; + + if (dstParent == null_transform) { + if (dst->transform.size) { + Sys_Error ("attempt to insert root in non-empty hierarchy"); + } + hierarchy_open (dst, 0, 1); + hierarchy_move (dst, src, 0, srcRoot, 1); + dst->parentIndex.a[0] = null_transform; + dst->childIndex.a[0] = 1; + dst->childCount.a[0] = 0; + insertIndex = 0; + } else { + if (!dst->transform.size) { + Sys_Error ("attempt to insert non-root in empty hierarchy"); + } + insertIndex = hierarchy_insert (dst, src, dstParent, srcRoot, 1); + } + // if src is null, then inserting a new transform which has no children + if (src) { + hierarchy_insert_children (dst, src, insertIndex, srcRoot); + } + Hierarchy_UpdateMatrices (dst); + return insertIndex; +} + +static void +hierarchy_remove_children (hierarchy_t *hierarchy, uint32_t index) +{ + uint32_t childIndex = hierarchy->childIndex.a[index]; + uint32_t childCount = hierarchy->childCount.a[index]; + uint32_t parentIndex = hierarchy->parentIndex.a[index]; + uint32_t nieceIndex = null_transform; + + if (parentIndex != null_transform) { + uint32_t siblingIndex = hierarchy->childIndex.a[parentIndex]; + siblingIndex += hierarchy->childCount.a[parentIndex] - 1; + nieceIndex = hierarchy->childIndex.a[siblingIndex]; + } + for (uint32_t i = childCount; i-- > 0; ) { + hierarchy_remove_children (hierarchy, childIndex + i); + } + hierarchy_close (hierarchy, childIndex, childCount); + hierarchy->childCount.a[index] = 0; + + if (childCount) { + hierarchy_UpdateTransformIndices (hierarchy, childIndex, -childCount); + hierarchy_UpdateChildIndices (hierarchy, index, -childCount); + if (nieceIndex != null_transform) { + hierarchy_UpdateParentIndices (hierarchy, nieceIndex, -childCount); + } + } +} + +void +Hierarchy_RemoveHierarchy (hierarchy_t *hierarchy, uint32_t index) +{ + uint32_t parentIndex = hierarchy->parentIndex.a[index]; + uint32_t childIndex = hierarchy->childIndex.a[index]; + uint32_t siblingIndex = null_transform; + if (parentIndex != null_transform) { + siblingIndex = hierarchy->childIndex.a[parentIndex]; + } + hierarchy_remove_children (hierarchy, index); + hierarchy_close (hierarchy, index, 1); + if (siblingIndex != null_transform) { + hierarchy_UpdateTransformIndices (hierarchy, index, -1); + hierarchy_UpdateChildIndices (hierarchy, siblingIndex, -1); + hierarchy_UpdateParentIndices (hierarchy, childIndex - 1, -1); + } +} + +hierarchy_t * +Hierarchy_New (size_t grow, int createRoot) +{ + if (!grow) { + grow = 16; + } + hierarchy_t *hierarchy = malloc (sizeof (hierarchy_t)); + + DARRAY_INIT (&hierarchy->transform, grow); + DARRAY_INIT (&hierarchy->entity, grow); + DARRAY_INIT (&hierarchy->childCount, grow); + DARRAY_INIT (&hierarchy->childIndex, grow); + DARRAY_INIT (&hierarchy->parentIndex, grow); + DARRAY_INIT (&hierarchy->name, grow); + DARRAY_INIT (&hierarchy->tag, grow); + DARRAY_INIT (&hierarchy->modified, grow); + DARRAY_INIT (&hierarchy->localMatrix, grow); + DARRAY_INIT (&hierarchy->localInverse, grow); + DARRAY_INIT (&hierarchy->worldMatrix, grow); + DARRAY_INIT (&hierarchy->worldInverse, grow); + DARRAY_INIT (&hierarchy->localRotation, grow); + DARRAY_INIT (&hierarchy->localScale, grow); + DARRAY_INIT (&hierarchy->worldRotation, grow); + DARRAY_INIT (&hierarchy->worldScale, grow); + + if (createRoot) { + hierarchy_open (hierarchy, 0, 1); + hierarchy_init (hierarchy, 0, null_transform, 1, 1); + } + + return hierarchy; +} + +void +Hierarchy_Delete (hierarchy_t *hierarchy) +{ + for (size_t i = 0; i < hierarchy->transform.size; i++) { + free (hierarchy->transform.a[i]); + } + for (size_t i = 0; i < hierarchy->name.size; i++) { + free (hierarchy->name.a[i]); + } + DARRAY_CLEAR (&hierarchy->transform); + DARRAY_CLEAR (&hierarchy->entity); + DARRAY_CLEAR (&hierarchy->childCount); + DARRAY_CLEAR (&hierarchy->childIndex); + DARRAY_CLEAR (&hierarchy->parentIndex); + DARRAY_CLEAR (&hierarchy->name); + DARRAY_CLEAR (&hierarchy->tag); + DARRAY_CLEAR (&hierarchy->modified); + DARRAY_CLEAR (&hierarchy->localMatrix); + DARRAY_CLEAR (&hierarchy->localInverse); + DARRAY_CLEAR (&hierarchy->worldMatrix); + DARRAY_CLEAR (&hierarchy->worldInverse); + DARRAY_CLEAR (&hierarchy->localRotation); + DARRAY_CLEAR (&hierarchy->localScale); + DARRAY_CLEAR (&hierarchy->worldRotation); + DARRAY_CLEAR (&hierarchy->worldScale); + free (hierarchy); +} diff --git a/libs/entity/test/Makemodule.am b/libs/entity/test/Makemodule.am new file mode 100644 index 000000000..b0f98ae2b --- /dev/null +++ b/libs/entity/test/Makemodule.am @@ -0,0 +1,19 @@ +libs_entity_tests = \ + libs/entity/test/test-hierarchy \ + $e + +TESTS += $(libs_entity_tests) + +check_PROGRAMS += $(libs_entity_tests) + +libs_entity_test_libs= \ + libs/entity/libQFentity.la \ + libs/util/libQFutil.la + +libs_entity_test_test_hierarchy_SOURCES= \ + libs/entity/test/test-hierarchy.c \ + $e +libs_entity_test_test_hierarchy_LDADD= \ + $(libs_entity_test_libs) +libs_entity_test_test_hierarchy_DEPENDENCIES= \ + $(libs_entity_test_libs) diff --git a/libs/entity/test/test-hierarchy.c b/libs/entity/test/test-hierarchy.c new file mode 100644 index 000000000..428dfcc5c --- /dev/null +++ b/libs/entity/test/test-hierarchy.c @@ -0,0 +1,709 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "QF/entity.h" + +// NOTE: these are the columns of the matrix! (not that it matters for a +// symmetrical matrix, but...) +mat4f_t identity = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 }, +}; +vec4f_t one = { 1, 1, 1, 1 }; + +static int +vec4_equal (vec4f_t a, vec4f_t b) +{ + vec4i_t res = a != b; + return !(res[0] || res[1] || res[2] || res[3]); +} + +static int +mat4_equal (const mat4f_t a, const mat4f_t b) +{ + vec4i_t res = {}; + + for (int i = 0; i < 4; i++) { + res |= a[i] != b[i]; + } + return !(res[0] || res[1] || res[2] || res[3]); +} + +static int +check_hierarchy_size (hierarchy_t *h, uint32_t size) +{ + if (h->transform.size != size + || h->entity.size != size + || h->childCount.size != size + || h->childIndex.size != size + || h->parentIndex.size != size + || h->name.size != size + || h->tag.size != size + || h->modified.size != size + || h->localMatrix.size != size + || h->localInverse.size != size + || h->worldMatrix.size != size + || h->worldInverse.size != size + || h->localRotation.size != size + || h->localScale.size != size + || h->worldRotation.size != size + || h->worldScale.size != size) { + printf ("hierarchy does not have exactly %u" + " transform or array sizes are inconsistent\n", size); + return 0; + } + for (size_t i = 0; i < h->transform.size; i++) { + if (h->transform.a[i]->hierarchy != h) { + printf ("transform %zd (%s) does not point to hierarchy\n", + i, h->name.a[i]); + } + } + return 1; +} + +static void +dump_hierarchy (hierarchy_t *h) +{ + for (size_t i = 0; i < h->transform.size; i++) { + printf ("%2zd: %5s %2u %2u %2u %2u\n", i, h->name.a[i], + h->transform.a[i]->index, h->parentIndex.a[i], + h->childIndex.a[i], h->childCount.a[i]); + } + puts (""); +} + +static int +check_indices (transform_t *transform, uint32_t index, uint32_t parentIndex, + uint32_t childIndex, uint32_t childCount) +{ + hierarchy_t *h = transform->hierarchy; + if (transform->index != index) { + printf ("%s/%s index incorrect: expect %u got %u\n", + h->name.a[transform->index], h->name.a[index], + index, transform->index); + return 0; + } + if (h->parentIndex.a[index] != parentIndex) { + printf ("%s parent index incorrect: expect %u got %u\n", + h->name.a[index], parentIndex, h->parentIndex.a[index]); + return 0; + } + if (h->childIndex.a[index] != childIndex) { + printf ("%s child index incorrect: expect %u got %u\n", + h->name.a[index], childIndex, h->childIndex.a[index]); + return 0; + } + if (h->childCount.a[index] != childCount) { + printf ("%s child count incorrect: expect %u got %u\n", + h->name.a[index], childCount, h->childCount.a[index]); + return 0; + } + return 1; +} + +static int +test_single_transform (void) +{ + transform_t *transform = Transform_New (0); + hierarchy_t *h; + + if (!transform) { + printf ("Transform_New returned null\n"); + return 1; + } + if (!(h = transform->hierarchy)) { + printf ("New transform has no hierarchy\n"); + return 1; + } + if (!check_hierarchy_size (h, 1)) { return 1; } + if (!check_indices (transform, 0, null_transform, 1, 0)) { return 1; } + + if (!mat4_equal (h->localMatrix.a[0], identity) + || !mat4_equal (h->localInverse.a[0], identity) + || !mat4_equal (h->worldMatrix.a[0], identity) + || !mat4_equal (h->worldInverse.a[0], identity)) { + printf ("New transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[0], identity[3]) + || !vec4_equal (h->localScale.a[0], one)) { + printf ("New transform rotation or scale not identity\n"); + return 1; + } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (transform->hierarchy); + + return 0; +} + +static int +test_parent_child_init (void) +{ + transform_t *parent = Transform_New (0); + transform_t *child = Transform_New (parent); + + if (parent->hierarchy != child->hierarchy) { + printf ("parent and child transforms have separate hierarchies\n"); + return 1; + } + + if (!check_hierarchy_size (parent->hierarchy, 2)) { return 1; } + + if (!check_indices (parent, 0, null_transform, 1, 1)) { return 1; } + if (!check_indices (child, 1, 0, 2, 0)) { return 1; } + + hierarchy_t *h = parent->hierarchy; + if (!mat4_equal (h->localMatrix.a[0], identity) + || !mat4_equal (h->localInverse.a[0], identity) + || !mat4_equal (h->worldMatrix.a[0], identity) + || !mat4_equal (h->worldInverse.a[0], identity)) { + printf ("Parent transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[0], identity[3]) + || !vec4_equal (h->localScale.a[0], one)) { + printf ("Parent transform rotation or scale not identity\n"); + return 1; + } + + if (!mat4_equal (h->localMatrix.a[1], identity) + || !mat4_equal (h->localInverse.a[1], identity) + || !mat4_equal (h->worldMatrix.a[1], identity) + || !mat4_equal (h->worldInverse.a[1], identity)) { + printf ("Child transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[1], identity[3]) + || !vec4_equal (h->localScale.a[1], one)) { + printf ("Child transform rotation or scale not identity\n"); + return 1; + } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (parent->hierarchy); + + return 0; +} + +static int +test_parent_child_setparent (void) +{ + transform_t *parent = Transform_New (0); + transform_t *child = Transform_New (0); + + Transform_SetName (parent, "parent"); + Transform_SetName (child, "child"); + + if (!check_indices (parent, 0, null_transform, 1, 0)) { return 1; } + if (!check_indices (child, 0, null_transform, 1, 0)) { return 1; } + + if (parent->hierarchy == child->hierarchy) { + printf ("parent and child transforms have same hierarchy before" + " set paret\n"); + return 1; + } + + Transform_SetParent (child, parent); + + if (parent->hierarchy != child->hierarchy) { + printf ("parent and child transforms have separate hierarchies\n"); + return 1; + } + + if (!check_hierarchy_size (parent->hierarchy, 2)) { return 1; } + + if (!check_indices (parent, 0, null_transform, 1, 1)) { return 1; } + if (!check_indices (child, 1, 0, 2, 0)) { return 1; } + + hierarchy_t *h = parent->hierarchy; + if (!mat4_equal (h->localMatrix.a[0], identity) + || !mat4_equal (h->localInverse.a[0], identity) + || !mat4_equal (h->worldMatrix.a[0], identity) + || !mat4_equal (h->worldInverse.a[0], identity)) { + printf ("Parent transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[0], identity[3]) + || !vec4_equal (h->localScale.a[0], one)) { + printf ("Parent transform rotation or scale not identity\n"); + return 1; + } + + if (!mat4_equal (h->localMatrix.a[1], identity) + || !mat4_equal (h->localInverse.a[1], identity) + || !mat4_equal (h->worldMatrix.a[1], identity) + || !mat4_equal (h->worldInverse.a[1], identity)) { + printf ("Child transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[1], identity[3]) + || !vec4_equal (h->localScale.a[1], one)) { + printf ("Child transform rotation or scale not identity\n"); + return 1; + } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (parent->hierarchy); + + return 0; +} + +static int +test_build_hierarchy (void) +{ + printf ("test_build_hierarchy\n"); + + transform_t *root = Transform_NewNamed (0, "root"); + transform_t *A = Transform_NewNamed (root, "A"); + transform_t *B = Transform_NewNamed (root, "B"); + transform_t *C = Transform_NewNamed (root, "C"); + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices (A, 1, 0, 4, 0)) { return 1; } + if (!check_indices (B, 2, 0, 4, 0)) { return 1; } + if (!check_indices (C, 3, 0, 4, 0)) { return 1; } + + transform_t *B1 = Transform_NewNamed (B, "B1"); + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( A, 1, 0, 4, 0)) { return 1; } + if (!check_indices ( B, 2, 0, 4, 1)) { return 1; } + if (!check_indices ( C, 3, 0, 5, 0)) { return 1; } + if (!check_indices (B1, 4, 2, 5, 0)) { return 1; } + + transform_t *A1 = Transform_NewNamed (A, "A1"); + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( A, 1, 0, 4, 1)) { return 1; } + if (!check_indices ( B, 2, 0, 5, 1)) { return 1; } + if (!check_indices ( C, 3, 0, 6, 0)) { return 1; } + if (!check_indices (A1, 4, 1, 6, 0)) { return 1; } + if (!check_indices (B1, 5, 2, 6, 0)) { return 1; } + transform_t *A1a = Transform_NewNamed (A1, "A1a"); + transform_t *B2 = Transform_NewNamed (B, "B2"); + transform_t *A2 = Transform_NewNamed (A, "A2"); + transform_t *B3 = Transform_NewNamed (B, "B3"); + transform_t *B2a = Transform_NewNamed (B2, "B2a"); + + if (!check_hierarchy_size (root->hierarchy, 11)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( A, 1, 0, 4, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 6, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 9, 0)) { return 1; } + if (!check_indices ( A1, 4, 1, 9, 1)) { return 1; } + if (!check_indices ( A2, 5, 1, 10, 0)) { return 1; } + if (!check_indices ( B1, 6, 2, 10, 0)) { return 1; } + if (!check_indices ( B2, 7, 2, 10, 1)) { return 1; } + if (!check_indices ( B3, 8, 2, 11, 0)) { return 1; } + if (!check_indices (A1a, 9, 4, 11, 0)) { return 1; } + if (!check_indices (B2a, 10, 7, 11, 0)) { return 1; } + + transform_t *D = Transform_NewNamed (root, "D"); + + if (!check_hierarchy_size (root->hierarchy, 12)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 10, 0)) { return 1; } + if (!check_indices ( D, 4, 0, 10, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 10, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 11, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 11, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 11, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 12, 0)) { return 1; } + if (!check_indices (A1a, 10, 5, 12, 0)) { return 1; } + if (!check_indices (B2a, 11, 8, 12, 0)) { return 1; } + + dump_hierarchy (root->hierarchy); + transform_t *C1 = Transform_NewNamed (C, "C1"); + dump_hierarchy (root->hierarchy); + if (!check_hierarchy_size (root->hierarchy, 13)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 10, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 11, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 11, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 12, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 12, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 12, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 13, 0)) { return 1; } + if (!check_indices ( C1, 10, 3, 13, 0)) { return 1; } + if (!check_indices (A1a, 11, 5, 13, 0)) { return 1; } + if (!check_indices (B2a, 12, 8, 13, 0)) { return 1; } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (root->hierarchy); + + return 0; +} + +static int +test_build_hierarchy2 (void) +{ + printf ("test_build_hierarchy2\n"); + + transform_t *root = Transform_NewNamed (0, "root"); + transform_t *A = Transform_NewNamed (root, "A"); + transform_t *B = Transform_NewNamed (root, "B"); + transform_t *C = Transform_NewNamed (root, "C"); + transform_t *B1 = Transform_NewNamed (B, "B1"); + transform_t *A1 = Transform_NewNamed (A, "A1"); + transform_t *A1a = Transform_NewNamed (A1, "A1a"); + transform_t *B2 = Transform_NewNamed (B, "B2"); + transform_t *A2 = Transform_NewNamed (A, "A2"); + transform_t *B3 = Transform_NewNamed (B, "B3"); + transform_t *B2a = Transform_NewNamed (B2, "B2a"); + transform_t *D = Transform_NewNamed (root, "D"); + transform_t *C1 = Transform_NewNamed (C, "C1"); + + if (!check_hierarchy_size (root->hierarchy, 13)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 10, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 11, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 11, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 12, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 12, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 12, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 13, 0)) { return 1; } + if (!check_indices ( C1, 10, 3, 13, 0)) { return 1; } + if (!check_indices (A1a, 11, 5, 13, 0)) { return 1; } + if (!check_indices (B2a, 12, 8, 13, 0)) { return 1; } + + transform_t *T = Transform_NewNamed (0, "T"); + transform_t *X = Transform_NewNamed (T, "X"); + transform_t *Y = Transform_NewNamed (T, "Y"); + transform_t *Z = Transform_NewNamed (T, "Z"); + transform_t *Y1 = Transform_NewNamed (Y, "Y1"); + transform_t *X1 = Transform_NewNamed (X, "X1"); + transform_t *X1a = Transform_NewNamed (X1, "X1a"); + transform_t *Y2 = Transform_NewNamed (Y, "Y2"); + transform_t *X2 = Transform_NewNamed (X, "X2"); + transform_t *Y3 = Transform_NewNamed (Y, "Y3"); + transform_t *Y2a = Transform_NewNamed (Y2, "Y2a"); + transform_t *Z1 = Transform_NewNamed (Z, "Z1"); + + dump_hierarchy (T->hierarchy); + if (!check_hierarchy_size (T->hierarchy, 12)) { return 1; } + + if (!check_indices ( T, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( X, 1, 0, 4, 2)) { return 1; } + if (!check_indices ( Y, 2, 0, 6, 3)) { return 1; } + if (!check_indices ( Z, 3, 0, 9, 1)) { return 1; } + if (!check_indices ( X1, 4, 1, 10, 1)) { return 1; } + if (!check_indices ( X2, 5, 1, 11, 0)) { return 1; } + if (!check_indices ( Y1, 6, 2, 11, 0)) { return 1; } + if (!check_indices ( Y2, 7, 2, 11, 1)) { return 1; } + if (!check_indices ( Y3, 8, 2, 12, 0)) { return 1; } + if (!check_indices ( Z1, 9, 3, 12, 0)) { return 1; } + if (!check_indices (X1a, 10, 4, 12, 0)) { return 1; } + if (!check_indices (Y2a, 11, 7, 12, 0)) { return 1; } + + Transform_SetParent (T, B); + + dump_hierarchy (root->hierarchy); + + if (!check_hierarchy_size (root->hierarchy, 25)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 4)) { return 1; } + if (!check_indices ( C, 3, 0, 11, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 12, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 12, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 13, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 13, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 13, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 14, 0)) { return 1; } + if (!check_indices ( T, 10, 2, 14, 3)) { return 1; } + if (!check_indices ( C1, 11, 3, 17, 0)) { return 1; } + if (!check_indices (A1a, 12, 5, 17, 0)) { return 1; } + if (!check_indices (B2a, 13, 8, 17, 0)) { return 1; } + if (!check_indices ( X, 14, 10, 17, 2)) { return 1; } + if (!check_indices ( Y, 15, 10, 19, 3)) { return 1; } + if (!check_indices ( Z, 16, 10, 22, 1)) { return 1; } + if (!check_indices ( X1, 17, 14, 23, 1)) { return 1; } + if (!check_indices ( X2, 18, 14, 24, 0)) { return 1; } + if (!check_indices ( Y1, 19, 15, 24, 0)) { return 1; } + if (!check_indices ( Y2, 20, 15, 24, 1)) { return 1; } + if (!check_indices ( Y3, 21, 15, 25, 0)) { return 1; } + if (!check_indices ( Z1, 22, 16, 25, 0)) { return 1; } + if (!check_indices (X1a, 23, 17, 25, 0)) { return 1; } + if (!check_indices (Y2a, 24, 20, 25, 0)) { return 1; } + + Transform_SetParent (Y, 0); + + dump_hierarchy (root->hierarchy); + dump_hierarchy (Y->hierarchy); + if (!check_hierarchy_size (root->hierarchy, 20)) { return 1; } + if (!check_hierarchy_size (Y->hierarchy, 5)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 4)) { return 1; } + if (!check_indices ( C, 3, 0, 11, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 12, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 12, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 13, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 13, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 13, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 14, 0)) { return 1; } + if (!check_indices ( T, 10, 2, 14, 3)) { return 1; } + if (!check_indices ( C1, 11, 3, 17, 0)) { return 1; } + if (!check_indices (A1a, 12, 5, 17, 0)) { return 1; } + if (!check_indices (B2a, 13, 8, 17, 0)) { return 1; } + if (!check_indices ( X, 14, 10, 16, 2)) { return 1; } + if (!check_indices ( Z, 15, 10, 18, 1)) { return 1; } + if (!check_indices ( X1, 16, 14, 19, 1)) { return 1; } + if (!check_indices ( X2, 17, 14, 20, 0)) { return 1; } + if (!check_indices ( Z1, 18, 15, 20, 0)) { return 1; } + if (!check_indices (X1a, 19, 16, 20, 0)) { return 1; } + + if (!check_indices ( Y, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( Y1, 1, 0, 4, 0)) { return 1; } + if (!check_indices ( Y2, 2, 0, 4, 1)) { return 1; } + if (!check_indices ( Y3, 3, 0, 5, 0)) { return 1; } + if (!check_indices (Y2a, 4, 2, 5, 0)) { return 1; } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (root->hierarchy); + Hierarchy_Delete (Y->hierarchy); + + return 0; +} + +static int +check_vector (const transform_t *transform, + vec4f_t (*func) (const transform_t *t), + vec4f_t expect, const char *msg) +{ + vec4f_t res = func(transform); + if (!vec4_equal (res, expect)) { + printf ("%s %s: expected "VEC4F_FMT" got "VEC4F_FMT"\n", + Transform_GetName (transform), msg, + VEC4_EXP (expect), VEC4_EXP (res)); + return 0; + } + return 1; +} + +static int +test_frames (void) +{ + transform_t *root = Transform_NewNamed (0, "root"); + transform_t *A = Transform_NewNamed (root, "A"); + transform_t *B = Transform_NewNamed (root, "B"); + transform_t *A1 = Transform_NewNamed (A, "A1"); + transform_t *B1 = Transform_NewNamed (B, "B1"); + + Transform_SetLocalPosition (root, (vec4f_t) { 0, 0, 1, 1 }); + Transform_SetLocalPosition (A, (vec4f_t) { 1, 0, 0, 1 }); + Transform_SetLocalRotation (A, (vec4f_t) { 0.5, 0.5, 0.5, 0.5 }); + Transform_SetLocalPosition (B, (vec4f_t) { 0, 1, 0, 1 }); + Transform_SetLocalRotation (B, (vec4f_t) { 0.5, -0.5, 0.5, 0.5 }); + Transform_SetLocalPosition (A1, (vec4f_t) { 1, 0, 0, 1 }); + Transform_SetLocalRotation (A1, (vec4f_t) { -0.5, -0.5, -0.5, 0.5 }); + Transform_SetLocalPosition (B1, (vec4f_t) { 0, 1, 0, 1 }); + Transform_SetLocalRotation (B1, (vec4f_t) { -0.5, 0.5, -0.5, 0.5 }); + + hierarchy_t *h = root->hierarchy; + for (size_t i = 0; i < h->transform.size; i++) { + mat4f_t res; + mmulf (res, h->localMatrix.a[i], h->localInverse.a[i]); + if (!mat4_equal (res, identity)) { + printf ("%s: localInverse not inverse of localMatrix\n", + h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 3)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 3)); + return 1; + } + puts (h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 3)); + } + for (size_t i = 0; i < h->transform.size; i++) { + mat4f_t res; + mmulf (res, h->worldMatrix.a[i], h->worldInverse.a[i]); + if (!mat4_equal (res, identity)) { + printf ("%s: worldInverse not inverse of worldMatrix\n", + h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 3)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 3)); + return 1; + } + puts (h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 3)); + } + + if (!check_vector (root, Transform_GetLocalPosition, + (vec4f_t) { 0, 0, 1, 1 }, "local position")) { + return 1; + } + if (!check_vector (root, Transform_GetWorldPosition, + (vec4f_t) { 0, 0, 1, 1 }, "world position")) { + return 1; + } + if (!check_vector (root, Transform_Forward, (vec4f_t) { 1, 0, 0, 0 }, + "forward")) { + return 1; + } + if (!check_vector (root, Transform_Right, (vec4f_t) { 0, -1, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (root, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, + "up")) { + return 1; + } + + if (!check_vector (A, Transform_GetLocalPosition, (vec4f_t) { 1, 0, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (A, Transform_GetWorldPosition, (vec4f_t) { 1, 0, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (A, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, + "forward")) { + return 1; + } + if (!check_vector (A, Transform_Right, (vec4f_t) { 0, 0, -1, 0 }, + "right")) { + return 1; + } + if (!check_vector (A, Transform_Up, (vec4f_t) { 1, 0, 0, 0 }, + "up")) { + return 1; + } + if (!check_vector (A1, Transform_GetLocalPosition, (vec4f_t) { 1, 0, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (A1, Transform_GetWorldPosition, (vec4f_t) { 1, 1, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (A1, Transform_Forward, (vec4f_t) { 1, 0, 0, 0 }, + "forward")) { + return 1; + } + if (!check_vector (A1, Transform_Right, (vec4f_t) { 0, -1, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (A1, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, + "up")) { + return 1; + } + + if (!check_vector (B, Transform_GetLocalPosition, (vec4f_t) { 0, 1, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (B, Transform_GetWorldPosition, (vec4f_t) { 0, 1, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (B, Transform_Forward, (vec4f_t) { 0, 0, 1, 0 }, + "forward")) { + return 1; + } + if (!check_vector (B, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (B, Transform_Up, (vec4f_t) { 0,-1, 0, 0 }, + "up")) { + return 1; + } + if (!check_vector (B1, Transform_GetLocalPosition, (vec4f_t) { 0, 1, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (B1, Transform_GetWorldPosition, (vec4f_t) {-1, 1, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (B1, Transform_Forward, (vec4f_t) { 1, 0, 0, 0 }, + "forward")) { + return 1; + } + if (!check_vector (B1, Transform_Right, (vec4f_t) { 0, -1, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (B1, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, + "up")) { + return 1; + } + + Transform_Delete (root); + + return 0; +} + +int +main (void) +{ + if (test_single_transform ()) { return 1; } + if (test_parent_child_init ()) { return 1; } + if (test_parent_child_setparent ()) { return 1; } + if (test_build_hierarchy ()) { return 1; } + if (test_build_hierarchy2 ()) { return 1; } + if (test_frames ()) { return 1; } + + return 0; +} diff --git a/libs/entity/transform.c b/libs/entity/transform.c new file mode 100644 index 000000000..0e274f83a --- /dev/null +++ b/libs/entity/transform.c @@ -0,0 +1,334 @@ +/* + transform.c + + General transform handling + + Copyright (C) 2021 Bill Currke + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/entity.h" +#include "QF/render.h" + +transform_t * +Transform_New (transform_t *parent) +{ + transform_t *transform = malloc (sizeof (transform_t)); + + if (parent) { + transform->hierarchy = parent->hierarchy; + transform->index = Hierarchy_InsertHierarchy (parent->hierarchy, 0, + parent->index, 0); + } else { + transform->hierarchy = Hierarchy_New (16, 1);//FIXME should be config + transform->index = 0; + } + transform->hierarchy->transform.a[transform->index] = transform; + Hierarchy_UpdateMatrices (transform->hierarchy); + return transform; +} + +void +Transform_Delete (transform_t *transform) +{ + if (transform->index != 0) { + // The transform is not the root, so pull it out of its current + // hierarchy so deleting it is easier + Transform_SetParent (transform, 0); + } + Hierarchy_Delete (transform->hierarchy); +} + +transform_t * +Transform_NewNamed (transform_t *parent, const char *name) +{ + transform_t *transform = Transform_New (parent); + Transform_SetName (transform, name); + return transform; +} + +uint32_t +Transform_ChildCount (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->childCount.a[transform->index]; +} + +transform_t * +Transform_GetChild (const transform_t *transform, uint32_t childIndex) +{ + hierarchy_t *h = transform->hierarchy; + if (childIndex >= h->childCount.a[transform->index]) { + return 0; + } + return h->transform.a[h->childIndex.a[transform->index] + childIndex]; +} + +void +Transform_SetParent (transform_t *transform, transform_t *parent) +{ + if (parent) { + hierarchy_t *hierarchy = transform->hierarchy; + uint32_t index = transform->index; + Hierarchy_InsertHierarchy (parent->hierarchy, hierarchy, + parent->index, index); + Hierarchy_RemoveHierarchy (hierarchy, index); + if (!hierarchy->name.size) { + Hierarchy_Delete (hierarchy); + } + } else { + // null parent -> make transform root + if (!transform->index) { + // already root + return; + } + hierarchy_t *hierarchy = transform->hierarchy; + uint32_t index = transform->index; + + hierarchy_t *new_hierarchy = Hierarchy_New (16, 0); + Hierarchy_InsertHierarchy (new_hierarchy, hierarchy, null_transform, + index); + Hierarchy_RemoveHierarchy (hierarchy, index); + } +} + +transform_t * +Transform_GetParent (const transform_t *transform) +{ + if (transform->index == 0) { + return 0; + } + hierarchy_t *h = transform->hierarchy; + return h->transform.a[h->parentIndex.a[transform->index]]; +} + +void +Transform_SetName (transform_t *transform, const char *name) +{ + hierarchy_t *h = transform->hierarchy; + //FIXME create a string pool (similar to qfcc's, or even move that to util) + if (h->name.a[transform->index]) { + free (h->name.a[transform->index]); + } + h->name.a[transform->index] = strdup (name); +} + +const char * +Transform_GetName (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->name.a[transform->index]; +} + +void +Transform_SetTag (transform_t *transform, uint32_t tag) +{ + hierarchy_t *h = transform->hierarchy; + h->tag.a[transform->index] = tag; +} + +uint32_t +Transform_GetTag (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->tag.a[transform->index]; +} + +void +Transform_GetLocalMatrix (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->localMatrix.a[transform->index], sizeof (mat4f_t)); +} + +void +Transform_GetLocalInverse (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->localInverse.a[transform->index], sizeof (mat4f_t)); +} + +void +Transform_GetWorldMatrix (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->worldMatrix.a[transform->index], sizeof (mat4f_t)); +} + +void +Transform_GetWorldInverse (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->worldInverse.a[transform->index], sizeof (mat4f_t)); +} + +vec4f_t +Transform_GetLocalPosition (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->localMatrix.a[transform->index][3]; +} + +void +Transform_SetLocalPosition (transform_t *transform, vec4f_t position) +{ + hierarchy_t *h = transform->hierarchy; + h->localMatrix.a[transform->index][3] = position; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + +vec4f_t +Transform_GetLocalRotation (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->localRotation.a[transform->index]; +} + +void +Transform_SetLocalRotation (transform_t *transform, vec4f_t rotation) +{ + hierarchy_t *h = transform->hierarchy; + vec4f_t scale = h->localScale.a[transform->index]; + + mat4f_t mat; + mat4fquat (mat, rotation); + + h->localMatrix.a[transform->index][0] = mat[0] * scale[0]; + h->localMatrix.a[transform->index][1] = mat[1] * scale[1]; + h->localMatrix.a[transform->index][2] = mat[2] * scale[2]; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + +vec4f_t +Transform_GetLocalScale (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->localScale.a[transform->index]; +} + +void +Transform_SetLocalScale (transform_t *transform, vec4f_t scale) +{ + hierarchy_t *h = transform->hierarchy; + vec4f_t rotation = h->localRotation.a[transform->index]; + + mat4f_t mat; + mat4fquat (mat, rotation); + + h->localMatrix.a[transform->index][0] = mat[0] * scale[0]; + h->localMatrix.a[transform->index][1] = mat[1] * scale[1]; + h->localMatrix.a[transform->index][2] = mat[2] * scale[2]; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + +vec4f_t +Transform_GetWorldPosition (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldMatrix.a[transform->index][3]; +} + +void +Transform_SetWorldPosition (transform_t *transform, vec4f_t position) +{ + if (transform->index) { + hierarchy_t *h = transform->hierarchy; + uint32_t parent = h->parentIndex.a[transform->index]; + position = mvmulf (h->worldInverse.a[parent], position); + } + Transform_SetLocalPosition (transform, position); +} + +vec4f_t +Transform_GetWorldRotation (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldRotation.a[transform->index]; +} + +void +Transform_SetWorldRotation (transform_t *transform, vec4f_t rotation) +{ + if (transform->index) { + hierarchy_t *h = transform->hierarchy; + uint32_t parent = h->parentIndex.a[transform->index]; + rotation = qmulf (qconjf (h->worldRotation.a[parent]), rotation); + } + Transform_SetLocalRotation (transform, rotation); +} + +vec4f_t +Transform_GetWorldScale (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldScale.a[transform->index]; +} + +void +Transform_SetLocalTransform (transform_t *transform, vec4f_t scale, + vec4f_t rotation, vec4f_t position) +{ + hierarchy_t *h = transform->hierarchy; + mat4f_t mat; + mat4fquat (mat, rotation); + + position[3] = 1; + h->localMatrix.a[transform->index][0] = mat[0] * scale[0]; + h->localMatrix.a[transform->index][1] = mat[1] * scale[1]; + h->localMatrix.a[transform->index][2] = mat[2] * scale[2]; + h->localMatrix.a[transform->index][3] = position; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + +vec4f_t +Transform_Forward (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldMatrix.a[transform->index][0]; +} + +vec4f_t +Transform_Right (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return -h->worldMatrix.a[transform->index][1]; +} + +vec4f_t +Transform_Up (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldMatrix.a[transform->index][2]; +} diff --git a/libs/gamecode/Makefile.am b/libs/gamecode/Makefile.am deleted file mode 100644 index 6d31504a8..000000000 --- a/libs/gamecode/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include -lib_ldflags= - -gc_deps=$(top_builddir)/libs/util/libQFutil.la - -noinst_LTLIBRARIES= libQFgamecode.la - -libQFgamecode_la_LDFLAGS= $(lib_ldflags) -libQFgamecode_la_LIBADD= $(gc_deps) -libQFgamecode_la_DEPENDENCIES= $(gc_deps) -libQFgamecode_la_SOURCES= \ - pr_builtins.c pr_edict.c pr_debug.c pr_exec.c pr_load.c pr_parse.c \ - pr_opcode.c pr_resolve.c pr_resource.c pr_strings.c pr_zone.c diff --git a/libs/gamecode/Makemodule.am b/libs/gamecode/Makemodule.am new file mode 100644 index 000000000..dfae7c388 --- /dev/null +++ b/libs/gamecode/Makemodule.am @@ -0,0 +1,19 @@ +gc_deps=libs/util/libQFutil.la + +noinst_LTLIBRARIES += libs/gamecode/libQFgamecode.la + +libs_gamecode_libQFgamecode_la_LDFLAGS= +libs_gamecode_libQFgamecode_la_LIBADD= $(gc_deps) +libs_gamecode_libQFgamecode_la_DEPENDENCIES=$(gc_deps) +libs_gamecode_libQFgamecode_la_SOURCES= \ + libs/gamecode/pr_builtins.c \ + libs/gamecode/pr_edict.c \ + libs/gamecode/pr_debug.c \ + libs/gamecode/pr_exec.c \ + libs/gamecode/pr_load.c \ + libs/gamecode/pr_parse.c \ + libs/gamecode/pr_opcode.c \ + libs/gamecode/pr_resolve.c \ + libs/gamecode/pr_resource.c \ + libs/gamecode/pr_strings.c \ + libs/gamecode/pr_zone.c diff --git a/libs/gamecode/pr_builtins.c b/libs/gamecode/pr_builtins.c index a3ab8c9d9..ab159e250 100644 --- a/libs/gamecode/pr_builtins.c +++ b/libs/gamecode/pr_builtins.c @@ -40,6 +40,7 @@ #include "QF/cmd.h" #include "QF/crc.h" #include "QF/cvar.h" +#include "QF/darray.h" #include "QF/hash.h" #include "QF/progs.h" #include "QF/qdefs.h" @@ -47,10 +48,11 @@ #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/zone.h" -#include "QF/va.h" #include "compat.h" +typedef struct biblock_s DARRAY_TYPE (builtin_t *) biblock_t; + static const char * builtin_get_key (const void *_bi, void *unused) { @@ -93,8 +95,12 @@ PR_RegisterBuiltins (progs_t *pr, builtin_t *builtins) int count; if (!pr->builtin_hash) { - pr->builtin_hash = Hash_NewTable (1021, builtin_get_key, 0, pr); - pr->builtin_num_hash = Hash_NewTable (1021, 0, 0, pr); + pr->builtin_blocks = malloc (sizeof (biblock_t)); + DARRAY_INIT (pr->builtin_blocks, 16); + pr->builtin_hash = Hash_NewTable (1021, builtin_get_key, 0, pr, + pr->hashlink_freelist); + pr->builtin_num_hash = Hash_NewTable (1021, 0, 0, pr, + pr->hashlink_freelist); Hash_SetHashCompare (pr->builtin_num_hash, builtin_get_hash, builtin_compare); } @@ -103,6 +109,7 @@ PR_RegisterBuiltins (progs_t *pr, builtin_t *builtins) for (bi = builtins, count = 1; bi->name; bi++) count++; bi = malloc (count * sizeof (builtin_t)); + DARRAY_APPEND (pr->builtin_blocks, bi); memcpy (bi, builtins, count * sizeof (builtin_t)); builtins = bi; @@ -158,7 +165,8 @@ bi_no_function (progs_t *pr) VISIBLE int PR_RelocateBuiltins (progs_t *pr) { - pr_int_t i, ind; + pr_uint_t i; + pr_int_t ind; int bad = 0; dfunction_t *desc; bfunction_t *func; diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 602a2cc15..598c2fa18 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -46,12 +46,12 @@ #include "QF/hash.h" #include "QF/mathlib.h" #include "QF/pr_debug.h" +#include "QF/pr_type.h" #include "QF/progs.h" #include "QF/qendian.h" #include "QF/quakefs.h" #include "QF/script.h" #include "QF/sys.h" -#include "QF/va.h" #include "QF/zone.h" #include "compat.h" @@ -64,17 +64,107 @@ typedef struct { typedef struct { char *name; char *text; + off_t size; line_t *lines; pr_uint_t num_lines; progs_t *pr; } file_t; +typedef struct compunit_s { + const char *file; + pr_compunit_t *unit; +} compunit_t; + +typedef struct prdeb_resources_s { + progs_t *pr; + dstring_t *string; + dstring_t *dva; + dstring_t *line; + dstring_t *dstr; + const char *debugfile; + pr_debug_header_t *debug; + pr_auxfunction_t *auxfunctions; + pr_auxfunction_t **auxfunction_map; + pr_lineno_t *linenos; + pr_def_t *local_defs; + pr_def_t *type_encodings_def; + qfot_type_t void_type; + qfot_type_t *type_encodings[ev_type_count]; + pr_def_t *debug_defs; + pr_type_t *debug_data; + hashtab_t *debug_syms; + hashtab_t *compunits; // by source file + PR_RESMAP (compunit_t) compmap; // handy allocation/freeing + hashtab_t *file_hash; +} prdeb_resources_t; + +typedef struct { + progs_t *pr; + dstring_t *dstr; +} pr_debug_data_t; + cvar_t *pr_debug; cvar_t *pr_source_path; -static hashtab_t *file_hash; -static char *source_path_string; -static char **source_paths; +static char *source_path_string; +static char **source_paths; +static void pr_debug_void_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_string_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_float_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_field_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_func_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_integer_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_uinteger_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_short_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_double_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_union_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_enum_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_array_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_class_view (qfot_type_t *type, pr_type_t *value, + void *_data); + +static type_view_t raw_type_view = { + pr_debug_void_view, + pr_debug_string_view, + pr_debug_float_view, + pr_debug_vector_view, + pr_debug_entity_view, + pr_debug_field_view, + pr_debug_func_view, + pr_debug_pointer_view, + pr_debug_quat_view, + pr_debug_integer_view, + pr_debug_uinteger_view, + pr_debug_short_view, + pr_debug_double_view, + pr_debug_struct_view, + pr_debug_union_view, + pr_debug_enum_view, + pr_debug_array_view, + pr_debug_class_view, +}; static const char * file_get_key (const void *_f, void *unused) @@ -94,56 +184,124 @@ file_free (void *_f, void *unused) free (f); } +static const char * +def_get_key (const void *d, void *p) +{ + __auto_type def = (pr_def_t *) d; + __auto_type pr = (progs_t *) p; + return PR_GetString (pr, def->name); +} + +static const char * +compunit_get_key (const void *cu, void *p) +{ + __auto_type compunit = (compunit_t *) cu; + return compunit->file; +} + static void source_path_f (cvar_t *var) { int i; char *s; - if (source_path_string) + if (source_path_string) { free (source_path_string); + } source_path_string = strdup (var->string); - if (source_paths) + if (source_paths) { free (source_paths); - for (i = 2, s = source_path_string; *s; s++) - if (*s == ';') - i++; - source_paths = malloc (i * sizeof (char **)); - source_paths[0] = source_path_string; - for (i = 1, s = source_path_string; *s; s++) + } + // i starts at 2 because an empty path is equivalent to "." and the + // list is null terminated + for (i = 2, s = source_path_string; *s; s++) { if (*s == ';') { - *s++ = 0; - source_paths[i++] = s; + i++; } + } + source_paths = malloc (i * sizeof (char *)); + source_paths[0] = source_path_string; + // i starts at one because the first path is in 0 and any additional + // paths come after, then the null terminator + for (i = 1, s = source_path_string; *s; s++) { + if (*s == ';') { + *s = 0; + source_paths[i++] = s + 1; + } + } source_paths[i] = 0; } -static void -pr_debug_expression_error (script_t *script, const char *msg) +#define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1)) +static pr_short_t __attribute__((pure)) +pr_debug_type_size (const progs_t *pr, const qfot_type_t *type) { - Sys_Printf ("%s\n", msg); + pr_short_t size; + qfot_type_t *aux_type; + switch (type->meta) { + case ty_basic: + return pr_type_size[type->type]; + case ty_struct: + case ty_union: + size = 0; + for (pr_int_t i = 0; i < type->strct.num_fields; i++) { + const qfot_var_t *field = &type->strct.fields[i]; + aux_type = &G_STRUCT (pr, qfot_type_t, field->type); + size = max (size, + field->offset + pr_debug_type_size (pr, aux_type)); + } + return size; + case ty_enum: + return pr_type_size[ev_integer]; + case ty_array: + aux_type = &G_STRUCT (pr, qfot_type_t, type->array.type); + size = pr_debug_type_size (pr, aux_type); + return type->array.size * size; + case ty_class: + return 1; //FIXME or should it return sizeof class struct? + case ty_alias: + aux_type = &G_STRUCT (pr, qfot_type_t, type->alias.aux_type); + return pr_debug_type_size (pr, aux_type); + } + return 0; } -static ddef_t +static qfot_type_t * +get_def_type (progs_t *pr, pr_def_t *def, qfot_type_t *type) +{ + if (!def->type_encoding) { + // no type encoding, so use basic type data to fill in and return + // the dummy encoding + memset (type, 0, sizeof (*type)); + type->type = def->type; + } else { + type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + if (!def->size) { + def->size = pr_debug_type_size (pr, type); + } + } + return type; +} + +static pr_def_t parse_expression (progs_t *pr, const char *expr, int conditional) { script_t *es; char *e; pr_type_t *expr_ptr; - ddef_t d; + pr_def_t d; d.ofs = 0; d.type = ev_invalid; - d.s_name = 0; + d.name = 0; es = Script_New (); - es->error = pr_debug_expression_error; Script_Start (es, "", expr); expr_ptr = 0; es->single = "{}()':[]."; if (Script_GetToken (es, 1)) { if (strequal (es->token->str, "[")) { edict_t *ent; - ddef_t *field; + pr_def_t *field; if (!Script_GetToken (es, 1)) goto error; @@ -160,14 +318,14 @@ parse_expression (progs_t *pr, const char *expr, int conditional) if (!field) goto error; d = *field; - expr_ptr = &ent->v[field->ofs]; + expr_ptr = &E_fld (ent, field->ofs); d.ofs = PR_SetPointer (pr, expr_ptr); } else if (isdigit ((byte) es->token->str[0])) { expr_ptr = PR_GetPointer (pr, strtol (es->token->str, 0, 0)); d.type = ev_void; d.ofs = PR_SetPointer (pr, expr_ptr); } else { - ddef_t *global = PR_FindGlobal (pr, es->token->str); + pr_def_t *global = PR_FindGlobal (pr, es->token->str); if (!global) goto error; d = *global; @@ -193,31 +351,53 @@ parse_expression (progs_t *pr, const char *expr, int conditional) Sys_Printf ("ignoring tail\n"); } error: + if (es->error) { + Sys_Printf (es->error); + } Script_Delete (es); return d; } -void -PR_Debug_Init (void) +static void +pr_debug_clear (progs_t *pr, void *data) { - file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); -} + __auto_type res = (prdeb_resources_t *) data; -void -PR_Debug_Init_Cvars (void) -{ - pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL, - "enable progs debugging"); - pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f, - "where to look (within gamedir) for source " - "files"); + dstring_clearstr (res->string); + dstring_clearstr (res->dva); + dstring_clearstr (res->line); + dstring_clearstr (res->dstr); + + if (res->debug) + pr->free_progs_mem (pr, res->debug); + Hash_FlushTable (res->file_hash); + Hash_FlushTable (res->debug_syms); + Hash_FlushTable (res->compunits); + PR_RESRESET (res->compmap); + res->debug = 0; + res->auxfunctions = 0; + if (res->auxfunction_map) + pr->free_progs_mem (pr, res->auxfunction_map); + res->auxfunction_map = 0; + res->linenos = 0; + res->local_defs = 0; + + pr->pr_debug_resources = res; + pr->watch = 0; + pr->wp_conditional = 0; + pr->wp_val.integer_var = 0; + + for (int i = 0; i < ev_type_count; i++ ) { + res->type_encodings[i] = &res->void_type; + } } static file_t * PR_Load_Source_File (progs_t *pr, const char *fname) { + prdeb_resources_t *res = pr->pr_debug_resources; char *l, *p, **dir; - file_t *f = Hash_Find (file_hash, fname); + file_t *f = Hash_Find (res->file_hash, fname); if (f) return f; @@ -225,8 +405,9 @@ PR_Load_Source_File (progs_t *pr, const char *fname) if (!f) return 0; for (dir = source_paths; *dir && !f->text; dir++) { - f->text = pr->load_file (pr, va ("%s%s%s", *dir, **dir ? "/" : "", - fname)); + f->text = pr->load_file (pr, dsprintf (res->dva, "%s%s%s", *dir, + **dir ? "/" : "", fname), + &f->size); } if (!f->text) { pr->file_error (pr, fname); @@ -263,29 +444,57 @@ PR_Load_Source_File (progs_t *pr, const char *fname) f->num_lines++; } f->pr = pr; - Hash_Add (file_hash, f); + Hash_Add (res->file_hash, f); return f; } +static void +byteswap_def (pr_def_t *def) +{ + def->type = LittleShort (def->type); + def->size = LittleShort (def->size); + def->ofs = LittleLong (def->ofs); + def->name = LittleLong (def->name); + def->type_encoding = LittleLong (def->type_encoding); +} + +static compunit_t * +new_compunit (prdeb_resources_t *res) +{ + return PR_RESNEW (res->compmap); +} + +static void +process_compunit (prdeb_resources_t *res, pr_def_t *def) +{ + progs_t *pr = res->pr; + __auto_type compunit = (pr_compunit_t *) (res->debug_data + def->ofs); + + for (unsigned i = 0; i < compunit->num_files; i++) { + compunit_t *cu = new_compunit (res); + cu->unit = compunit; + cu->file = PR_GetString (pr, compunit->files[i]); + Hash_Add (res->compunits, cu); + } +} + VISIBLE int PR_LoadDebug (progs_t *pr) { + prdeb_resources_t *res = PR_Resources_Find (pr, "PR_Debug"); char *sym_path; const char *path_end, *sym_file; + off_t debug_size; pr_uint_t i; - ddef_t *def; + pr_def_t *def; pr_type_t *str = 0; + qfot_type_encodings_t *encodings = 0; + pointer_t type_encodings = 0; + pointer_t type_ptr; + qfot_type_t *type; + string_t compunit_str; - if (pr->debug) - pr->free_progs_mem (pr, pr->debug); - pr->debug = 0; - pr->auxfunctions = 0; - if (pr->auxfunction_map) - pr->free_progs_mem (pr, pr->auxfunction_map); - pr->auxfunction_map = 0; - pr->linenos = 0; - pr->local_defs = 0; - + pr->pr_debug_resources = res; if (!pr_debug->int_val) return 1; @@ -293,110 +502,221 @@ PR_LoadDebug (progs_t *pr) if (def) str = &pr->pr_globals[def->ofs]; - Hash_FlushTable (file_hash); if (!str) return 1; - pr->debugfile = PR_GetString (pr, str->string_var); - sym_file = QFS_SkipPath (pr->debugfile); + res->debugfile = PR_GetString (pr, str->string_var); + sym_file = QFS_SkipPath (res->debugfile); path_end = QFS_SkipPath (pr->progs_name); sym_path = malloc (strlen (sym_file) + (path_end - pr->progs_name) + 1); strncpy (sym_path, pr->progs_name, path_end - pr->progs_name); strcpy (sym_path + (path_end - pr->progs_name), sym_file); - pr->debug = pr->load_file (pr, sym_path); - if (!pr->debug) { + res->debug = pr->load_file (pr, sym_path, &debug_size); + if (!res->debug) { Sys_Printf ("can't load %s for debug info\n", sym_path); free (sym_path); return 1; } - pr->debug->version = LittleLong (pr->debug->version); - if (pr->debug->version != PROG_DEBUG_VERSION) { + res->debug->version = LittleLong (res->debug->version); + if (res->debug->version != PROG_DEBUG_VERSION) { Sys_Printf ("ignoring %s with unsupported version %x.%03x.%03x\n", sym_path, - (pr->debug->version >> 24) & 0xff, - (pr->debug->version >> 12) & 0xfff, - pr->debug->version & 0xfff); - pr->debug = 0; + (res->debug->version >> 24) & 0xff, + (res->debug->version >> 12) & 0xfff, + res->debug->version & 0xfff); + res->debug = 0; free (sym_path); return 1; } - pr->debug->crc = LittleShort (pr->debug->crc); - if (pr->debug->crc != pr->crc) { + res->debug->crc = LittleShort (res->debug->crc); + if (res->debug->crc != pr->crc) { Sys_Printf ("ignoring %s that doesn't match %s. (CRCs: " "sym:%d dat:%d)\n", sym_path, pr->progs_name, - pr->debug->crc, + res->debug->crc, pr->crc); - pr->debug = 0; + res->debug = 0; free (sym_path); return 1; } free (sym_path); - pr->debug->you_tell_me_and_we_will_both_know = LittleShort - (pr->debug->you_tell_me_and_we_will_both_know); - pr->debug->auxfunctions = LittleLong (pr->debug->auxfunctions); - pr->debug->num_auxfunctions = LittleLong (pr->debug->num_auxfunctions); - pr->debug->linenos = LittleLong (pr->debug->linenos); - pr->debug->num_linenos = LittleLong (pr->debug->num_linenos); - pr->debug->locals = LittleLong (pr->debug->locals); - pr->debug->num_locals = LittleLong (pr->debug->num_locals); + res->debug->you_tell_me_and_we_will_both_know = LittleShort + (res->debug->you_tell_me_and_we_will_both_know); + res->debug->auxfunctions = LittleLong (res->debug->auxfunctions); + res->debug->num_auxfunctions = LittleLong (res->debug->num_auxfunctions); + res->debug->linenos = LittleLong (res->debug->linenos); + res->debug->num_linenos = LittleLong (res->debug->num_linenos); + res->debug->locals = LittleLong (res->debug->locals); + res->debug->num_locals = LittleLong (res->debug->num_locals); + res->debug->debug_defs = LittleLong (res->debug->debug_defs); + res->debug->num_debug_defs = LittleLong (res->debug->num_debug_defs); + res->debug->debug_data = LittleLong (res->debug->debug_data); + res->debug->debug_data_size = LittleLong (res->debug->debug_data_size); - pr->auxfunctions = (pr_auxfunction_t*)((char*)pr->debug + - pr->debug->auxfunctions); - pr->linenos = (pr_lineno_t*)((char*)pr->debug + pr->debug->linenos); - pr->local_defs = (ddef_t*)((char*)pr->debug + pr->debug->locals); + res->auxfunctions = (pr_auxfunction_t*)((char*)res->debug + + res->debug->auxfunctions); + res->linenos = (pr_lineno_t*)((char*)res->debug + res->debug->linenos); + res->local_defs = (pr_def_t*)((char*)res->debug + res->debug->locals); + res->debug_defs = (pr_def_t*)((char*)res->debug + res->debug->debug_defs); + res->debug_data = (pr_type_t*)((char*)res->debug + res->debug->debug_data); i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *); - pr->auxfunction_map = pr->allocate_progs_mem (pr, i); - for (i = 0; (int) i < pr->progs->numfunctions; i++) //FIXME (cast) - pr->auxfunction_map[i] = 0; + res->auxfunction_map = pr->allocate_progs_mem (pr, i); + for (i = 0; i < pr->progs->numfunctions; i++) + res->auxfunction_map[i] = 0; - for (i = 0; i < pr->debug->num_auxfunctions; i++) { - pr->auxfunctions[i].function = LittleLong - (pr->auxfunctions[i].function); - pr->auxfunctions[i].source_line = LittleLong - (pr->auxfunctions[i].source_line); - pr->auxfunctions[i].line_info = LittleLong - (pr->auxfunctions[i].line_info); - pr->auxfunctions[i].local_defs = LittleLong - (pr->auxfunctions[i].local_defs); - pr->auxfunctions[i].num_locals = LittleLong - (pr->auxfunctions[i].num_locals); + res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); + if (res->type_encodings_def) { + encodings = &G_STRUCT (pr, qfot_type_encodings_t, + res->type_encodings_def->ofs); + type_encodings = encodings->types; + } + for (i = 0; i < res->debug->num_auxfunctions; i++) { + res->auxfunctions[i].function = LittleLong + (res->auxfunctions[i].function); + res->auxfunctions[i].source_line = LittleLong + (res->auxfunctions[i].source_line); + res->auxfunctions[i].line_info = LittleLong + (res->auxfunctions[i].line_info); + res->auxfunctions[i].local_defs = LittleLong + (res->auxfunctions[i].local_defs); + res->auxfunctions[i].num_locals = LittleLong + (res->auxfunctions[i].num_locals); - pr->auxfunction_map[pr->auxfunctions[i].function] = - &pr->auxfunctions[i]; + if (type_encodings) { + res->auxfunctions[i].return_type += type_encodings; + } + res->auxfunction_map[res->auxfunctions[i].function] = + &res->auxfunctions[i]; } - for (i = 0; i < pr->debug->num_linenos; i++) { - pr->linenos[i].fa.func = LittleLong (pr->linenos[i].fa.func); - pr->linenos[i].line = LittleLong (pr->linenos[i].line); + for (i = 0; i < res->debug->num_linenos; i++) { + res->linenos[i].fa.func = LittleLong (res->linenos[i].fa.func); + res->linenos[i].line = LittleLong (res->linenos[i].line); } - for (i = 0; i < pr->debug->num_locals; i++) { - pr->local_defs[i].type = LittleShort (pr->local_defs[i].type); - pr->local_defs[i].ofs = LittleShort (pr->local_defs[i].ofs); - pr->local_defs[i].s_name = LittleLong (pr->local_defs[i].s_name); + for (i = 0; i < res->debug->num_locals; i++) { + byteswap_def (&res->local_defs[i]); + if (type_encodings) { + res->local_defs[i].type_encoding += type_encodings; + } + } + compunit_str = PR_FindString (pr, ".compile_unit"); + for (i = 0; i < res->debug->num_debug_defs; i++) { + pr_def_t *def = &res->debug_defs[i]; + byteswap_def (def); + if (type_encodings) { + def->type_encoding += type_encodings; + } + Hash_Add (res->debug_syms, def); + if (def->name == compunit_str) { + process_compunit (res, def); + } + } + if (encodings) { + for (type_ptr = 4; type_ptr < encodings->size; + type_ptr += type->size) { + type = &G_STRUCT (pr, qfot_type_t, type_encodings + type_ptr); + if (type->meta == ty_basic + && type->type >= 0 && type->type < ev_type_count) { + res->type_encodings[type->type] = type; + } + } } return 1; } +VISIBLE const char * +PR_Debug_GetBaseDirectory (progs_t *pr, const char *file) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + __auto_type cu = (compunit_t *) Hash_Find (res->compunits, file); + + if (cu) { + return PR_GetString (pr, cu->unit->basedir); + } + return 0; +} + +VISIBLE pr_auxfunction_t * +PR_Debug_AuxFunction (progs_t *pr, pr_uint_t func) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || func >= res->debug->num_auxfunctions) { + return 0; + } + return &res->auxfunctions[func]; +} + +VISIBLE pr_auxfunction_t * +PR_Debug_MappedAuxFunction (progs_t *pr, pr_uint_t func) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || func >= pr->progs->numfunctions) { + return 0; + } + return res->auxfunction_map[func]; +} + +VISIBLE pr_def_t * +PR_Debug_LocalDefs (progs_t *pr, pr_auxfunction_t *aux_function) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || !aux_function) { + return 0; + } + if (aux_function->local_defs > res->debug->num_locals) { + return 0; + } + return res->local_defs + aux_function->local_defs; +} + +VISIBLE pr_lineno_t * +PR_Debug_Linenos (progs_t *pr, pr_auxfunction_t *aux_function, + pr_uint_t *num_linenos) +{ + pr_uint_t i, count; + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug) { + return 0; + } + if (!aux_function) { + *num_linenos = res->debug->num_linenos; + return res->linenos; + } + if (aux_function->line_info > res->debug->num_linenos) { + return 0; + } + //FIXME put lineno count in sym file + for (count = 1, i = aux_function->line_info + 1; + i < res->debug->num_linenos; i++, count++) { + if (!res->linenos[i].line) { + break; + } + } + *num_linenos = count; + return res->linenos + aux_function->line_info; +} + pr_auxfunction_t * PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno) { - while (lineno > pr->linenos && lineno->line) + prdeb_resources_t *res = pr->pr_debug_resources; + while (lineno > res->linenos && lineno->line) lineno--; if (lineno->line) return 0; - return &pr->auxfunctions[lineno->fa.func]; + return &res->auxfunctions[lineno->fa.func]; } pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_auxfunction_t *f; if (lineno->line) return lineno->fa.addr; - if (lineno->fa.func < pr->debug->num_auxfunctions) { - f = &pr->auxfunctions[lineno->fa.func]; + if (lineno->fa.func < res->debug->num_auxfunctions) { + f = &res->auxfunctions[lineno->fa.func]; return pr->pr_functions[f->function].first_statement; } // take a wild guess that only the line number is bogus and return @@ -415,16 +735,17 @@ PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) pr_lineno_t * PR_Find_Lineno (progs_t *pr, pr_uint_t addr) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_uint_t i; pr_lineno_t *lineno = 0; - if (!pr->debug) + if (!res->debug) return 0; - if (!pr->debug->num_linenos) + if (!res->debug->num_linenos) return 0; - for (i = pr->debug->num_linenos; i > 0; i--) { - if (PR_Get_Lineno_Addr (pr, &pr->linenos[i - 1]) <= addr) { - lineno = &pr->linenos[i - 1]; + for (i = res->debug->num_linenos; i > 0; i--) { + if (PR_Get_Lineno_Addr (pr, &res->linenos[i - 1]) <= addr) { + lineno = &res->linenos[i - 1]; break; } } @@ -445,6 +766,7 @@ PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) const char * PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) { + prdeb_resources_t *res = pr->pr_debug_resources; const char *fname; pr_uint_t line; file_t *file; @@ -464,22 +786,24 @@ PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) file = PR_Load_Source_File (pr, fname); if (!file || !file->lines || !line || line > file->num_lines) - return va ("%s:%u", fname, line); + return dsprintf (res->dva, "%s:%u", fname, line); - return va ("%s:%u:%.*s", fname, line, (int)file->lines[line - 1].len, - file->lines[line - 1].text); + return dsprintf (res->dva, "%s:%u:%.*s", fname, line, + (int)file->lines[line - 1].len, + file->lines[line - 1].text); } -ddef_t * +pr_def_t * PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_uint_t i; pr_auxfunction_t *aux_func; - ddef_t *ddef = 0; + pr_def_t *ddef = 0; int num_params; int param_offs = 0; - if (!pr->debug) + if (!res->debug) return 0; if (!func) return 0; @@ -492,12 +816,12 @@ PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) if (parm >= (unsigned) num_params) return 0; - aux_func = pr->auxfunction_map[func - pr->pr_functions]; + aux_func = res->auxfunction_map[func - pr->pr_functions]; if (!aux_func) return 0; for (i = 0; i < aux_func->num_locals; i++) { - ddef = &pr->local_defs[aux_func->local_defs + param_offs + i]; + ddef = &res->local_defs[aux_func->local_defs + param_offs + i]; if (!parm--) break; } @@ -507,42 +831,58 @@ PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) static pr_auxfunction_t * get_aux_function (progs_t *pr) { + prdeb_resources_t *res = pr->pr_debug_resources; dfunction_t *func; - if (!pr->pr_xfunction || !pr->auxfunction_map) + if (!pr->pr_xfunction || !res->auxfunction_map) return 0; func = pr->pr_xfunction->descriptor; - return pr->auxfunction_map[func - pr->pr_functions]; + return res->auxfunction_map[func - pr->pr_functions]; } -ddef_t * -PR_Get_Local_Def (progs_t *pr, pr_int_t offs) +static qfot_type_t * +get_type (prdeb_resources_t *res, int typeptr) { - pr_uint_t i; + progs_t *pr = res->pr; + + if (!typeptr) { + return &res->void_type; + } + return &G_STRUCT (pr, qfot_type_t, typeptr); +} + +pr_def_t * +PR_Get_Local_Def (progs_t *pr, pointer_t *offset) +{ + prdeb_resources_t *res = pr->pr_debug_resources; dfunction_t *func; pr_auxfunction_t *aux_func; + pointer_t offs = *offset; + pr_def_t *def; if (!pr->pr_xfunction) return 0; func = pr->pr_xfunction->descriptor; if (!func) return 0; - aux_func = pr->auxfunction_map[func - pr->pr_functions]; + aux_func = res->auxfunction_map[func - pr->pr_functions]; if (!aux_func) return 0; offs -= func->parm_start; - if (offs < 0 || offs >= func->locals) + if (offs >= func->locals) return 0; - for (i = 0; i < aux_func->num_locals; i++) - if (pr->local_defs[aux_func->local_defs + i].ofs == offs) - return &pr->local_defs[aux_func->local_defs + i]; - return 0; + if ((def = PR_SearchDefs (res->local_defs + aux_func->local_defs, + aux_func->num_locals, offs))) { + *offset = offs - def->ofs; + } + return def; } VISIBLE void PR_DumpState (progs_t *pr) { + prdeb_resources_t *res = pr->pr_debug_resources; if (pr->pr_xfunction) { - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { pr_lineno_t *lineno; pr_auxfunction_t *func = 0; dfunction_t *descriptor = pr->pr_xfunction->descriptor; @@ -567,182 +907,415 @@ PR_DumpState (progs_t *pr) #define ISDENORM(x) ((x) && !((x) & 0x7f800000)) static const char * -value_string (progs_t *pr, etype_t type, pr_type_t *val) +value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value) { - static dstring_t *line; - ddef_t *def; - pr_int_t ofs; - edict_t *edict; - dfunction_t *f; - const char *str; - - if (!line) - line = dstring_new (); - - type &= ~DEF_SAVEGLOBAL; - - switch (type) { - case ev_string: - if (!PR_StringValid (pr, val->string_var)) - return "*** invalid ***"; - str = PR_GetString (pr, val->string_var); - dstring_copystr (line, "\""); - while (*str) { - const char *s; - - for (s = str; *s && !strchr ("\"\n\t", *s); s++) - ; - if (s != str) - dstring_appendsubstr (line, str, s - str); - if (*s) { - switch (*s) { - case '\"': - dstring_appendstr (line, "\\\""); - break; - case '\n': - dstring_appendstr (line, "\\n"); - break; - case '\t': - dstring_appendstr (line, "\\t"); - break; - default: - dasprintf (line, "\\x%02x", *s & 0xff); - } - s++; - } - str = s; - } - dstring_appendstr (line, "\""); - break; - case ev_entity: - edict = PROG_TO_EDICT (pr, val->entity_var); - dsprintf (line, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); - break; - case ev_func: - if (val->func_var < 0 || val->func_var >= pr->progs->numfunctions) - dsprintf (line, "INVALID:%d", val->func_var); - else if (!val->func_var) - return "NULL"; - else { - f = pr->pr_functions + val->func_var; - dsprintf (line, "%s()", PR_GetString (pr, f->s_name)); + switch (type->meta) { + case ty_basic: + switch (type->type) { + case ev_void: + raw_type_view.void_view (type, value, data); + break; + case ev_string: + raw_type_view.string_view (type, value, data); + break; + case ev_float: + raw_type_view.float_view (type, value, data); + break; + case ev_vector: + raw_type_view.vector_view (type, value, data); + break; + case ev_entity: + raw_type_view.entity_view (type, value, data); + break; + case ev_field: + raw_type_view.field_view (type, value, data); + break; + case ev_func: + raw_type_view.func_view (type, value, data); + break; + case ev_pointer: + raw_type_view.pointer_view (type, value, data); + break; + case ev_quat: + raw_type_view.quat_view (type, value, data); + break; + case ev_integer: + raw_type_view.integer_view (type, value, data); + break; + case ev_uinteger: + raw_type_view.uinteger_view (type, value, data); + break; + case ev_short: + raw_type_view.short_view (type, value, data); + break; + case ev_double: + raw_type_view.double_view (type, value, data); + break; + case ev_invalid: + case ev_type_count: + dstring_appendstr (data->dstr, ""); } break; - case ev_field: - def = PR_FieldAtOfs (pr, val->integer_var); - if (def) - dsprintf (line, ".%s", PR_GetString (pr, def->s_name)); - else - dsprintf (line, ".<$%04x>", val->integer_var); + case ty_struct: + raw_type_view.struct_view (type, value, data); break; - case ev_void: - return "void"; - case ev_float: - if (ISDENORM (val->integer_var) && val->uinteger_var != 0x80000000) - dsprintf (line, "<%08x>", val->integer_var); - else - dsprintf (line, "%g", val->float_var); + case ty_union: + raw_type_view.union_view (type, value, data); break; - case ev_vector: - dsprintf (line, "'%g %g %g'", - val->vector_var[0], val->vector_var[1], - val->vector_var[2]); + case ty_enum: + raw_type_view.enum_view (type, value, data); break; - case ev_pointer: - def = 0; - ofs = val->integer_var; - if (pr_debug->int_val && pr->debug) - def = PR_Get_Local_Def (pr, ofs); - if (!def) - def = PR_GlobalAtOfs (pr, ofs); - if (def && def->s_name) - dsprintf (line, "&%s", PR_GetString (pr, def->s_name)); - else - dsprintf (line, "[$%x]", ofs); + case ty_array: + raw_type_view.array_view (type, value, data); break; - case ev_quat: - dsprintf (line, "'%g %g %g %g'", - val->vector_var[0], val->vector_var[1], - val->vector_var[2], val->vector_var[3]); - break; - case ev_integer: - dsprintf (line, "%d", val->integer_var); - break; - case ev_uinteger: - dsprintf (line, "$%08x", val->uinteger_var); - break; - default: - //dsprintf (line, "bad type %i", type); - dsprintf (line, "<%x %x %x %x>", - val[0].integer_var, val[1].integer_var, - val[2].integer_var, val[3].integer_var); + case ty_class: + raw_type_view.class_view (type, value, data); break; + case ty_alias://XXX + type = &G_STRUCT (data->pr, qfot_type_t, type->alias.aux_type); + return value_string (data, type, value); } - - return line->str; + return data->dstr->str; } -static ddef_t * -def_string (progs_t *pr, pr_int_t ofs, dstring_t *dstr) +static pr_def_t * +pr_debug_find_def (progs_t *pr, pointer_t *ofs) { - ddef_t *def = 0; - const char *name; + prdeb_resources_t *res = pr->pr_debug_resources; + pr_def_t *def = 0; - if (pr_debug->int_val && pr->debug) + if (*ofs >= pr->progs->numglobals) { + return 0; + } + if (pr_debug->int_val && res->debug) { def = PR_Get_Local_Def (pr, ofs); - if (!def) - def = PR_GlobalAtOfs (pr, ofs); - if (!def || !*(name = PR_GetString (pr, def->s_name))) - dsprintf (dstr, "[$%x]", ofs); - else - dsprintf (dstr, "%s", name); + } + if (!def) { + def = PR_GlobalAtOfs (pr, *ofs); + if (def) { + *ofs -= def->ofs; + } + } return def; } static const char * -global_string (progs_t *pr, pointer_t ofs, etype_t type, int contents) +global_string (pr_debug_data_t *data, pointer_t offset, qfot_type_t *type, + int contents) { - static dstring_t *line = NULL; - ddef_t *def = NULL; - const char *s; + progs_t *pr = data->pr; + prdeb_resources_t *res = pr->pr_debug_resources; + dstring_t *dstr = data->dstr; + pr_def_t *def = NULL; + qfot_type_t dummy_type = { }; + const char *name = 0; + pointer_t offs = offset; - if (!line) - line = dstring_newstr(); + dstring_clearstr (dstr); - if (type == ev_short) { - dsprintf (line, "%04x", (short) ofs); - return line->str; + if (type && type->meta == ty_basic && type->type == ev_short) { + dsprintf (dstr, "%04x", (short) offset); + return dstr->str; } - def = def_string (pr, ofs, line); + if (offset > pr->globals_size) { + dsprintf (dstr, "%08x out of bounds", offset); + return dstr->str; + } - if (contents && (def || type != ev_void)) { - const char *oi = ""; - if (def) { - if (type == ev_void) - type = def->type; - if (type != (etype_t) (def->type & ~DEF_SAVEGLOBAL)) - oi = "?"; - } - - if (ofs > pr->globals_size) - s = "Out of bounds"; - else - s = value_string (pr, type, &pr->pr_globals[ofs]); - - if (strequal(line->str, "IMMEDIATE") || strequal(line->str, ".imm")) { - dsprintf (line, "%s", s); + def = pr_debug_find_def (pr, &offs); + if (!def || !PR_StringValid (pr, def->name) + || !*(name = PR_GetString (pr, def->name))) { + dsprintf (dstr, "[$%x]", offset); + } + if (name) { + if (strequal (name, "IMMEDIATE") || strequal (name, ".imm")) { + contents = 1; } else { - dasprintf (line, "%s(%s)", oi, s); + if (offs) { + dsprintf (dstr, "{%s + %u}", name, offs); + } else { + dsprintf (dstr, "%s", name); + } } } - return line->str; + if (contents) { + if (name) { + dstring_appendstr (dstr, "("); + } + if (!type) { + if (def) { + if (!def->type_encoding) { + dummy_type.type = def->type; + type = &dummy_type; + } else { + type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + } + } else { + type = &res->void_type; + } + } + value_string (data, type, pr->pr_globals + offset); + if (name) { + dstring_appendstr (dstr, ")"); + } + } + return dstr->str; +} + +static void +pr_debug_void_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dasprintf (data->dstr, ""); +} + +static void +pr_debug_string_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + string_t string = value->string_var; + if (PR_StringValid (data->pr, string)) { + const char *str = PR_GetString (data->pr, string); + + dstring_appendstr (dstr, "\""); + while (*str) { + const char *s; + + for (s = str; *s && !strchr ("\"\n\t", *s); s++) { + } + if (s != str) { + dstring_appendsubstr (dstr, str, s - str); + } + if (*s) { + switch (*s) { + case '\"': + dstring_appendstr (dstr, "\\\""); + break; + case '\n': + dstring_appendstr (dstr, "\\n"); + break; + case '\t': + dstring_appendstr (dstr, "\\t"); + break; + default: + dasprintf (dstr, "\\x%02x", *s & 0xff); + } + s++; + } + str = s; + } + dstring_appendstr (dstr, "\""); + } else { + dstring_appendstr (dstr, "*** invalid string offset ***"); + } +} + +static void +pr_debug_float_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + if (data->pr->progs->version == PROG_ID_VERSION + && ISDENORM (value->integer_var) + && value->uinteger_var != 0x80000000) { + dasprintf (dstr, "<%08x>", value->integer_var); + } else { + dasprintf (dstr, "%.9g", value->float_var); + } +} + +static void +pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "'%.9g %.9g %.9g'", VectorExpand (&value->vector_var)); +} + +static void +pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + + if (pr->pr_edicts) { + edict_t *edict = PROG_TO_EDICT (pr, value->entity_var); + dasprintf (dstr, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); + } else { + dasprintf (dstr, "entity [%x]",value->entity_var); + } +} + +static void +pr_debug_field_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + pr_def_t *def = PR_FieldAtOfs (pr, value->integer_var); + + if (def) { + dasprintf (dstr, ".%s", PR_GetString (pr, def->name)); + } else { + dasprintf (dstr, ".<$%04x>", value->integer_var); + } +} + +static void +pr_debug_func_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + + if (value->func_var >= pr->progs->numfunctions) { + dasprintf (dstr, "INVALID:%d", value->func_var); + } else if (!value->func_var) { + dstring_appendstr (dstr, "NULL"); + } else { + dfunction_t *f = pr->pr_functions + value->func_var; + dasprintf (dstr, "%s()", PR_GetString (pr, f->s_name)); + } +} + +static void +pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + pointer_t offset = value->integer_var; + pointer_t offs = offset; + pr_def_t *def = 0; + + def = pr_debug_find_def (pr, &offs); + if (def && def->name) { + if (offs) { + dasprintf (dstr, "&%s + %u", PR_GetString (pr, def->name), offs); + } else { + dasprintf (dstr, "&%s", PR_GetString (pr, def->name)); + } + } else { + dasprintf (dstr, "[$%x]", offset); + } +} + +static void +pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "'%.9g %.9g %.9g %.9g'", QuatExpand (&value->quat_var)); +} + +static void +pr_debug_integer_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%d", value->integer_var); +} + +static void +pr_debug_uinteger_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "$%08x", value->uinteger_var); +} + +static void +pr_debug_short_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%04x", (short)value->integer_var); +} + +static void +pr_debug_double_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%.17g", *(double *)value); +} + +static void +pr_dump_struct (qfot_type_t *type, pr_type_t *value, void *_data, + const char *struct_type) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + qfot_struct_t *strct = &type->strct; + + dstring_appendstr (dstr, "{"); + for (int i = 0; i < strct->num_fields; i++) { + qfot_var_t *field = strct->fields + i; + qfot_type_t *val_type = &G_STRUCT (pr, qfot_type_t, field->type); + pr_type_t *val = value + field->offset; + dasprintf (dstr, "%s=", PR_GetString (pr, field->name)); + value_string (data, val_type, val); + if (i < strct->num_fields - 1) { + dstring_appendstr (dstr, ", "); + } + } + dstring_appendstr (dstr, "}"); + //dasprintf (dstr, "<%s>", struct_type); +} +static void +pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + pr_dump_struct (type, value, _data, "struct"); +} + +static void +pr_debug_union_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + pr_dump_struct (type, value, _data, "union"); +} + +static void +pr_debug_enum_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_array_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_class_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); } VISIBLE void PR_Debug_Watch (progs_t *pr, const char *expr) { - ddef_t watch; + pr_def_t watch; if (!expr) { Sys_Printf ("watch \n"); if (pr->watch) { @@ -751,8 +1324,7 @@ PR_Debug_Watch (progs_t *pr, const char *expr) if (pr->wp_conditional) Sys_Printf (" if new val == %d\n", pr->wp_val.integer_var); - } else { - Sys_Printf (" none active\n"); + } else { Sys_Printf (" none active\n"); } return; } @@ -773,7 +1345,9 @@ PR_Debug_Watch (progs_t *pr, const char *expr) VISIBLE void PR_Debug_Print (progs_t *pr, const char *expr) { - ddef_t print; + prdeb_resources_t *res = pr->pr_debug_resources; + pr_def_t print; + pr_debug_data_t data = {pr, res->dstr}; if (!expr) { Sys_Printf ("print \n"); @@ -781,8 +1355,9 @@ PR_Debug_Print (progs_t *pr, const char *expr) } print = parse_expression (pr, expr, 0); - if (print.type != ev_invalid) { - const char *s = global_string (pr, print.ofs, print.type, 1); + if (print.type_encoding) { + qfot_type_t *type = get_type (res, print.type_encoding); + const char *s = global_string (&data, print.ofs, type, 1); Sys_Printf ("[%d] = %s\n", print.ofs, s); } } @@ -790,28 +1365,29 @@ PR_Debug_Print (progs_t *pr, const char *expr) VISIBLE void PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) { + prdeb_resources_t *res = pr->pr_debug_resources; int addr = s - pr->pr_statements; int dump_code = contents & 2; const char *fmt; opcode_t *op; - static dstring_t *line; dfunction_t *call_func = 0; - ddef_t *parm_def = 0; + pr_def_t *parm_def = 0; pr_auxfunction_t *aux_func = 0; + pr_debug_data_t data; - if (!line) - line = dstring_new (); + dstring_clearstr (res->line); - dstring_clearstr (line); + data.pr = pr; + data.dstr = res->dstr; if (pr_debug->int_val > 1) dump_code = 1; - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { const char *source_line = PR_Get_Source_Line (pr, addr); if (source_line) { - dasprintf (line, "%s%s", source_line, dump_code ? "\n" : ""); + dasprintf (res->line, "%s%s", source_line, dump_code ? "\n" : ""); if (!dump_code) goto do_print; } @@ -821,34 +1397,35 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) op = PR_Opcode (s->op); if (!op) { - Sys_Printf ("%sUnknown instruction %d\n", line->str, s->op); + Sys_Printf ("%sUnknown instruction %d\n", res->line->str, s->op); return; } if (!(fmt = op->fmt)) fmt = "%Ga, %Gb, %gc"; - dasprintf (line, "%04x ", addr); + dasprintf (res->line, "%04x ", addr); if (pr_debug->int_val > 2) - dasprintf (line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t", + dasprintf (res->line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t", s->op, s->a, pr_type_name[op->type_a], s->b, pr_type_name[op->type_b], s->c, pr_type_name[op->type_c]); - dasprintf (line, "%s ", op->opname); + dasprintf (res->line, "%s ", op->opname); while (*fmt) { if (*fmt == '%') { if (fmt[1] == '%') { - dstring_appendsubstr (line, fmt + 1, 1); + dstring_appendsubstr (res->line, fmt + 1, 1); fmt += 2; } else { const char *str; char mode = fmt[1], opchar = fmt[2]; unsigned parm_ind = 0; pr_int_t opval; - etype_t optype = ev_void; + qfot_type_t *optype = &res->void_type; + func_t func; if (mode == 'P') { opchar = fmt[3]; @@ -861,15 +1438,15 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) switch (opchar) { case 'a': opval = s->a; - optype = op->type_a; + optype = res->type_encodings[op->type_a]; break; case 'b': opval = s->b; - optype = op->type_b; + optype = res->type_encodings[op->type_b]; break; case 'c': opval = s->c; - optype = op->type_c; + optype = res->type_encodings[op->type_c]; break; case 'x': if (mode == 'P') { @@ -882,40 +1459,48 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) } switch (mode) { case 'R': - optype = ev_void; + optype = &res->void_type; aux_func = get_aux_function (pr); - if (aux_func) - optype = aux_func->return_type; - str = global_string (pr, opval, optype, contents & 1); + if (aux_func) { + optype = get_type (res, aux_func->return_type); + } + str = global_string (&data, opval, optype, + contents & 1); break; case 'F': - str = global_string (pr, opval, optype, contents & 1); - if (G_FUNCTION (pr, opval) >= 0 - && G_FUNCTION (pr, opval) - < pr->progs->numfunctions) - call_func = pr->pr_functions + G_FUNCTION (pr, opval); + str = global_string (&data, opval, optype, + contents & 1); + func = G_FUNCTION (pr, opval); + if (func < pr->progs->numfunctions) { + call_func = pr->pr_functions + func; + } break; case 'P': parm_def = PR_Get_Param_Def (pr, call_func, parm_ind); - optype = ev_void; - if (parm_def) - optype = parm_def->type; - str = global_string (pr, opval, optype, contents & 1); + optype = &res->void_type; + if (parm_def) { + optype = get_type (res, parm_def->type_encoding); + } + str = global_string (&data, opval, optype, + contents & 1); break; case 'V': - str = global_string (pr, opval, ev_void, contents & 1); + str = global_string (&data, opval, ev_void, + contents & 1); break; case 'G': - str = global_string (pr, opval, optype, contents & 1); + str = global_string (&data, opval, optype, + contents & 1); break; case 'g': - str = global_string (pr, opval, optype, 0); + str = global_string (&data, opval, optype, 0); break; case 's': - str = va ("%d", (short) opval); + str = dsprintf (res->dva, "%d", (short) opval); break; case 'O': - str = va ("%04x", addr + (short) opval); + str = dsprintf (res->dva, "%04x", + addr + (short) opval); break; case 'E': { @@ -924,69 +1509,71 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) parm_ind = pr->pr_globals[s->b].uinteger_var; if (parm_ind < pr->progs->entityfields && opval >= 0 - && opval < pr->pr_edictareasize) { + && opval < pr->pr_edict_area_size) { ed = PROG_TO_EDICT (pr, opval); - opval = &ed->v[parm_ind] - pr->pr_globals; + opval = &E_fld(ed, parm_ind) - pr->pr_globals; } if (!ed) { str = "bad entity.field"; break; } - str = global_string (pr, opval, optype, + str = global_string (&data, opval, optype, contents & 1); - str = va ("$%x $%x %s", s->a, s->b, str); + str = dsprintf (res->dva, "$%x $%x %s", + s->a, s->b, str); } break; default: goto err; } - dstring_appendstr (line, str); + dstring_appendstr (res->line, str); fmt += 3; continue; err: - dstring_appendstr (line, fmt); + dstring_appendstr (res->line, fmt); break; } } else { - dstring_appendsubstr (line, fmt++, 1); + dstring_appendsubstr (res->line, fmt++, 1); } } do_print: - Sys_Printf ("%s\n", line->str); + Sys_Printf ("%s\n", res->line->str); } static void dump_frame (progs_t *pr, prstack_t *frame) { - dfunction_t *f = frame->f ? frame->f->descriptor : 0; + prdeb_resources_t *res = pr->pr_debug_resources; + dfunction_t *f = frame->func ? frame->func->descriptor : 0; if (!f) { Sys_Printf ("\n"); return; } - if (pr_debug->int_val && pr->debug) { - pr_lineno_t *lineno = PR_Find_Lineno (pr, frame->s); + if (pr_debug->int_val && res->debug) { + pr_lineno_t *lineno = PR_Find_Lineno (pr, frame->staddr); pr_auxfunction_t *func = PR_Get_Lineno_Func (pr, lineno); pr_uint_t line = PR_Get_Lineno_Line (pr, lineno); pr_int_t addr = PR_Get_Lineno_Addr (pr, lineno); line += func->source_line; - if (addr == frame->s) { + if (addr == frame->staddr) { Sys_Printf ("%12s:%u : %s: %x\n", PR_GetString (pr, f->s_file), line, PR_GetString (pr, f->s_name), - frame->s); + frame->staddr); } else { Sys_Printf ("%12s:%u+%d : %s: %x\n", PR_GetString (pr, f->s_file), - line, frame->s - addr, + line, frame->staddr - addr, PR_GetString (pr, f->s_name), - frame->s); + frame->staddr); } } else { Sys_Printf ("%12s : %s: %x\n", PR_GetString (pr, f->s_file), - PR_GetString (pr, f->s_name), frame->s); + PR_GetString (pr, f->s_name), frame->staddr); } } @@ -1001,8 +1588,8 @@ PR_StackTrace (progs_t *pr) return; } - top.s = pr->pr_xstatement; - top.f = pr->pr_xfunction; + top.staddr = pr->pr_xstatement; + top.func = pr->pr_xfunction; dump_frame (pr, &top); for (i = pr->pr_depth - 1; i >= 0; i--) dump_frame (pr, pr->pr_stack + i); @@ -1011,7 +1598,7 @@ PR_StackTrace (progs_t *pr) VISIBLE void PR_Profile (progs_t * pr) { - pr_int_t max, num, i; + pr_uint_t max, num, i; dfunction_t *best, *f; num = 0; @@ -1043,11 +1630,15 @@ PR_Profile (progs_t * pr) VISIBLE void ED_Print (progs_t *pr, edict_t *ed) { - int type, l; - pr_uint_t i; + prdeb_resources_t *res = pr->pr_debug_resources; + int l; + pr_uint_t i, j; const char *name; - ddef_t *d; + pr_def_t *d; pr_type_t *v; + qfot_type_t dummy_type = { }; + qfot_type_t *type; + pr_debug_data_t data = {pr, res->dstr}; if (ed->free) { Sys_Printf ("FREE\n"); @@ -1057,50 +1648,68 @@ ED_Print (progs_t *pr, edict_t *ed) Sys_Printf ("\nEDICT %d:\n", NUM_FOR_BAD_EDICT (pr, ed)); for (i = 0; i < pr->progs->numfielddefs; i++) { d = &pr->pr_fielddefs[i]; - if (!d->s_name) // null field def (probably 1st) + if (!d->name) // null field def (probably 1st) continue; - name = PR_GetString (pr, d->s_name); + type = get_def_type (pr, d, &dummy_type); + name = PR_GetString (pr, d->name); if (name[strlen (name) - 2] == '_' && strchr ("xyz", name[strlen (name) -1])) continue; // skip _x, _y, _z vars - v = ed->v + d->ofs; - - // if the value is still all 0, skip the field - type = d->type & ~DEF_SAVEGLOBAL; - - switch (type) { - case ev_entity: - case ev_integer: - case ev_uinteger: - case ev_pointer: - case ev_func: - case ev_field: - if (!v->integer_var) - continue; + for (j = 0; j < d->size; j++) { + if (E_INT (ed, d->ofs + j)) { break; - case ev_string: - if (PR_StringValid (pr, v->string_var)) - if (!PR_GetString (pr, v->string_var)[0]) - continue; - break; - case ev_float: - if (!v->float_var) - continue; - break; - case ev_vector: - if (!v[0].float_var && !v[1].float_var && !v[2].float_var) - continue; - break; - case ev_void: - break; - default: - PR_Error (pr, "ED_Print: Unhandled type %d", type); + } } + if (j == d->size) { + continue; + } + + v = &E_fld (ed, d->ofs); l = 15 - strlen (name); if (l < 1) l = 1; - Sys_Printf ("%s%*s%s\n", name, l, "", value_string (pr, d->type, v)); + + dstring_clearstr (res->dstr); + value_string (&data, type, v); + Sys_Printf ("%s%*s%s\n", name, l, "", res->dstr->str); } } + +void +PR_Debug_Init (progs_t *pr) +{ + prdeb_resources_t *res = calloc (1, sizeof (*res)); + res->pr = pr; + res->string = dstring_newstr (); + res->dva = dstring_newstr (); + res->line = dstring_newstr (); + res->dstr = dstring_newstr (); + + res->void_type.meta = ty_basic; + res->void_type.size = 4; + res->void_type.encoding = 0; + res->void_type.type = ev_void; + for (int i = 0; i < ev_type_count; i++ ) { + res->type_encodings[i] = &res->void_type; + } + res->file_hash = Hash_NewTable (509, file_get_key, file_free, 0, + pr->hashlink_freelist); + res->debug_syms = Hash_NewTable (509, def_get_key, 0, pr, + pr->hashlink_freelist); + res->compunits = Hash_NewTable (509, compunit_get_key, 0, pr, + pr->hashlink_freelist); + + PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); +} + +void +PR_Debug_Init_Cvars (void) +{ + pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL, + "enable progs debugging"); + pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f, + "where to look (within gamedir) for source " + "files"); +} diff --git a/libs/gamecode/pr_edict.c b/libs/gamecode/pr_edict.c index 2241e3e9f..55a96124e 100644 --- a/libs/gamecode/pr_edict.c +++ b/libs/gamecode/pr_edict.c @@ -34,22 +34,10 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cbuf.h" -#include "QF/crc.h" #include "QF/cvar.h" -#include "QF/dstring.h" -#include "QF/hash.h" -#include "QF/idparse.h" #include "QF/progs.h" -#include "QF/qdefs.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -63,16 +51,14 @@ ED_ClearEdict (progs_t *pr, edict_t *e, int val) { pr_uint_t i; - if (NUM_FOR_EDICT (pr, e) < *pr->reserved_edicts) + if (pr->reserved_edicts && NUM_FOR_EDICT (pr, e) < *pr->reserved_edicts) Sys_Printf ("clearing reserved edict %d\n", NUM_FOR_EDICT (pr, e)); for (i=0; i < pr->progs->entityfields; i++) - e->v[i].integer_var = val; + E_INT (e, i) = val; e->free = false; } /* - ED_Alloc - Either finds a free edict, or allocates a new one. Try to avoid reusing an entity that was recently freed, because it can cause the client to think the entity morphed into something else @@ -86,6 +72,9 @@ ED_Alloc (progs_t *pr) edict_t *e; int start = pr->reserved_edicts ? *pr->reserved_edicts : 0; + if (!pr->num_edicts) { + PR_RunError (pr, "Edicts not supported in this VM\n"); + } for (i = start + 1; i < *pr->num_edicts; i++) { e = EDICT_NUM (pr, i); // the first couple seconds of server time can involve a lot of @@ -145,6 +134,10 @@ ED_Free (progs_t *pr, edict_t *ed) VISIBLE void ED_PrintNum (progs_t *pr, pr_int_t ent) { + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } ED_Print (pr, EDICT_NUM (pr, ent)); } @@ -158,13 +151,17 @@ ED_PrintEdicts (progs_t *pr, const char *fieldval) { pr_int_t i; int count; - ddef_t *def; + pr_def_t *def; def = PR_FindField(pr, "classname"); + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } if (fieldval && fieldval[0] && def) { count = 0; - for (i = 0; i < *(pr)->num_edicts; i++) + for (i = 0; i < *pr->num_edicts; i++) if (strequal(fieldval, E_GSTRING (pr, EDICT_NUM(pr, i), def->ofs))) { ED_PrintNum (pr, i); @@ -172,9 +169,9 @@ ED_PrintEdicts (progs_t *pr, const char *fieldval) } Sys_Printf ("%i entities\n", count); } else { - for (i = 0; i < *(pr)->num_edicts; i++) + for (i = 0; i < *pr->num_edicts; i++) ED_PrintNum (pr, i); - Sys_Printf ("%i entities\n", *(pr)->num_edicts); + Sys_Printf ("%i entities\n", *pr->num_edicts); } } @@ -188,14 +185,18 @@ ED_Count (progs_t *pr) { pr_int_t i; int active, models, solid, step, zombie; - ddef_t *solid_def; - ddef_t *model_def; + pr_def_t *solid_def; + pr_def_t *model_def; edict_t *ent; + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } solid_def = PR_FindField (pr, "solid"); model_def = PR_FindField (pr, "model"); active = models = solid = step = zombie = 0; - for (i = 0; i < *(pr)->num_edicts; i++) { + for (i = 0; i < *pr->num_edicts; i++) { ent = EDICT_NUM (pr, i); if (ent->free) { if (pr->globals.time && *pr->globals.time - ent->freetime <= 0.5) @@ -203,13 +204,13 @@ ED_Count (progs_t *pr) continue; } active++; - if (solid_def && ent->v[solid_def->ofs].float_var) + if (solid_def && E_FLOAT (ent, solid_def->ofs)) solid++; - if (model_def && ent->v[model_def->ofs].float_var) + if (model_def && E_FLOAT (ent, model_def->ofs)) models++; } - Sys_Printf ("num_edicts:%3i\n", *(pr)->num_edicts); + Sys_Printf ("num_edicts:%3i\n", *pr->num_edicts); Sys_Printf ("active :%3i\n", active); Sys_Printf ("view :%3i\n", models); Sys_Printf ("touch :%3i\n", solid); @@ -219,12 +220,10 @@ ED_Count (progs_t *pr) edict_t * ED_EdictNum (progs_t *pr, pr_int_t n) { - pr_int_t offs = n * pr->pr_edict_size; - - if (offs < 0 || n >= pr->pr_edictareasize) + if (n < 0 || n >= *pr->num_edicts) PR_RunError (pr, "EDICT_NUM: bad number %d", n); - return PROG_TO_EDICT (pr, offs); + return PR_edicts(pr) + n; } pr_int_t @@ -234,9 +233,9 @@ ED_NumForEdict (progs_t *pr, edict_t *e) b = NUM_FOR_BAD_EDICT (pr, e); - if (b && (b < 0 || b >= *(pr)->num_edicts)) + if (b && (b < 0 || b >= *pr->num_edicts)) PR_RunError (pr, "NUM_FOR_EDICT: bad pointer %d %p %p", b, e, - *(pr)->edicts); + pr->pr_edicts); return b; } @@ -244,7 +243,10 @@ ED_NumForEdict (progs_t *pr, edict_t *e) qboolean PR_EdictValid (progs_t *pr, pr_int_t e) { - if (e < 0 || e >= pr->pr_edictareasize) + if (!pr->num_edicts) { + return false; + } + if (e < 0 || e >= pr->pr_edict_area_size) return false; if (e % pr->pr_edict_size) return false; diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 579992271..a2455a0fb 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -55,54 +55,63 @@ VISIBLE void PR_RunError (progs_t * pr, const char *error, ...) { - dstring_t *string = dstring_new (); + dstring_t *string = dstring_new ();//FIXME leaks when debugging va_list argptr; va_start (argptr, error); dvsprintf (string, error, argptr); va_end (argptr); + if (pr->debug_handler) { + pr->debug_handler (prd_runerror, string->str, pr->debug_data); + // not expected to return, but if so, behave as if there was no handler + } + Sys_Printf ("%s\n", string->str); PR_DumpState (pr); // dump the stack so PR_Error can shutdown functions pr->pr_depth = 0; + pr->localstack_used = 0; PR_Error (pr, "Program error: %s", string->str); } -VISIBLE void -PR_SaveParams (progs_t *pr) +VISIBLE pr_stashed_params_t * +_PR_SaveParams (progs_t *pr, pr_stashed_params_t *params) { int i; int size = pr->pr_param_size * sizeof (pr_type_t); - pr->pr_param_ptrs[0] = pr->pr_params[0]; - pr->pr_param_ptrs[1] = pr->pr_params[1]; + params->param_ptrs[0] = pr->pr_params[0]; + params->param_ptrs[1] = pr->pr_params[1]; pr->pr_params[0] = pr->pr_real_params[0]; pr->pr_params[1] = pr->pr_real_params[1]; for (i = 0; i < pr->pr_argc; i++) { - memcpy (pr->pr_saved_params + i * pr->pr_param_size, + memcpy (params->params + i * pr->pr_param_size, pr->pr_real_params[i], size); - if (i < 2) - memcpy (pr->pr_real_params[i], pr->pr_param_ptrs[0], size); + if (i < 2) { //XXX FIXME what the what?!? + memcpy (pr->pr_real_params[i], params->param_ptrs[0], size); + } } - pr->pr_saved_argc = pr->pr_argc; + params->argc = pr->pr_argc; + return params; } VISIBLE void -PR_RestoreParams (progs_t *pr) +PR_RestoreParams (progs_t *pr, pr_stashed_params_t *params) { int i; int size = pr->pr_param_size * sizeof (pr_type_t); - pr->pr_params[0] = pr->pr_param_ptrs[0]; - pr->pr_params[1] = pr->pr_param_ptrs[1]; - pr->pr_argc = pr->pr_saved_argc; - for (i = 0; i < pr->pr_argc; i++) + pr->pr_params[0] = params->param_ptrs[0]; + pr->pr_params[1] = params->param_ptrs[1]; + pr->pr_argc = params->argc; + for (i = 0; i < pr->pr_argc; i++) { memcpy (pr->pr_real_params[i], - pr->pr_saved_params + i * pr->pr_param_size, size); + params->params + i * pr->pr_param_size, size); + } } VISIBLE inline void @@ -115,11 +124,12 @@ PR_PushFrame (progs_t *pr) frame = pr->pr_stack + pr->pr_depth++; - frame->s = pr->pr_xstatement; - frame->f = pr->pr_xfunction; - frame->tstr = pr->pr_xtstr; + frame->staddr = pr->pr_xstatement; + frame->func = pr->pr_xfunction; + frame->tstr = pr->pr_xtstr; - pr->pr_xtstr = 0; + pr->pr_xtstr = pr->pr_pushtstr; + pr->pr_pushtstr = 0; pr->pr_xfunction = 0; } @@ -133,15 +143,41 @@ PR_PopFrame (progs_t *pr) if (pr->pr_xtstr) PR_FreeTempStrings (pr); + // normally, this won't happen, but if a builtin pushed a temp string + // when calling a function and the callee was another builtin that + // did not call a progs function, then the push strings will still be + // valid because PR_EnterFunction was never called + // however, not if a temp string survived: better to hold on to the push + // strings a little longer than lose one erroneously + if (!pr->pr_xtstr && pr->pr_pushtstr) { + pr->pr_xtstr = pr->pr_pushtstr; + pr->pr_pushtstr = 0; + PR_FreeTempStrings (pr); + } // up stack frame = pr->pr_stack + --pr->pr_depth; - pr->pr_xfunction = frame->f; - pr->pr_xstatement = frame->s; + pr->pr_xfunction = frame->func; + pr->pr_xstatement = frame->staddr; pr->pr_xtstr = frame->tstr; } +static __attribute__((pure)) long +align_offset (long offset, dparmsize_t parmsize) +{ + int mask = (1 << parmsize.alignment) - 1; + return (offset + mask) & ~mask; +} + +static void +copy_param (pr_type_t *dst, pr_type_t *src, size_t size) +{ + while (size--) { + memcpy (dst++, src++, sizeof (pr_type_t)); + } +} + /** Setup the stackframe prior to calling a progs function. Saves all local data the called function will trample on and copies the parameters used by the function into the function's local data space. @@ -153,39 +189,52 @@ PR_PopFrame (progs_t *pr) static void PR_EnterFunction (progs_t *pr, bfunction_t *f) { - pr_int_t i, j, c, o; - pr_int_t k; - pr_int_t count = 0; - int size[2] = {0, 0}; - long paramofs = 0; - long offs; + pr_int_t i; + pr_type_t *dstParams[MAX_PARMS]; + pointer_t paramofs = 0; + + if (pr->pr_trace && !pr->debug_handler) { + Sys_Printf ("Entering function %s\n", + PR_GetString (pr, f->descriptor->s_name)); + } PR_PushFrame (pr); if (f->numparms > 0) { - for (i = 0; i < 2 && i < f->numparms; i++) { - paramofs += f->parm_size[i]; - size[i] = f->parm_size[i]; + paramofs = f->parm_start; + for (i = 0; i < f->numparms; i++) { + paramofs = align_offset (paramofs, f->parm_size[i]); + dstParams[i] = pr->pr_globals + paramofs; + paramofs += f->parm_size[i].size; + if (pr->pr_params[i] != pr->pr_real_params[i]) { + copy_param (pr->pr_real_params[i], pr->pr_params[i], + f->parm_size[i].size); + pr->pr_params[i] = pr->pr_real_params[i]; + } } - count = i; } else if (f->numparms < 0) { - for (i = 0; i < 2 && i < -f->numparms - 1; i++) { - paramofs += f->parm_size[i]; - size[i] = f->parm_size[i]; + paramofs = f->parm_start + 2; // argc and argv + for (i = 0; i < -f->numparms - 1; i++) { + paramofs = align_offset (paramofs, f->parm_size[i]); + dstParams[i] = pr->pr_globals + paramofs; + paramofs += f->parm_size[i].size; + if (pr->pr_params[i] != pr->pr_real_params[i]) { + copy_param (pr->pr_real_params[i], pr->pr_params[i], + f->parm_size[i].size); + pr->pr_params[i] = pr->pr_real_params[i]; + } } - for (; i < 2; i++) { - paramofs += pr->pr_param_size; - size[i] = pr->pr_param_size; + dparmsize_t parmsize = { pr->pr_param_size, pr->pr_param_alignment }; + paramofs = align_offset (paramofs, parmsize ); + if (i < MAX_PARMS) { + dstParams[i] = pr->pr_globals + paramofs; } - count = i; - } - - for (i = 0; i < count && i < pr->pr_argc; i++) { - offs = (pr->pr_params[i] - pr->pr_globals) - f->parm_start; - if (offs >= 0 && offs < paramofs) { - memcpy (pr->pr_real_params[i], pr->pr_params[i], - size[i] * sizeof (pr_type_t)); - pr->pr_params[i] = pr->pr_real_params[i]; + for (; i < pr->pr_argc; i++) { + if (pr->pr_params[i] != pr->pr_real_params[i]) { + copy_param (pr->pr_real_params[i], pr->pr_params[i], + parmsize.size); + pr->pr_params[i] = pr->pr_real_params[i]; + } } } @@ -194,64 +243,69 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) pr->pr_xstatement = f->first_statement - 1; // offset the st++ // save off any locals that the new function steps on - c = f->locals; - if (pr->localstack_used + c > LOCALSTACK_SIZE) + if (pr->localstack_used + f->locals > LOCALSTACK_SIZE) PR_RunError (pr, "PR_EnterFunction: locals stack overflow"); memcpy (&pr->localstack[pr->localstack_used], &pr->pr_globals[f->parm_start], - sizeof (pr_type_t) * c); - pr->localstack_used += c; + sizeof (pr_type_t) * f->locals); + pr->localstack_used += f->locals; if (pr_deadbeef_locals->int_val) - for (k = f->parm_start; k < f->parm_start + c; k++) - pr->pr_globals[k].integer_var = 0xdeadbeef; + for (i = f->parm_start; i < f->parm_start + f->locals; i++) + pr->pr_globals[i].integer_var = 0xdeadbeef; // copy parameters - o = f->parm_start; if (f->numparms >= 0) { for (i = 0; i < f->numparms; i++) { - for (j = 0; j < f->parm_size[i]; j++) { - memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j, - sizeof (pr_type_t)); - o++; - } + copy_param (dstParams[i], pr->pr_params[i], f->parm_size[i].size); } } else { - pr_type_t *argc = &pr->pr_globals[o++]; - pr_type_t *argv = &pr->pr_globals[o++]; + int copy_args; + pr_type_t *argc = &pr->pr_globals[f->parm_start + 0]; + pr_type_t *argv = &pr->pr_globals[f->parm_start + 1]; for (i = 0; i < -f->numparms - 1; i++) { - for (j = 0; j < f->parm_size[i]; j++) { - memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j, - sizeof (pr_type_t)); - o++; - } + copy_param (dstParams[i], pr->pr_params[i], f->parm_size[i].size); } - argc->integer_var = pr->pr_argc - i; - argv->integer_var = o; + copy_args = pr->pr_argc - i; + argc->integer_var = copy_args; + argv->integer_var = dstParams[i] - pr->pr_globals; if (i < MAX_PARMS) { - memcpy (&pr->pr_globals[o], &P_INT (pr, i), - (MAX_PARMS - i) * pr->pr_param_size * sizeof (pr_type_t)); + memcpy (dstParams[i], pr->pr_params[i], + (copy_args * pr->pr_param_size) * sizeof (pr_type_t)); } } } static void -PR_LeaveFunction (progs_t *pr) +PR_LeaveFunction (progs_t *pr, int to_engine) { - int c; bfunction_t *f = pr->pr_xfunction; PR_PopFrame (pr); + if (pr->pr_trace && !pr->debug_handler) { + Sys_Printf ("Leaving function %s\n", + PR_GetString (pr, f->descriptor->s_name)); + if (to_engine) { + Sys_Printf ("Returning to engine\n"); + } else { + bfunction_t *rf = pr->pr_xfunction; + if (rf) { + Sys_Printf ("Returning to function %s\n", + PR_GetString (pr, rf->descriptor->s_name)); + } + } + } + // restore locals from the stack - c = f->locals; - pr->localstack_used -= c; + pr->localstack_used -= f->locals; if (pr->localstack_used < 0) PR_RunError (pr, "PR_LeaveFunction: locals stack underflow"); memcpy (&pr->pr_globals[f->parm_start], - &pr->localstack[pr->localstack_used], sizeof (pr_type_t) * c); + &pr->localstack[pr->localstack_used], + sizeof (pr_type_t) * f->locals); } VISIBLE void @@ -280,12 +334,15 @@ PR_BoundsCheck (progs_t *pr, int addr, etype_t type) #define OPB (*op_b) #define OPC (*op_c) +#define OPA_double_var (*((double *) (op_a))) +#define OPB_double_var (*((double *) (op_b))) +#define OPC_double_var (*((double *) (op_c))) + /* This gets around the problem of needing to test for -0.0 but denormals causing exceptions (or wrong results for what we need) on the alpha. */ -#define FNZ(x) ((x).uinteger_var && (x).uinteger_var != 0x80000000u) - +#define FNZ(x) ((x).uinteger_var & ~0x80000000u) static int signal_hook (int sig, void *data) @@ -317,6 +374,8 @@ signal_hook (int sig, void *data) return 1; case OP_MOD_I: case OP_MOD_F: + case OP_REM_I: + case OP_REM_F: OPC.integer_var = 0x00000000; return 1; default: @@ -346,7 +405,7 @@ PR_CallFunction (progs_t *pr, func_t fnum) f = pr->function_table + fnum; if (f->first_statement < 0) { // negative statements are built in functions - if (pr->pr_trace) { + if (pr->pr_trace && !pr->debug_handler) { Sys_Printf ("Calling builtin %s @ %p\n", PR_GetString (pr, f->descriptor->s_name), f->func); } @@ -358,20 +417,39 @@ PR_CallFunction (progs_t *pr, func_t fnum) } } +static void +check_stack_pointer (progs_t *pr, pointer_t stack, int size) +{ + if (stack < pr->stack_bottom) { + PR_RunError (pr, "Progs stack overflow"); + } + if (stack > pr->globals_size - size) { + PR_RunError (pr, "Progs stack underflow"); + } +} + +static inline void +pr_memset (pr_type_t *dst, int val, int count) +{ + while (count-- > 0) { + (*dst++).integer_var = val; + } +} + /* PR_ExecuteProgram The interpretation main loop */ VISIBLE void -PR_ExecuteProgram (progs_t * pr, func_t fnum) +PR_ExecuteProgram (progs_t *pr, func_t fnum) { int exitdepth, profile, startprofile; + int fldofs; pr_uint_t pointer; dstatement_t *st; - edict_t *ed; pr_type_t *ptr; - pr_type_t old_val = {0}, *watch = 0; + pr_type_t old_val = {0}; // make a stack frame exitdepth = pr->pr_depth; @@ -380,6 +458,10 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) Sys_PushSignalHook (signal_hook, pr); Sys_PushErrorHandler (error_handler, pr); + if (pr->debug_handler) { + pr->debug_handler (prd_subenter, &fnum, pr->debug_data); + } + if (!PR_CallFunction (pr, fnum)) { // called a builtin instead of progs code goto exit_program; @@ -387,8 +469,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) st = pr->pr_statements + pr->pr_xstatement; if (pr->watch) { - watch = pr->watch; - old_val = *watch; + old_val = *pr->watch; } while (1) { @@ -406,18 +487,35 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) op_b = pr->pr_globals + st->b; op_c = pr->pr_globals + st->c; - if (pr->pr_trace) - PR_PrintStatement (pr, st, 1); + if (pr->pr_trace) { + if (pr->debug_handler) { + pr->debug_handler (prd_trace, 0, pr->debug_data); + } else { + PR_PrintStatement (pr, st, 1); + } + } - switch (st->op) { + if (st->op & OP_BREAK) { + if (pr->debug_handler) { + pr->debug_handler (prd_breakpoint, 0, pr->debug_data); + } else { + PR_RunError (pr, "breakpoint hit"); + } + } + + pr_opcode_e op = st->op & ~OP_BREAK; + switch (op) { + case OP_ADD_D: + OPC_double_var = OPA_double_var + OPB_double_var; + break; case OP_ADD_F: OPC.float_var = OPA.float_var + OPB.float_var; break; case OP_ADD_V: - VectorAdd (OPA.vector_var, OPB.vector_var, OPC.vector_var); + VectorAdd (&OPA.vector_var, &OPB.vector_var, &OPC.vector_var); break; case OP_ADD_Q: - QuatAdd (OPA.quat_var, OPB.quat_var, OPC.quat_var); + QuatAdd (&OPA.quat_var, &OPB.quat_var, &OPC.quat_var); break; case OP_ADD_S: OPC.string_var = PR_CatStrings (pr, @@ -426,27 +524,50 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_GetString (pr, OPB.string_var)); break; + case OP_SUB_D: + OPC_double_var = OPA_double_var - OPB_double_var; + break; case OP_SUB_F: OPC.float_var = OPA.float_var - OPB.float_var; break; case OP_SUB_V: - VectorSubtract (OPA.vector_var, OPB.vector_var, OPC.vector_var); + VectorSubtract (&OPA.vector_var, &OPB.vector_var, + &OPC.vector_var); break; case OP_SUB_Q: - QuatSubtract (OPA.quat_var, OPB.quat_var, OPC.quat_var); + QuatSubtract (&OPA.quat_var, &OPB.quat_var, &OPC.quat_var); + break; + case OP_MUL_D: + OPC_double_var = OPA_double_var * OPB_double_var; break; case OP_MUL_F: OPC.float_var = OPA.float_var * OPB.float_var; break; case OP_MUL_V: - OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var); + OPC.float_var = DotProduct (&OPA.vector_var, &OPB.vector_var); + break; + case OP_MUL_DV: + { + // avoid issues with the likes of x = x.x * x; + // makes for faster code, too + double scale = OPA_double_var; + VectorScale (&OPB.vector_var, scale, &OPC.vector_var); + } + break; + case OP_MUL_VD: + { + // avoid issues with the likes of x = x * x.x; + // makes for faster code, too + double scale = OPB_double_var; + VectorScale (&OPA.vector_var, scale, &OPC.vector_var); + } break; case OP_MUL_FV: { // avoid issues with the likes of x = x.x * x; // makes for faster code, too float scale = OPA.float_var; - VectorScale (OPB.vector_var, scale, OPC.vector_var); + VectorScale (&OPB.vector_var, scale, &OPC.vector_var); } break; case OP_MUL_VF: @@ -454,21 +575,37 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) // avoid issues with the likes of x = x * x.x; // makes for faster code, too float scale = OPB.float_var; - VectorScale (OPA.vector_var, scale, OPC.vector_var); + VectorScale (&OPA.vector_var, scale, &OPC.vector_var); } break; case OP_MUL_Q: - QuatMult (OPA.quat_var, OPB.quat_var, OPC.quat_var); + QuatMult (&OPA.quat_var, &OPB.quat_var, &OPC.quat_var); break; case OP_MUL_QV: - QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var); + QuatMultVec (&OPA.quat_var, &OPB.vector_var, &OPC.vector_var); + break; + case OP_MUL_DQ: + { + // avoid issues with the likes of x = x.s * x; + // makes for faster code, too + double scale = OPA_double_var; + QuatScale (&OPB.quat_var, scale, &OPC.quat_var); + } + break; + case OP_MUL_QD: + { + // avoid issues with the likes of x = x * x.s; + // makes for faster code, too + double scale = OPB_double_var; + QuatScale (&OPA.quat_var, scale, &OPC.quat_var); + } break; case OP_MUL_FQ: { // avoid issues with the likes of x = x.s * x; // makes for faster code, too float scale = OPA.float_var; - QuatScale (OPB.quat_var, scale, OPC.quat_var); + QuatScale (&OPB.quat_var, scale, &OPC.quat_var); } break; case OP_MUL_QF: @@ -476,11 +613,14 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) // avoid issues with the likes of x = x * x.s; // makes for faster code, too float scale = OPB.float_var; - QuatScale (OPA.quat_var, scale, OPC.quat_var); + QuatScale (&OPA.quat_var, scale, &OPC.quat_var); } break; case OP_CONJ_Q: - QuatConj (OPA.quat_var, OPC.quat_var); + QuatConj (&OPA.quat_var, &OPC.quat_var); + break; + case OP_DIV_D: + OPC_double_var = OPA_double_var / OPB_double_var; break; case OP_DIV_F: OPC.float_var = OPA.float_var / OPB.float_var; @@ -534,10 +674,10 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) OPC.integer_var = !FNZ (OPA); break; case OP_NOT_V: - OPC.integer_var = VectorIsZero (OPA.vector_var); + OPC.integer_var = VectorIsZero (&OPA.vector_var); break; case OP_NOT_Q: - OPC.integer_var = QuatIsZero (OPA.quat_var); + OPC.integer_var = QuatIsZero (&OPA.quat_var); break; case OP_NOT_S: OPC.integer_var = !OPA.string_var || @@ -553,11 +693,11 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) OPC.integer_var = OPA.float_var == OPB.float_var; break; case OP_EQ_V: - OPC.integer_var = VectorCompare (OPA.vector_var, - OPB.vector_var); + OPC.integer_var = VectorCompare (&OPA.vector_var, + &OPB.vector_var); break; case OP_EQ_Q: - OPC.integer_var = QuatCompare (OPA.quat_var, OPB.quat_var); + OPC.integer_var = QuatCompare (&OPA.quat_var, &OPB.quat_var); break; case OP_EQ_E: OPC.integer_var = OPA.integer_var == OPB.integer_var; @@ -569,11 +709,11 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) OPC.integer_var = OPA.float_var != OPB.float_var; break; case OP_NE_V: - OPC.integer_var = !VectorCompare (OPA.vector_var, - OPB.vector_var); + OPC.integer_var = !VectorCompare (&OPA.vector_var, + &OPB.vector_var); break; case OP_NE_Q: - OPC.integer_var = !QuatCompare (OPA.quat_var, OPB.quat_var); + OPC.integer_var = !QuatCompare (&OPA.quat_var, &OPB.quat_var); break; case OP_LE_S: case OP_GE_S: @@ -614,10 +754,13 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) OPB.integer_var = OPA.integer_var; break; case OP_STORE_V: - VectorCopy (OPA.vector_var, OPB.vector_var); + VectorCopy (&OPA.vector_var, &OPB.vector_var); break; case OP_STORE_Q: - QuatCopy (OPA.quat_var, OPB.quat_var); + QuatCopy (&OPA.quat_var, &OPB.quat_var); + break; + case OP_STORE_D: + OPB_double_var = OPA_double_var; break; case OP_STOREP_F: @@ -640,7 +783,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (OPA.vector_var, ptr->vector_var); + VectorCopy (&OPA.vector_var, &ptr->vector_var); break; case OP_STOREP_Q: pointer = OPB.integer_var; @@ -648,13 +791,21 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (OPA.quat_var, ptr->quat_var); + QuatCopy (&OPA.quat_var, &ptr->quat_var); + break; + case OP_STOREP_D: + pointer = OPB.integer_var; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_double); + } + ptr = pr->pr_globals + pointer; + *(double *) ptr = OPA_double_var; break; case OP_ADDRESS: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 - || OPA.entity_var >= pr->pr_edictareasize) + || OPA.entity_var >= pr->pr_edict_area_size) PR_RunError (pr, "Progs attempted to address an out " "of bounds edict"); if (OPA.entity_var == 0 && pr->null_bad) @@ -663,8 +814,8 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_RunError (pr, "Progs attempted to address an " "invalid field in an edict"); } - ed = PROG_TO_EDICT (pr, OPA.entity_var); - OPC.integer_var = &ed->v[OPB.integer_var] - pr->pr_globals; + fldofs = OPA.entity_var + OPB.integer_var; + OPC.integer_var = &pr->pr_edict_area[fldofs] - pr->pr_globals; break; case OP_ADDRESS_VOID: case OP_ADDRESS_F: @@ -676,6 +827,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) case OP_ADDRESS_FN: case OP_ADDRESS_I: case OP_ADDRESS_P: + case OP_ADDRESS_D: OPC.integer_var = st->a; break; @@ -688,41 +840,54 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) case OP_LOAD_P: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 - || OPA.entity_var >= pr->pr_edictareasize) + || OPA.entity_var >= pr->pr_edict_area_size) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } - ed = PROG_TO_EDICT (pr, OPA.entity_var); - OPC.integer_var = ed->v[OPB.integer_var].integer_var; + fldofs = OPA.entity_var + OPB.integer_var; + OPC.integer_var = pr->pr_edict_area[fldofs].integer_var; break; case OP_LOAD_V: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 - || OPA.entity_var >= pr->pr_edictareasize) + || OPA.entity_var >= pr->pr_edict_area_size) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var + 2 >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } - ed = PROG_TO_EDICT (pr, OPA.entity_var); - memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC)); + fldofs = OPA.entity_var + OPB.integer_var; + memcpy (&OPC, &pr->pr_edict_area[fldofs], 3 * sizeof (OPC)); break; case OP_LOAD_Q: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 - || OPA.entity_var >= pr->pr_edictareasize) + || OPA.entity_var >= pr->pr_edict_area_size) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var + 3 >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } - ed = PROG_TO_EDICT (pr, OPA.entity_var); - memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC)); + fldofs = OPA.entity_var + OPB.integer_var; + memcpy (&OPC, &pr->pr_edict_area[fldofs], 4 * sizeof (OPC)); + break; + case OP_LOAD_D: + if (pr_boundscheck->int_val) { + if (OPA.entity_var < 0 + || OPA.entity_var >= pr->pr_edict_area_size) + PR_RunError (pr, "Progs attempted to read an out of " + "bounds edict number"); + if (OPB.uinteger_var + 1 >= pr->progs->entityfields) + PR_RunError (pr, "Progs attempted to read an invalid " + "field in an edict"); + } + fldofs = OPA.entity_var + OPB.integer_var; + memcpy (&OPC, &pr->pr_edict_area[fldofs], sizeof (double)); break; case OP_LOADB_F: @@ -745,7 +910,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (ptr->vector_var, OPC.vector_var); + VectorCopy (&ptr->vector_var, &OPC.vector_var); break; case OP_LOADB_Q: pointer = OPA.integer_var + OPB.integer_var; @@ -753,7 +918,15 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (ptr->quat_var, OPC.quat_var); + QuatCopy (&ptr->quat_var, &OPC.quat_var); + break; + case OP_LOADB_D: + pointer = OPA.integer_var + OPB.integer_var; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_double); + } + ptr = pr->pr_globals + pointer; + OPC_double_var = *(double *) ptr; break; case OP_LOADBI_F: @@ -776,7 +949,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (ptr->vector_var, OPC.vector_var); + VectorCopy (&ptr->vector_var, &OPC.vector_var); break; case OP_LOADBI_Q: pointer = OPA.integer_var + (short) st->b; @@ -784,7 +957,15 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (ptr->quat_var, OPC.quat_var); + QuatCopy (&ptr->quat_var, &OPC.quat_var); + break; + case OP_LOADBI_D: + pointer = OPA.integer_var + (short) st->b; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_quat); + } + ptr = pr->pr_globals + pointer; + OPC_double_var = *(double *) ptr; break; case OP_LEA: @@ -817,7 +998,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (OPA.vector_var, ptr->vector_var); + VectorCopy (&OPA.vector_var, &ptr->vector_var); break; case OP_STOREB_Q: pointer = OPB.integer_var + OPC.integer_var; @@ -825,7 +1006,15 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (OPA.quat_var, ptr->quat_var); + QuatCopy (&OPA.quat_var, &ptr->quat_var); + break; + case OP_STOREB_D: + pointer = OPB.integer_var + OPC.integer_var; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_quat); + } + ptr = pr->pr_globals + pointer; + *(double *) ptr = OPA_double_var; break; case OP_STOREBI_F: @@ -848,7 +1037,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (OPA.vector_var, ptr->vector_var); + VectorCopy (&OPA.vector_var, &ptr->vector_var); break; case OP_STOREBI_Q: pointer = OPB.integer_var + (short) st->c; @@ -856,7 +1045,327 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (OPA.quat_var, ptr->quat_var); + QuatCopy (&OPA.quat_var, &ptr->quat_var); + break; + case OP_STOREBI_D: + pointer = OPB.integer_var + (short) st->c; + if (pr_boundscheck->int_val) { + PR_BoundsCheck (pr, pointer, ev_quat); + } + ptr = pr->pr_globals + pointer; + *(double *) ptr = OPA_double_var; + break; + + case OP_PUSH_F: + case OP_PUSH_FLD: + case OP_PUSH_ENT: + case OP_PUSH_S: + case OP_PUSH_FN: + case OP_PUSH_I: + case OP_PUSH_P: + { + pointer_t stack = *pr->globals.stack - 1; + pr_type_t *stk = pr->pr_globals + stack; + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 1); + } + stk->integer_var = OPA.integer_var; + *pr->globals.stack = stack; + } + break; + case OP_PUSH_V: + { + pointer_t stack = *pr->globals.stack - 3; + pr_type_t *stk = pr->pr_globals + stack; + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 3); + } + memcpy (stk, &OPA, 3 * sizeof (OPC)); + *pr->globals.stack = stack; + } + break; + case OP_PUSH_Q: + { + pointer_t stack = *pr->globals.stack - 4; + pr_type_t *stk = pr->pr_globals + stack; + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 4); + } + memcpy (stk, &OPA, 4 * sizeof (OPC)); + *pr->globals.stack = stack; + } + break; + + case OP_PUSHB_F: + case OP_PUSHB_S: + case OP_PUSHB_ENT: + case OP_PUSHB_FLD: + case OP_PUSHB_FN: + case OP_PUSHB_I: + case OP_PUSHB_P: + { + pointer_t stack = *pr->globals.stack - 1; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + OPB.integer_var; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 1); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + stk->integer_var = ptr->integer_var; + *pr->globals.stack = stack; + } + break; + case OP_PUSHB_V: + { + pointer_t stack = *pr->globals.stack - 3; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + OPB.integer_var; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 3); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + VectorCopy (&ptr->vector_var, &stk->vector_var); + *pr->globals.stack = stack; + } + break; + case OP_PUSHB_Q: + { + pointer_t stack = *pr->globals.stack - 4; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + OPB.integer_var; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 4); + PR_BoundsCheck (pr, pointer, ev_quat); + } + + QuatCopy (&ptr->quat_var, &stk->quat_var); + *pr->globals.stack = stack; + } + break; + + case OP_PUSHBI_F: + case OP_PUSHBI_S: + case OP_PUSHBI_ENT: + case OP_PUSHBI_FLD: + case OP_PUSHBI_FN: + case OP_PUSHBI_I: + case OP_PUSHBI_P: + { + pointer_t stack = *pr->globals.stack - 1; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + st->b; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 1); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + stk->integer_var = ptr->integer_var; + *pr->globals.stack = stack; + } + break; + case OP_PUSHBI_V: + { + pointer_t stack = *pr->globals.stack - 3; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + st->b; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 3); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + VectorCopy (&ptr->vector_var, &stk->vector_var); + *pr->globals.stack = stack; + } + break; + case OP_PUSHBI_Q: + { + pointer_t stack = *pr->globals.stack - 4; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + st->b; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 4); + PR_BoundsCheck (pr, pointer, ev_quat); + } + + QuatCopy (&ptr->quat_var, &stk->quat_var); + *pr->globals.stack = stack; + } + break; + + case OP_POP_F: + case OP_POP_FLD: + case OP_POP_ENT: + case OP_POP_S: + case OP_POP_FN: + case OP_POP_I: + case OP_POP_P: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 1); + } + stk->integer_var = OPA.integer_var; + *pr->globals.stack = stack + 1; + } + break; + case OP_POP_V: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 3); + } + memcpy (stk, &OPA, 3 * sizeof (OPC)); + *pr->globals.stack = stack + 3; + } + break; + case OP_POP_Q: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 4); + } + memcpy (stk, &OPA, 4 * sizeof (OPC)); + *pr->globals.stack = stack + 4; + } + break; + + case OP_POPB_F: + case OP_POPB_S: + case OP_POPB_ENT: + case OP_POPB_FLD: + case OP_POPB_FN: + case OP_POPB_I: + case OP_POPB_P: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + OPB.integer_var; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 1); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + stk->integer_var = ptr->integer_var; + *pr->globals.stack = stack + 1; + } + break; + case OP_POPB_V: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + OPB.integer_var; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 3); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + VectorCopy (&ptr->vector_var, &stk->vector_var); + *pr->globals.stack = stack + 3; + } + break; + case OP_POPB_Q: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + OPB.integer_var; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 4); + PR_BoundsCheck (pr, pointer, ev_quat); + } + + QuatCopy (&ptr->quat_var, &stk->quat_var); + *pr->globals.stack = stack + 4; + } + break; + + case OP_POPBI_F: + case OP_POPBI_S: + case OP_POPBI_ENT: + case OP_POPBI_FLD: + case OP_POPBI_FN: + case OP_POPBI_I: + case OP_POPBI_P: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + st->b; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 1); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + stk->integer_var = ptr->integer_var; + *pr->globals.stack = stack + 1; + } + break; + case OP_POPBI_V: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + st->b; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 3); + PR_BoundsCheck (pr, pointer, ev_integer); + } + + VectorCopy (&ptr->vector_var, &stk->vector_var); + *pr->globals.stack = stack + 3; + } + break; + case OP_POPBI_Q: + { + pointer_t stack = *pr->globals.stack; + pr_type_t *stk = pr->pr_globals + stack; + + pointer = OPA.integer_var + st->b; + ptr = pr->pr_globals + pointer; + + if (pr_boundscheck->int_val) { + check_stack_pointer (pr, stack, 4); + PR_BoundsCheck (pr, pointer, ev_quat); + } + + QuatCopy (&ptr->quat_var, &stk->quat_var); + *pr->globals.stack = stack + 4; + } break; // ================== @@ -967,7 +1476,7 @@ op_call: case OP_RETURN_V: pr->pr_xfunction->profile += profile - startprofile; startprofile = profile; - PR_LeaveFunction (pr); + PR_LeaveFunction (pr, pr->pr_depth == exitdepth); st = pr->pr_statements + pr->pr_xstatement; if (pr->pr_depth == exitdepth) { if (pr->pr_trace && pr->pr_depth <= pr->pr_trace_depth) @@ -977,18 +1486,34 @@ op_call: } break; case OP_STATE: - ed = PROG_TO_EDICT (pr, *pr->globals.self); - ed->v[pr->fields.nextthink].float_var = *pr->globals.time + - 0.1; - ed->v[pr->fields.frame].float_var = OPA.float_var; - ed->v[pr->fields.think].func_var = OPB.func_var; + { + int self = *pr->globals.self; + int nextthink = pr->fields.nextthink; + int frame = pr->fields.frame; + int think = pr->fields.think; + fldofs = self + nextthink; + pr->pr_edict_area[fldofs].float_var = *pr->globals.time + + 0.1; + fldofs = self + frame; + pr->pr_edict_area[fldofs].float_var = OPA.float_var; + fldofs = self + think; + pr->pr_edict_area[fldofs].func_var = OPB.func_var; + } break; case OP_STATE_F: - ed = PROG_TO_EDICT (pr, *pr->globals.self); - ed->v[pr->fields.nextthink].float_var = *pr->globals.time + - OPC.float_var; - ed->v[pr->fields.frame].float_var = OPA.float_var; - ed->v[pr->fields.think].func_var = OPB.func_var; + { + int self = *pr->globals.self; + int nextthink = pr->fields.nextthink; + int frame = pr->fields.frame; + int think = pr->fields.think; + fldofs = self + nextthink; + pr->pr_edict_area[fldofs].float_var = *pr->globals.time + + OPC.float_var; + fldofs = self + frame; + pr->pr_edict_area[fldofs].float_var = OPA.float_var; + fldofs = self + think; + pr->pr_edict_area[fldofs].func_var = OPB.func_var; + } break; case OP_ADD_I: OPC.integer_var = OPA.integer_var + OPB.integer_var; @@ -999,22 +1524,58 @@ op_call: case OP_MUL_I: OPC.integer_var = OPA.integer_var * OPB.integer_var; break; -/* - case OP_DIV_VF: - { - float temp = 1.0f / OPB.float_var; - VectorScale (OPA.vector_var, temp, OPC.vector_var); - } - break; -*/ case OP_DIV_I: OPC.integer_var = OPA.integer_var / OPB.integer_var; break; case OP_MOD_I: + { + // implement true modulo for integers: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + int a = OPA.integer_var; + int b = OPB.integer_var; + int c = a % b; + // % is really remainder and so has the same sign rules + // as division: -5 % 3 = -2, so need to add b (3 here) + // if c's sign is incorrect, but only if c is non-zero + int mask = (a ^ b) >> 31; + mask &= ~(!!c + 0) + 1; // +0 to convert bool to int (gcc) + OPC.integer_var = c + (mask & b); + } + break; + case OP_REM_I: OPC.integer_var = OPA.integer_var % OPB.integer_var; break; + case OP_MOD_D: + { + double a = OPA_double_var; + double b = OPB_double_var; + // floating point modulo is so much easier :P + OPC_double_var = a - b * floor (a / b); + } + break; + case OP_REM_D: + { + double a = OPA_double_var; + double b = OPB_double_var; + OPC_double_var = a - b * trunc (a / b); + } + break; case OP_MOD_F: - OPC.float_var = (int) OPA.float_var % (int) OPB.float_var; + { + float a = OPA.float_var; + float b = OPB.float_var; + OPC.float_var = a - b * floorf (a / b); + } + break; + case OP_REM_F: + { + float a = OPA.float_var; + float b = OPB.float_var; + OPC.float_var = a - b * truncf (a / b); + } break; case OP_CONV_IF: OPC.float_var = OPA.integer_var; @@ -1104,6 +1665,57 @@ op_call: pr->pr_globals + OPA.integer_var, st->b * 4); break; + case OP_MEMSETI: + pr_memset (&OPC, OPA.integer_var, st->b); + break; + case OP_MEMSETP: + if (pr_boundscheck->int_val) { + PR_BoundsCheckSize (pr, OPC.pointer_var, OPB.integer_var); + } + pr_memset (pr->pr_globals + OPC.pointer_var, OPA.integer_var, + OPB.integer_var); + break; + case OP_MEMSETPI: + if (pr_boundscheck->int_val) { + PR_BoundsCheckSize (pr, OPC.pointer_var, st->b); + } + pr_memset (pr->pr_globals + OPC.pointer_var, OPA.integer_var, + st->b); + break; + case OP_GE_D: + OPC.float_var = OPA_double_var >= OPB_double_var; + break; + case OP_LE_D: + OPC.float_var = OPA_double_var <= OPB_double_var; + break; + case OP_GT_D: + OPC.float_var = OPA_double_var > OPB_double_var; + break; + case OP_LT_D: + OPC.float_var = OPA_double_var < OPB_double_var; + break; + case OP_NOT_D: + OPC.integer_var = (op_a[0].integer_var + || (op_a[1].integer_var & ~0x80000000u)); + break; + case OP_EQ_D: + OPC.integer_var = OPA_double_var == OPB_double_var; + break; + case OP_NE_D: + OPC.integer_var = OPA_double_var != OPB_double_var; + break; + case OP_CONV_ID: + OPC_double_var = OPA.integer_var; + break; + case OP_CONV_DI: + OPC.integer_var = OPA_double_var; + break; + case OP_CONV_FD: + OPC_double_var = OPA.float_var; + break; + case OP_CONV_DF: + OPC.float_var = OPA_double_var; + break; // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized /* @@ -1118,13 +1730,24 @@ op_call: default: PR_RunError (pr, "Bad opcode %i", st->op); } - if (watch && watch->integer_var != old_val.integer_var - && (!pr->wp_conditional - || watch->integer_var == pr->wp_val.integer_var)) - PR_RunError (pr, "watchpoint hit: %d -> %d", old_val.integer_var, - watch->integer_var); + if (pr->watch && pr->watch->integer_var != old_val.integer_var) { + if (!pr->wp_conditional + || pr->watch->integer_var == pr->wp_val.integer_var) { + if (pr->debug_handler) { + pr->debug_handler (prd_watchpoint, 0, pr->debug_data); + } else { + PR_RunError (pr, "watchpoint hit: %d -> %d", + old_val.integer_var, pr->watch->integer_var); + } + } + old_val.integer_var = pr->watch->integer_var; + } } exit_program: + if (pr->debug_handler) { + pr->debug_handler (prd_subexit, 0, pr->debug_data); + } + pr->pr_argc = 0; Sys_PopErrorHandler (); Sys_PopSignalHook (); } diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index b9a6df13a..934a8480b 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -34,22 +34,17 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cmd.h" #include "QF/crc.h" #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" #include "QF/mathlib.h" #include "QF/progs.h" -#include "QF/qdefs.h" #include "QF/qendian.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -70,8 +65,8 @@ static const char * var_get_key (const void *d, void *_pr) { progs_t *pr = (progs_t*)_pr; - ddef_t *def = (ddef_t*)d; - return PR_GetString (pr, def->s_name); + pr_def_t *def = (pr_def_t*)d; + return PR_GetString (pr, def->name); } static void @@ -81,9 +76,11 @@ file_error (progs_t *pr, const char *path) } static void * -load_file (progs_t *pr, const char *path) +load_file (progs_t *pr, const char *path, off_t *size) { - return QFS_LoadHunkFile (QFS_FOpenFile (path)); + void *data = QFS_LoadHunkFile (QFS_FOpenFile (path)); + *size = qfs_filesize; + return data; } static void * @@ -97,14 +94,28 @@ free_progs_mem (progs_t *pr, void *mem) { } +static int +align_size (int size) +{ + // round off to next highest whole word address (esp for Alpha) + // this ensures that pointers in the engine data area are always + // properly aligned + size += sizeof (void*) - 1; + size &= ~(sizeof (void*) - 1); + return size; +} + VISIBLE void -PR_LoadProgsFile (progs_t *pr, QFile *file, int size, int max_edicts, int zone) +PR_LoadProgsFile (progs_t *pr, QFile *file, int size) { size_t i; int mem_size; int offset_tweak; dprograms_t progs; byte *base; + pr_def_t *xdefs_def = 0; + ddef_t *global_ddefs; + ddef_t *field_ddefs; if (!pr->file_error) pr->file_error = file_error; @@ -116,7 +127,6 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size, int max_edicts, int zone) pr->free_progs_mem = free_progs_mem; PR_Resources_Clear (pr); - PR_ClearReturnStrings (pr); if (pr->progs) pr->free_progs_mem (pr, pr->progs); pr->progs = 0; @@ -160,36 +170,29 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size, int max_edicts, int zone) // size of progs themselves pr->progs_size = size + offset_tweak; Sys_MaskPrintf (SYS_DEV, "Programs occupy %iK.\n", size / 1024); - // round off to next highest whole word address (esp for Alpha) - // this ensures that pointers in the engine data area are always - // properly aligned - pr->progs_size += sizeof (void*) - 1; - pr->progs_size &= ~(sizeof (void*) - 1); - // size of heap asked for by vm-subsystem - pr->zone_size = zone; - // round off to next highest whole word address (esp for Alpha) - // this ensures that pointers in the engine data area are always - // properly aligned - pr->zone_size += sizeof (void*) - 1; - pr->zone_size &= ~(sizeof (void*) - 1); + pr->progs_size = align_size (pr->progs_size); + pr->zone_size = align_size (pr->zone_size); + pr->stack_size = align_size (pr->stack_size); - // size of edict asked for by progs - pr->pr_edict_size = max (1, progs.entityfields) * 4; - // size of engine data - pr->pr_edict_size += sizeof (edict_t) - sizeof (pr_type_t); - // round off to next highest whole word address (esp for Alpha) - // this ensures that pointers in the engine data area are always - // properly aligned - pr->pr_edict_size += sizeof (void*) - 1; - pr->pr_edict_size &= ~(sizeof (void*) - 1); - pr->pr_edictareasize = max_edicts * pr->pr_edict_size; - pr->max_edicts = max_edicts; + // size of edict asked for by progs, but at least 1 + pr->pr_edict_size = max (1, progs.entityfields); + // round off to next highest multiple of 4 words + // this ensures that progs that try to align vectors and quaternions + // get what they want + pr->pr_edict_size += (4 - 1); + pr->pr_edict_size &= ~(4 - 1); + pr->pr_edict_area_size = pr->max_edicts * pr->pr_edict_size; - mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize; + mem_size = pr->pr_edict_area_size * sizeof (pr_type_t); + mem_size += pr->progs_size + pr->zone_size + pr->stack_size; + + // +1 for a nul terminator pr->progs = pr->allocate_progs_mem (pr, mem_size + 1); if (!pr->progs) return; + // Place a nul at the end of progs memory to ensure any unterminated + // strings within progs memory don't run off the end. ((byte *) pr->progs)[mem_size] = 0; memcpy (pr->progs, &progs, sizeof (progs)); @@ -198,40 +201,49 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size, int max_edicts, int zone) CRC_ProcessBlock (base, &pr->crc, size - sizeof (progs)); base -= sizeof (progs); // offsets are from file start - if (pr->edicts) - *pr->edicts = (edict_t *)((byte *) pr->progs + pr->progs_size); - pr->zone = (memzone_t *)((byte *) pr->progs + pr->progs_size - + pr->pr_edictareasize); + pr->pr_edict_area = (pr_type_t *)((byte *) pr->progs + pr->progs_size); - pr->pr_functions = - (dfunction_t *) (base + pr->progs->ofs_functions); + pr->zone = 0; + if (pr->zone_size) { + //FIXME zone_size needs to be at least as big as memzone_t, but + //memzone_t is opaque so its size is unknown + pr->zone = (memzone_t *)(&pr->pr_edict_area[pr->pr_edict_area_size]); + } + + pr->pr_functions = (dfunction_t *) (base + pr->progs->ofs_functions); pr->pr_strings = (char *) base + pr->progs->ofs_strings; pr->pr_stringsize = (char *) pr->zone + pr->zone_size - (char *) base; - pr->pr_globaldefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); - pr->pr_fielddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); + global_ddefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); + field_ddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); pr->pr_statements = (dstatement_t *) (base + pr->progs->ofs_statements); pr->pr_globals = (pr_type_t *) (base + pr->progs->ofs_globals); - - pr->globals_size = (pr_type_t*)((byte *) pr->zone + pr->zone_size) + pr->stack = (pr_type_t *) ((byte *) pr->zone + pr->zone_size); + pr->stack_bottom = pr->stack - pr->pr_globals; + pr->globals_size = (pr_type_t *) ((byte *) pr->stack + pr->stack_size) - pr->pr_globals; - if (pr->zone_size) + + if (pr->zone) { PR_Zone_Init (pr); + } if (pr->function_hash) { Hash_FlushTable (pr->function_hash); } else { - pr->function_hash = Hash_NewTable (1021, function_get_key, 0, pr); + pr->function_hash = Hash_NewTable (1021, function_get_key, 0, pr, + pr->hashlink_freelist); } if (pr->global_hash) { Hash_FlushTable (pr->global_hash); } else { - pr->global_hash = Hash_NewTable (1021, var_get_key, 0, pr); + pr->global_hash = Hash_NewTable (1021, var_get_key, 0, pr, + pr->hashlink_freelist); } if (pr->field_hash) { Hash_FlushTable (pr->field_hash); } else { - pr->field_hash = Hash_NewTable (1021, var_get_key, 0, pr); + pr->field_hash = Hash_NewTable (1021, var_get_key, 0, pr, + pr->hashlink_freelist); } // byte swap the lumps @@ -256,24 +268,67 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size, int max_edicts, int zone) Hash_Add (pr->function_hash, &pr->pr_functions[i]); } + if (pr->pr_globaldefs) { + free (pr->pr_globaldefs); + } + pr->pr_globaldefs = calloc (pr->progs->numglobaldefs, sizeof (pr_def_t)); + for (i = 0; i < pr->progs->numglobaldefs; i++) { - pr->pr_globaldefs[i].type = LittleShort (pr->pr_globaldefs[i].type); - pr->pr_globaldefs[i].ofs = LittleShort (pr->pr_globaldefs[i].ofs); - pr->pr_globaldefs[i].s_name = LittleLong (pr->pr_globaldefs[i].s_name); + pr_ushort_t safe_type = global_ddefs[i].type & ~DEF_SAVEGLOBAL; + global_ddefs[i].type = LittleShort (global_ddefs[i].type); + global_ddefs[i].ofs = LittleShort (global_ddefs[i].ofs); + global_ddefs[i].s_name = LittleLong (global_ddefs[i].s_name); + + pr->pr_globaldefs[i].type = global_ddefs[i].type; + pr->pr_globaldefs[i].size = pr_type_size[safe_type]; + pr->pr_globaldefs[i].ofs = global_ddefs[i].ofs; + pr->pr_globaldefs[i].name = global_ddefs[i].s_name; Hash_Add (pr->global_hash, &pr->pr_globaldefs[i]); } + if (pr->pr_fielddefs) { + free (pr->pr_fielddefs); + } + pr->pr_fielddefs = calloc (pr->progs->numfielddefs, sizeof (pr_def_t)); for (i = 0; i < pr->progs->numfielddefs; i++) { - pr->pr_fielddefs[i].type = LittleShort (pr->pr_fielddefs[i].type); - if (pr->pr_fielddefs[i].type & DEF_SAVEGLOBAL) - PR_Error (pr, "PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); - pr->pr_fielddefs[i].ofs = LittleShort (pr->pr_fielddefs[i].ofs); - pr->pr_fielddefs[i].s_name = LittleLong (pr->pr_fielddefs[i].s_name); + field_ddefs[i].type = LittleShort (field_ddefs[i].type); + if (field_ddefs[i].type & DEF_SAVEGLOBAL) + PR_Error (pr, "PR_LoadProgs: DEF_SAVEGLOBAL on field def %zd", i); + field_ddefs[i].ofs = LittleShort (field_ddefs[i].ofs); + field_ddefs[i].s_name = LittleLong (field_ddefs[i].s_name); + + pr->pr_fielddefs[i].type = field_ddefs[i].type; + pr->pr_fielddefs[i].ofs = field_ddefs[i].ofs; + pr->pr_fielddefs[i].name = field_ddefs[i].s_name; Hash_Add (pr->field_hash, &pr->pr_fielddefs[i]); } for (i = 0; i < pr->progs->numglobals; i++) ((int *) pr->pr_globals)[i] = LittleLong (((int *) pr->pr_globals)[i]); + + xdefs_def = PR_FindGlobal (pr, ".xdefs"); + if (xdefs_def) { + pr_xdefs_t *xdefs = &G_STRUCT (pr, pr_xdefs_t, xdefs_def->ofs); + xdef_t *xdef = &G_STRUCT (pr, xdef_t, xdefs->xdefs); + pr_def_t *def; + for (def = pr->pr_globaldefs, i = 0; i < pr->progs->numglobaldefs; + i++, xdef++, def++) { + def->ofs = xdef->ofs; + def->type_encoding = xdef->type; + } + for (def = pr->pr_fielddefs, i = 0; i < pr->progs->numfielddefs; + i++, xdef++, def++) { + def->ofs = xdef->ofs; + def->type_encoding = xdef->type; + } + } + pr->pr_trace = 0; + pr->pr_trace_depth = 0; + pr->pr_xfunction = 0; + pr->pr_xstatement = 0; + pr->pr_depth = 0; + pr->localstack_used = 0; + pr->pr_argc = 0; } VISIBLE void @@ -307,7 +362,7 @@ PR_AddLoadFinishFunc (progs_t *pr, int (*func)(progs_t *)) static int pr_run_ctors (progs_t *pr) { - pr_int_t fnum; + pr_uint_t fnum; dfunction_t *func; for (fnum = 0; fnum < pr->progs->numfunctions; fnum++) { @@ -365,6 +420,12 @@ PR_RunLoadFuncs (progs_t *pr) if (!pr->load_funcs[i] (pr)) return 0; + return 1; +} + +VISIBLE int +PR_RunPostLoadFuncs (progs_t *pr) +{ if (!pr_run_ctors (pr)) return 0; @@ -379,21 +440,25 @@ PR_RunLoadFuncs (progs_t *pr) PR_LoadProgs */ VISIBLE void -PR_LoadProgs (progs_t *pr, const char *progsname, int max_edicts, int zone) +PR_LoadProgs (progs_t *pr, const char *progsname) { QFile *file; file = QFS_FOpenFile (progsname); pr->progs_name = progsname; if (file) { - PR_LoadProgsFile (pr, file, qfs_filesize, max_edicts, zone); + PR_LoadProgsFile (pr, file, qfs_filesize); Qclose (file); } if (!pr->progs) return; - if (!PR_RunLoadFuncs (pr)) + if (!PR_RunLoadFuncs (pr)) { PR_Error (pr, "unable to load %s", progsname); + } + if (!pr->debug_handler && !PR_RunPostLoadFuncs (pr)) { + PR_Error (pr, "unable to load %s", progsname); + } } VISIBLE void @@ -413,21 +478,27 @@ PR_Init_Cvars (void) } VISIBLE void -PR_Init (void) +PR_Init (progs_t *pr) { - PR_Opcode_Init (); - PR_Debug_Init (); + PR_Opcode_Init (); // idempotent + PR_Resources_Init (pr); + PR_Strings_Init (pr); + PR_Debug_Init (pr); } VISIBLE void PR_Error (progs_t *pr, const char *error, ...) { va_list argptr; - dstring_t *string = dstring_new (); + dstring_t *string = dstring_new ();//FIXME leaks when debugging va_start (argptr, error); dvsprintf (string, error, argptr); va_end (argptr); + if (pr->debug_handler) { + pr->debug_handler (prd_error, string->str, pr->debug_data); + // not expected to return, but if so, behave as if there was no handler + } Sys_Error ("%s: %s", pr->progs_name, string->str); } diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index d93e7340c..15cdb93ad 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -44,9 +44,11 @@ #include "QF/progs.h" #include "QF/sys.h" -hashtab_t *opcode_table; +#include "compat.h" -VISIBLE int pr_type_size[ev_type_count] = { +static hashtab_t *opcode_table; + +VISIBLE const pr_ushort_t pr_type_size[ev_type_count] = { 1, // ev_void 1, // ev_string 1, // ev_float @@ -59,9 +61,11 @@ VISIBLE int pr_type_size[ev_type_count] = { 1, // ev_integer 1, // ev_uinteger 0, // ev_short value in opcode + 2, // ev_double + 0, // ev_invalid not a valid/simple type }; -VISIBLE const char *pr_type_name[ev_type_count] = { +VISIBLE const char * const pr_type_name[ev_type_count] = { "void", "string", "float", @@ -74,6 +78,7 @@ VISIBLE const char *pr_type_name[ev_type_count] = { "integer", "uinteger", "short", + "double", "invalid", }; @@ -93,13 +98,17 @@ VISIBLE const char *pr_type_name[ev_type_count] = { // c operand c // x place holder for P (padding) // 0-7 parameter index (for P) -VISIBLE opcode_t pr_opcodes[] = { +VISIBLE const opcode_t pr_opcodes[] = { {"", "done", OP_DONE, false, // OP_DONE is actually the same as ev_entity, ev_field, ev_void, // OP_RETURN, the types are bogus PROG_ID_VERSION, "%Va", }, + {"*", "mul.d", OP_MUL_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, {"*", "mul.f", OP_MUL_F, false, ev_float, ev_float, ev_float, PROG_ID_VERSION, @@ -116,6 +125,14 @@ VISIBLE opcode_t pr_opcodes[] = { ev_vector, ev_float, ev_vector, PROG_ID_VERSION, }, + {"*", "mul.dv", OP_MUL_DV, false, + ev_double, ev_vector, ev_vector, + PROG_ID_VERSION, + }, + {"*", "mul.vd", OP_MUL_VD, false, + ev_vector, ev_double, ev_vector, + PROG_ID_VERSION, + }, {"*", "mul.q", OP_MUL_Q, false, ev_quat, ev_quat, ev_quat, PROG_VERSION, @@ -128,6 +145,14 @@ VISIBLE opcode_t pr_opcodes[] = { ev_quat, ev_float, ev_quat, PROG_VERSION, }, + {"*", "mul.dq", OP_MUL_DQ, false, + ev_double, ev_quat, ev_quat, + PROG_VERSION, + }, + {"*", "mul.qd", OP_MUL_QD, false, + ev_quat, ev_double, ev_quat, + PROG_VERSION, + }, {"*", "mul.qv", OP_MUL_QV, false, ev_quat, ev_vector, ev_vector, PROG_VERSION, @@ -143,7 +168,23 @@ VISIBLE opcode_t pr_opcodes[] = { ev_float, ev_float, ev_float, PROG_ID_VERSION, }, + {"/", "div.d", OP_DIV_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, + {"%", "rem.d", OP_REM_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, + {"%%", "mod.d", OP_MOD_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, + {"+", "add.d", OP_ADD_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, {"+", "add.f", OP_ADD_F, false, ev_float, ev_float, ev_float, PROG_ID_VERSION, @@ -161,6 +202,10 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, }, + {"-", "sub.d", OP_SUB_D, false, + ev_double, ev_double, ev_double, + PROG_VERSION, + }, {"-", "sub.f", OP_SUB_F, false, ev_float, ev_float, ev_float, PROG_ID_VERSION, @@ -174,6 +219,10 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, }, + {"==", "eq.d", OP_EQ_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"==", "eq.f", OP_EQ_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -199,6 +248,10 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_ID_VERSION, }, + {"!=", "ne.d", OP_NE_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"!=", "ne.f", OP_NE_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -224,10 +277,18 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_ID_VERSION, }, + {"<=", "le.d", OP_LE_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"<=", "le.f", OP_LE_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, }, + {">=", "ge.d", OP_GE_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {">=", "ge.f", OP_GE_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -240,10 +301,18 @@ VISIBLE opcode_t pr_opcodes[] = { ev_string, ev_string, ev_integer, PROG_VERSION, }, + {"<", "lt.d", OP_LT_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {"<", "lt.f", OP_LT_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, }, + {">", "gt.d", OP_GT_D, false, + ev_double, ev_double, ev_integer, + PROG_VERSION, + }, {">", "gt.f", OP_GT_F, false, ev_float, ev_float, ev_integer, PROG_ID_VERSION, @@ -262,6 +331,11 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_ID_VERSION, "%Ga.%Gb(%Ec), %gc",//FIXME %E more flexible? }, + {".", "load.d", OP_LOAD_D, false, + ev_entity, ev_field, ev_double, + PROG_VERSION, + "%Ga.%Gb(%Ec), %gc", + }, {".", "load.v", OP_LOAD_V, false, ev_entity, ev_field, ev_vector, PROG_ID_VERSION, @@ -303,6 +377,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga.%Gb(%Ec), %gc", }, + {".", "loadb.d", OP_LOADB_D, false, + ev_pointer, ev_integer, ev_double, + PROG_VERSION, + "*(%Ga + %Gb), %gc", + }, {".", "loadb.f", OP_LOADB_F, false, ev_pointer, ev_integer, ev_float, PROG_VERSION, @@ -349,6 +428,11 @@ VISIBLE opcode_t pr_opcodes[] = { "*(%Ga + %Gb), %gc", }, + {".", "loadbi.d", OP_LOADBI_D, false, + ev_pointer, ev_short, ev_double, + PROG_VERSION, + "*(%Ga + %sb), %gc", + }, {".", "loadbi.f", OP_LOADBI_F, false, ev_pointer, ev_short, ev_float, PROG_VERSION, @@ -406,6 +490,11 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, "%Ga, %gc", }, + {"&", "address.d", OP_ADDRESS_D, false, + ev_double, ev_invalid, ev_pointer, + PROG_VERSION, + "%Ga, %gc", + }, {"&", "address.f", OP_ADDRESS_F, false, ev_float, ev_invalid, ev_pointer, PROG_VERSION, @@ -455,12 +544,12 @@ VISIBLE opcode_t pr_opcodes[] = { {"&", "lea", OP_LEA, false, ev_pointer, ev_integer, ev_pointer, PROG_VERSION, - "%Ga, %Gb, %gc", + "(%Ga + %Gb), %gc", }, {"&", "leai", OP_LEAI, false, ev_pointer, ev_short, ev_pointer, PROG_VERSION, - "%Ga, %sb, %gc", + "(%Ga + %sb), %gc", }, {"", "conv.if", OP_CONV_IF, false, @@ -473,7 +562,32 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, "%Ga, %gc", }, + {"", "conv.id", OP_CONV_ID, false, + ev_integer, ev_invalid, ev_double, + PROG_VERSION, + "%Ga, %gc", + }, + {"", "conv.di", OP_CONV_DI, false, + ev_double, ev_invalid, ev_integer, + PROG_VERSION, + "%Ga, %gc", + }, + {"", "conv.fd", OP_CONV_FD, false, + ev_float, ev_invalid, ev_double, + PROG_VERSION, + "%Ga, %gc", + }, + {"", "conv.df", OP_CONV_DF, false, + ev_double, ev_invalid, ev_float, + PROG_VERSION, + "%Ga, %gc", + }, + {"=", "store.d", OP_STORE_D, true, + ev_double, ev_double, ev_invalid, + PROG_VERSION, + "%Ga, %gb", + }, {"=", "store.f", OP_STORE_F, true, ev_float, ev_float, ev_invalid, PROG_ID_VERSION, @@ -520,6 +634,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga, %gb", }, + {".=", "storep.d", OP_STOREP_D, true, + ev_double, ev_pointer, ev_invalid, + PROG_ID_VERSION, + "%Ga, *%Gb", + }, {".=", "storep.f", OP_STOREP_F, true, ev_float, ev_pointer, ev_invalid, PROG_ID_VERSION, @@ -566,6 +685,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga, *%Gb", }, + {".=", "storeb.d", OP_STOREB_D, true, + ev_double, ev_pointer, ev_integer, + PROG_VERSION, + "%Ga, *(%Gb + %Gc)", + }, {".=", "storeb.f", OP_STOREB_F, true, ev_float, ev_pointer, ev_integer, PROG_VERSION, @@ -612,6 +736,11 @@ VISIBLE opcode_t pr_opcodes[] = { "%Ga, *(%Gb + %Gc)", }, + {".=", "storebi.d", OP_STOREBI_D, true, + ev_double, ev_pointer, ev_short, + PROG_VERSION, + "%Ga, *(%Gb + %sc)", + }, {".=", "storebi.f", OP_STOREBI_F, true, ev_float, ev_pointer, ev_short, PROG_VERSION, @@ -670,6 +799,11 @@ VISIBLE opcode_t pr_opcodes[] = { "", }, + {"!", "not.d", OP_NOT_D, false, + ev_double, ev_invalid, ev_integer, + PROG_VERSION, + "%Ga, %gc", + }, {"!", "not.f", OP_NOT_F, false, ev_float, ev_invalid, ev_integer, PROG_ID_VERSION, @@ -907,7 +1041,11 @@ VISIBLE opcode_t pr_opcodes[] = { ev_integer, ev_integer, ev_integer, PROG_VERSION, }, - {"%", "mod.i", OP_MOD_I, false, + {"%", "rem.i", OP_REM_I, false, + ev_integer, ev_integer, ev_integer, + PROG_VERSION, + }, + {"%%", "mod.i", OP_MOD_I, false, ev_integer, ev_integer, ev_integer, PROG_VERSION, }, @@ -920,7 +1058,12 @@ VISIBLE opcode_t pr_opcodes[] = { PROG_VERSION, }, - {"%", "mod.f", OP_MOD_F, false, + {"%", "rem.f", OP_REM_F, false, + ev_float, ev_float, ev_float, + PROG_VERSION, + }, + + {"%%", "mod.f", OP_MOD_F, false, ev_float, ev_float, ev_float, PROG_VERSION, }, @@ -1038,8 +1181,299 @@ VISIBLE opcode_t pr_opcodes[] = { {"", "movepi", OP_MOVEPI, true, ev_pointer, ev_short, ev_pointer, PROG_VERSION, + "%Ga, %sb, %Gc", + }, + {"", "memseti", OP_MEMSETI, true, + ev_integer, ev_short, ev_void, + PROG_VERSION, + "%Ga, %sb, %gc", + }, + {"", "memsetp", OP_MEMSETP, true, + ev_integer, ev_integer, ev_pointer, + PROG_VERSION, "%Ga, %Gb, %Gc", }, + {"", "memsetpi", OP_MEMSETPI, true, + ev_integer, ev_short, ev_pointer, + PROG_VERSION, + "%Ga, %sb, %Gc", + }, + + {"", "push.s", OP_PUSH_S, false, + ev_string, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.f", OP_PUSH_F, false, + ev_float, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.v", OP_PUSH_V, false, + ev_vector, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.ent", OP_PUSH_ENT, false, + ev_entity, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.fld", OP_PUSH_FLD, false, + ev_field, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.fn", OP_PUSH_FN, false, + ev_func, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.p", OP_PUSH_P, false, + ev_pointer, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.q", OP_PUSH_Q, false, + ev_quat, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + {"", "push.i", OP_PUSH_I, false, + ev_integer, ev_invalid, ev_invalid, + PROG_VERSION, + "%Ga", + }, + + {"", "pushb.s", OP_PUSHB_S, false, + ev_pointer, ev_integer, ev_string, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.f", OP_PUSHB_F, false, + ev_pointer, ev_integer, ev_float, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.v", OP_PUSHB_V, false, + ev_pointer, ev_integer, ev_vector, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.ent", OP_PUSHB_ENT, false, + ev_pointer, ev_integer, ev_entity, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.fld", OP_PUSHB_FLD, false, + ev_pointer, ev_integer, ev_field, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.fn", OP_PUSHB_FN, false, + ev_pointer, ev_integer, ev_func, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.p", OP_PUSHB_P, false, + ev_pointer, ev_integer, ev_pointer, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.q", OP_PUSHB_Q, false, + ev_pointer, ev_integer, ev_quat, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "pushb.i", OP_PUSHB_I, false, + ev_pointer, ev_integer, ev_integer, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + + {"", "pushbi.s", OP_PUSHBI_S, false, + ev_pointer, ev_short, ev_string, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.f", OP_PUSHBI_F, false, + ev_pointer, ev_short, ev_float, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.v", OP_PUSHBI_V, false, + ev_pointer, ev_short, ev_vector, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.ent", OP_PUSHBI_ENT, false, + ev_pointer, ev_short, ev_entity, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.fld", OP_PUSHBI_FLD, false, + ev_pointer, ev_short, ev_field, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.fn", OP_PUSHBI_FN, false, + ev_pointer, ev_short, ev_func, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.p", OP_PUSHBI_P, false, + ev_pointer, ev_short, ev_pointer, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.q", OP_PUSHBI_Q, false, + ev_pointer, ev_short, ev_quat, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "pushbi.i", OP_PUSHBI_I, false, + ev_pointer, ev_short, ev_integer, + PROG_VERSION, + "*(%Ga + %sb)", + }, + + {"", "pop.s", OP_POP_S, false, + ev_string, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.f", OP_POP_F, false, + ev_float, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.v", OP_POP_V, false, + ev_vector, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.ent", OP_POP_ENT, false, + ev_entity, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.fld", OP_POP_FLD, false, + ev_field, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.fn", OP_POP_FN, false, + ev_func, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.p", OP_POP_P, false, + ev_pointer, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.q", OP_POP_Q, false, + ev_quat, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + {"", "pop.i", OP_POP_I, false, + ev_integer, ev_invalid, ev_invalid, + PROG_VERSION, + "%ga", + }, + + {"", "popb.s", OP_POPB_S, false, + ev_pointer, ev_integer, ev_string, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.f", OP_POPB_F, false, + ev_pointer, ev_integer, ev_float, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.v", OP_POPB_V, false, + ev_pointer, ev_integer, ev_vector, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.ent", OP_POPB_ENT, false, + ev_pointer, ev_integer, ev_entity, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.fld", OP_POPB_FLD, false, + ev_pointer, ev_integer, ev_field, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.fn", OP_POPB_FN, false, + ev_pointer, ev_integer, ev_func, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.p", OP_POPB_P, false, + ev_pointer, ev_integer, ev_pointer, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.q", OP_POPB_Q, false, + ev_pointer, ev_integer, ev_quat, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + {"", "popb.i", OP_POPB_I, false, + ev_pointer, ev_integer, ev_integer, + PROG_VERSION, + "*(%Ga + %Gb)", + }, + + {"", "popbi.s", OP_POPBI_S, false, + ev_pointer, ev_short, ev_string, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.f", OP_POPBI_F, false, + ev_pointer, ev_short, ev_float, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.v", OP_POPBI_V, false, + ev_pointer, ev_short, ev_vector, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.ent", OP_POPBI_ENT, false, + ev_pointer, ev_short, ev_entity, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.fld", OP_POPBI_FLD, false, + ev_pointer, ev_short, ev_field, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.fn", OP_POPBI_FN, false, + ev_pointer, ev_short, ev_func, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.p", OP_POPBI_P, false, + ev_pointer, ev_short, ev_pointer, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.q", OP_POPBI_Q, false, + ev_pointer, ev_short, ev_quat, + PROG_VERSION, + "*(%Ga + %sb)", + }, + {"", "popbi.i", OP_POPBI_I, false, + ev_pointer, ev_short, ev_integer, + PROG_VERSION, + "*(%Ga + %sb)", + }, // end of table {0}, @@ -1073,13 +1507,17 @@ PR_Opcode (pr_short_t opcode) VISIBLE void PR_Opcode_Init (void) { - opcode_t *op; + const opcode_t *op; - opcode_table = Hash_NewTable (1021, 0, 0, 0); + if (opcode_table) { + // already initialized + return; + } + opcode_table = Hash_NewTable (1021, 0, 0, 0, 0); Hash_SetHashCompare (opcode_table, opcode_get_hash, opcode_compare); for (op = pr_opcodes; op->name; op++) { - Hash_AddElement (opcode_table, op); + Hash_AddElement (opcode_table, (void *) op); } } @@ -1117,7 +1555,7 @@ check_global (progs_t *pr, dstatement_t *st, opcode_t *op, etype_t type, unsigned short operand, int check_denorm) { const char *msg; - ddef_t *def; + pr_def_t *def; switch (type) { case ev_short: @@ -1192,11 +1630,16 @@ PR_Check_Opcodes (progs_t *pr) opcode_t *op; dstatement_t *st; int state_ok = 0; + int pushpop_ok = 0; pr_uint_t i; if (pr->globals.time && pr->globals.self && pr->fields.nextthink != -1 - && pr->fields.think != -1 && pr->fields.frame != -1) + && pr->fields.think != -1 && pr->fields.frame != -1) { state_ok = 1; + } + if (pr->globals.stack) { + pushpop_ok = 1; + } //FIXME need to decide if I really want to always do static bounds checking // the only problem is that it slows progs load a little, but it's the only @@ -1214,6 +1657,11 @@ PR_Check_Opcodes (progs_t *pr) PR_Error (pr, "PR_Check_Opcodes: %s used with missing fields " "or globals", op->opname); } + if ((strequal(op->name, "") || strequal(op->name, "")) + && !pushpop_ok) { + PR_Error (pr, "PR_Check_Opcodes: %s used with missing .stack " + "globals", op->opname); + } } } else { for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements; @@ -1267,6 +1715,72 @@ PR_Check_Opcodes (progs_t *pr) check_global_size (pr, st, op, st->b, st->a); check_global_size (pr, st, op, st->b, st->c); break; + case OP_MEMSETI: + check_global_size (pr, st, op, st->b, st->c); + break; + case OP_PUSHB_F: + case OP_PUSHB_S: + case OP_PUSHB_ENT: + case OP_PUSHB_FLD: + case OP_PUSHB_FN: + case OP_PUSHB_I: + case OP_PUSHB_P: + case OP_PUSHB_V: + case OP_PUSHB_Q: + case OP_PUSHBI_F: + case OP_PUSHBI_S: + case OP_PUSHBI_ENT: + case OP_PUSHBI_FLD: + case OP_PUSHBI_FN: + case OP_PUSHBI_I: + case OP_PUSHBI_P: + case OP_PUSHBI_V: + case OP_PUSHBI_Q: + // op->type_c is used for selecting the operator during + // compilation, but is invalid when running + check_global (pr, st, op, op->type_a, st->a, 1); + check_global (pr, st, op, op->type_b, st->b, 1); + check_global (pr, st, op, ev_invalid, st->c, 1); + break; + case OP_POP_F: + case OP_POP_FLD: + case OP_POP_ENT: + case OP_POP_S: + case OP_POP_FN: + case OP_POP_I: + case OP_POP_P: + case OP_POP_V: + case OP_POP_Q: + // don't want to check for denormal floats, otherwise + // OP_POP_* could use the defualt rule + check_global (pr, st, op, op->type_a, st->a, 0); + check_global (pr, st, op, ev_invalid, st->b, 1); + check_global (pr, st, op, ev_invalid, st->c, 1); + break; + case OP_POPB_F: + case OP_POPB_S: + case OP_POPB_ENT: + case OP_POPB_FLD: + case OP_POPB_FN: + case OP_POPB_I: + case OP_POPB_P: + case OP_POPB_V: + case OP_POPB_Q: + case OP_POPBI_F: + case OP_POPBI_S: + case OP_POPBI_ENT: + case OP_POPBI_FLD: + case OP_POPBI_FN: + case OP_POPBI_I: + case OP_POPBI_P: + case OP_POPBI_V: + case OP_POPBI_Q: + // op->type_c is used for selecting the operator during + // compilation, but is invalid when running + check_global (pr, st, op, op->type_a, st->a, 1); + check_global (pr, st, op, op->type_b, st->b, 1); + check_global (pr, st, op, ev_invalid, st->c, 1); + break; default: check_global (pr, st, op, op->type_a, st->a, 1); check_global (pr, st, op, op->type_b, st->b, diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index a8259ee78..a4c327940 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -43,21 +43,12 @@ #include #endif -#include "QF/cbuf.h" -#include "QF/crc.h" -#include "QF/cvar.h" #include "QF/dstring.h" -#include "QF/hash.h" #include "QF/mathlib.h" +#include "QF/plist.h" #include "QF/progs.h" -#include "QF/qdefs.h" -#include "QF/qfplist.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/script.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -68,15 +59,11 @@ Easier to parse than PR_ValueString */ static const char * -PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) +PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val, dstring_t *line) { - static dstring_t *line = 0; - ddef_t *def; + pr_def_t *def; dfunction_t *f; - if (!line) - line = dstring_new (); - type &= ~DEF_SAVEGLOBAL; switch (type) { @@ -93,7 +80,7 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) break; case ev_field: def = PR_FieldAtOfs (pr, val->integer_var); - dsprintf (line, "%s", PR_GetString (pr, def->s_name)); + dsprintf (line, "%s", PR_GetString (pr, def->name)); break; case ev_void: dstring_copystr (line, "void"); @@ -105,10 +92,10 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) dsprintf (line, "%d", val->integer_var); break; case ev_vector: - dsprintf (line, "%.9g %.9g %.9g", VectorExpand (val->vector_var)); + dsprintf (line, "%.9g %.9g %.9g", VectorExpand (&val->vector_var)); break; case ev_quat: - dsprintf (line, "%.9g %.9g %.9g %.9g", QuatExpand (val->quat_var)); + dsprintf (line, "%.9g %.9g %.9g %.9g", QuatExpand (&val->quat_var)); break; default: dsprintf (line, "bad type %i", type); @@ -121,7 +108,8 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) VISIBLE plitem_t * ED_EntityDict (progs_t *pr, edict_t *ed) { - plitem_t *entity = PL_NewDictionary (); + dstring_t *dstr = dstring_newstr (); + plitem_t *entity = PL_NewDictionary (pr->hashlink_freelist); pr_uint_t i; int j; int type; @@ -131,15 +119,15 @@ ED_EntityDict (progs_t *pr, edict_t *ed) if (!ed->free) { for (i = 0; i < pr->progs->numfielddefs; i++) { - ddef_t *d = &pr->pr_fielddefs[i]; + pr_def_t *d = &pr->pr_fielddefs[i]; - name = PR_GetString (pr, d->s_name); + name = PR_GetString (pr, d->name); if (!name[0]) continue; // skip unnamed fields if (name[strlen (name) - 2] == '_') continue; // skip _x, _y, _z vars - v = &ed->v[d->ofs]; + v = &E_fld (ed, d->ofs); // if the value is still all 0, skip the field type = d->type & ~DEF_SAVEGLOBAL; @@ -149,10 +137,11 @@ ED_EntityDict (progs_t *pr, edict_t *ed) if (j == pr_type_size[type]) continue; - value = PR_UglyValueString (pr, type, v); + value = PR_UglyValueString (pr, type, v, dstr); PL_D_AddObject (entity, name, PL_NewString (value)); } } + dstring_delete (dstr); return entity; } @@ -165,11 +154,12 @@ ED_EntityDict (progs_t *pr, edict_t *ed) VISIBLE plitem_t * ED_GlobalsDict (progs_t *pr) { - plitem_t *globals = PL_NewDictionary (); + dstring_t *dstr = dstring_newstr (); + plitem_t *globals = PL_NewDictionary (pr->hashlink_freelist); pr_uint_t i; const char *name; const char *value; - ddef_t *def; + pr_def_t *def; int type; for (i = 0; i < pr->progs->numglobaldefs; i++) { @@ -182,10 +172,11 @@ ED_GlobalsDict (progs_t *pr) if (type != ev_string && type != ev_float && type != ev_entity) continue; - name = PR_GetString (pr, def->s_name); - value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs]); + name = PR_GetString (pr, def->name); + value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs], dstr); PL_D_AddObject (globals, name, PL_NewString (value)); } + dstring_delete (dstr); return globals; } @@ -222,11 +213,11 @@ ED_NewString (progs_t *pr, const char *string) returns false if error */ VISIBLE qboolean -ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s) +ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) { int i; char *string; - ddef_t *def; + pr_def_t *def; char *v, *w; pr_type_t *d; dfunction_t *func; @@ -250,7 +241,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s) while (*v && *v != ' ') v++; *v = 0; - d->vector_var[i] = atof (w); + (&d->vector_var)[i] = atof (w); w = v = v + 1; } free (string); @@ -299,8 +290,9 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s) */ VISIBLE plitem_t * -ED_ConvertToPlist (script_t *script, int nohack) +ED_ConvertToPlist (script_t *script, int nohack, struct hashlink_s **hashlinks) { + dstring_t *dstr = dstring_newstr (); plitem_t *plist = PL_NewArray (); plitem_t *ent; plitem_t *key; @@ -312,7 +304,7 @@ ED_ConvertToPlist (script_t *script, int nohack) token = script->token->str; if (!strequal (token, "{")) Sys_Error ("ED_ConvertToPlist: EOF without closing brace"); - ent = PL_NewDictionary (); + ent = PL_NewDictionary (hashlinks); while (1) { int n; @@ -341,15 +333,18 @@ ED_ConvertToPlist (script_t *script, int nohack) token = script->token->str; if (strequal (token, "}")) Sys_Error ("ED_ConvertToPlist: closing brace without data"); - if (anglehack) - value = PL_NewString (va ("0 %s 0", token)); - else + if (anglehack) { + dsprintf (dstr, "0 %s 0", token); + value = PL_NewString (dstr->str); + } else { value = PL_NewString (token); + } PL_D_AddObject (ent, PL_String (key), value); PL_Free (key); } PL_A_AddObject (plist, ent); } + dstring_delete (dstr); return plist; } @@ -357,8 +352,8 @@ ED_ConvertToPlist (script_t *script, int nohack) VISIBLE void ED_InitGlobals (progs_t *pr, plitem_t *globals) { - ddef_t vector_def; - ddef_t *global; + pr_def_t vector_def; + pr_def_t *global; plitem_t *keys; int count; const char *global_name; @@ -405,7 +400,7 @@ ED_InitGlobals (progs_t *pr, plitem_t *globals) VISIBLE void ED_InitEntity (progs_t *pr, plitem_t *entity, edict_t *ent) { - ddef_t *field; + pr_def_t *field; plitem_t *keys; const char *field_name; const char *value; @@ -425,7 +420,7 @@ ED_InitEntity (progs_t *pr, plitem_t *entity, edict_t *ent) continue; } } else { - if (!ED_ParseEpair (pr, ent->v, field, value)) + if (!ED_ParseEpair (pr, &E_fld (ent, 0), field, value)) PR_Error (pr, "ED_InitEntity: parse error"); } init = 1; @@ -446,7 +441,7 @@ ED_SpawnEntities (progs_t *pr, plitem_t *entity_list) int count; const char *classname; dfunction_t *func; - pr_int_t max_edicts = pr->pr_edictareasize / pr->pr_edict_size; + pr_int_t max_edicts = pr->pr_edict_area_size / pr->pr_edict_size; max_edicts -= *pr->num_edicts; count = PL_A_NumObjects (entity_list); @@ -504,11 +499,11 @@ ED_Parse (progs_t *pr, const char *data) if (Script_GetToken (script, 1)) { if (strequal (script->token->str, "(")) { // new style (plist) entity data - entity_list = PL_GetPropertyList (data); + entity_list = PL_GetPropertyList (data, pr->hashlink_freelist); } else { - // oldstyle entity data + // old style entity data Script_UngetToken (script); - entity_list = ED_ConvertToPlist (script, 0); + entity_list = ED_ConvertToPlist (script, 0, pr->hashlink_freelist); } } Script_Delete (script); @@ -524,6 +519,7 @@ ED_LoadFromFile (progs_t *pr, const char *data) PR_PushFrame (pr); PR_RESET_PARAMS (pr); P_INT (pr, 0) = PR_SetTempString (pr, data); + pr->pr_argc = 1; PR_ExecuteProgram (pr, pr->edict_parse); PR_PopFrame (pr); return; diff --git a/libs/gamecode/pr_resolve.c b/libs/gamecode/pr_resolve.c index 626540fda..6270653d2 100644 --- a/libs/gamecode/pr_resolve.c +++ b/libs/gamecode/pr_resolve.c @@ -34,59 +34,59 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cmd.h" -#include "QF/crc.h" -#include "QF/cvar.h" #include "QF/hash.h" #include "QF/progs.h" -#include "QF/qdefs.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" +static const char param_str[] = ".param_0"; -ddef_t * -PR_GlobalAtOfs (progs_t * pr, pr_int_t ofs) +pr_def_t * +PR_SearchDefs (pr_def_t *defs, unsigned num_defs, pointer_t offset) { - ddef_t *def; - pr_uint_t i; + // fuzzy bsearh + unsigned left = 0; + unsigned right = num_defs - 1; + unsigned mid; - for (i = 0; i < pr->progs->numglobaldefs; i++) { - def = &pr->pr_globaldefs[i]; - if (def->ofs == ofs) - return def; + if (!num_defs) { + return 0; } - return NULL; + while (left != right) { + mid = (left + right + 1) / 2; + if (defs[mid].ofs > offset) { + right = mid - 1; + } else { + left = mid; + } + } + if (defs[left].ofs <= offset) { + return defs + left; + } + return 0; } -VISIBLE ddef_t * -PR_FieldAtOfs (progs_t * pr, pr_int_t ofs) +pr_def_t * +PR_GlobalAtOfs (progs_t * pr, pointer_t ofs) { - ddef_t *def; - pr_uint_t i; - - for (i = 0; i < pr->progs->numfielddefs; i++) { - def = &pr->pr_fielddefs[i]; - if (def->ofs == ofs) - return def; - } - return NULL; + return PR_SearchDefs (pr->pr_globaldefs, pr->progs->numglobaldefs, ofs); } -VISIBLE ddef_t * +VISIBLE pr_def_t * +PR_FieldAtOfs (progs_t * pr, pointer_t ofs) +{ + return PR_SearchDefs (pr->pr_fielddefs, pr->progs->numfielddefs, ofs); +} + +VISIBLE pr_def_t * PR_FindField (progs_t * pr, const char *name) { return Hash_Find (pr->field_hash, name); } -VISIBLE ddef_t * +VISIBLE pr_def_t * PR_FindGlobal (progs_t * pr, const char *name) { return Hash_Find (pr->global_hash, name); @@ -108,7 +108,7 @@ VISIBLE int PR_ResolveGlobals (progs_t *pr) { const char *sym; - ddef_t *def; + pr_def_t *def; int i; if (pr->progs->version == PROG_ID_VERSION) { @@ -122,23 +122,26 @@ PR_ResolveGlobals (progs_t *pr) pr->pr_params[6] = &pr->pr_globals[OFS_PARM6]; pr->pr_params[7] = &pr->pr_globals[OFS_PARM7]; pr->pr_param_size = OFS_PARM1 - OFS_PARM0; + pr->pr_param_alignment = 0; // log2 } else { + char *param_n = alloca (sizeof (param_str)); + strcpy (param_n, param_str); if (!(def = PR_FindGlobal (pr, sym = ".return"))) goto error; pr->pr_return = &pr->pr_globals[def->ofs]; for (i = 0; i < MAX_PARMS; i++) { - if (!(def = PR_FindGlobal (pr, sym = va(".param_%d", i)))) + param_n[sizeof (param_str) - 2] = i + '0'; + if (!(def = PR_FindGlobal (pr, sym = param_n))) goto error; pr->pr_params[i] = &pr->pr_globals[def->ofs]; } if (!(def = PR_FindGlobal (pr, sym = ".param_size"))) goto error; pr->pr_param_size = G_INT (pr, def->ofs); + if (!(def = PR_FindGlobal (pr, sym = ".param_alignment"))) + goto error; + pr->pr_param_alignment = G_INT (pr, def->ofs); } - if (pr->pr_saved_params) - free (pr->pr_saved_params); - pr->pr_saved_params = calloc (pr->pr_param_size * MAX_PARMS, - sizeof (pr_type_t)); memcpy (pr->pr_real_params, pr->pr_params, sizeof (pr->pr_params)); if (!pr->globals.time) { if ((def = PR_FindGlobal (pr, "time"))) @@ -149,6 +152,14 @@ PR_ResolveGlobals (progs_t *pr) || (def = PR_FindGlobal (pr, "self"))) pr->globals.self = &G_INT (pr, def->ofs); } + if (!pr->globals.stack) { + if ((def = PR_FindGlobal (pr, ".stack")) + || (def = PR_FindGlobal (pr, "stack"))) { + pr->globals.stack = &G_POINTER (pr, def->ofs); + // the stack is at the very end of the progs memory map + *pr->globals.stack = pr->globals_size; + } + } if (pr->fields.nextthink == -1) if ((def = PR_FindField (pr, "nextthink"))) pr->fields.nextthink = def->ofs; @@ -168,7 +179,7 @@ int PR_AccessField (progs_t *pr, const char *name, etype_t type, const char *file, int line) { - ddef_t *def = PR_FindField (pr, name); + pr_def_t *def = PR_FindField (pr, name); if (!def) PR_Error (pr, "undefined field %s accessed at %s:%d", name, file, line); diff --git a/libs/gamecode/pr_resource.c b/libs/gamecode/pr_resource.c index 14cd4a38b..9a86d2302 100644 --- a/libs/gamecode/pr_resource.c +++ b/libs/gamecode/pr_resource.c @@ -53,7 +53,8 @@ resource_get_key (const void *r, void *unused) VISIBLE void PR_Resources_Init (progs_t *pr) { - pr->resource_hash = Hash_NewTable (1021, resource_get_key, 0, 0); + pr->resource_hash = Hash_NewTable (1021, resource_get_key, 0, 0, + pr->hashlink_freelist); pr->resources = 0; } diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index f6983469a..82e9540da 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -42,7 +42,51 @@ #include "QF/dstring.h" #include "QF/hash.h" #include "QF/progs.h" -#include "QF/va.h" + +// format adjustments +#define FMT_ALTFORM (1<<0) +#define FMT_LJUSTIFY (1<<1) +#define FMT_ZEROPAD (1<<2) +#define FMT_ADDSIGN (1<<3) +#define FMT_ADDBLANK (1<<4) +#define FMT_HEX (1<<5) +#define FMT_LONG (1<<6) + +typedef struct fmt_item_s { + byte type; + unsigned flags; + int minFieldWidth; + int precision; + union { + const char *string_var; + int integer_var; + unsigned uinteger_var; + float float_var; + double double_var; + } data; + struct fmt_item_s *next; +} fmt_item_t; + +typedef struct strref_slot_s { + struct strref_slot_s *next; + struct strref_slot_s **prev; + strref_t *strref; +} strref_slot_t; + +typedef struct prstr_resources_s { + progs_t *pr; + dstring_mem_t ds_mem; + strref_t *free_string_refs; + strref_t *static_strings; + strref_t **string_map; + strref_slot_t return_strings[PR_RS_SLOTS]; + strref_slot_t *rs_slot; + unsigned dyn_str_size; + struct hashtab_s *strref_hash; + int num_strings; + fmt_item_t *free_fmt_items; + dstring_t *print_str; +} prstr_resources_t; typedef enum { str_free, @@ -55,7 +99,7 @@ typedef enum { struct strref_s { strref_t *next; - strref_t **prev; + strref_slot_t *rs_slot; str_e type; union { char *string; @@ -63,30 +107,6 @@ struct strref_s { } s; }; -// format adjustments -#define FMT_ALTFORM (1<<0) -#define FMT_LJUSTIFY (1<<1) -#define FMT_ZEROPAD (1<<2) -#define FMT_ADDSIGN (1<<3) -#define FMT_ADDBLANK (1<<4) -#define FMT_HEX (1<<5) - -typedef struct fmt_item_s { - byte type; - unsigned flags; - int minFieldWidth; - int precision; - union { - const char *string_var; - int integer_var; - unsigned uinteger_var; - float float_var; - } data; - struct fmt_item_s *next; -} fmt_item_t; - -static fmt_item_t *free_fmt_items; - static void * pr_strings_alloc (void *_pr, size_t size) { @@ -109,51 +129,50 @@ pr_strings_realloc (void *_pr, void *ptr, size_t size) } static strref_t * -new_string_ref (progs_t *pr) +new_string_ref (prstr_resources_t *res) { strref_t *sr; - if (!pr->free_string_refs) { + if (!res->free_string_refs) { int i; size_t size; - pr->dyn_str_size++; - size = pr->dyn_str_size * sizeof (strref_t *); - pr->string_map = realloc (pr->string_map, size); - if (!pr->string_map) - PR_Error (pr, "out of memory"); - if (!(pr->free_string_refs = calloc (1024, sizeof (strref_t)))) - PR_Error (pr, "out of memory"); - pr->string_map[pr->dyn_str_size - 1] = pr->free_string_refs; - for (i = 0, sr = pr->free_string_refs; i < 1023; i++, sr++) + res->dyn_str_size++; + size = res->dyn_str_size * sizeof (strref_t *); + res->string_map = realloc (res->string_map, size); + if (!res->string_map) + PR_Error (res->pr, "out of memory"); + if (!(res->free_string_refs = calloc (1024, sizeof (strref_t)))) + PR_Error (res->pr, "out of memory"); + res->string_map[res->dyn_str_size - 1] = res->free_string_refs; + for (i = 0, sr = res->free_string_refs; i < 1023; i++, sr++) sr->next = sr + 1; sr->next = 0; } - sr = pr->free_string_refs; - pr->free_string_refs = sr->next; + sr = res->free_string_refs; + res->free_string_refs = sr->next; sr->next = 0; + sr->rs_slot = 0; return sr; } static void -free_string_ref (progs_t *pr, strref_t *sr) +free_string_ref (prstr_resources_t *res, strref_t *sr) { sr->type = str_free; - if (sr->prev) - *sr->prev = sr->next; - sr->next = pr->free_string_refs; - pr->free_string_refs = sr; + sr->next = res->free_string_refs; + res->free_string_refs = sr; } -static string_t -string_index (progs_t *pr, strref_t *sr) +static __attribute__((pure)) string_t +string_index (prstr_resources_t *res, strref_t *sr) { - long o = (long) (sr - pr->static_strings); + long o = (long) (sr - res->static_strings); unsigned i; - if (o >= 0 && o < pr->num_strings) - return sr->s.string - pr->pr_strings; - for (i = 0; i < pr->dyn_str_size; i++) { - int d = sr - pr->string_map[i]; + if (o >= 0 && o < res->num_strings) + return sr->s.string - res->pr->pr_strings; + for (i = 0; i < res->dyn_str_size; i++) { + int d = sr - res->string_map[i]; if (d >= 0 && d < 1024) return ~(i * 1024 + d); } @@ -170,70 +189,124 @@ strref_get_key (const void *_sr, void *notused) } static void -strref_free (void *_sr, void *_pr) +strref_free (void *_sr, void *_res) { - progs_t *pr = (progs_t*)_pr; - strref_t *sr = (strref_t*)_sr; + __auto_type res = (prstr_resources_t *) _res; + __auto_type sr = (strref_t *) _sr; // Since this is called only by Hash_FlushTable, the memory pointed // to by sr->string or sr->dstring has already been lost in the progs // load/reload and thus there's no need to free it. // free the string and ref only if it's not a static string - if (sr < pr->static_strings || sr >= pr->static_strings + pr->num_strings) { - free_string_ref (pr, sr); + if (sr < res->static_strings + || sr >= res->static_strings + res->num_strings) { + free_string_ref (res, sr); } } +static void +pr_strings_clear (progs_t *pr, void *data) +{ + __auto_type res = (prstr_resources_t *) data; + int i; + + for (i = 0; i < PR_RS_SLOTS; i++) { + if (res->return_strings[i].strref) + free_string_ref (res, res->return_strings[i].strref); + res->return_strings[i].strref = 0; + } + if (!res->rs_slot) { + strref_slot_t * const rs = res->return_strings; + for (i = 0; i < PR_RS_SLOTS; i++) { + rs[i].next = &rs[(i + 1) % PR_RS_SLOTS]; + rs[i].prev = &rs[(i - 1 + PR_RS_SLOTS) % PR_RS_SLOTS].next; + } + res->rs_slot = rs; + } + + pr->pr_string_resources = res; + pr->pr_xtstr = 0; +} + VISIBLE int PR_LoadStrings (progs_t *pr) { + prstr_resources_t *res = PR_Resources_Find (pr, "Strings"); + char *end = pr->pr_strings + pr->progs->numstrings; char *str = pr->pr_strings; int count = 0; + pr->float_promoted = 0; + while (str < end) { count++; + if (*str == '@' && pr->progs->version == PROG_VERSION) { + if (!strcmp (str, "@float_promoted@")) { + pr->float_promoted = 1; + } + } str += strlen (str) + 1; } - if (!pr->ds_mem) { - pr->ds_mem = malloc (sizeof (dstring_mem_t)); - pr->ds_mem->alloc = pr_strings_alloc; - pr->ds_mem->free = pr_strings_free; - pr->ds_mem->realloc = pr_strings_realloc; - pr->ds_mem->data = pr; - } - if (pr->strref_hash) { - Hash_FlushTable (pr->strref_hash); + res->ds_mem.alloc = pr_strings_alloc; + res->ds_mem.free = pr_strings_free; + res->ds_mem.realloc = pr_strings_realloc; + res->ds_mem.data = pr; + + if (res->strref_hash) { + Hash_FlushTable (res->strref_hash); } else { - pr->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, - pr); - pr->string_map = 0; - pr->free_string_refs = 0; - pr->dyn_str_size = 0; + res->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, + res, pr->hashlink_freelist); + res->string_map = 0; + res->free_string_refs = 0; + res->dyn_str_size = 0; } - if (pr->static_strings) - free (pr->static_strings); - pr->static_strings = malloc (count * sizeof (strref_t)); + if (res->static_strings) + free (res->static_strings); + res->static_strings = calloc (count, sizeof (strref_t)); count = 0; str = pr->pr_strings; while (str < end) { - if (!Hash_Find (pr->strref_hash, str)) { - pr->static_strings[count].type = str_static; - pr->static_strings[count].s.string = str; - Hash_Add (pr->strref_hash, &pr->static_strings[count]); + if (!Hash_Find (res->strref_hash, str)) { + res->static_strings[count].type = str_static; + res->static_strings[count].s.string = str; + Hash_Add (res->strref_hash, &res->static_strings[count]); count++; } str += strlen (str) + 1; } - pr->num_strings = count; + res->num_strings = count; return 1; } +static void +requeue_strref (prstr_resources_t *res, strref_t *sr) +{ + strref_slot_t *rs_slot = sr->rs_slot; + if (rs_slot->next != res->rs_slot) { + // this is the oldest slot, so advance res->rs_slot to the + // next oldest slot so this slot does not get reused just yet + if (res->rs_slot == rs_slot) { + res->rs_slot = rs_slot->next; + } + // unlink this slot from the chain + rs_slot->next->prev = rs_slot->prev; + *rs_slot->prev = rs_slot->next; + // link this slot just before the oldest slot: all the slots + // form a doubly linked circular list + rs_slot->prev = res->rs_slot->prev; + rs_slot->next = res->rs_slot; + *res->rs_slot->prev = rs_slot; + res->rs_slot->prev = &rs_slot->next; + } +} + static inline strref_t * -get_strref (progs_t *pr, string_t num) +get_strref (prstr_resources_t *res, string_t num) { if (num < 0) { strref_t *ref; @@ -241,9 +314,9 @@ get_strref (progs_t *pr, string_t num) num = ~num % 1024; - if (row >= pr->dyn_str_size) + if (row >= res->dyn_str_size) return 0; - ref = &pr->string_map[row][num]; + ref = &res->string_map[row][num]; if (ref->type == str_free) return 0; return ref; @@ -251,25 +324,27 @@ get_strref (progs_t *pr, string_t num) return 0; } -static inline const char * +static inline __attribute__((pure)) const char * get_string (progs_t *pr, string_t num) { + __auto_type res = pr->pr_string_resources; if (num < 0) { - strref_t *ref = get_strref (pr, num); + strref_t *ref = get_strref (res, num); if (!ref) return 0; switch (ref->type) { + case str_return: + requeue_strref (res, ref); case str_static: case str_temp: case str_dynamic: - case str_return: return ref->s.string; case str_mutable: return ref->s.dstring->str; case str_free: break; } - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: line:%d", __LINE__); } else { if (num >= pr->pr_stringsize) return 0; @@ -280,7 +355,21 @@ get_string (progs_t *pr, string_t num) VISIBLE qboolean PR_StringValid (progs_t *pr, string_t num) { - return get_string (pr, num) != 0; + if (num >= 0) { + return num < pr->pr_stringsize; + } + return get_strref (pr->pr_string_resources, num) != 0; +} + +VISIBLE qboolean +PR_StringMutable (progs_t *pr, string_t num) +{ + strref_t *sr; + if (num >= 0) { + return 0; + } + sr = get_strref (pr->pr_string_resources, num); + return sr && sr->type == str_mutable; } VISIBLE const char * @@ -297,7 +386,7 @@ PR_GetString (progs_t *pr, string_t num) VISIBLE dstring_t * PR_GetMutableString (progs_t *pr, string_t num) { - strref_t *ref = get_strref (pr, num); + strref_t *ref = get_strref (pr->pr_string_resources, num); if (ref) { if (ref->type == str_mutable) return ref->s.dstring; @@ -306,10 +395,16 @@ PR_GetMutableString (progs_t *pr, string_t num) PR_RunError (pr, "Invalid string offset: %d", num); } +static inline void * +pr_strmalloc (progs_t *pr, size_t size) +{ + return PR_Zone_Malloc (pr, size); +} + static inline char * pr_stralloc (progs_t *pr, size_t len) { - return PR_Zone_Malloc (pr, len + 1); + return pr_strmalloc (pr, len + 1); } static inline void @@ -329,70 +424,89 @@ pr_strdup (progs_t *pr, const char *s) VISIBLE string_t PR_SetString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) s = ""; - sr = Hash_Find (pr->strref_hash, s); + sr = Hash_Find (res->strref_hash, s); if (__builtin_expect (!sr, 1)) { - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_static; sr->s.string = pr_strdup(pr, s); - Hash_Add (pr->strref_hash, sr); + Hash_Add (res->strref_hash, sr); } - return string_index (pr, sr); + return string_index (res, sr); } -void -PR_ClearReturnStrings (progs_t *pr) +VISIBLE string_t +PR_FindString (progs_t *pr, const char *s) { - int i; + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr; - for (i = 0; i < PR_RS_SLOTS; i++) { - if (pr->return_strings[i]) - free_string_ref (pr, pr->return_strings[i]); - pr->return_strings[i] = 0; + if (!s) + s = ""; + sr = Hash_Find (res->strref_hash, s); + + if (sr) { + return string_index (res, sr); } + return 0; } VISIBLE string_t PR_SetReturnString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) s = ""; - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + if (sr->type == str_return && sr->rs_slot) { + requeue_strref (res, sr); + } else if ((sr->type == str_return && !sr->rs_slot) + || (sr->type != str_return && sr->rs_slot)) { + PR_Error (pr, "internal string error: line:%d %d %p", __LINE__, + sr->type, sr->rs_slot); + } + return string_index (res, sr); } - if ((sr = pr->return_strings[pr->rs_slot])) { - if (sr->type != str_return) - PR_Error (pr, "internal string error"); + // grab the string ref from the oldest slot, or make a new one if the + // slot is empty + if ((sr = res->rs_slot->strref)) { + if (sr->type != str_return || sr->rs_slot != res->rs_slot) { + PR_Error (pr, "internal string error: line:%d", __LINE__); + } pr_strfree (pr, sr->s.string); } else { - sr = new_string_ref (pr); + sr = new_string_ref (res); + res->rs_slot->strref = sr; } sr->type = str_return; + sr->rs_slot = res->rs_slot; sr->s.string = pr_strdup(pr, s); - pr->return_strings[pr->rs_slot++] = sr; - pr->rs_slot %= PR_RS_SLOTS; - return string_index (pr, sr); + // the oldest slot just became the newest, so advance to the next oldest + res->rs_slot = res->rs_slot->next; + + return string_index (res, sr); } static inline string_t -pr_settempstring (progs_t *pr, char *s) +pr_settempstring (progs_t *pr, prstr_resources_t *res, char *s) { strref_t *sr; - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_temp; sr->s.string = s; sr->next = pr->pr_xtstr; pr->pr_xtstr = sr; - return string_index (pr, sr); + return string_index (res, sr); } VISIBLE string_t @@ -408,46 +522,77 @@ PR_CatStrings (progs_t *pr, const char *a, const char *b) strcpy (c, a); strcpy (c + lena, b); - return pr_settempstring (pr, c); + return pr_settempstring (pr, pr->pr_string_resources, c); } VISIBLE string_t PR_SetTempString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) return PR_SetString (pr, ""); - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + return string_index (res, sr); } - return pr_settempstring (pr, pr_strdup (pr, s)); + return pr_settempstring (pr, res, pr_strdup (pr, s)); +} + +VISIBLE string_t +PR_AllocTempBlock (progs_t *pr, size_t size) +{ + prstr_resources_t *res = pr->pr_string_resources; + return pr_settempstring (pr, res, pr_strmalloc (pr, size)); +} + +VISIBLE void +PR_PushTempString (progs_t *pr, string_t num) +{ + prstr_resources_t *res = pr->pr_string_resources; + strref_t *ref = get_strref (res, num); + strref_t **temp_ref; + + if (!ref || ref->type != str_temp) { + PR_Error (pr, "attempt to push a non-temp string"); + } + for (temp_ref = &pr->pr_xtstr; *temp_ref; temp_ref = &(*temp_ref)->next) { + if (*temp_ref == ref) { + *temp_ref = ref->next; + ref->next = pr->pr_pushtstr; + pr->pr_pushtstr = ref; + return; + } + } + PR_Error (pr, "attempt to push stale temp string"); } VISIBLE string_t PR_SetDynamicString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) return PR_SetString (pr, ""); - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + return string_index (res, sr); } - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_dynamic; sr->s.string = pr_strdup (pr, s); - return string_index (pr, sr); + return string_index (res, sr); } -void +VISIBLE void PR_MakeTempString (progs_t *pr, string_t str) { - strref_t *sr = get_strref (pr, str); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = get_strref (res, str); if (!sr) PR_RunError (pr, "invalid string %d", str); @@ -468,21 +613,54 @@ PR_MakeTempString (progs_t *pr, string_t str) VISIBLE string_t PR_NewMutableString (progs_t *pr) { - strref_t *sr = new_string_ref (pr); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = new_string_ref (res); sr->type = str_mutable; - sr->s.dstring = _dstring_newstr (pr->ds_mem); - return string_index (pr, sr); + sr->s.dstring = _dstring_newstr (&res->ds_mem); + return string_index (res, sr); +} + +VISIBLE void +PR_HoldString (progs_t *pr, string_t str) +{ + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = get_strref (res, str); + + if (sr) { + switch (sr->type) { + case str_temp: + break; + case str_return: + sr->rs_slot->strref = 0; + sr->rs_slot = 0; + break; + case str_static: + case str_mutable: + case str_dynamic: + // non-ephemeral string, no-op + return; + default: + PR_Error (pr, "internal string error: line:%d", __LINE__); + } + sr->type = str_dynamic; + return; + } + if (!PR_StringValid (pr, str)) { + PR_RunError (pr, "attempt to hold invalid string %d", str); + } } VISIBLE void PR_FreeString (progs_t *pr, string_t str) { - strref_t *sr = get_strref (pr, str); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = get_strref (res, str); if (sr) { switch (sr->type) { case str_static: case str_temp: + case str_return: return; case str_mutable: dstring_delete (sr->s.dstring); @@ -490,34 +668,45 @@ PR_FreeString (progs_t *pr, string_t str) case str_dynamic: pr_strfree (pr, sr->s.string); break; - case str_return: default: - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: line:%d", __LINE__); } - free_string_ref (pr, sr); + free_string_ref (res, sr); return; } - if (!get_string (pr, str)) + if (!PR_StringValid (pr, str)) { PR_RunError (pr, "attempt to free invalid string %d", str); + } } -void +VISIBLE void PR_FreeTempStrings (progs_t *pr) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr, *t; for (sr = pr->pr_xtstr; sr; sr = t) { t = sr->next; + if (sr->type == str_dynamic) { + // the string has been held, so simply remove the ref from the + // queue + continue; + } if (sr->type != str_temp) - PR_Error (pr, "internal string error"); - if (R_STRING (pr) < 0 && string_index (pr, sr) == R_STRING (pr) + PR_Error (pr, "internal string error: line:%d", __LINE__); + if (R_STRING (pr) < 0 && string_index (res, sr) == R_STRING (pr) && pr->pr_depth) { + // It looks like the temp string is being returned. While this + // may be a false positive (just a random integer with the same + // value), it is better to hold onto the temp string a little + // longer than to remove it prematurely. This allows functions + // to return the result of "str a" + "str b" prstack_t *frame = pr->pr_stack + pr->pr_depth - 1; sr->next = frame->tstr; frame->tstr = sr; } else { pr_strfree (pr, sr->s.string); - free_string_ref (pr, sr); + free_string_ref (res, sr); } } pr->pr_xtstr = 0; @@ -549,10 +738,9 @@ PR_FreeTempStrings (progs_t *pr) list item. */ static void -I_DoPrint (dstring_t *result, fmt_item_t *formatting) +I_DoPrint (dstring_t *tmp, dstring_t *result, fmt_item_t *formatting) { fmt_item_t *current = formatting; - dstring_t *tmp = dstring_new (); while (current) { qboolean doPrecision, doWidth; @@ -596,270 +784,442 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting) break; case 'f': dstring_appendstr (tmp, "f"); - PRINT (float); + if (current->flags & FMT_LONG) { + PRINT (double); + } else { + PRINT (float); + } break; case 'g': dstring_appendstr (tmp, "g"); - PRINT (float); + if (current->flags & FMT_LONG) { + PRINT (double); + } else { + PRINT (float); + } break; default: break; } current = current->next; } - dstring_delete (tmp); } static fmt_item_t * -new_fmt_item (void) +new_fmt_item (prstr_resources_t *res) { int i; fmt_item_t *fi; - if (!free_fmt_items) { - free_fmt_items = malloc (16 * sizeof (fmt_item_t)); + if (!res->free_fmt_items) { + res->free_fmt_items = malloc (16 * sizeof (fmt_item_t)); for (i = 0; i < 15; i++) - free_fmt_items[i].next = free_fmt_items + i + 1; - free_fmt_items[i].next = 0; + res->free_fmt_items[i].next = res->free_fmt_items + i + 1; + res->free_fmt_items[i].next = 0; } - fi = free_fmt_items; - free_fmt_items = fi->next; + fi = res->free_fmt_items; + res->free_fmt_items = fi->next; memset (fi, 0, sizeof (*fi)); fi->precision = -1; return fi; } static void -free_fmt_item (fmt_item_t *fi) +free_fmt_item (prstr_resources_t *res, fmt_item_t *fi) { - fi->next = free_fmt_items; - free_fmt_items = fi; + fi->next = res->free_fmt_items; + res->free_fmt_items = fi; +} + +struct fmt_state_s; +typedef void (*fmt_state_f) (struct fmt_state_s *); + +typedef struct fmt_state_s { + fmt_state_f state; + prstr_resources_t *res; + progs_t *pr; + pr_type_t **args; + const char *c; + const char *msg; + fmt_item_t *fmt_items; + fmt_item_t **fi; + int fmt_count; +} fmt_state_t; + +static inline void +fmt_append_item (fmt_state_t *state) +{ + (*state->fi)->next = new_fmt_item (state->res); + state->fi = &(*state->fi)->next; } #undef P_var -#define P_var(p,n,t) (args[n]->t##_var) +#define P_var(p,n,t) (state->args[n]->t##_var) +#undef P_DOUBLE +#define P_DOUBLE(p,n) (*(double *) (state->args[n])) + +/** State machine for PR_Sprintf + * + * Parsing of the format string is implemented via the following state + * machine. Note that in all states, end-of-string terminates the machine. + * If the machine terminates in any state other than format or conversion, + * an error is generated. + * \dot + * digraph PR_Sprintf_fmt_state_machine { + * format -> flags [label="{%}"]; + * flogs -> format [label="{%}"]; + * flags -> flags [label="{#+0 -}"]; + * flags -> var_field_width [label="{*}"]; + * flags -> precision [label="{.}"]; + * flags -> field_width [label="{[1-9]}"]; + * flags -> modifiers [label="other"]; + * var_field_width -> precision [label="{.}"]; + * var_field_width -> modifiers [label="other"]; + * field_width -> field_width [label="{[0-9]}"]; + * field_width -> precision [label="{.}"]; + * field_width -> modifiers [label="other"]; + * precision -> var_precision [label="{*}"]; + * precision -> fixed_precision [label="{[0-9]}"]; + * precision -> modifiers [label="other"]; + * var_precision -> modifiers [label="instant"]; + * fixed_precision -> fixed_precision [label="{[0-9]}"]; + * fixed_precision -> modifiers [label="other"]; + * modifiers -> conversion [label="instant/other"]; + * conversion -> format [label="other"]; + * } + * \enddot + */ +///@{ +static void fmt_state_format (fmt_state_t *state); +static void fmt_state_flags (fmt_state_t *state); +static void fmt_state_var_field_width (fmt_state_t *state); +static void fmt_state_field_width (fmt_state_t *state); +static void fmt_state_precision (fmt_state_t *state); +static void fmt_state_var_precision (fmt_state_t *state); +static void fmt_state_fixed_precision (fmt_state_t *state); +static void fmt_state_modifiers (fmt_state_t *state); +static void fmt_state_conversion (fmt_state_t *state); + +static void +fmt_state_flags (fmt_state_t *state) +{ + state->c++; // skip over % + while (1) { + switch (*state->c) { + case '%': + state->c++; + (*state->fi)->flags = 0; + (*state->fi)->precision = 1; + (*state->fi)->minFieldWidth = 0; + (*state->fi)->type = 's'; + (*state->fi)->data.string_var = "%"; + + fmt_append_item (state); + state->state = fmt_state_format; + return; + case '0': + (*state->fi)->flags |= FMT_ZEROPAD; + break; + case '#': + (*state->fi)->flags |= FMT_ALTFORM; + break; + case ' ': + (*state->fi)->flags |= FMT_ADDBLANK; + break; + case '-': + (*state->fi)->flags |= FMT_LJUSTIFY; + break; + case '+': + (*state->fi)->flags |= FMT_ADDSIGN; + break; + case '*': + state->state = fmt_state_var_field_width; + return; + case '.': + state->state = fmt_state_precision; + return; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + state->state = fmt_state_field_width; + return; + default: + state->state = fmt_state_modifiers; + return; + } + state->c++; + } +} + +static void +fmt_state_var_field_width (fmt_state_t *state) +{ + (*state->fi)->minFieldWidth = P_INT (pr, state->fmt_count); + state->fmt_count++; + if (*++state->c == '.') { + state->state = fmt_state_precision; + } else { + state->state = fmt_state_modifiers; + } +} + +static void +fmt_state_field_width (fmt_state_t *state) +{ + while (isdigit ((byte )*state->c)) { + (*state->fi)->minFieldWidth *= 10; + (*state->fi)->minFieldWidth += *state->c++ - '0'; + } + if (*state->c == '.') { + state->state = fmt_state_precision; + } else { + state->state = fmt_state_modifiers; + } +} + +static void +fmt_state_precision (fmt_state_t *state) +{ + state->c++; // skip over . + (*state->fi)->precision = 0; + if (isdigit ((byte )*state->c)) { + state->state = fmt_state_fixed_precision; + } else if (*state->c == '*') { + state->state = fmt_state_var_precision; + } else { + state->state = fmt_state_modifiers; + } +} + +static void +fmt_state_var_precision (fmt_state_t *state) +{ + state->c++; // skip over * + (*state->fi)->precision = P_INT (pr, state->fmt_count); + state->fmt_count++; + state->state = fmt_state_modifiers; +} + +static void +fmt_state_fixed_precision (fmt_state_t *state) +{ + while (isdigit ((byte )*state->c)) { + (*state->fi)->precision *= 10; + (*state->fi)->precision += *state->c++ - '0'; + } + state->state = fmt_state_modifiers; +} + +static void +fmt_state_modifiers (fmt_state_t *state) +{ + // no modifiers supported + state->state = fmt_state_conversion; +} + +static void +fmt_state_conversion (fmt_state_t *state) +{ + progs_t *pr = state->pr; + char conv; + switch ((conv = *state->c++)) { + case '@': + // object + state->fmt_count++; + fmt_append_item (state); + break; + case 'e': + // entity + (*state->fi)->type = 'i'; + (*state->fi)->data.integer_var = + P_EDICTNUM (pr, state->fmt_count); + + state->fmt_count++; + fmt_append_item (state); + break; + case 'i': + case 'd': + case 'c': + // integer + (*state->fi)->type = conv; + (*state->fi)->data.integer_var = P_INT (pr, state->fmt_count); + + state->fmt_count++; + fmt_append_item (state); + break; + case 'f': + // float or double + case 'g': + // float or double, no trailing zeroes, trim "." + // if nothing after + (*state->fi)->type = conv; + if (pr->float_promoted) { + (*state->fi)->flags |= FMT_LONG; + (*state->fi)->data.double_var + = P_DOUBLE (pr, state->fmt_count); + } else { + (*state->fi)->data.float_var + = P_FLOAT (pr, state->fmt_count); + } + + state->fmt_count++; + fmt_append_item (state); + break; + case 'p': + // pointer + (*state->fi)->flags |= FMT_ALTFORM; + (*state->fi)->type = 'x'; + (*state->fi)->data.uinteger_var = P_UINT (pr, state->fmt_count); + + state->fmt_count++; + fmt_append_item (state); + break; + case 's': + // string + (*state->fi)->type = conv; + (*state->fi)->data.string_var = P_GSTRING (pr, state->fmt_count); + + state->fmt_count++; + fmt_append_item (state); + break; + case 'v': + case 'q': + // vector + { + int i, count = 3; + int flags = (*state->fi)->flags; + int precision = (*state->fi)->precision; + unsigned minWidth = (*state->fi)->minFieldWidth; + + (*state->fi)->flags = 0; + (*state->fi)->precision = -1; + (*state->fi)->minFieldWidth = 0; + + if (conv == 'q') + count = 4; + + for (i = 0; i < count; i++) { + if (i == 0) { + (*state->fi)->type = 's'; + (*state->fi)->data.string_var = "'"; + } else { + (*state->fi)->type = 's'; + (*state->fi)->data.string_var = " "; + } + fmt_append_item (state); + + (*state->fi)->flags = flags; + (*state->fi)->precision = precision; + (*state->fi)->minFieldWidth = minWidth; + (*state->fi)->type = 'g'; + (*state->fi)->data.float_var = + P_VECTOR (pr, state->fmt_count)[i]; + + fmt_append_item (state); + } + } + + (*state->fi)->type = 's'; + (*state->fi)->data.string_var = "'"; + + state->fmt_count++; + fmt_append_item (state); + break; + case 'x': + // integer, hex notation + (*state->fi)->type = conv; + (*state->fi)->data.uinteger_var = P_UINT (pr, state->fmt_count); + + state->fmt_count++; + fmt_append_item (state); + break; + } + if (*state->c) { + state->state = fmt_state_format; + } else { + state->state = 0; // finished + } +} + +static void +fmt_state_format (fmt_state_t *state) +{ + const char *l = state->c; + while (*state->c && *state->c != '%') { + state->c++; + } + if (state->c != l) { + // have some unformatted text to print + (*state->fi)->precision = state->c - l; + (*state->fi)->type = 's'; + (*state->fi)->data.string_var = l; + if (*state->c) { + fmt_append_item (state); + } + } + if (*state->c) { + state->state = fmt_state_flags; + } else { + state->state = 0; // finished + } +} +///@} + VISIBLE void PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, const char *format, int count, pr_type_t **args) { - const char *c, *l; - const char *msg = ""; - fmt_item_t *fmt_items = 0; - fmt_item_t **fi = &fmt_items; - int fmt_count = 0; + prstr_resources_t *res = pr->pr_string_resources; + fmt_state_t state = { }; + + state.pr = pr; + state.res = res; + state.args = args; + state.fi = &state.fmt_items; + *state.fi = new_fmt_item (res); + state.c = format; + state.state = fmt_state_format; if (!name) - name = "PF_InternalSprintf"; + name = "PR_Sprintf"; - *fi = new_fmt_item (); - c = l = format; - while (*c) { - if (*c++ == '%') { - if (c != l + 1) { - // have some unformatted text to print - (*fi)->precision = c - l - 1; - (*fi)->type = 's'; - (*fi)->data.string_var = l; - - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - } - if (*c == '%') { - (*fi)->type = 's'; - (*fi)->data.string_var = "%"; - - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - } else { - do { - switch (*c) { - // format options - case '\0': - msg = "Unexpected end of format string"; - goto error; - case '0': - (*fi)->flags |= FMT_ZEROPAD; - c++; - continue; - case '#': - (*fi)->flags |= FMT_ALTFORM; - c++; - continue; - case ' ': - (*fi)->flags |= FMT_ADDBLANK; - c++; - continue; - case '-': - (*fi)->flags |= FMT_LJUSTIFY; - c++; - continue; - case '+': - (*fi)->flags |= FMT_ADDSIGN; - c++; - continue; - case '.': - (*fi)->precision = 0; - c++; - while (isdigit ((byte )*c)) { - (*fi)->precision *= 10; - (*fi)->precision += *c++ - '0'; - } - continue; - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - while (isdigit ((byte )*c)) { - (*fi)->minFieldWidth *= 10; - (*fi)->minFieldWidth += *c++ - '0'; - } - continue; - // format types - case '@': - // object - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - case 'e': - // entity - (*fi)->type = 'i'; - (*fi)->data.integer_var = - P_EDICTNUM (pr, fmt_count); - - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - case 'i': - case 'd': - case 'c': - // integer - (*fi)->type = *c; - (*fi)->data.integer_var = P_INT (pr, fmt_count); - - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - case 'f': - // float - case 'g': - // float, no trailing zeroes, trim "." if nothing - // after - (*fi)->type = *c; - (*fi)->data.float_var = P_FLOAT (pr, fmt_count); - - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - case 'p': - // pointer - (*fi)->flags |= FMT_ALTFORM; - (*fi)->type = 'x'; - (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); - - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - case 's': - // string - (*fi)->type = *c; - (*fi)->data.string_var = P_GSTRING (pr, fmt_count); - - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - case 'v': - case 'q': - // vector - { - int i, count = 3; - int flags = (*fi)->flags; - int precision = (*fi)->precision; - unsigned minWidth = (*fi)->minFieldWidth; - - (*fi)->flags = 0; - (*fi)->precision = -1; - (*fi)->minFieldWidth = 0; - - if (*c == 'q') - count = 4; - - for (i = 0; i < count; i++) { - if (i == 0) { - (*fi)->type = 's'; - (*fi)->data.string_var = "'"; - } else { - (*fi)->type = 's'; - (*fi)->data.string_var = " "; - } - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - - (*fi)->flags = flags; - (*fi)->precision = precision; - (*fi)->minFieldWidth = minWidth; - (*fi)->type = 'g'; - (*fi)->data.float_var = - P_VECTOR (pr, fmt_count)[i]; - - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - } - } - - (*fi)->type = 's'; - (*fi)->data.string_var = "'"; - - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - case 'x': - // integer, hex notation - (*fi)->type = *c; - (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); - - fmt_count++; - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; - break; - } - break; - } while (1); - } - l = ++c; - } - } - if (c != l) { - // have some unformatted text to print - (*fi)->precision = c - l; - (*fi)->type = 's'; - (*fi)->data.string_var = l; - - (*fi)->next = new_fmt_item (); - fi = &(*fi)->next; + while (*state.c && state.state) { + state.state (&state); } - if (fmt_count != count) { - if (fmt_count > count) - msg = "Not enough arguments for format string."; + if (state.state) { + state.msg = "Unexpected end of format string"; + } else if (state.fmt_count != count) { + if (state.fmt_count > count) + state.msg = "Not enough arguments for format string."; else - msg = "Too many arguments for format string."; - msg = va ("%s: %d %d", msg, fmt_count, count); + state.msg = "Too many arguments for format string."; + } + if (state.msg) { + dsprintf (res->print_str, "%s: %d %d", state.msg, state.fmt_count, + count); + state.msg = res->print_str->str; goto error; } - I_DoPrint (result, fmt_items); - while (fmt_items) { - fmt_item_t *t = fmt_items->next; - free_fmt_item (fmt_items); - fmt_items = t; + dstring_clear (res->print_str); + I_DoPrint (res->print_str, result, state.fmt_items); + while (state.fmt_items) { + fmt_item_t *t = state.fmt_items->next; + free_fmt_item (res, state.fmt_items); + state.fmt_items = t; } return; error: - PR_RunError (pr, "%s: %s", name, msg); + PR_RunError (pr, "%s: %s", name, state.msg); +} + +void +PR_Strings_Init (progs_t *pr) +{ + prstr_resources_t *res = calloc (1, sizeof (*res)); + res->pr = pr; + res->print_str = dstring_new (); + + PR_Resources_Register (pr, "Strings", res, pr_strings_clear); } diff --git a/libs/gamecode/pr_zone.c b/libs/gamecode/pr_zone.c index e7239bc0c..5b85a7ffd 100644 --- a/libs/gamecode/pr_zone.c +++ b/libs/gamecode/pr_zone.c @@ -49,6 +49,7 @@ static void pr_zone_error (void *_pr, const char *msg) { progs_t *pr = (progs_t *) _pr; + Z_Print (pr->zone); PR_RunError (pr, "%s", msg); } @@ -74,6 +75,14 @@ PR_Zone_Malloc (progs_t *pr, pr_int_t size) return Z_Malloc (pr->zone, size); } +VISIBLE void * +PR_Zone_TagMalloc (progs_t *pr, int size, int tag) +{ + if (size <= 0) + PR_RunError (pr, "attempt to allocate less than 1 byte"); + return Z_TagMalloc (pr->zone, size, tag); +} + VISIBLE void * PR_Zone_Realloc (progs_t *pr, void *ptr, pr_int_t size) { diff --git a/libs/gib/Makefile.am b/libs/gib/Makefile.am deleted file mode 100644 index 80ea92067..000000000 --- a/libs/gib/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -AUTOMAKE_OPTIONS= foreign -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(FNM_FLAGS) - -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined - -gib_deps= \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(top_builddir)/libs/util/libQFutil.la - -lib_LTLIBRARIES= libQFgib.la - -libQFgib_la_LDFLAGS= $(lib_ldflags) -libQFgib_la_LIBADD= $(gib_deps) -libQFgib_la_DEPENDENCIES= $(gib_deps) -libQFgib_la_SOURCES= \ - bi_gib.c \ - gib_buffer.c gib_builtin.c gib_classes.c gib_execute.c gib_function.c \ - gib_parse.c gib_handle.c gib_object.c gib_process.c gib_regex.c \ - gib_thread.c gib_vars.c gib_init.c gib_tree.c \ - gib_semantics.c ops.c exp.c regex.c diff --git a/libs/gib/Makemodule.am b/libs/gib/Makemodule.am new file mode 100644 index 000000000..e0fbe14c2 --- /dev/null +++ b/libs/gib/Makemodule.am @@ -0,0 +1,29 @@ +gib_deps= \ + libs/ruamoko/libQFruamoko.la \ + libs/util/libQFutil.la + +lib_LTLIBRARIES += libs/gib/libQFgib.la + +libs_gib_libQFgib_la_LDFLAGS= $(lib_ldflags) +libs_gib_libQFgib_la_LIBADD= $(gib_deps) +libs_gib_libQFgib_la_DEPENDENCIES= $(gib_deps) +libs_gib_libQFgib_la_SOURCES= \ + libs/gib/bi_gib.c \ + libs/gib/gib_buffer.c \ + libs/gib/gib_builtin.c \ + libs/gib/gib_classes.c \ + libs/gib/gib_execute.c \ + libs/gib/gib_function.c \ + libs/gib/gib_parse.c \ + libs/gib/gib_handle.c \ + libs/gib/gib_object.c \ + libs/gib/gib_process.c \ + libs/gib/gib_regex.c \ + libs/gib/gib_thread.c \ + libs/gib/gib_vars.c \ + libs/gib/gib_init.c \ + libs/gib/gib_tree.c \ + libs/gib/gib_semantics.c \ + libs/gib/ops.c \ + libs/gib/exp.c \ + libs/gib/regex.c diff --git a/libs/gib/bi_gib.c b/libs/gib/bi_gib.c index b1482c030..2b1c6c5b4 100644 --- a/libs/gib/bi_gib.c +++ b/libs/gib/bi_gib.c @@ -91,6 +91,7 @@ bi_gib_builtin_f (void) PR_RESET_PARAMS (builtin->pr); P_INT (builtin->pr, 0) = GIB_Argc(); P_INT (builtin->pr, 1) = PR_SetPointer (builtin->pr, pr_list); + builtin->pr->pr_argc = 2; PR_ExecuteProgram (builtin->pr, builtin->func); PR_PopFrame (builtin->pr); PR_Zone_Free (builtin->pr, pr_list); @@ -192,7 +193,8 @@ GIB_Progs_Init (progs_t *pr) PR_Resources_Register (pr, "GIB", res, bi_gib_builtin_clear); bi_gib_builtins = Hash_NewTable (1021, bi_gib_builtin_get_key, - bi_gib_builtin_free, 0); + bi_gib_builtin_free, 0, + pr->hashlink_freelist); PR_RegisterBuiltins (pr, builtins); } diff --git a/libs/gib/exp.c b/libs/gib/exp.c index 7f831a122..3ca5b19b8 100644 --- a/libs/gib/exp.c +++ b/libs/gib/exp.c @@ -154,7 +154,7 @@ EXP_FindFuncByStr (const char *str) return 0; } -static int +static __attribute__((pure)) int EXP_ContainsCommas (token * chain) { token *cur; @@ -311,7 +311,7 @@ EXP_ParseString (char *str) } else { EXP_DestroyTokens (chain); EXP_Error (EXP_E_INVOP, - va ("Unknown operator or function '%s'.", buf)); + va (0, "Unknown operator or function '%s'.", buf)); return 0; } } @@ -347,8 +347,7 @@ EXP_SimplifyTokens (token * chain) cur = cur->generic.prev; if (EXP_DoFunction (cur)) return EXP_Error (EXP_E_SYNTAX, - va - ("Invalid number of arguments to function '%s'.", + va (0, "Invalid number of arguments to function '%s'.", cur->func.func->str)); } else { if (EXP_ContainsCommas (cur)) @@ -374,8 +373,7 @@ EXP_SimplifyTokens (token * chain) if (cur->generic.next->generic.type == TOKEN_OP) if (EXP_DoUnary (cur->generic.next)) return EXP_Error (EXP_E_SYNTAX, - va - ("Unary operator '%s' not followed by a unary operator or numerical value.", + va (0, "Unary operator '%s' not followed by a unary operator or numerical value.", cur->generic.next->op.op->str)); if (optable[i].operands == 1 && cur->generic.next->generic.type == TOKEN_NUM) { @@ -482,14 +480,12 @@ EXP_Validate (token * chain) cur->generic.next->op.op = EXP_FindOpByStr ("neg"); else if (cur->generic.next->op.op->operands == 2) return EXP_Error (EXP_E_SYNTAX, - va - ("Operator '%s' does not follow a number or numerical value.", + va (0, "Operator '%s' does not follow a number or numerical value.", cur->generic.next->op.op->str)); } else if (cur->generic.type == TOKEN_FUNC && cur->generic.next->generic.type != TOKEN_OPAREN) return EXP_Error (EXP_E_SYNTAX, - va - ("Function '%s' called without an argument list.", + va (0, "Function '%s' called without an argument list.", cur->func.func->str)); else if (cur->generic.type == TOKEN_COMMA && @@ -501,7 +497,7 @@ EXP_Validate (token * chain) else if (cur->generic.type == TOKEN_OP && cur->generic.next->generic.type == TOKEN_CPAREN) return EXP_Error (EXP_E_SYNTAX, - va ("Operator '%s' is missing an operand.", + va (0, "Operator '%s' is missing an operand.", cur->op.op->str)); else if (cur->generic.type == TOKEN_NUM && cur->generic.next->generic.type == TOKEN_NUM) diff --git a/libs/gib/gib_builtin.c b/libs/gib/gib_builtin.c index c3ba2910a..190ec8373 100644 --- a/libs/gib/gib_builtin.c +++ b/libs/gib/gib_builtin.c @@ -99,7 +99,7 @@ GIB_Builtin_Add (const char *name, void (*func) (void)) if (!gib_builtins) gib_builtins = - Hash_NewTable (1024, GIB_Builtin_Get_Key, GIB_Builtin_Free, 0); + Hash_NewTable (1024, GIB_Builtin_Get_Key, GIB_Builtin_Free, 0, 0); new = calloc (1, sizeof (gib_builtin_t)); new->func = func; @@ -236,8 +236,8 @@ GIB_Local_f (void) for (i = 3; i < GIB_Argc(); i++) GIB_Return (GIB_Argv(i)); } else for (i = 1; i < GIB_Argc(); i++) - var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero, - GIB_Argv (i), &index, true); + GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero, + GIB_Argv (i), &index, true); } @@ -261,8 +261,8 @@ GIB_Shared_f (void) for (i = 3; i < GIB_Argc(); i++) GIB_Return (GIB_Argv(i)); } else for (i = 1; i < GIB_Argc(); i++) - var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero, - GIB_Argv (i), &index, true); + GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero, + GIB_Argv (i), &index, true); } static void @@ -823,7 +823,7 @@ GIB_File_Write_f (void) } path = GIB_Argv (1); - QFS_WriteFile (va ("%s/%s", qfs_gamedir->dir.def, path), + QFS_WriteFile (va (0, "%s/%s", qfs_gamedir->dir.def, path), GIB_Argv(2), GIB_Argd(2)->size-1); } diff --git a/libs/gib/gib_classes.c b/libs/gib/gib_classes.c index 749e7ff07..55087dcdf 100644 --- a/libs/gib/gib_classes.c +++ b/libs/gib/gib_classes.c @@ -388,8 +388,7 @@ ObjectHash_Construct (gib_object_t *obj) { ObjectHash_t *data = malloc (sizeof (ObjectHash_t)); - data->objects = Hash_NewTable (1024, ObjRef_Get_Key, ObjRef_Free, - NULL); + data->objects = Hash_NewTable (1024, ObjRef_Get_Key, ObjRef_Free, NULL, 0); return data; } @@ -445,7 +444,7 @@ ObjectHash_Get_f (gib_object_t *obj, gib_method_t *method, void *data, if ((refs = (ObjRef_t **) Hash_FindList (objh->objects, mesg.argv[1]))) { for (r = refs, len = 0; *r; r++, len++); - reply = malloc (sizeof (char **) * len); + reply = malloc (sizeof (char *) * len); for (r = refs, i = 0; *r; r++, i++) reply[i] = (*r)->obj->handstr; GIB_Reply (obj, mesg, len, reply); @@ -613,9 +612,9 @@ static const char *g_gcbs_name; static const char *gcbs_fname (const char *str) { if (g_gcbs_mode == INSTANCE) - return va ("__%s_%s__", g_gcbs_name, str); + return va (0, "__%s_%s__", g_gcbs_name, str); else - return va ("%s::%s", g_gcbs_name, str); + return va (0, "%s::%s", g_gcbs_name, str); } void diff --git a/libs/gib/gib_function.c b/libs/gib/gib_function.c index 72c1d1ea5..c960a7d49 100644 --- a/libs/gib/gib_function.c +++ b/libs/gib/gib_function.c @@ -117,8 +117,8 @@ GIB_Function_Define (const char *name, const char *text, gib_tree_t * program, if (script) script->refs++; if (!gib_functions) - gib_functions = - Hash_NewTable (1024, GIB_Function_Get_Key, GIB_Function_Free, 0); + gib_functions = Hash_NewTable (1024, GIB_Function_Get_Key, + GIB_Function_Free, 0, 0); func = Hash_Find (gib_functions, name); if (func) { @@ -234,11 +234,10 @@ GIB_Function_Prepare_Args_D (cbuf_t * cbuf, dstring_t **args, unsigned int g_fpad_args = args; g_fpad_argc = argc; - i = 1; llist_iterate (arglist, LLIST_ICAST (fpad_iterate)); + llist_iterate (arglist, LLIST_ICAST (fpad_iterate)); - var = - GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, &g_fpad_zero, argss, - &g_fpad_ind, true); + var = GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, &g_fpad_zero, argss, + &g_fpad_ind, true); var->array = realloc (var->array, sizeof (struct gib_varray_s) * argc); memset (var->array + 1, 0, (argc - 1) * sizeof (struct gib_varray_s)); var->size = argc; diff --git a/libs/gib/gib_object.c b/libs/gib/gib_object.c index a4954762b..b9fbf66a9 100644 --- a/libs/gib/gib_object.c +++ b/libs/gib/gib_object.c @@ -125,7 +125,8 @@ GIB_Method_Build_Hash (gib_class_t *class, hashtab_t *inherited, { gib_methodtab_t *m; gib_method_t *method; - hashtab_t *new = Hash_NewTable (1024, GIB_Method_Get_Key, GIB_Method_Free, 0); + hashtab_t *new = Hash_NewTable (1024, GIB_Method_Get_Key, + GIB_Method_Free, 0, 0); for (m = methods; m->name; m++) { method = malloc (sizeof (gib_method_t)); @@ -204,10 +205,10 @@ GIB_Object_Create (const char *classname, qboolean classobj) obj->data = malloc (sizeof (void *) * (class->depth+1)); obj->methods = classobj ? class->class_methods : class->methods; obj->handle = classobj ? 0 : GIB_Handle_New (obj); - obj->handstr = strdup (va ("%lu", obj->handle)); + obj->handstr = strdup (va (0, "%lu", obj->handle)); obj->refs = 1; obj->signals = Hash_NewTable (128, GIB_Signal_Get_Key, - GIB_Signal_Free, NULL); + GIB_Signal_Free, NULL, 0); obj->slots = llist_new (GIB_Slot_Free, NULL, NULL); if (classobj) { @@ -392,7 +393,8 @@ GIB_Object_Signal_Emit (gib_object_t *sender, int argc, const char **argv) void GIB_Object_Init (void) { - gib_classes = Hash_NewTable (1024, GIB_Class_Get_Key, GIB_Class_Free, 0); + gib_classes = Hash_NewTable (1024, GIB_Class_Get_Key, + GIB_Class_Free, 0, 0); GIB_Classes_Init (); } diff --git a/libs/gib/gib_parse.c b/libs/gib/gib_parse.c index 0ace51571..c0afaa8d5 100644 --- a/libs/gib/gib_parse.c +++ b/libs/gib/gib_parse.c @@ -333,7 +333,8 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs) return nodes; ERROR: if (c) - GIB_Parse_Error (va ("Could not find match for '%c'.", c), *i + pofs); + GIB_Parse_Error (va (0, "Could not find match for '%c'.", c), + *i + pofs); if (nodes) GIB_Tree_Unref (&nodes); return 0; @@ -496,7 +497,8 @@ GIB_Parse_Embedded (gib_tree_t *token) return lines; ERROR: if (c) - GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + token->start); + GIB_Parse_Error (va (0, "Could not find match for '%c'.", c), + i + token->start); if (lines) GIB_Tree_Unref (&lines); return 0; diff --git a/libs/gib/gib_regex.c b/libs/gib/gib_regex.c index e808532d6..dbe43cf04 100644 --- a/libs/gib/gib_regex.c +++ b/libs/gib/gib_regex.c @@ -63,7 +63,7 @@ GIB_Regex_Free (void *ele, void *ptr) void GIB_Regex_Init (void) { - gib_regexs = Hash_NewTable (512, GIB_Regex_Get_Key, GIB_Regex_Free, 0); + gib_regexs = Hash_NewTable (512, GIB_Regex_Get_Key, GIB_Regex_Free, 0, 0); } regex_t * diff --git a/libs/gib/gib_thread.c b/libs/gib/gib_thread.c index 9c317d9fe..01d1fd98f 100644 --- a/libs/gib/gib_thread.c +++ b/libs/gib/gib_thread.c @@ -171,5 +171,5 @@ GIB_Event_Callback (gib_event_t * event, unsigned int argc, ...) void GIB_Event_Init (void) { - gib_events = Hash_NewTable (1024, GIB_Event_Get_Key, GIB_Event_Free, 0); + gib_events = Hash_NewTable (1024, GIB_Event_Get_Key, GIB_Event_Free, 0, 0); } diff --git a/libs/gib/gib_vars.c b/libs/gib/gib_vars.c index d8a555673..2d40141e1 100644 --- a/libs/gib/gib_vars.c +++ b/libs/gib/gib_vars.c @@ -51,7 +51,7 @@ GIB_Var_New (const char *key) { gib_var_t *new = calloc (1, sizeof (gib_var_t)); - new->array = calloc (1, sizeof (dstring_t *)); + new->array = calloc (1, sizeof (struct gib_varray_s)); new->key = strdup (key); return new; } @@ -117,7 +117,8 @@ GIB_Var_Get_Complex (hashtab_t ** first, hashtab_t ** second, char *key, if (!(var = GIB_Var_Get (*first, *second, key+start)) && create) { var = GIB_Var_New (key+start); if (!*first) - *first = Hash_NewTable (256, GIB_Var_Get_Key, GIB_Var_Free, 0); + *first = Hash_NewTable (256, GIB_Var_Get_Key, + GIB_Var_Free, 0, 0); Hash_Add (*first, var); } @@ -181,7 +182,8 @@ GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *ke if (create) { var = GIB_Var_New (key->str+start); if (!*first) - *first = Hash_NewTable (256, GIB_Var_Get_Key, GIB_Var_Free, 0); + *first = Hash_NewTable (256, GIB_Var_Get_Key, + GIB_Var_Free, 0, 0); Hash_Add (*first, var); } else return 0; @@ -208,7 +210,7 @@ GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *ke key->str[i] = 0; if ((var = GIB_Var_Get_Very_Complex (&one, &two, key, n+1+varstartskip, &index2, create))) { if (key->str[n] == '#') - str = va("%u", var->size); + str = va (0, "%u", var->size); else str = var->array[index2].value->str; key->str[i] = c; @@ -293,7 +295,7 @@ GIB_Domain_Get (const char *name) if (!d) { d = calloc (1, sizeof (gib_domain_t)); d->name = strdup (name); - d->vars = Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0); + d->vars = Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0, 0); Hash_Add (gib_domains, d); } return d->vars; @@ -302,12 +304,13 @@ GIB_Domain_Get (const char *name) hashtab_t * GIB_Var_Hash_New (void) { - return Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0); + return Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0, 0); } void GIB_Var_Init (void) { - gib_globals = Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0); - gib_domains = Hash_NewTable (1024, GIB_Domain_Get_Key, GIB_Domain_Free, 0); + gib_globals = Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0, 0); + gib_domains = Hash_NewTable (1024, GIB_Domain_Get_Key, + GIB_Domain_Free, 0, 0); } diff --git a/libs/image/Makefile.am b/libs/image/Makefile.am deleted file mode 100644 index 344bd7dd7..000000000 --- a/libs/image/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -AUTOMAKE_OPTIONS= foreign -AM_CFLAGS= @PREFER_PIC@ $(Z_CFLAGS) $(PNG_CFLAGS) -AM_CPPFLAGS= -I$(top_srcdir)/include - -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined - -image_deps=$(top_builddir)/libs/util/libQFutil.la - -lib_LTLIBRARIES= libQFimage.la - -libQFimage_la_LDFLAGS= $(lib_ldflags) -libQFimage_la_LIBADD= $(image_deps) $(PNG_LIBS) -libQFimage_la_DEPENDENCIES= $(pmage_deps) -libQFimage_la_SOURCES= \ - image.c pcx.c png.c tga.c - -EXTRA_DIST= diff --git a/libs/image/Makemodule.am b/libs/image/Makemodule.am new file mode 100644 index 000000000..00d1191d1 --- /dev/null +++ b/libs/image/Makemodule.am @@ -0,0 +1,14 @@ +image_deps=libs/util/libQFutil.la + +lib_LTLIBRARIES += libs/image/libQFimage.la + +libs_image_libQFimage_la_LDFLAGS= $(lib_ldflags) +libs_image_libQFimage_la_LIBADD= $(image_deps) $(PNG_LIBS) +libs_image_libQFimage_la_DEPENDENCIES= $(image_deps) +libs_image_libQFimage_la_SOURCES= \ + libs/image/convert.c \ + libs/image/image.c \ + libs/image/pcx.c \ + libs/image/png.c \ + libs/image/tga.c \ + $e diff --git a/libs/image/convert.c b/libs/image/convert.c new file mode 100644 index 000000000..cc49d6759 --- /dev/null +++ b/libs/image/convert.c @@ -0,0 +1,177 @@ +/* + convert.c + + Image/color conversion routins (RGB to paletted) + + Copyright (C) 2013 Bill Currie + + Author: Bill Currie + Date: 2013/5/10 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/alloc.h" +#include "QF/hash.h" +#include "QF/image.h" +#include "QF/mathlib.h" + +struct colcache_s { + struct colcache_s *next; + hashtab_t *tab; +}; + +typedef struct colcache_color_s { + struct colcache_color_s *next; + byte rgb[3]; + byte col; +} colcache_color_t; + +static colcache_t *colcache_freelist; +static colcache_color_t *colcache_color_freelist; + +static colcache_color_t * +colcache_new_color (const byte *rgb, byte ind) +{ + colcache_color_t *col; + ALLOC (256, colcache_color_t, colcache_color, col); + VectorCopy (rgb, col->rgb); + col->col = ind; + return col; +} + +static void +colcache_free_color (void *_col, void *unused) +{ + colcache_color_t *col = (colcache_color_t *) _col; + FREE (colcache_color, col); +} + +static uintptr_t +colcache_get_hash (const void *_col, void *unused) +{ + colcache_color_t *col = (colcache_color_t *) _col; + uintptr_t r, g, b; + r = col->rgb[0]; + g = col->rgb[1]; + b = col->rgb[2]; + return (r << 8) ^ (g << 4) ^ b; +} + +static int +colcache_compare (const void *_cola, const void *_colb, void *unused) +{ + colcache_color_t *cola = (colcache_color_t *) _cola; + colcache_color_t *colb = (colcache_color_t *) _colb; + + return VectorCompare (cola->rgb, colb->rgb); +} + +colcache_t * +ColorCache_New (void) +{ + colcache_t *cache; + + ALLOC (16, colcache_t, colcache, cache); + cache->tab = Hash_NewTable (1023, 0, colcache_free_color, 0, 0); + Hash_SetHashCompare (cache->tab, colcache_get_hash, colcache_compare); + return cache; +} + +void +ColorCache_Delete (colcache_t *cache) +{ + Hash_DelTable (cache->tab); + FREE (colcache, cache); +} + +byte +ConvertColor (const byte *rgb, const byte *pal, colcache_t *cache) +{ + //FIXME slow! + int dist[3]; + int d, bestd = 256 * 256 * 3, bestc = -1; + int i; + colcache_color_t *col; + + if (cache) { + colcache_color_t search; + VectorCopy (rgb, search.rgb); + col = Hash_FindElement (cache->tab, &search); + if (col) + return col->col; + } + + for (i = 0; i < 256; i++) { + VectorSubtract (pal + i * 3, rgb, dist); + d = DotProduct (dist, dist); + if (d < bestd) { + bestd = d; + bestc = i; + } + } + if (cache) { + col = colcache_new_color (rgb, bestc); + Hash_AddElement (cache->tab, col); + } + return bestc; +} + +tex_t * +ConvertImage (const tex_t *tex, const byte *pal) +{ + tex_t *new; + int pixels; + int bpp = 3; + int i; + colcache_t *cache; + + pixels = tex->width * tex->height; + new = malloc (sizeof (tex_t) + pixels); + new->data = (byte *) (new + 1); + new->width = tex->width; + new->height = tex->height; + new->format = tex_palette; + new->palette = pal; + switch (tex->format) { + case tex_palette: + case tex_l: // will not work as expected FIXME + case tex_a: // will not work as expected FIXME + case tex_frgba: // will not work as expected FIXME + memcpy (new->data, tex->data, pixels); + break; + case tex_la: // will not work as expected FIXME + for (i = 0; i < pixels; i++) + new->data[i] = tex->data[i * 2]; + break; + case tex_rgba: + bpp = 4; + case tex_rgb: + cache = ColorCache_New (); + for (i = 0; i < pixels; i++) + new->data[i] = ConvertColor (tex->data + i * bpp, pal, cache); + ColorCache_Delete (cache); + break; + } + return new; +} diff --git a/libs/image/image.c b/libs/image/image.c index 7df5d9bb2..4da1e5827 100644 --- a/libs/image/image.c +++ b/libs/image/image.c @@ -43,7 +43,7 @@ #include "QF/tga.h" VISIBLE tex_t * -LoadImage (const char *imageFile) +LoadImage (const char *imageFile, int load) { int tmp; dstring_t *tmpFile; @@ -64,7 +64,7 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".png", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadPNG (fp); + tex = LoadPNG (fp, load); Qclose (fp); dstring_delete (tmpFile); return (tex); @@ -74,7 +74,7 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".tga", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadTGA (fp); + tex = LoadTGA (fp, load); Qclose (fp); dstring_delete (tmpFile); return (tex); @@ -85,7 +85,7 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".jpg", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadJPG (fp); + tex = LoadJPG (fp, load); Qclose (fp); dstring_delete (tmpFile); return (tex); @@ -96,7 +96,8 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".pcx", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadPCX (fp, 1, NULL); // Convert, some users don't grok paletted + // Convert, some users don't grok paletted + tex = LoadPCX (fp, 1, NULL, load); Qclose (fp); dstring_delete (tmpFile); return (tex); diff --git a/libs/image/pcx.c b/libs/image/pcx.c index 468ce24b8..a0909536d 100644 --- a/libs/image/pcx.c +++ b/libs/image/pcx.c @@ -47,7 +47,7 @@ VISIBLE tex_t * -LoadPCX (QFile *f, qboolean convert, const byte *pal) +LoadPCX (QFile *f, qboolean convert, const byte *pal, int load) { pcx_t *pcx; int pcx_mark; @@ -58,8 +58,11 @@ LoadPCX (QFile *f, qboolean convert, const byte *pal) int runLength = 1; int count; tex_t *tex; - int fsize = Qfilesize(f); + int fsize = sizeof (pcx_t); + if (load) { + fsize = Qfilesize(f); + } // parse the PCX file pcx_mark = Hunk_LowMark (); pcx = Hunk_AllocName (fsize, "PCX"); @@ -79,20 +82,24 @@ LoadPCX (QFile *f, qboolean convert, const byte *pal) || pcx->encoding != 1 || pcx->bits_per_pixel != 8) { Sys_Printf ("Bad pcx file: %x %d %d %d\n", - pcx->manufacturer, pcx->version, pcx->encoding, pcx->bits_per_pixel); + pcx->manufacturer, pcx->version, pcx->encoding, + pcx->bits_per_pixel); + Hunk_FreeToLowMark (pcx_mark); return 0; } end = palette = ((byte *) pcx) + fsize - 768; dataByte = (byte *) &pcx[1]; - count = (pcx->xmax + 1) * (pcx->ymax + 1); + count = load ? (pcx->xmax + 1) * (pcx->ymax + 1) : 0; if (convert) { - tex = Hunk_TempAlloc (field_offset (tex_t, data[count * 3])); + tex = Hunk_TempAlloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); tex->format = tex_rgb; tex->palette = 0; } else { - tex = Hunk_TempAlloc (field_offset (tex_t, data[count])); + tex = Hunk_TempAlloc (sizeof (tex_t) + count); + tex->data = (byte *) (tex + 1); tex->format = tex_palette; if (pal) tex->palette = pal; @@ -101,6 +108,11 @@ LoadPCX (QFile *f, qboolean convert, const byte *pal) } tex->width = pcx->xmax + 1; tex->height = pcx->ymax + 1; + tex->loaded = load; + if (!load) { + Hunk_FreeToLowMark (pcx_mark); + return tex; + } pix = tex->data; while (count) { diff --git a/libs/image/png.c b/libs/image/png.c index 62d9977df..ddf9066a9 100644 --- a/libs/image/png.c +++ b/libs/image/png.c @@ -115,7 +115,7 @@ readpng_init (QFile *infile, png_structp *png_ptr, png_infop *info_ptr) /* Load the png file and return a texture */ VISIBLE tex_t * -LoadPNG (QFile *infile) +LoadPNG (QFile *infile, int load) { double gamma; png_structp png_ptr = NULL; @@ -131,37 +131,43 @@ LoadPNG (QFile *infile) png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand (png_ptr); + if (load) { + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand (png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand (png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand (png_ptr); - if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand (png_ptr); + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand (png_ptr); - if (bit_depth == 16) - png_set_strip_16 (png_ptr); + if (bit_depth == 16) + png_set_strip_16 (png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb (png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (png_ptr); - /* NOTE: gamma support? */ - /* unlike the example in the libpng documentation, we have *no* idea where - * this file may have come from--so if it doesn't have a file gamma, don't - * do any correction ("do no harm") - */ - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma (png_ptr, 1.0, gamma); + /* NOTE: gamma support? */ + /* unlike the example in the libpng documentation, we have *no* idea + * wherethis file may have come from--so if it doesn't have a file + * gamma, don't do any correction ("do no harm") + */ + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma (png_ptr, 1.0, gamma); - /* All transformations have been registered, now update the info_ptr - * structure */ - png_read_update_info (png_ptr, info_ptr); + /* All transformations have been registered, now update the info_ptr + * structure */ + png_read_update_info (png_ptr, info_ptr); - /* Allocate tex_t structure */ - rowbytes = png_get_rowbytes(png_ptr, info_ptr); - tex = Hunk_TempAlloc (field_offset (tex_t, data[height * rowbytes])); + /* Allocate tex_t structure */ + rowbytes = png_get_rowbytes(png_ptr, info_ptr); + tex = Hunk_TempAlloc (sizeof (tex_t) + height * rowbytes); + tex->data = (byte *) (tex + 1); + } else { + tex = Hunk_TempAlloc (sizeof (tex_t)); + tex->data = 0; + } tex->width = width; tex->height = height; @@ -170,6 +176,12 @@ LoadPNG (QFile *infile) else tex->format = tex_rgb; tex->palette = NULL; + tex->loaded = load; + + if (!load) { + png_read_end (png_ptr, NULL); + return tex; + } if ((row_pointers = (png_bytepp) malloc (height * sizeof (png_bytep))) == NULL) { diff --git a/libs/image/tga.c b/libs/image/tga.c index 323a05d04..1f72e2687 100644 --- a/libs/image/tga.c +++ b/libs/image/tga.c @@ -620,15 +620,18 @@ static decoder_t decoder_functions[] = { / sizeof (decoder_functions[0])) struct tex_s * -LoadTGA (QFile *fin) +LoadTGA (QFile *fin, int load) { byte *dataByte; decoder_t decode; - int fsize = Qfilesize (fin); + int fsize = sizeof (TargaHeader); int numPixels, targa_mark; TargaHeader *targa; tex_t *tex; + if (load) { + fsize = Qfilesize (fin); + } targa_mark = Hunk_LowMark (); targa = Hunk_AllocName (fsize, "TGA"); Qread (fin, targa, fsize); @@ -641,20 +644,31 @@ LoadTGA (QFile *fin) targa->height = LittleShort (targa->height); if (targa->image_type >= NUM_DECODERS - || !(decode = decoder_functions[targa->image_type])) - Sys_Error ("LoadTGA: Unsupported targa type"); + || !(decode = decoder_functions[targa->image_type])) { + Sys_Printf ("LoadTGA: Unsupported targa type"); + Hunk_FreeToLowMark (targa_mark); + return 0; + } - numPixels = targa->width * targa->height; - tex = Hunk_TempAlloc (field_offset (tex_t, data[numPixels * 4])); + if (load) { + numPixels = targa->width * targa->height; + } else { + numPixels = 0; + } + tex = Hunk_TempAlloc (sizeof (tex_t) + numPixels * 4); + tex->data = (byte *) (tex + 1); tex->width = targa->width; tex->height = targa->height; tex->palette = 0; + tex->loaded = load; - // skip TARGA image comment - dataByte = (byte *) (targa + 1); - dataByte += targa->id_length; + if (load) { + // skip TARGA image comment + dataByte = (byte *) (targa + 1); + dataByte += targa->id_length; - decode (targa, tex, dataByte); + decode (targa, tex, dataByte); + } Hunk_FreeToLowMark (targa_mark); return tex; diff --git a/libs/models/Makefile.am b/libs/models/Makefile.am deleted file mode 100644 index 2fa145649..000000000 --- a/libs/models/Makefile.am +++ /dev/null @@ -1,58 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= alias brush iqm sprite . test -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -lib_LTLIBRARIES= libQFmodels.la -noinst_LTLIBRARIES= @models_libs@ -EXTRA_LTLIBRARIES= libmodels_gl.la libmodels_glsl.la libmodels_sw.la - -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined - -models_sources = clip_hull.c model.c portal.c trace.c winding.c - -common_libs = \ - $(top_builddir)/libs/util/libQFutil.la - -models_libs=brush/libbrush.la $(common_libs) - -libQFmodels_la_LDFLAGS= $(lib_ldflags) -libQFmodels_la_LIBADD= $(models_libs) -libQFmodels_la_DEPENDENCIES= $(models_libs) -libQFmodels_la_SOURCES= $(models_sources) - -gl_sources=gl_model_fullbright.c gl_skin.c skin.c -gl_libs= \ - alias/libalias_gl.la \ - brush/libbrush_gl.la \ - iqm/libiqm_gl.la \ - sprite/libsprite_gl.la \ - $(top_builddir)/libs/image/libQFimage.la -libmodels_gl_la_LDFLAGS= -libmodels_gl_la_LIBADD= $(gl_libs) -libmodels_gl_la_DEPENDENCIES= $(gl_libs) -libmodels_gl_la_SOURCES= $(gl_sources) - -glsl_libs= \ - alias/libalias_glsl.la \ - brush/libbrush_glsl.la \ - iqm/libiqm_glsl.la \ - sprite/libsprite_glsl.la \ - $(top_builddir)/libs/image/libQFimage.la -libmodels_glsl_la_LDFLAGS= -libmodels_glsl_la_LIBADD= $(glsl_libs) -libmodels_glsl_la_DEPENDENCIES= $(glsl_libs) -libmodels_glsl_la_SOURCES= glsl_skin.c skin.c - -sw_libs= \ - alias/libalias_sw.la \ - brush/libbrush_sw.la \ - iqm/libiqm_sw.la \ - sprite/libsprite_sw.la \ - $(top_builddir)/libs/image/libQFimage.la -libmodels_sw_la_LDFLAGS= -libmodels_sw_la_LIBADD= $(sw_libs) -libmodels_sw_la_DEPENDENCIES= $(sw_libs) -libmodels_sw_la_SOURCES= sw_skin.c skin.c diff --git a/libs/models/Makemodule.am b/libs/models/Makemodule.am new file mode 100644 index 000000000..982e96a3a --- /dev/null +++ b/libs/models/Makemodule.am @@ -0,0 +1,76 @@ +include libs/models/alias/Makemodule.am +include libs/models/brush/Makemodule.am +include libs/models/iqm/Makemodule.am +include libs/models/sprite/Makemodule.am +include libs/models/test/Makemodule.am + +lib_LTLIBRARIES += libs/models/libQFmodels.la +noinst_LTLIBRARIES += @models_libs@ +EXTRA_LTLIBRARIES += \ + libs/models/libmodels_gl.la \ + libs/models/libmodels_glsl.la \ + libs/models/libmodels_sw.la \ + libs/models/libmodels_vulkan.la + +models_sources = \ + libs/models/clip_hull.c \ + libs/models/fullbright.c \ + libs/models/model.c \ + libs/models/portal.c \ + libs/models/trace.c \ + libs/models/winding.c + +common_libs = \ + libs/util/libQFutil.la + +models_libs=libs/models/brush/libbrush.la $(common_libs) + +libs_models_libQFmodels_la_LDFLAGS= $(lib_ldflags) +libs_models_libQFmodels_la_LIBADD= $(models_libs) +libs_models_libQFmodels_la_DEPENDENCIES= $(models_libs) +libs_models_libQFmodels_la_SOURCES= $(models_sources) + +gl_sources=libs/models/gl_model_fullbright.c libs/models/gl_skin.c libs/models/skin.c +gl_libs= \ + libs/models/alias/libalias_gl.la \ + libs/models/brush/libbrush_gl.la \ + libs/models/iqm/libiqm_gl.la \ + libs/models/sprite/libsprite_gl.la \ + libs/image/libQFimage.la +libs_models_libmodels_gl_la_LDFLAGS= +libs_models_libmodels_gl_la_LIBADD= $(gl_libs) +libs_models_libmodels_gl_la_DEPENDENCIES= $(gl_libs) +libs_models_libmodels_gl_la_SOURCES= $(gl_sources) + +glsl_libs= \ + libs/models/alias/libalias_glsl.la \ + libs/models/brush/libbrush_glsl.la \ + libs/models/iqm/libiqm_glsl.la \ + libs/models/sprite/libsprite_glsl.la \ + libs/image/libQFimage.la +libs_models_libmodels_glsl_la_LDFLAGS= +libs_models_libmodels_glsl_la_LIBADD= $(glsl_libs) +libs_models_libmodels_glsl_la_DEPENDENCIES= $(glsl_libs) +libs_models_libmodels_glsl_la_SOURCES= libs/models/glsl_skin.c libs/models/skin.c + +sw_libs= \ + libs/models/alias/libalias_sw.la \ + libs/models/brush/libbrush_sw.la \ + libs/models/iqm/libiqm_sw.la \ + libs/models/sprite/libsprite_sw.la \ + libs/image/libQFimage.la +libs_models_libmodels_sw_la_LDFLAGS= +libs_models_libmodels_sw_la_LIBADD= $(sw_libs) +libs_models_libmodels_sw_la_DEPENDENCIES= $(sw_libs) +libs_models_libmodels_sw_la_SOURCES= libs/models/sw_skin.c libs/models/skin.c + +vulkan_libs= \ + libs/models/alias/libalias_vulkan.la \ + libs/models/brush/libbrush_vulkan.la \ + libs/models/iqm/libiqm_vulkan.la \ + libs/models/sprite/libsprite_vulkan.la \ + libs/image/libQFimage.la +libs_models_libmodels_vulkan_la_LDFLAGS= +libs_models_libmodels_vulkan_la_LIBADD= $(vulkan_libs) +libs_models_libmodels_vulkan_la_DEPENDENCIES= $(vulkan_libs) +libs_models_libmodels_vulkan_la_SOURCES= libs/models/vulkan_skin.c libs/models/skin.c diff --git a/libs/models/alias/Makefile.am b/libs/models/alias/Makefile.am deleted file mode 100644 index e74edfeda..000000000 --- a/libs/models/alias/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= @alias_libs@ -EXTRA_LTLIBRARIES=libalias_gl.la libalias_glsl.la libalias_sw.la - -alias_src= model_alias.c -gl_src= gl_mesh.c gl_model_alias.c floodfill.c -glsl_src= glsl_model_alias.c floodfill.c -sw_src= sw_model_alias.c - -libalias_gl_la_SOURCES= $(gl_src) $(alias_src) - -libalias_glsl_la_SOURCES= $(glsl_src) $(alias_src) - -libalias_sw_la_SOURCES= $(sw_src) $(alias_src) - -EXTRA_DIST= $(gl_src) $(glsl_src) $(sw_src) $(alias_src) diff --git a/libs/models/alias/Makemodule.am b/libs/models/alias/Makemodule.am new file mode 100644 index 000000000..cac8d4a09 --- /dev/null +++ b/libs/models/alias/Makemodule.am @@ -0,0 +1,26 @@ +noinst_LTLIBRARIES += @alias_libs@ +EXTRA_LTLIBRARIES += \ + libs/models/alias/libalias_gl.la \ + libs/models/alias/libalias_glsl.la \ + libs/models/alias/libalias_sw.la \ + libs/models/alias/libalias_vulkan.la + +alias_src= libs/models/alias/model_alias.c +alias_gl_src= libs/models/alias/gl_mesh.c libs/models/alias/gl_model_alias.c libs/models/alias/floodfill.c +alias_glsl_src= libs/models/alias/glsl_model_alias.c libs/models/alias/floodfill.c +alias_sw_src= libs/models/alias/sw_model_alias.c +alias_vulkan_src= libs/models/alias/vulkan_model_alias.c + +libs_models_alias_libalias_gl_la_SOURCES= $(alias_gl_src) $(alias_src) + +libs_models_alias_libalias_glsl_la_SOURCES= $(alias_glsl_src) $(alias_src) + +libs_models_alias_libalias_sw_la_SOURCES= $(alias_sw_src) $(alias_src) +libs_models_alias_libalias_vulkan_la_SOURCES= $(alias_vulkan_src) $(alias_src) + +EXTRA_DIST += \ + $(alias_gl_src) \ + $(alias_glsl_src) \ + $(alias_sw_src) \ + $(alias_vulkan_src) \ + $(alias_src) diff --git a/libs/models/alias/gl_mesh.c b/libs/models/alias/gl_mesh.c index 22498ddea..73c65b56d 100644 --- a/libs/models/alias/gl_mesh.c +++ b/libs/models/alias/gl_mesh.c @@ -49,9 +49,6 @@ // ALIAS MODEL DISPLAY LIST GENERATION ======================================== -static model_t *aliasmodel; -static aliashdr_t *paliashdr; - static qboolean *used; static int used_size; @@ -126,14 +123,15 @@ add_strip (int vert, int tri) } static int -StripLength (int starttri, int startv) +StripLength (mod_alias_ctx_t *alias_ctx, int starttri, int startv) { + aliashdr_t *header = alias_ctx->header; int m1, m2, j, k; mtriangle_t *last, *check; used[starttri] = 2; - last = &triangles[starttri]; + last = &alias_ctx->triangles.a[starttri]; stripcount = 0; add_strip (last->vertindex[(startv) % 3], starttri); @@ -145,8 +143,8 @@ StripLength (int starttri, int startv) // look for a matching triangle nexttri: - for (j = starttri + 1, check = &triangles[starttri + 1]; - j < pheader->mdl.numtris; j++, check++) { + for (j = starttri + 1, check = &alias_ctx->triangles.a[starttri + 1]; + j < header->mdl.numtris; j++, check++) { if (check->facesfront != last->facesfront) continue; for (k = 0; k < 3; k++) { @@ -176,7 +174,7 @@ nexttri: done: // clear the temp used flags - for (j = starttri + 1; j < pheader->mdl.numtris; j++) + for (j = starttri + 1; j < header->mdl.numtris; j++) if (used[j] == 2) used[j] = 0; @@ -184,14 +182,15 @@ done: } static int -FanLength (int starttri, int startv) +FanLength (mod_alias_ctx_t *alias_ctx, int starttri, int startv) { + aliashdr_t *header = alias_ctx->header; int m1, m2, j, k; mtriangle_t *last, *check; used[starttri] = 2; - last = &triangles[starttri]; + last = &alias_ctx->triangles.a[starttri]; stripcount = 0; add_strip (last->vertindex[(startv) % 3], starttri); @@ -204,8 +203,8 @@ FanLength (int starttri, int startv) // look for a matching triangle nexttri: - for (j = starttri + 1, check = &triangles[starttri + 1]; - j < pheader->mdl.numtris; j++, check++) { + for (j = starttri + 1, check = &alias_ctx->triangles.a[starttri + 1]; + j < header->mdl.numtris; j++, check++) { if (check->facesfront != last->facesfront) continue; for (k = 0; k < 3; k++) { @@ -232,7 +231,7 @@ FanLength (int starttri, int startv) done: // clear the temp used flags - for (j = starttri + 1; j < pheader->mdl.numtris; j++) + for (j = starttri + 1; j < header->mdl.numtris; j++) if (used[j] == 2) used[j] = 0; @@ -246,8 +245,9 @@ FanLength (int starttri, int startv) for the model, which holds for all frames */ static void -BuildTris (void) +BuildTris (mod_alias_ctx_t *alias_ctx) { + aliashdr_t *header = alias_ctx->header; float s, t; int bestlen, len, startv, type, i, j, k; int besttype = 0; @@ -257,10 +257,10 @@ BuildTris (void) numorder = 0; numcommands = 0; stripcount = 0; - alloc_used (pheader->mdl.numtris); + alloc_used (header->mdl.numtris); memset (used, 0, used_size * sizeof (used[0])); - for (i = 0; i < pheader->mdl.numtris; i++) { + for (i = 0; i < header->mdl.numtris; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; @@ -270,9 +270,9 @@ BuildTris (void) // type = 1; for (startv = 0; startv < 3; startv++) { if (type == 1) - len = StripLength (i, startv); + len = StripLength (alias_ctx, i, startv); else - len = FanLength (i, startv); + len = FanLength (alias_ctx, i, startv); if (len > bestlen) { besttype = type; bestlen = len; @@ -304,12 +304,13 @@ BuildTris (void) add_vertex (k); // emit s/t coords into the commands stream - s = stverts[k].s; - t = stverts[k].t; - if (!triangles[besttris[0]].facesfront && stverts[k].onseam) - s += pheader->mdl.skinwidth / 2; // on back side - s = (s + 0.5) / pheader->mdl.skinwidth; - t = (t + 0.5) / pheader->mdl.skinheight; + s = alias_ctx->stverts.a[k].s; + t = alias_ctx->stverts.a[k].t; + if (!alias_ctx->triangles.a[besttris[0]].facesfront + && alias_ctx->stverts.a[k].onseam) + s += header->mdl.skinwidth / 2; // on back side + s = (s + 0.5) / header->mdl.skinwidth; + t = (t + 0.5) / header->mdl.skinheight; memcpy (&tmp, &s, 4); add_command (tmp); @@ -321,10 +322,10 @@ BuildTris (void) add_command (0); // end of list marker Sys_MaskPrintf (SYS_DEV, "%3i tri %3i vert %3i cmd\n", - pheader->mdl.numtris, numorder, numcommands); + header->mdl.numtris, numorder, numcommands); allverts += numorder; - alltris += pheader->mdl.numtris; + alltris += header->mdl.numtris; if (bestverts) free (bestverts); @@ -333,9 +334,10 @@ BuildTris (void) } void -gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +gl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra) { + aliashdr_t *header = alias_ctx->header; dstring_t *cache, *fullpath; unsigned char model_digest[MDFOUR_DIGEST_BYTES]; unsigned char mesh_digest[MDFOUR_DIGEST_BYTES]; @@ -345,24 +347,21 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, qboolean remesh = true; qboolean do_cache = false; - aliasmodel = m; - paliashdr = hdr; - cache = dstring_new (); fullpath = dstring_new (); if (!gl_alias_render_tri->int_val) { if (gl_mesh_cache->int_val - && gl_mesh_cache->int_val <= paliashdr->mdl.numtris) { + && gl_mesh_cache->int_val <= header->mdl.numtris) { do_cache = true; mdfour (model_digest, (unsigned char *) _m, _s); // look for a cached version dstring_copystr (cache, "glquake/"); - dstring_appendstr (cache, m->name); - QFS_StripExtension (m->name + strlen ("progs/"), + dstring_appendstr (cache, alias_ctx->mod->path); + QFS_StripExtension (alias_ctx->mod->path + strlen ("progs/"), cache->str + strlen ("glquake/")); dstring_appendstr (cache, ".qfms"); @@ -433,9 +432,9 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } if (remesh) { // build it from scratch - Sys_MaskPrintf (SYS_DEV, "meshing %s...\n", m->name); + Sys_MaskPrintf (SYS_DEV, "meshing %s...\n", alias_ctx->mod->path); - BuildTris (); // trifans or lists + BuildTris (alias_ctx); // trifans or lists if (do_cache) { // save out the cached version @@ -474,35 +473,36 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } // save the data out - paliashdr->poseverts = numorder; + header->poseverts = numorder; cmds = Hunk_Alloc (numcommands * sizeof (int)); - paliashdr->commands = (byte *) cmds - (byte *) paliashdr; + header->commands = (byte *) cmds - (byte *) header; memcpy (cmds, commands, numcommands * sizeof (int)); } else { tex_coord_t *tex_coord; numorder = 0; - for (i=0; i < pheader->mdl.numtris; i++) { - add_vertex(triangles[i].vertindex[0]); - add_vertex(triangles[i].vertindex[1]); - add_vertex(triangles[i].vertindex[2]); + for (i=0; i < header->mdl.numtris; i++) { + add_vertex(alias_ctx->triangles.a[i].vertindex[0]); + add_vertex(alias_ctx->triangles.a[i].vertindex[1]); + add_vertex(alias_ctx->triangles.a[i].vertindex[2]); } - paliashdr->poseverts = numorder; + header->poseverts = numorder; tex_coord = Hunk_Alloc (numorder * sizeof(tex_coord_t)); - paliashdr->tex_coord = (byte *) tex_coord - (byte *) paliashdr; + header->tex_coord = (byte *) tex_coord - (byte *) header; for (i=0; i < numorder; i++) { float s, t; int k; k = vertexorder[i]; - s = stverts[k].s; - t = stverts[k].t; - if (!triangles[i/3].facesfront && stverts[k].onseam) - s += pheader->mdl.skinwidth / 2; // on back side - s = (s + 0.5) / pheader->mdl.skinwidth; - t = (t + 0.5) / pheader->mdl.skinheight; + s = alias_ctx->stverts.a[k].s; + t = alias_ctx->stverts.a[k].t; + if (!alias_ctx->triangles.a[i/3].facesfront + && alias_ctx->stverts.a[k].onseam) + s += header->mdl.skinwidth / 2; // on back side + s = (s + 0.5) / header->mdl.skinwidth; + t = (t + 0.5) / header->mdl.skinheight; tex_coord[i].st[0] = s; tex_coord[i].st[1] = t; } @@ -510,11 +510,11 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, if (extra) { trivertx16_t *verts; - verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts + verts = Hunk_Alloc (header->numposes * header->poseverts * sizeof (trivertx16_t)); - paliashdr->posedata = (byte *) verts - (byte *) paliashdr; - for (i = 0; i < paliashdr->numposes; i++) { - trivertx_t *pv = poseverts[i]; + header->posedata = (byte *) verts - (byte *) header; + for (i = 0; i < header->numposes; i++) { + trivertx_t *pv = alias_ctx->poseverts.a[i]; for (j = 0; j < numorder; j++) { trivertx16_t v; // convert MD16's split coordinates into something a little @@ -523,21 +523,21 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // fractional bits of the vertex, giving 8.8. However, it's // easier for us to multiply everything by 256 and adjust the // model scale appropriately - VectorMultAdd (pv[vertexorder[j] + hdr->mdl.numverts].v, + VectorMultAdd (pv[vertexorder[j] + header->mdl.numverts].v, 256, pv[vertexorder[j]].v, v.v); v.lightnormalindex = - poseverts[i][vertexorder[j]].lightnormalindex; + alias_ctx->poseverts.a[i][vertexorder[j]].lightnormalindex; *verts++ = v; } } } else { trivertx_t *verts; - verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts + verts = Hunk_Alloc (header->numposes * header->poseverts * sizeof (trivertx_t)); - paliashdr->posedata = (byte *) verts - (byte *) paliashdr; - for (i = 0; i < paliashdr->numposes; i++) { + header->posedata = (byte *) verts - (byte *) header; + for (i = 0; i < header->numposes; i++) { for (j = 0; j < numorder; j++) - *verts++ = poseverts[i][vertexorder[j]]; + *verts++ = alias_ctx->poseverts.a[i][vertexorder[j]]; } } dstring_delete (cache); diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index ec304b80d..4b8d6ccb7 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -38,6 +38,7 @@ # include #endif +#include "QF/dstring.h" #include "QF/image.h" #include "QF/qendian.h" #include "QF/quakefs.h" @@ -52,60 +53,64 @@ #include "compat.h" void * -gl_Mod_LoadSkin (byte * skin, int skinsize, int snum, int gnum, qboolean group, +gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) { + aliashdr_t *header = alias_ctx->header; byte *pskin; - char name[32], modname[MAX_QPATH + 4]; + char modname[MAX_QPATH + 4]; int fb_texnum = 0, texnum = 0; + dstring_t *name = dstring_new (); - pskin = Hunk_AllocName (skinsize, loadname); - skindesc->skin = (byte *) pskin - (byte *) pheader; + pskin = Hunk_AllocName (skinsize, alias_ctx->mod->name); + skindesc->skin = (byte *) pskin - (byte *) header; memcpy (pskin, skin, skinsize); - Mod_FloodFillSkin (pskin, pheader->mdl.skinwidth, pheader->mdl.skinheight); + Mod_FloodFillSkin (pskin, header->mdl.skinwidth, header->mdl.skinheight); // save 8 bit texels for the player model to remap // FIXME remove model restriction - if (strequal (loadmodel->name, "progs/player.mdl")) - gl_Skin_SetPlayerSkin (pheader->mdl.skinwidth, pheader->mdl.skinheight, + if (strequal (alias_ctx->mod->path, "progs/player.mdl")) + gl_Skin_SetPlayerSkin (header->mdl.skinwidth, header->mdl.skinheight, pskin); - QFS_StripExtension (loadmodel->name, modname); + QFS_StripExtension (alias_ctx->mod->path, modname); - if (!loadmodel->fullbright) { + if (!alias_ctx->mod->fullbright) { if (group) { - snprintf (name, sizeof (name), "fb_%s_%i_%i", modname, - snum, gnum); + dsprintf (name, "fb_%s_%i_%i", modname, snum, gnum); } else { - snprintf (name, sizeof (name), "fb_%s_%i", modname, snum); + dsprintf (name, "fb_%s_%i", modname, snum); } - fb_texnum = Mod_Fullbright (pskin, pheader->mdl.skinwidth, - pheader->mdl.skinheight, name); - Sys_MaskPrintf (SYS_GLT, "%s %d\n", name, fb_texnum); + fb_texnum = Mod_Fullbright (pskin, header->mdl.skinwidth, + header->mdl.skinheight, name->str); + Sys_MaskPrintf (SYS_GLT, "%s %d\n", name->str, fb_texnum); } if (group) { - snprintf (name, sizeof (name), "%s_%i_%i", modname, snum, - gnum); + dsprintf (name, "%s_%i_%i", modname, snum, gnum); } else { - snprintf (name, sizeof (name), "%s_%i", modname, snum); + dsprintf (name, "%s_%i", modname, snum); } - texnum = GL_LoadTexture (name, pheader->mdl.skinwidth, - pheader->mdl.skinheight, pskin, true, false, 1); - Sys_MaskPrintf (SYS_GLT, "%s %d\n", name, texnum); + texnum = GL_LoadTexture (name->str, header->mdl.skinwidth, + header->mdl.skinheight, pskin, true, false, 1); + Sys_MaskPrintf (SYS_GLT, "%s %d\n", name->str, texnum); skindesc->texnum = texnum; skindesc->fb_texnum = fb_texnum; - loadmodel->hasfullbrights = fb_texnum; + alias_ctx->mod->hasfullbrights = fb_texnum; + dstring_delete (name); // alpha param was true for non group skins return skin + skinsize; } void -gl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) +gl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) { - if (strequal (m->name, "progs/eyes.mdl")) { - hdr->mdl.scale_origin[2] -= (22 + 8); - VectorScale (hdr->mdl.scale, 2, hdr->mdl.scale); + aliashdr_t *header = alias_ctx->header; + + if (strequal (alias_ctx->mod->path, "progs/eyes.mdl")) { + header->mdl.scale_origin[2] -= (22 + 8); + VectorScale (header->mdl.scale, 2, header->mdl.scale); } } @@ -119,9 +124,9 @@ Mod_LoadExternalSkin (maliasskindesc_t *pskindesc, char *filename) if (!ptr) ptr = filename; - tex = LoadImage (filename); + tex = LoadImage (filename, 1); if (!tex) - tex = LoadImage (va ("textures/%s", ptr + 1)); + tex = LoadImage (va (0, "textures/%s", ptr + 1), 1); if (tex) { pskindesc->texnum = GL_LoadTexture (filename, tex->width, tex->height, tex->data, true, false, @@ -129,49 +134,50 @@ Mod_LoadExternalSkin (maliasskindesc_t *pskindesc, char *filename) pskindesc->fb_texnum = 0; - glow = LoadImage (va ("%s_luma", filename)); + glow = LoadImage (va (0, "%s_luma", filename), 1); if (!glow) - glow = LoadImage (va ("%s_glow", filename)); + glow = LoadImage (va (0, "%s_glow", filename), 1); if (!glow) - glow = LoadImage (va ("textures/%s_luma", ptr + 1)); + glow = LoadImage (va (0, "textures/%s_luma", ptr + 1), 1); if (!glow) - glow = LoadImage (va ("textures/%s_glow", ptr + 1)); + glow = LoadImage (va (0, "textures/%s_glow", ptr + 1), 1); if (glow) pskindesc->fb_texnum = - GL_LoadTexture (va ("fb_%s", filename), glow->width, + GL_LoadTexture (va (0, "fb_%s", filename), glow->width, glow->height, glow->data, true, true, glow->format > 2 ? glow->format : 1); else if (tex->format < 3) pskindesc->fb_texnum = Mod_Fullbright (tex->data, tex->width, tex->height, - va ("fb_%s", filename)); + va (0, "fb_%s", filename)); } } void -gl_Mod_LoadExternalSkins (model_t *mod) +gl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx) { - char filename[MAX_QPATH + 4], modname[MAX_QPATH + 4]; + aliashdr_t *header = alias_ctx->header; + char modname[MAX_QPATH + 4]; int i, j; maliasskindesc_t *pskindesc; maliasskingroup_t *pskingroup; + dstring_t *filename = dstring_new (); - QFS_StripExtension (mod->name, modname); + QFS_StripExtension (alias_ctx->mod->path, modname); - for (i = 0; i < pheader->mdl.numskins; i++) { + for (i = 0; i < header->mdl.numskins; i++) { pskindesc = ((maliasskindesc_t *) - ((byte *) pheader + pheader->skindesc)) + i; + ((byte *) header + header->skindesc)) + i; if (pskindesc->type == ALIAS_SKIN_SINGLE) { - snprintf (filename, sizeof (filename), "%s_%i", modname, i); - Mod_LoadExternalSkin (pskindesc, filename); + dsprintf (filename, "%s_%i", modname, i); + Mod_LoadExternalSkin (pskindesc, filename->str); } else { pskingroup = (maliasskingroup_t *) - ((byte *) pheader + pskindesc->skin); + ((byte *) header + pskindesc->skin); for (j = 0; j < pskingroup->numskins; j++) { - snprintf (filename, sizeof (filename), "%s_%i_%i", - modname, i, j); - Mod_LoadExternalSkin (pskingroup->skindescs + j, filename); + dsprintf (filename, "%s_%i_%i", modname, i, j); + Mod_LoadExternalSkin (pskingroup->skindescs + j, filename->str); } } } diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index 5e80ccbb8..c48500ad7 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -55,27 +55,27 @@ static vec3_t vertex_normals[NUMVERTEXNORMALS] = { }; static void -glsl_alias_clear (model_t *m) +glsl_alias_clear (model_t *m, void *data) { int i, j; - aliashdr_t *hdr; + aliashdr_t *header; GLuint bufs[2]; maliasskindesc_t *skins; maliasskingroup_t *group; m->needload = true; - if (!(hdr = m->aliashdr)) - hdr = Cache_Get (&m->cache); + if (!(header = m->aliashdr)) + header = Cache_Get (&m->cache); - bufs[0] = hdr->posedata; - bufs[1] = hdr->commands; + bufs[0] = header->posedata; + bufs[1] = header->commands; qfeglDeleteBuffers (2, bufs); - skins = ((maliasskindesc_t *) ((byte *) hdr + hdr->skindesc)); - for (i = 0; i < hdr->mdl.numskins; i++) { + skins = ((maliasskindesc_t *) ((byte *) header + header->skindesc)); + for (i = 0; i < header->mdl.numskins; i++) { if (skins[i].type == ALIAS_SKIN_GROUP) { - group = (maliasskingroup_t *) ((byte *) hdr + skins[i].skin); + group = (maliasskingroup_t *) ((byte *) header + skins[i].skin); for (j = 0; j < group->numskins; j++) { GLSL_ReleaseTexture (group->skindescs[j].texnum); } @@ -91,44 +91,49 @@ glsl_alias_clear (model_t *m) } void * -glsl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc) +glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc) { + aliashdr_t *header = alias_ctx->header; byte *tskin; const char *name; int w, h; - w = pheader->mdl.skinwidth; - h = pheader->mdl.skinheight; + w = header->mdl.skinwidth; + h = header->mdl.skinheight; tskin = malloc (skinsize); memcpy (tskin, skin, skinsize); Mod_FloodFillSkin (tskin, w, h); if (group) - name = va ("%s_%i_%i", loadmodel->name, snum, gnum); + name = va (0, "%s_%i_%i", alias_ctx->mod->path, snum, gnum); else - name = va ("%s_%i", loadmodel->name, snum); + name = va (0, "%s_%i", alias_ctx->mod->path, snum); skindesc->texnum = GLSL_LoadQuakeTexture (name, w, h, tskin); free (tskin); return skin + skinsize; } void -glsl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) +glsl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) { - if (hdr->mdl.ident == HEADER_MDL16) - VectorScale (hdr->mdl.scale, 1/256.0, hdr->mdl.scale); - m->clear = glsl_alias_clear; + aliashdr_t *header = alias_ctx->header; + + if (header->mdl.ident == HEADER_MDL16) + VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale); + alias_ctx->mod->clear = glsl_alias_clear; } void -glsl_Mod_LoadExternalSkins (model_t *mod) +glsl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx) { } void -glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +glsl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra) { + aliashdr_t *header = alias_ctx->header; mtriangle_t *tris; stvert_t *st; aliasvrt_t *verts; @@ -142,12 +147,12 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int i, j; int pose; - numverts = hdr->mdl.numverts; - numtris = hdr->mdl.numtris; + numverts = header->mdl.numverts; + numtris = header->mdl.numtris; // copy triangles before editing them tris = malloc (numtris * sizeof (mtriangle_t)); - memcpy (tris, triangles, numtris * sizeof (mtriangle_t)); + memcpy (tris, alias_ctx->triangles.a, numtris * sizeof (mtriangle_t)); // initialize indexmap to -1 (unduplicated). any other value indicates // both that the vertex has been duplicated and the index of the @@ -157,7 +162,7 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // copy stverts. need space for duplicates st = malloc (2 * numverts * sizeof (stvert_t)); - memcpy (st, stverts, numverts * sizeof (stvert_t)); + memcpy (st, alias_ctx->stverts.a, numverts * sizeof (stvert_t)); // check for onseam verts, and duplicate any that are associated with // back-facing triangles. the s coordinate is shifted right by half @@ -168,7 +173,7 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, if (st[vind].onseam && !tris[i].facesfront) { if (indexmap[vind] == -1) { st[numverts] = st[vind]; - st[numverts].s += hdr->mdl.skinwidth / 2; + st[numverts].s += header->mdl.skinwidth / 2; indexmap[vind] = numverts++; } tris[i].vertindex[j] = indexmap[vind]; @@ -178,13 +183,13 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // we now know exactly how many vertices we need, so built the vertex // array - vertexsize = hdr->numposes * numverts * sizeof (aliasvrt_t); + vertexsize = header->numposes * numverts * sizeof (aliasvrt_t); verts = malloc (vertexsize); - for (i = 0, pose = 0; i < hdr->numposes; i++, pose += numverts) { - for (j = 0; j < hdr->mdl.numverts; j++) { - pv = &poseverts[i][j]; + for (i = 0, pose = 0; i < header->numposes; i++, pose += numverts) { + for (j = 0; j < header->mdl.numverts; j++) { + pv = &alias_ctx->poseverts.a[i][j]; if (extra) { - VectorMultAdd (pv[hdr->mdl.numverts].v, 256, pv->v, + VectorMultAdd (pv[header->mdl.numverts].v, 256, pv->v, verts[pose + j].vertex); } else { VectorCopy (pv->v, verts[pose + j].vertex); @@ -218,14 +223,14 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // finished with tris free (tris); - hdr->poseverts = numverts; + header->poseverts = numverts; // load the vertex data and indices into GL qfeglGenBuffers (2, bnum); - hdr->posedata = bnum[0]; - hdr->commands = bnum[1]; - qfeglBindBuffer (GL_ARRAY_BUFFER, hdr->posedata); - qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, hdr->commands); + header->posedata = bnum[0]; + header->commands = bnum[1]; + qfeglBindBuffer (GL_ARRAY_BUFFER, header->posedata); + qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, header->commands); qfeglBufferData (GL_ARRAY_BUFFER, vertexsize, verts, GL_STATIC_DRAW); qfeglBufferData (GL_ELEMENT_ARRAY_BUFFER, indexsize, indices, GL_STATIC_DRAW); diff --git a/libs/models/alias/model_alias.c b/libs/models/alias/model_alias.c index af2731d71..583df43fa 100644 --- a/libs/models/alias/model_alias.c +++ b/libs/models/alias/model_alias.c @@ -49,23 +49,11 @@ #include "mod_internal.h" #include "r_local.h" -aliashdr_t *pheader; - -stvert_t *stverts; -mtriangle_t *triangles; -int stverts_size = 0; -int triangles_size = 0; - -// a pose is a single set of vertexes. a frame may be an animating -// sequence of poses -trivertx_t *poseverts[MAXALIASFRAMES]; -int posenum = 0; -int aliasbboxmins[3], aliasbboxmaxs[3]; - - static void * -Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) +Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx, int numskins, + daliasskintype_t *pskintype, int *pskinindex) { + aliashdr_t *header = alias_ctx->header; byte *skin; float *poutskinintervals; int groupskins, skinsize, gnum, snum, t; @@ -77,34 +65,34 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) if (numskins < 1 || numskins > MAX_SKINS) Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d", numskins); - skinsize = pheader->mdl.skinwidth * pheader->mdl.skinheight; + skinsize = header->mdl.skinwidth * header->mdl.skinheight; pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), - loadname); + alias_ctx->mod->name); - *pskinindex = (byte *) pskindesc - (byte *) pheader; + *pskinindex = (byte *) pskindesc - (byte *) header; for (snum = 0; snum < numskins; snum++) { pskindesc[snum].type = pskintype->type; if (pskintype->type == ALIAS_SKIN_SINGLE) { skin = (byte *) (pskintype + 1); - skin = m_funcs->Mod_LoadSkin (skin, skinsize, snum, 0, false, - &pskindesc[snum]); + skin = m_funcs->Mod_LoadSkin (alias_ctx, skin, skinsize, snum, 0, + false, &pskindesc[snum]); } else { pskintype++; pinskingroup = (daliasskingroup_t *) pskintype; groupskins = LittleLong (pinskingroup->numskins); t = field_offset (maliasskingroup_t, skindescs[groupskins]); - paliasskingroup = Hunk_AllocName (t, loadname); + paliasskingroup = Hunk_AllocName (t, alias_ctx->mod->name); paliasskingroup->numskins = groupskins; - pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) pheader; + pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) header; pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1); poutskinintervals = Hunk_AllocName (groupskins * sizeof (float), - loadname); + alias_ctx->mod->name); paliasskingroup->intervals = - (byte *) poutskinintervals - (byte *) pheader; + (byte *) poutskinintervals - (byte *) header; for (gnum = 0; gnum < groupskins; gnum++) { *poutskinintervals = LittleFloat (pinskinintervals->interval); if (*poutskinintervals <= 0) @@ -119,8 +107,9 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) for (gnum = 0; gnum < groupskins; gnum++) { paliasskingroup->skindescs[gnum].type = ALIAS_SKIN_SINGLE; - skin = mod_funcs->Mod_LoadSkin (skin, skinsize, snum, gnum, - true, &paliasskingroup->skindescs[gnum]); + skin = mod_funcs->Mod_LoadSkin (alias_ctx, skin, skinsize, + snum, gnum, true, + &paliasskingroup->skindescs[gnum]); } } pskintype = (daliasskintype_t *) skin; @@ -129,16 +118,17 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) return pskintype; } -void * -Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, - int extra) +static void * +Mod_LoadAliasFrame (mod_alias_ctx_t *alias_ctx, void *pin, int *posenum, + maliasframedesc_t *frame, int extra) { + aliashdr_t *header = alias_ctx->header; daliasframe_t *pdaliasframe; trivertx_t *pinframe; pdaliasframe = (daliasframe_t *) pin; - strncpy (frame->name, pdaliasframe->name, sizeof (frame->name)); + memcpy (frame->name, pdaliasframe->name, sizeof (frame->name)); frame->name[sizeof (frame->name) - 1] = 0; frame->firstpose = (*posenum); frame->numposes = 1; @@ -146,25 +136,29 @@ Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, // byte values, don't worry about endianness VectorCopy (pdaliasframe->bboxmin.v, frame->bboxmin.v); VectorCopy (pdaliasframe->bboxmax.v, frame->bboxmax.v); - VectorCompMin (frame->bboxmin.v, aliasbboxmins, aliasbboxmins); - VectorCompMax (frame->bboxmax.v, aliasbboxmaxs, aliasbboxmaxs); + VectorCompMin (frame->bboxmin.v, alias_ctx->aliasbboxmins, + alias_ctx->aliasbboxmins); + VectorCompMax (frame->bboxmax.v, alias_ctx->aliasbboxmaxs, + alias_ctx->aliasbboxmaxs); pinframe = (trivertx_t *) (pdaliasframe + 1); - poseverts[(*posenum)] = pinframe; + DARRAY_APPEND (&alias_ctx->poseverts, pinframe); (*posenum)++; - pinframe += pheader->mdl.numverts; + pinframe += header->mdl.numverts; if (extra) - pinframe += pheader->mdl.numverts; + pinframe += header->mdl.numverts; return pinframe; } -void * -Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, - int extra) +static void * +Mod_LoadAliasGroup (mod_alias_ctx_t *alias_ctx, void *pin, int *posenum, + maliasframedesc_t *frame, int extra) { + aliashdr_t *header = alias_ctx->header; + model_t *mod = alias_ctx->mod; daliasgroup_t *pingroup; daliasinterval_t *pin_intervals; float *poutintervals; @@ -180,19 +174,21 @@ Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, frame->numposes = numframes; paliasgroup = Hunk_AllocName (field_offset (maliasgroup_t, - frames[numframes]), loadname); + frames[numframes]), mod->name); paliasgroup->numframes = numframes; - frame->frame = (byte *) paliasgroup - (byte *) pheader; + frame->frame = (byte *) paliasgroup - (byte *) header; // these are byte values, so we don't have to worry about endianness VectorCopy (pingroup->bboxmin.v, frame->bboxmin.v); VectorCopy (pingroup->bboxmax.v, frame->bboxmax.v); - VectorCompMin (frame->bboxmin.v, aliasbboxmins, aliasbboxmins); - VectorCompMax (frame->bboxmax.v, aliasbboxmaxs, aliasbboxmaxs); + VectorCompMin (frame->bboxmin.v, alias_ctx->aliasbboxmins, + alias_ctx->aliasbboxmins); + VectorCompMax (frame->bboxmax.v, alias_ctx->aliasbboxmaxs, + alias_ctx->aliasbboxmaxs); pin_intervals = (daliasinterval_t *) (pingroup + 1); - poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); - paliasgroup->intervals = (byte *) poutintervals - (byte *) pheader; + poutintervals = Hunk_AllocName (numframes * sizeof (float), mod->name); + paliasgroup->intervals = (byte *) poutintervals - (byte *) header; frame->interval = LittleFloat (pin_intervals->interval); for (i = 0; i < numframes; i++) { *poutintervals = LittleFloat (pin_intervals->interval); @@ -205,7 +201,8 @@ Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, ptemp = (void *) pin_intervals; for (i = 0; i < numframes; i++) { maliasframedesc_t temp_frame; - ptemp = Mod_LoadAliasFrame (ptemp, posenum, &temp_frame, extra); + ptemp = Mod_LoadAliasFrame (alias_ctx, ptemp, posenum, &temp_frame, + extra); memcpy (&paliasgroup->frames[i], &temp_frame, sizeof (paliasgroup->frames[i])); } @@ -225,6 +222,14 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) mdl_t *pinmodel, *pmodel; unsigned short crc; stvert_t *pinstverts; + mod_alias_ctx_t alias_ctx = {}; + aliashdr_t *header; + + alias_ctx.mod = mod; + //FIXME should be per batch rather than per model + DARRAY_INIT (&alias_ctx.poseverts, 256); + DARRAY_INIT (&alias_ctx.stverts, 256); + DARRAY_INIT (&alias_ctx.triangles, 256); if (LittleLong (* (unsigned int *) buffer) == HEADER_MDL16) extra = 1; // extra precision bytes @@ -244,12 +249,13 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) // allocate space for a working header, plus all the data except the // frames, skin and group info size = field_offset (aliashdr_t, frames[LittleLong (pinmodel->numframes)]); - pheader = Hunk_AllocName (size, loadname); - memset (pheader, 0, size); - pmodel = &pheader->mdl; - pheader->model = (byte *) pmodel - (byte *) pheader; + header = Hunk_AllocName (size, mod->name); + memset (header, 0, size); + alias_ctx.header = header; + pmodel = &header->mdl; + header->model = (byte *) pmodel - (byte *) header; - pheader->crc = crc; + header->crc = crc; mod->flags = LittleLong (pinmodel->flags); @@ -264,30 +270,20 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); + DARRAY_RESIZE (&alias_ctx.poseverts, 0); pmodel->numverts = LittleLong (pinmodel->numverts); if (pmodel->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); - if (pmodel->numverts > stverts_size) { - stverts = realloc (stverts, pmodel->numverts * sizeof (stvert_t)); - if (!stverts) - Sys_Error ("model_alias: out of memory"); - stverts_size = pmodel->numverts; - } + DARRAY_RESIZE (&alias_ctx.stverts, pmodel->numverts); pmodel->numtris = LittleLong (pinmodel->numtris); if (pmodel->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); - if (pmodel->numtris > triangles_size) { - triangles = realloc (triangles, - pmodel->numtris * sizeof (mtriangle_t)); - if (!triangles) - Sys_Error ("model_alias: out of memory"); - triangles_size = pmodel->numtris; - } + DARRAY_RESIZE (&alias_ctx.triangles, pmodel->numtris); pmodel->numframes = LittleLong (pinmodel->numframes); numframes = pmodel->numframes; @@ -306,86 +302,92 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) // load the skins pskintype = (daliasskintype_t *) &pinmodel[1]; - pskintype = Mod_LoadAllSkins (pheader->mdl.numskins, pskintype, - &pheader->skindesc); + pskintype = Mod_LoadAllSkins (&alias_ctx, header->mdl.numskins, pskintype, + &header->skindesc); // load base s and t vertices pinstverts = (stvert_t *) pskintype; - for (i = 0; i < pheader->mdl.numverts; i++) { - stverts[i].onseam = LittleLong (pinstverts[i].onseam); - stverts[i].s = LittleLong (pinstverts[i].s); - stverts[i].t = LittleLong (pinstverts[i].t); + for (i = 0; i < header->mdl.numverts; i++) { + alias_ctx.stverts.a[i].onseam = LittleLong (pinstverts[i].onseam); + alias_ctx.stverts.a[i].s = LittleLong (pinstverts[i].s); + alias_ctx.stverts.a[i].t = LittleLong (pinstverts[i].t); } // load triangle lists - pintriangles = (dtriangle_t *) &pinstverts[pheader->mdl.numverts]; + pintriangles = (dtriangle_t *) &pinstverts[header->mdl.numverts]; - for (i = 0; i < pheader->mdl.numtris; i++) { - triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); + for (i = 0; i < header->mdl.numtris; i++) { + alias_ctx.triangles.a[i].facesfront = + LittleLong (pintriangles[i].facesfront); for (j = 0; j < 3; j++) { - triangles[i].vertindex[j] = + alias_ctx.triangles.a[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } // load the frames - posenum = 0; - pframetype = (daliasframetype_t *) &pintriangles[pheader->mdl.numtris]; - aliasbboxmins[0] = aliasbboxmins[1] = aliasbboxmins[2] = 99999; - aliasbboxmaxs[0] = aliasbboxmaxs[1] = aliasbboxmaxs[2] = -99999; + int posenum = 0; + pframetype = (daliasframetype_t *) &pintriangles[header->mdl.numtris]; + VectorSet (99999, 99999, 99999, alias_ctx.aliasbboxmins); + VectorSet (-99999, -99999, -99999, alias_ctx.aliasbboxmaxs); for (i = 0; i < numframes; i++) { aliasframetype_t frametype; frametype = LittleLong (pframetype->type); - pheader->frames[i].type = frametype; + header->frames[i].type = frametype; if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) - Mod_LoadAliasFrame (pframetype + 1, &posenum, - &pheader->frames[i], extra); + Mod_LoadAliasFrame (&alias_ctx, pframetype + 1, &posenum, + &header->frames[i], extra); } else { pframetype = (daliasframetype_t *) - Mod_LoadAliasGroup (pframetype + 1, &posenum, - &pheader->frames[i], extra); + Mod_LoadAliasGroup (&alias_ctx, pframetype + 1, &posenum, + &header->frames[i], extra); } } - pheader->numposes = posenum; + header->numposes = posenum; mod->type = mod_alias; - for (i = 0; i < 3; i++) { - mod->mins[i] = aliasbboxmins[i] * pheader->mdl.scale[i] + - pheader->mdl.scale_origin[i]; - mod->maxs[i] = aliasbboxmaxs[i] * pheader->mdl.scale[i] + - pheader->mdl.scale_origin[i]; - } + VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale, + alias_ctx.aliasbboxmins, mod->mins); + VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale, + alias_ctx.aliasbboxmaxs, mod->maxs); mod->radius = RadiusFromBounds (mod->mins, mod->maxs); // build the draw lists - m_funcs->Mod_MakeAliasModelDisplayLists (mod, pheader, buffer, + m_funcs->Mod_MakeAliasModelDisplayLists (&alias_ctx, buffer, qfs_filesize, extra); - m_funcs->Mod_FinalizeAliasModel (mod, pheader); + if (m_funcs->Mod_FinalizeAliasModel) { + m_funcs->Mod_FinalizeAliasModel (&alias_ctx); + } - m_funcs->Mod_LoadExternalSkins (mod); + if (m_funcs->Mod_LoadExternalSkins) { + m_funcs->Mod_LoadExternalSkins (&alias_ctx); + } // move the complete, relocatable alias model to the cache if (m_funcs->alias_cache) { end = Hunk_LowMark (); total = end - start; - mem = allocator (&mod->cache, total, loadname); + mem = allocator (&mod->cache, total, mod->name); if (mem) - memcpy (mem, pheader, total); + memcpy (mem, header, total); Hunk_FreeToLowMark (start); mod->aliashdr = 0; } else { - mod->aliashdr = pheader; + mod->aliashdr = header; } + DARRAY_CLEAR (&alias_ctx.poseverts); + DARRAY_CLEAR (&alias_ctx.stverts); + DARRAY_CLEAR (&alias_ctx.triangles); } diff --git a/libs/models/alias/sw_model_alias.c b/libs/models/alias/sw_model_alias.c index b252ad474..0bd57d5ce 100644 --- a/libs/models/alias/sw_model_alias.c +++ b/libs/models/alias/sw_model_alias.c @@ -50,13 +50,14 @@ void * -sw_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, +sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, + int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) { byte *pskin; - pskin = Hunk_AllocName (skinsize, loadname); - skindesc->skin = (byte *) pskin - (byte *) pheader; + pskin = Hunk_AllocName (skinsize, alias_ctx->mod->name); + skindesc->skin = (byte *) pskin - (byte *) alias_ctx->header; memcpy (pskin, skin, skinsize); @@ -64,73 +65,67 @@ sw_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, } static void -process_frame (maliasframedesc_t *frame, int posenum, int extra) +process_frame (mod_alias_ctx_t *alias_ctx, maliasframedesc_t *frame, + int posenum, int extra) { - int size = pheader->mdl.numverts * sizeof (trivertx_t); + aliashdr_t *header = alias_ctx->header; + int size = header->mdl.numverts * sizeof (trivertx_t); trivertx_t *frame_verts; if (extra) size *= 2; - frame_verts = Hunk_AllocName (size, loadname); - frame->frame = (byte *) frame_verts - (byte *) pheader; + frame_verts = Hunk_AllocName (size, alias_ctx->mod->name); + frame->frame = (byte *) frame_verts - (byte *) header; // The low-order 8 bits (actually, fractional) are completely separate // from the high-order bits (see R_AliasTransformFinalVert16 in // sw_ralias.c), but in adjacant arrays. This means we can get away with // just one memcpy as there are no endian issues. - memcpy (frame_verts, poseverts[posenum], size); + memcpy (frame_verts, alias_ctx->poseverts.a[posenum], size); } void -sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +sw_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra) { + aliashdr_t *header = alias_ctx->header; int i, j; int posenum = 0; - int numv = hdr->mdl.numverts, numt = hdr->mdl.numtris; - stvert_t *pstverts; - mtriangle_t *ptri; + int numv = header->mdl.numverts, numt = header->mdl.numtris; + stvert_t *stverts; + mtriangle_t *tris; - pstverts = (stvert_t *) Hunk_AllocName (numv * sizeof (stvert_t), - loadname); - ptri = (mtriangle_t *) Hunk_AllocName (numt * sizeof (mtriangle_t), - loadname); + stverts = (stvert_t *) Hunk_AllocName (numv * sizeof (stvert_t), + alias_ctx->mod->name); + tris = (mtriangle_t *) Hunk_AllocName (numt * sizeof (mtriangle_t), + alias_ctx->mod->name); - hdr->stverts = (byte *) pstverts - (byte *) hdr; - hdr->triangles = (byte *) ptri - (byte *) hdr; + header->stverts = (byte *) stverts - (byte *) header; + header->triangles = (byte *) tris - (byte *) header; for (i = 0; i < numv; i++) { - pstverts[i].onseam = stverts[i].onseam; - pstverts[i].s = stverts[i].s << 16; - pstverts[i].t = stverts[i].t << 16; + stverts[i].onseam = alias_ctx->stverts.a[i].onseam; + stverts[i].s = alias_ctx->stverts.a[i].s << 16; + stverts[i].t = alias_ctx->stverts.a[i].t << 16; } for (i = 0; i < numt; i++) { - ptri[i].facesfront = triangles[i].facesfront; - VectorCopy (triangles[i].vertindex, ptri[i].vertindex); + tris[i].facesfront = alias_ctx->triangles.a[i].facesfront; + VectorCopy (alias_ctx->triangles.a[i].vertindex, tris[i].vertindex); } - for (i = 0; i < pheader->mdl.numframes; i++) { - maliasframedesc_t *frame = pheader->frames + i; + for (i = 0; i < header->mdl.numframes; i++) { + maliasframedesc_t *frame = header->frames + i; if (frame->type) { maliasgroup_t *group; - group = (maliasgroup_t *) ((byte *) pheader + frame->frame); - for (j = 0; j < group->numframes; j++) - process_frame ((maliasframedesc_t *) &group->frames[j], - posenum++, extra); + group = (maliasgroup_t *) ((byte *) header + frame->frame); + for (j = 0; j < group->numframes; j++) { + __auto_type frame = (maliasframedesc_t *) &group->frames[j]; + process_frame (alias_ctx, frame, posenum++, extra); + } } else { - process_frame (frame, posenum++, extra); + process_frame (alias_ctx, frame, posenum++, extra); } } } - -void -sw_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) -{ -} - -void -sw_Mod_LoadExternalSkins (model_t *mod) -{ -} diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c new file mode 100644 index 000000000..fd1f8c731 --- /dev/null +++ b/libs/models/alias/vulkan_model_alias.c @@ -0,0 +1,469 @@ +/* + vulkan_model_alais.c + + Alias model processing for Vulkan + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/24 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include + +#include "QF/va.h" + +#include "QF/modelgen.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" + +#include "mod_internal.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +static vec3_t vertex_normals[NUMVERTEXNORMALS] = { +#include "anorms.h" +}; + +static void +skin_clear (int skin_offset, aliashdr_t *hdr, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + qfv_alias_skin_t *skin = (qfv_alias_skin_t *) ((byte *) hdr + skin_offset); + + dfunc->vkDestroyImageView (device->dev, skin->view, 0); + dfunc->vkDestroyImage (device->dev, skin->image, 0); + dfunc->vkFreeMemory (device->dev, skin->memory, 0); +} + +static void +vulkan_alias_clear (model_t *m, void *data) +{ + vulkan_ctx_t *ctx = data; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliashdr_t *hdr; + qfv_alias_mesh_t *mesh; + + m->needload = true; //FIXME is this right? + if (!(hdr = m->aliashdr)) { + hdr = Cache_Get (&m->cache); + } + mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); + dfunc->vkDestroyBuffer (device->dev, mesh->vertex_buffer, 0); + dfunc->vkDestroyBuffer (device->dev, mesh->uv_buffer, 0); + dfunc->vkDestroyBuffer (device->dev, mesh->index_buffer, 0); + dfunc->vkFreeMemory (device->dev, mesh->memory, 0); + + __auto_type skins = (maliasskindesc_t *) ((byte *) hdr + hdr->skindesc); + for (int i = 0; i < hdr->mdl.numskins; i++) { + if (skins[i].type == ALIAS_SKIN_GROUP) { + __auto_type group = (maliasskingroup_t *) + ((byte *) hdr + skins[i].skin); + for (int j = 0; j < group->numskins; j++) { + skin_clear (group->skindescs[j].skin, hdr, ctx); + } + } else { + skin_clear (skins[i].skin, hdr, ctx); + } + } +} + +void * +Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliashdr_t *header = alias_ctx->header; + qfv_alias_skin_t *skin; + byte *tskin; + int w, h; + + skin = Hunk_Alloc (sizeof (qfv_alias_skin_t)); + QuatCopy (vid.palette32 + (TOP_RANGE + 15) * 4, skin->colora); + QuatCopy (vid.palette32 + (BOTTOM_RANGE + 15) * 4, skin->colorb); + skindesc->skin = (byte *) skin - (byte *) header; + //FIXME move all skins into arrays(?) + w = header->mdl.skinwidth; + h = header->mdl.skinheight; + tskin = malloc (2 * skinsize); + memcpy (tskin, skinpix, skinsize); + Mod_FloodFillSkin (tskin, w, h); + + int mipLevels = QFV_MipLevels (w, h); + VkExtent3D extent = { w, h, 1 }; + skin->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, extent, + mipLevels, 4, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skin->image, + va (ctx->va_ctx, "image:%s:%d:%d", + alias_ctx->mod->name, snum, gnum)); + skin->memory = QFV_AllocImageMemory (device, skin->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, skin->memory, + va (ctx->va_ctx, "memory:%s:%d:%d", + alias_ctx->mod->name, snum, gnum)); + QFV_BindImageMemory (device, skin->image, skin->memory, 0); + skin->view = QFV_CreateImageView (device, skin->image, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, skin->view, + va (ctx->va_ctx, "iview:%s:%d:%d", + alias_ctx->mod->name, snum, gnum)); + + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, "alias stage", + 4 * skinsize * 4, + ctx->cmdpool); + qfv_packet_t *packet = QFV_PacketAcquire (stage); + byte *base_data = QFV_PacketExtend (packet, skinsize * 4); + byte *cola_data = QFV_PacketExtend (packet, skinsize * 4); + byte *colb_data = QFV_PacketExtend (packet, skinsize * 4); + byte *glow_data = QFV_PacketExtend (packet, skinsize * 4); + + Mod_CalcFullbright (tskin, tskin + skinsize, skinsize); + Vulkan_ExpandPalette (glow_data, tskin + skinsize, vid.palette, 1, + skinsize); + Mod_ClearFullbright (tskin, tskin, skinsize); + + Skin_CalcTopColors (tskin, tskin + skinsize, skinsize); + Vulkan_ExpandPalette (cola_data, tskin + skinsize, vid.palette, 1, + skinsize); + Skin_ClearTopColors (tskin, tskin, skinsize); + + Skin_CalcBottomColors (tskin, tskin + skinsize, skinsize); + Vulkan_ExpandPalette (colb_data, tskin + skinsize, vid.palette, 1, + skinsize); + Skin_ClearBottomColors (tskin, tskin, skinsize); + + Vulkan_ExpandPalette (base_data, tskin, vid.palette, 1, skinsize); + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = skin->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + + VkBufferImageCopy copy = { + packet->offset, 0, 0, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 4}, + {0, 0, 0}, {w, h, 1}, + }; + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + skin->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©); + + if (mipLevels == 1) { + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = skin->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + } else { + QFV_GenerateMipMaps (device, packet->cmd, skin->image, + mipLevels, w, h, 4); + } + QFV_PacketSubmit (packet); + QFV_DestroyStagingBuffer (stage); + + free (tskin); + + return skinpix + skinsize; +} + +void +Vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) +{ + alias_ctx->mod->clear = vulkan_alias_clear; + alias_ctx->mod->data = ctx; +} + +void +Vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) +{ +} + +static size_t +get_buffer_size (qfv_device_t *device, VkBuffer buffer) +{ + qfv_devfuncs_t *dfunc = device->funcs; + size_t size; + size_t align; + + VkMemoryRequirements requirements; + dfunc->vkGetBufferMemoryRequirements (device->dev, buffer, &requirements); + size = requirements.size; + align = requirements.alignment - 1; + size = (size + align) & ~(align); + return size; +} + +void +Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, + int _s, int extra, vulkan_ctx_t *ctx) +{ + aliashdr_t *header = alias_ctx->header; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasvrt_t *verts; + aliasuv_t *uv; + trivertx_t *pv; + int *indexmap; + uint32_t *indices; + int numverts; + int numtris; + int i, j; + int pose; + vec3_t pos; + + if (header->mdl.ident == HEADER_MDL16) + VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale); + + numverts = header->mdl.numverts; + numtris = header->mdl.numtris; + + // initialize indexmap to -1 (unduplicated). any other value indicates + // both that the vertex has been duplicated and the index of the + // duplicate vertex. + indexmap = malloc (numverts * sizeof (int)); + memset (indexmap, -1, numverts * sizeof (int)); + + // check for onseam verts, and duplicate any that are associated with + // back-facing triangles + for (i = 0; i < numtris; i++) { + for (j = 0; j < 3; j++) { + int vind = alias_ctx->triangles.a[i].vertindex[j]; + if (alias_ctx->stverts.a[vind].onseam + && !alias_ctx->triangles.a[i].facesfront) { + // duplicate the vertex if it has not alreaddy been + // duplicated + if (indexmap[vind] == -1) { + indexmap[vind] = numverts++; + } + } + } + } + + // we now know exactly how many vertices we need, so built the vertex + // and index data arrays + // The layout is: + // vbuf:{vertex, normal} * (numposes * numverts) + // uvbuf:{uv} * (numverts) + // ibuf:{index} * (numtris * 3) + // numverts includes the duplicated seam vertices. + // The vertex buffer will be bound with various offsets based on the + // current and previous pose, uvbuff "statically" bound as uvs are not + // animated by pose, and the same for ibuf: indices will never change for + // the mesh + size_t vert_count = numverts * header->numposes; + size_t vert_size = vert_count * sizeof (aliasvrt_t); + size_t uv_size = numverts * sizeof (aliasuv_t); + size_t ind_size = 3 * numtris * sizeof (uint32_t); + + VkBuffer vbuff = QFV_CreateBuffer (device, vert_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + VkBuffer uvbuff = QFV_CreateBuffer (device, uv_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + VkBuffer ibuff = QFV_CreateBuffer (device, ind_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, vbuff, + va (ctx->va_ctx, "buffer:alias:vertex:%s", + alias_ctx->mod->name)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, uvbuff, + va (ctx->va_ctx, "buffer:alias:uv:%s", + alias_ctx->mod->name)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, ibuff, + va (ctx->va_ctx, "buffer:alias:index:%s", + alias_ctx->mod->name)); + size_t voffs = 0; + size_t uvoffs = voffs + get_buffer_size (device, vbuff); + size_t ioffs = uvoffs + get_buffer_size (device, uvbuff); + size_t buff_size = ioffs + get_buffer_size (device, ibuff); + VkDeviceMemory mem; + mem = QFV_AllocBufferMemory (device, vbuff, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + buff_size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, mem, + va (ctx->va_ctx, "memory:alias:vuvi:%s", + alias_ctx->mod->name)); + QFV_BindBufferMemory (device, vbuff, mem, voffs); + QFV_BindBufferMemory (device, uvbuff, mem, uvoffs); + QFV_BindBufferMemory (device, ibuff, mem, ioffs); + + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, + va (ctx->va_ctx, + "alias:%s", + alias_ctx->mod->name), + buff_size, ctx->cmdpool); + qfv_packet_t *packet = QFV_PacketAcquire (stage); + verts = QFV_PacketExtend (packet, vert_size); + uv = QFV_PacketExtend (packet, uv_size); + indices = QFV_PacketExtend (packet, ind_size); + + // populate the uvs, duplicating and shifting any that are on the seam + // and associated with back-facing triangles (marked by non-negative + // indexmap entry). + // the s coordinate is shifted right by half the skin width. + for (i = 0; i < header->mdl.numverts; i++) { + int vind = indexmap[i]; + uv[i].u = (float) alias_ctx->stverts.a[i].s / header->mdl.skinwidth; + uv[i].v = (float) alias_ctx->stverts.a[i].t / header->mdl.skinheight; + if (vind != -1) { + uv[vind] = uv[i]; + uv[vind].u += 0.5; + } + } + + // poputlate the vertex position and normal data, duplicating for + // back-facing on-seam verts (indicated by non-negative indexmap entry) + for (i = 0, pose = 0; i < header->numposes; i++, pose += numverts) { + for (j = 0; j < header->mdl.numverts; j++) { + pv = &alias_ctx->poseverts.a[i][j]; + if (extra) { + VectorMultAdd (pv[header->mdl.numverts].v, 256, pv->v, pos); + } else { + VectorCopy (pv->v, pos); + } + VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale, + pos, verts[pose + j].vertex); + verts[pose + j].vertex[3] = 1; + VectorCopy (vertex_normals[pv->lightnormalindex], + verts[pose + j].normal); + verts[pose + j].normal[3] = 0; + // duplicate on-seam vert associated with back-facing triangle + if (indexmap[j] != -1) { + verts[pose + indexmap[j]] = verts[pose + j]; + } + } + } + + // now build the indices for DrawElements + for (i = 0; i < numtris; i++) { + for (j = 0; j < 3; j++) { + int vind = alias_ctx->triangles.a[i].vertindex[j]; + if (alias_ctx->stverts.a[vind].onseam + && !alias_ctx->triangles.a[i].facesfront) { + vind = indexmap[vind]; + } + indices[3 * i + j] = vind; + } + } + // finished with indexmap + free (indexmap); + + header->poseverts = numverts; + + VkBufferMemoryBarrier wr_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + vbuff, 0, vert_size}, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + uvbuff, 0, uv_size}, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ibuff, 0, ind_size}, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 3, wr_barriers, 0, 0); + VkBufferCopy copy_region[] = { + { packet->offset, 0, vert_size }, + { packet->offset + vert_size, 0, uv_size }, + { packet->offset + vert_size + uv_size, 0, ind_size }, + }; + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, + vbuff, 1, ©_region[0]); + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, + uvbuff, 1, ©_region[1]); + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, + ibuff, 1, ©_region[2]); + VkBufferMemoryBarrier rd_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + vbuff, 0, vert_size }, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + uvbuff, 0, uv_size }, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ibuff, 0, ind_size }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 3, rd_barriers, 0, 0); + QFV_PacketSubmit (packet); + QFV_DestroyStagingBuffer (stage); + + qfv_alias_mesh_t *mesh = Hunk_Alloc (sizeof (qfv_alias_mesh_t)); + mesh->vertex_buffer = vbuff; + mesh->uv_buffer = uvbuff; + mesh->index_buffer = ibuff; + mesh->memory = mem; + header->commands = (byte *) mesh - (byte *) header; +} diff --git a/libs/models/brush/Makefile.am b/libs/models/brush/Makefile.am deleted file mode 100644 index cd728baed..000000000 --- a/libs/models/brush/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= libbrush.la @brush_libs@ -EXTRA_LTLIBRARIES=libbrush_gl.la libbrush_glsl.la libbrush_sw.la - -brush_src= model_brush.c -gl_src= gl_model_brush.c -glsl_src= glsl_model_brush.c -sw_src= sw_model_brush.c - -libbrush_la_SOURCES= $(brush_src) - -libbrush_gl_la_SOURCES= $(gl_src) $(brush_src) - -libbrush_glsl_la_SOURCES= $(glsl_src) $(brush_src) - -libbrush_sw_la_SOURCES= $(sw_src) $(brush_src) - -EXTRA_DIST= $(gl_src) $(glsl_src) $(sw_src) $(brush_src) diff --git a/libs/models/brush/Makemodule.am b/libs/models/brush/Makemodule.am new file mode 100644 index 000000000..4a6f03a1f --- /dev/null +++ b/libs/models/brush/Makemodule.am @@ -0,0 +1,29 @@ +noinst_LTLIBRARIES += libs/models/brush/libbrush.la @brush_libs@ +EXTRA_LTLIBRARIES += \ + libs/models/brush/libbrush_gl.la \ + libs/models/brush/libbrush_glsl.la \ + libs/models/brush/libbrush_sw.la \ + libs/models/brush/libbrush_vulkan.la + +brush_src= libs/models/brush/model_brush.c +brush_gl_src= libs/models/brush/gl_model_brush.c +brush_glsl_src= libs/models/brush/glsl_model_brush.c +brush_sw_src= libs/models/brush/sw_model_brush.c +brush_vulkan_src= libs/models/brush/vulkan_model_brush.c + +libs_models_brush_libbrush_la_SOURCES= $(brush_src) + +libs_models_brush_libbrush_gl_la_SOURCES= $(brush_gl_src) $(brush_src) + +libs_models_brush_libbrush_glsl_la_SOURCES= $(brush_glsl_src) $(brush_src) + +libs_models_brush_libbrush_sw_la_SOURCES= $(brush_sw_src) $(brush_src) + +libs_models_brush_libbrush_vulkan_la_SOURCES= $(brush_vulkan_src) $(brush_src) + +EXTRA_DIST += \ + $(brush_gl_src) \ + $(brush_glsl_src) \ + $(brush_sw_src) \ + ${brush_vulkan_src} \ + $(brush_src) diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 18744a529..9585bb108 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -51,24 +51,10 @@ #include "mod_internal.h" #include "r_internal.h" - -void -gl_Mod_ProcessTexture (texture_t *tx) -{ - char name[32]; - - if (!strncmp (tx->name, "sky", 3)) - return; - snprintf (name, sizeof (name), "fb_%s", tx->name); - tx->gl_fb_texturenum = - Mod_Fullbright ((byte *) (tx + 1), tx->width, tx->height, name); - tx->gl_texturenum = - GL_LoadTexture (tx->name, tx->width, tx->height, (byte *) (tx + 1), - true, false, 1); -} +static gltex_t gl_notexture = { }; static tex_t * -Mod_LoadAnExternalTexture (char * tname, char *mname) +Mod_LoadAnExternalTexture (char *tname, char *mname) { char rname[32]; tex_t *image; @@ -77,64 +63,86 @@ Mod_LoadAnExternalTexture (char * tname, char *mname) if (rname[0] == '*') rname[0] = '#'; - image = LoadImage (va ("textures/%.*s/%s", (int) strlen (mname + 5) - 4, - mname + 5, rname)); + image = LoadImage (va (0, "textures/%.*s/%s", (int) strlen (mname + 5) - 4, + mname + 5, rname), 1); if (!image) - image = LoadImage (va ("maps/%.*s/%s", - (int) strlen (mname + 5) - 4, - mname + 5, rname)); + image = LoadImage (va (0, "maps/%.*s/%s", (int) strlen (mname + 5) - 4, + mname + 5, rname), 1); // if (!image) -// image = LoadImage (va ("textures/bmodels/%s", rname)); +// image = LoadImage (va (0, "textures/bmodels/%s", rname)); if (!image) - image = LoadImage (va ("textures/%s", rname)); + image = LoadImage (va (0, "textures/%s", rname), 1); if (!image) - image = LoadImage (va ("maps/%s", rname)); + image = LoadImage (va (0, "maps/%s", rname), 1); return image; } -void -gl_Mod_LoadExternalTextures (model_t *mod) +static int +Mod_LoadExternalTextures (model_t *mod, texture_t *tx) { - int i; tex_t *base, *luma; - texture_t *tx; + gltex_t *gltx; + int external = 0; - for (i = 0; i < mod->numtextures; i++) { - tx = mod->textures[i]; - if (!tx) - continue; + gltx = tx->render; + if ((base = Mod_LoadAnExternalTexture (tx->name, mod->path))) { + external = 1; + gltx->gl_texturenum = + GL_LoadTexture (tx->name, base->width, base->height, + base->data, true, false, + base->format > 2 ? base->format : 1); - if ((base = Mod_LoadAnExternalTexture (tx->name, mod->name))) { - tx->gl_texturenum = - GL_LoadTexture (tx->name, base->width, base->height, - base->data, true, false, - base->format > 2 ? base->format : 1); + luma = Mod_LoadAnExternalTexture (va (0, "%s_luma", tx->name), + mod->path); + if (!luma) + luma = Mod_LoadAnExternalTexture (va (0, "%s_glow", tx->name), + mod->path); - luma = Mod_LoadAnExternalTexture (va ("%s_luma", tx->name), - mod->name); - if (!luma) - luma = Mod_LoadAnExternalTexture (va ("%s_glow", tx->name), - mod->name); + gltx->gl_fb_texturenum = 0; - tx->gl_fb_texturenum = 0; - - if (luma) { - tx->gl_fb_texturenum = - GL_LoadTexture (va ("fb_%s", tx->name), luma->width, - luma->height, luma->data, true, true, - luma->format > 2 ? luma->format : 1); - } else if (base->format < 3) { - tx->gl_fb_texturenum = - Mod_Fullbright (base->data, base->width, base->height, - va ("fb_%s", tx->name)); - } + if (luma) { + gltx->gl_fb_texturenum = + GL_LoadTexture (va (0, "fb_%s", tx->name), luma->width, + luma->height, luma->data, true, true, + luma->format > 2 ? luma->format : 1); + } else if (base->format < 3) { + gltx->gl_fb_texturenum = + Mod_Fullbright (base->data, base->width, base->height, + va (0, "fb_%s", tx->name)); } } + return external; } void -gl_Mod_LoadLighting (bsp_t *bsp) +gl_Mod_ProcessTexture (model_t *mod, texture_t *tx) +{ + const char *name; + + if (!tx) { + r_notexture_mip->render = &gl_notexture; + return; + } + if (gl_textures_external && gl_textures_external->int_val) { + if (Mod_LoadExternalTextures (mod, tx)) { + return; + } + } + if (strncmp (tx->name, "sky", 3) == 0) { + return; + } + gltex_t *gltex = tx->render; + name = va (0, "fb_%s", tx->name); + gltex->gl_fb_texturenum = + Mod_Fullbright ((byte *) (tx + 1), tx->width, tx->height, name); + gltex->gl_texturenum = + GL_LoadTexture (tx->name, tx->width, tx->height, (byte *) (tx + 1), + true, false, 1); +} + +void +gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { byte d; byte *in, *out, *data; @@ -142,14 +150,15 @@ gl_Mod_LoadLighting (bsp_t *bsp) size_t i; int ver; QFile *lit_file; + mod_brush_t *brush = &mod->brush; - dstring_copystr (litfilename, loadmodel->name); - loadmodel->lightdata = NULL; + dstring_copystr (litfilename, mod->path); + brush->lightdata = NULL; if (mod_lightmap_bytes > 1) { // LordHavoc: check for a .lit file to load QFS_StripExtension (litfilename->str, litfilename->str); dstring_appendstr (litfilename, ".lit"); - lit_file = QFS_VOpenFile (litfilename->str, 0, loadmodel->vpath); + lit_file = QFS_VOpenFile (litfilename->str, 0, mod->vpath); data = (byte *) QFS_LoadHunkFile (lit_file); if (data) { if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' @@ -157,7 +166,7 @@ gl_Mod_LoadLighting (bsp_t *bsp) ver = LittleLong (((int32_t *) data)[1]); if (ver == 1) { Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str); - loadmodel->lightdata = data + 8; + brush->lightdata = data + 8; return; } else Sys_MaskPrintf (SYS_DEV, @@ -171,11 +180,10 @@ gl_Mod_LoadLighting (bsp_t *bsp) dstring_delete (litfilename); return; } - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize - * mod_lightmap_bytes, - litfilename->str); + brush->lightdata = Hunk_AllocName (bsp->lightdatasize * mod_lightmap_bytes, + litfilename->str); in = bsp->lightdata; - out = loadmodel->lightdata; + out = brush->lightdata; if (mod_lightmap_bytes > 1) for (i = 0; i < bsp->lightdatasize ; i++) { @@ -222,7 +230,7 @@ SubdividePolygon (int numverts, float *verts) vec3_t mins, maxs; vec3_t front[64], back[64]; - if (numverts > 60) + if (numverts < 3 || numverts > 60) Sys_Error ("numverts = %i", numverts); BoundPoly (numverts, verts, mins, maxs); @@ -296,26 +304,29 @@ SubdividePolygon (int numverts, float *verts) can be done reasonably. */ void -gl_Mod_SubdivideSurface (msurface_t *fa) +gl_Mod_SubdivideSurface (model_t *mod, msurface_t *fa) { float *vec; int lindex, numverts, i; vec3_t verts[64]; + mod_brush_t *brush = &mod->brush; warpface = fa; // convert edges back to a normal polygon numverts = 0; for (i = 0; i < fa->numedges; i++) { - lindex = loadmodel->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) - vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; + vec = brush->vertexes[brush->edges[lindex].v[0]].position; else - vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; + vec = brush->vertexes[brush->edges[-lindex].v[1]].position; VectorCopy (vec, verts[numverts]); numverts++; } - SubdividePolygon (numverts, verts[0]); + if (numverts > 3) { + SubdividePolygon (numverts, verts[0]); + } } diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index 8827844da..f44327acd 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -57,26 +57,34 @@ #include "compat.h" #include "mod_internal.h" +#include "r_internal.h" + +static glsltex_t glsl_notexture = { }; static void -glsl_brush_clear (model_t *m) +glsl_brush_clear (model_t *m, void *data) { int i; + mod_brush_t *brush = &m->brush; m->needload = true; - for (i = 0; i < m->numtextures; i++) { + for (i = 0; i < brush->numtextures; i++) { // NOTE: some maps (eg e1m2) have empty texture slots - if (m->textures[i] && m->textures[i]->gl_texturenum) { - GLSL_ReleaseTexture (m->textures[i]->gl_texturenum); - GLSL_ReleaseTexture (m->textures[i]->sky_tex[0]); - GLSL_ReleaseTexture (m->textures[i]->sky_tex[1]); - m->textures[i]->gl_texturenum = 0; + glsltex_t *tex = 0; + if (brush->textures[i]) { + tex = brush->textures[i]->render; + } + if (tex && tex->gl_texturenum) { + GLSL_ReleaseTexture (tex->gl_texturenum); + GLSL_ReleaseTexture (tex->sky_tex[0]); + GLSL_ReleaseTexture (tex->sky_tex[1]); + tex->gl_texturenum = 0; } } - for (i = 0; i < m->numsurfaces; i++) { - if (m->surfaces[i].polys) { - free (m->surfaces[i].polys); - m->surfaces[i].polys = 0; + for (i = 0; i < brush->numsurfaces; i++) { + if (brush->surfaces[i].polys) { + free (brush->surfaces[i].polys); + brush->surfaces[i].polys = 0; } } } @@ -94,8 +102,13 @@ load_skytex (texture_t *tx, byte *data) } void -glsl_Mod_ProcessTexture (texture_t *tx) +glsl_Mod_ProcessTexture (model_t *mod, texture_t *tx) { + if (!tx) { + r_notexture_mip->render = &glsl_notexture; + return; + } + glsltex_t *tex = tx->render; if (!strncmp (tx->name, "sky", 3)) { // sky textures need to be loaded as two separate textures to allow // wrapping on both sky layers. @@ -112,46 +125,36 @@ glsl_Mod_ProcessTexture (texture_t *tx) // a square sky texture probably means it's black, but just in // case some other magic is being done, duplicate the square to // both sky layers. - tx->sky_tex[0] = load_skytex (tx, tx_data); - tx->sky_tex[1] = tx->sky_tex[0]; + tex->sky_tex[0] = load_skytex (tx, tx_data); + tex->sky_tex[1] = tex->sky_tex[0]; } else if (tx_w == 2 * tx_h) { data = alloca (tx_h * tx_h); for (i = 0; i < 2; i++) { for (j = 0; j < tx_h; j++) memcpy (&data[j * tx_h], &tx_data[j * tx_w + i * tx_h], tx_h); - tx->sky_tex[i] = load_skytex (tx, data); + tex->sky_tex[i] = load_skytex (tx, data); } - tx->gl_texturenum = 0; + tex->gl_texturenum = 0; } else { Sys_Error ("Mod_ProcessTexture: invalid sky texture: %dx%d\n", tx_w, tx_h); } } else { - tx->gl_texturenum = GLSL_LoadQuakeMipTex (tx); + tex->gl_texturenum = GLSL_LoadQuakeMipTex (tx); } } void -glsl_Mod_LoadExternalTextures (model_t *mod) +glsl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { -} - -void -glsl_Mod_LoadLighting (bsp_t *bsp) -{ - // a big hacky, but it's as good a place as any - loadmodel->clear = glsl_brush_clear; + // a bit hacky, but it's as good a place as any + mod->clear = glsl_brush_clear; mod_lightmap_bytes = 1; if (!bsp->lightdatasize) { - loadmodel->lightdata = NULL; + mod->brush.lightdata = NULL; return; } - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname); - memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize); -} - -void -glsl_Mod_SubdivideSurface (msurface_t *fa) -{ + mod->brush.lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); + memcpy (mod->brush.lightdata, bsp->lightdata, bsp->lightdatasize); } diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 931575534..a2f02a322 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -42,6 +42,7 @@ #include "QF/checksum.h" #include "QF/cvar.h" +#include "QF/dstring.h" #include "QF/model.h" #include "QF/qendian.h" #include "QF/quakefs.h" @@ -52,8 +53,9 @@ #include "QF/plugin/vid_render.h" #include "compat.h" +#include "mod_internal.h" -byte mod_novis[MAX_MAP_LEAFS / 8]; +static byte mod_novis[MAP_PVS_BYTES]; VISIBLE cvar_t *gl_sky_divide; //FIXME visibility? VISIBLE int mod_lightmap_bytes = 1; //FIXME should this be visible? @@ -65,10 +67,10 @@ Mod_PointInLeaf (const vec3_t p, model_t *model) mnode_t *node; plane_t *plane; - if (!model || !model->nodes) + if (!model || !model->brush.nodes) Sys_Error ("Mod_PointInLeaf: bad model"); - node = model->nodes; + node = model->brush.nodes; while (1) { if (node->contents < 0) return (mleaf_t *) node; @@ -83,22 +85,21 @@ Mod_PointInLeaf (const vec3_t p, model_t *model) return NULL; // never reached } -static inline byte * -Mod_DecompressVis (byte * in, model_t *model) +static inline void +Mod_DecompressVis_set (const byte *in, const mod_brush_t *brush, byte defvis, + byte *out) { - static byte decompressed[MAX_MAP_LEAFS / 8]; - byte *out; + byte *start = out; int row, c; - row = (model->numleafs + 7) >> 3; - out = decompressed; + row = (brush->numleafs + 7) >> 3; if (!in) { // no vis info, so make all visible while (row) { - *out++ = 0xff; + *out++ = defvis; row--; } - return decompressed; + return; } do { @@ -113,17 +114,77 @@ Mod_DecompressVis (byte * in, model_t *model) *out++ = 0; c--; } - } while (out - decompressed < row); + } while (out - start < row); +} - return decompressed; +static inline void +Mod_DecompressVis_mix (const byte *in, const mod_brush_t *brush, byte defvis, + byte *out) +{ + byte *start = out; + int row, c; + + row = (brush->numleafs + 7) >> 3; + + if (!in) { // no vis info, so make all visible + while (row) { + *out++ |= defvis; + row--; + } + return; + } + + do { + if (*in) { + *out++ |= *in++; + continue; + } + + c = in[1]; + in += 2; + out += c; + } while (out - start < row); } VISIBLE byte * -Mod_LeafPVS (mleaf_t *leaf, model_t *model) +Mod_LeafPVS (const mleaf_t *leaf, const model_t *model) { - if (leaf == model->leafs) + static byte decompressed[MAP_PVS_BYTES]; + if (leaf == model->brush.leafs) { + if (!mod_novis[0]) { + memset (mod_novis, 0xff, sizeof (mod_novis)); + } return mod_novis; - return Mod_DecompressVis (leaf->compressed_vis, model); + } + Mod_DecompressVis_set (leaf->compressed_vis, &model->brush, 0xff, + decompressed); + return decompressed; +} + +VISIBLE void +Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out) +{ + if (leaf == model->brush.leafs) { + memset (out, defvis, sizeof (mod_novis)); + return; + } + return Mod_DecompressVis_set (leaf->compressed_vis, &model->brush, defvis, + out); +} + +VISIBLE void +Mod_LeafPVS_mix (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out) +{ + if (leaf == model->brush.leafs) { + for (int i = MAP_PVS_BYTES; i-- > 0; ) { + *out++ |= defvis; + } + return; + } + return Mod_DecompressVis_mix (leaf->compressed_vis, &model->brush, defvis, + out); } // BRUSHMODEL LOADING ========================================================= @@ -132,45 +193,49 @@ Mod_LeafPVS (mleaf_t *leaf, model_t *model) static void mod_unique_miptex_name (texture_t **textures, texture_t *tx, int ind) { - char name[17]; + char *name; int num = 0, i; - const char *tag; + dstring_t *tag = 0; - strncpy (name, tx->name, 16); - name[16] = 0; + name = tx->name; do { for (i = 0; i < ind; i++) if (textures[i] && !strcmp (textures[i]->name, tx->name)) break; if (i == ind) break; - tag = va ("~%x", num++); - strncpy (tx->name, name, 16); - if (strlen (name) + strlen (tag) <= 15) - strcat (tx->name, tag); - else - strcpy (tx->name + 15 - strlen (tag), tag); + if (!tag) { + tag = dstring_new (); + } + dsprintf (tag, "%s~%x", name, num++); + tx->name = tag->str; } while (1); + + if (tag) { + tx->name = dstring_freeze (tag); + free(name); + } } static void -Mod_LoadTextures (bsp_t *bsp) +Mod_LoadTextures (model_t *mod, bsp_t *bsp) { dmiptexlump_t *m; int i, j, pixels, num, max, altmax; miptex_t *mt; texture_t *tx, *tx2; texture_t *anims[10], *altanims[10]; + mod_brush_t *brush = &mod->brush; if (!bsp->texdatasize) { - loadmodel->textures = NULL; + brush->textures = NULL; return; } m = (dmiptexlump_t *) bsp->texdata; - loadmodel->numtextures = m->nummiptex; - loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof - (*loadmodel->textures), loadname); + brush->numtextures = m->nummiptex; + brush->textures = Hunk_AllocName (m->nummiptex * sizeof (*brush->textures), + mod->name); for (i = 0; i < m->nummiptex; i++) { if (m->dataofs[i] == -1) @@ -184,12 +249,12 @@ Mod_LoadTextures (bsp_t *bsp) if ((mt->width & 15) || (mt->height & 15)) Sys_Error ("Texture %s is not 16 aligned", mt->name); pixels = mt->width * mt->height / 64 * 85; - tx = Hunk_AllocName (sizeof (texture_t) + pixels, loadname); + tx = Hunk_AllocName (sizeof (texture_t) + pixels, mod->name); - loadmodel->textures[i] = tx; + brush->textures[i] = tx; - memcpy (tx->name, mt->name, sizeof (tx->name)); - mod_unique_miptex_name (loadmodel->textures, tx, i); + tx->name = strndup(mt->name, sizeof (mt->name)); + mod_unique_miptex_name (brush->textures, tx, i); tx->width = mt->width; tx->height = mt->height; for (j = 0; j < MIPLEVELS; j++) @@ -199,14 +264,30 @@ Mod_LoadTextures (bsp_t *bsp) memcpy (tx + 1, mt + 1, pixels); if (!strncmp (mt->name, "sky", 3)) - loadmodel->skytexture = tx; - if (mod_funcs) - mod_funcs->Mod_ProcessTexture (tx); + brush->skytexture = tx; + } + if (mod_funcs && mod_funcs->Mod_ProcessTexture) { + size_t render_size = mod_funcs->texture_render_size; + byte *render_data = 0; + if (render_size) { + render_data = Hunk_AllocName (m->nummiptex * render_size, + mod->name); + } + for (i = 0; i < m->nummiptex; i++) { + if (!(tx = brush->textures[i])) { + continue; + } + tx->render = render_data; + render_data += render_size; + mod_funcs->Mod_ProcessTexture (mod, tx); + } + // signal the end of the textures + mod_funcs->Mod_ProcessTexture (mod, 0); } // sequence the animations for (i = 0; i < m->nummiptex; i++) { - tx = loadmodel->textures[i]; + tx = brush->textures[i]; if (!tx || tx->name[0] != '+') continue; if (tx->anim_next) @@ -217,7 +298,6 @@ Mod_LoadTextures (bsp_t *bsp) memset (altanims, 0, sizeof (altanims)); max = tx->name[1]; - altmax = 0; if (max >= 'a' && max <= 'z') max -= 'a' - 'A'; if (max >= '0' && max <= '9') { @@ -234,7 +314,7 @@ Mod_LoadTextures (bsp_t *bsp) Sys_Error ("Bad animating texture %s", tx->name); for (j = i + 1; j < m->nummiptex; j++) { - tx2 = loadmodel->textures[j]; + tx2 = brush->textures[j]; if (!tx2 || tx2->name[0] != '+') continue; if (strcmp (tx2->name + 2, tx->name + 2)) @@ -285,29 +365,29 @@ Mod_LoadTextures (bsp_t *bsp) } static void -Mod_LoadVisibility (bsp_t *bsp) +Mod_LoadVisibility (model_t *mod, bsp_t *bsp) { if (!bsp->visdatasize) { - loadmodel->visdata = NULL; + mod->brush.visdata = NULL; return; } - loadmodel->visdata = Hunk_AllocName (bsp->visdatasize, loadname); - memcpy (loadmodel->visdata, bsp->visdata, bsp->visdatasize); + mod->brush.visdata = Hunk_AllocName (bsp->visdatasize, mod->name); + memcpy (mod->brush.visdata, bsp->visdata, bsp->visdatasize); } static void -Mod_LoadEntities (bsp_t *bsp) +Mod_LoadEntities (model_t *mod, bsp_t *bsp) { if (!bsp->entdatasize) { - loadmodel->entities = NULL; + mod->brush.entities = NULL; return; } - loadmodel->entities = Hunk_AllocName (bsp->entdatasize, loadname); - memcpy (loadmodel->entities, bsp->entdata, bsp->entdatasize); + mod->brush.entities = Hunk_AllocName (bsp->entdatasize, mod->name); + memcpy (mod->brush.entities, bsp->entdata, bsp->entdatasize); } static void -Mod_LoadVertexes (bsp_t *bsp) +Mod_LoadVertexes (model_t *mod, bsp_t *bsp) { dvertex_t *in; int count, i; @@ -315,27 +395,28 @@ Mod_LoadVertexes (bsp_t *bsp) in = bsp->vertexes; count = bsp->numvertexes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->vertexes = out; - loadmodel->numvertexes = count; + mod->brush.vertexes = out; + mod->brush.numvertexes = count; for (i = 0; i < count; i++, in++, out++) VectorCopy (in->point, out->position); } static void -Mod_LoadSubmodels (bsp_t *bsp) +Mod_LoadSubmodels (model_t *mod, bsp_t *bsp) { dmodel_t *in, *out; int count, i, j; + mod_brush_t *brush = &mod->brush; in = bsp->models; count = bsp->nummodels; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->submodels = out; - loadmodel->numsubmodels = count; + brush->submodels = out; + brush->numsubmodels = count; for (i = 0; i < count; i++, in++, out++) { static vec3_t offset = {1, 1, 1}; @@ -350,11 +431,11 @@ Mod_LoadSubmodels (bsp_t *bsp) out->numfaces = in->numfaces; } - out = loadmodel->submodels; + out = brush->submodels; if (out->visleafs > MAX_MAP_LEAFS) { Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s", - out->visleafs, MAX_MAP_LEAFS, loadmodel->name); + out->visleafs, MAX_MAP_LEAFS, mod->path); } if (out->visleafs > 8192) @@ -364,7 +445,7 @@ Mod_LoadSubmodels (bsp_t *bsp) } static void -Mod_LoadEdges (bsp_t *bsp) +Mod_LoadEdges (model_t *mod, bsp_t *bsp) { dedge_t *in; int count, i; @@ -372,10 +453,10 @@ Mod_LoadEdges (bsp_t *bsp) in = bsp->edges; count = bsp->numedges; - out = Hunk_AllocName ((count + 1) * sizeof (*out), loadname); + out = Hunk_AllocName ((count + 1) * sizeof (*out), mod->name); - loadmodel->edges = out; - loadmodel->numedges = count; + mod->brush.edges = out; + mod->brush.numedges = count; for (i = 0; i < count; i++, in++, out++) { out->v[0] = in->v[0]; @@ -384,7 +465,7 @@ Mod_LoadEdges (bsp_t *bsp) } static void -Mod_LoadTexinfo (bsp_t *bsp) +Mod_LoadTexinfo (model_t *mod, bsp_t *bsp) { float len1, len2; int count, miptex, i, j; @@ -393,10 +474,10 @@ Mod_LoadTexinfo (bsp_t *bsp) in = bsp->texinfo; count = bsp->numtexinfo; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->texinfo = out; - loadmodel->numtexinfo = count; + mod->brush.texinfo = out; + mod->brush.numtexinfo = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 4; j++) { @@ -419,13 +500,13 @@ Mod_LoadTexinfo (bsp_t *bsp) miptex = in->miptex; out->flags = in->flags; - if (!loadmodel->textures) { + if (!mod->brush.textures) { out->texture = r_notexture_mip; // checkerboard texture out->flags = 0; } else { - if (miptex >= loadmodel->numtextures) - Sys_Error ("miptex >= loadmodel->numtextures"); - out->texture = loadmodel->textures[miptex]; + if (miptex >= mod->brush.numtextures) + Sys_Error ("miptex >= mod->brush.numtextures"); + out->texture = mod->brush.textures[miptex]; if (!out->texture) { out->texture = r_notexture_mip; // texture not found out->flags = 0; @@ -440,13 +521,14 @@ Mod_LoadTexinfo (bsp_t *bsp) Fills in s->texturemins[] and s->extents[] */ static void -CalcSurfaceExtents (msurface_t *s) +CalcSurfaceExtents (model_t *mod, msurface_t *s) { float mins[2], maxs[2], val; int e, i, j; int bmins[2], bmaxs[2]; mtexinfo_t *tex; mvertex_t *v; + mod_brush_t *brush = &mod->brush; mins[0] = mins[1] = 999999; maxs[0] = maxs[1] = -99999; @@ -454,11 +536,11 @@ CalcSurfaceExtents (msurface_t *s) tex = s->texinfo; for (i = 0; i < s->numedges; i++) { - e = loadmodel->surfedges[s->firstedge + i]; + e = brush->surfedges[s->firstedge + i]; if (e >= 0) - v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + v = &brush->vertexes[brush->edges[e].v[0]]; else - v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + v = &brush->vertexes[brush->edges[-e].v[1]]; for (j = 0; j < 2; j++) { val = v->position[0] * tex->vecs[j][0] + @@ -485,23 +567,24 @@ CalcSurfaceExtents (msurface_t *s) } static void -Mod_LoadFaces (bsp_t *bsp) +Mod_LoadFaces (model_t *mod, bsp_t *bsp) { dface_t *in; int count, planenum, side, surfnum, i; msurface_t *out; + mod_brush_t *brush = &mod->brush; in = bsp->faces; count = bsp->numfaces; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, "%i faces exceeds standard limit of 32767.\n", count); } - loadmodel->surfaces = out; - loadmodel->numsurfaces = count; + brush->surfaces = out; + brush->numsurfaces = count; for (surfnum = 0; surfnum < count; surfnum++, in++, out++) { out->firstedge = in->firstedge; @@ -513,11 +596,11 @@ Mod_LoadFaces (bsp_t *bsp) if (side) out->flags |= SURF_PLANEBACK; - out->plane = loadmodel->planes + planenum; + out->plane = brush->planes + planenum; - out->texinfo = loadmodel->texinfo + in->texinfo; + out->texinfo = brush->texinfo + in->texinfo; - CalcSurfaceExtents (out); + CalcSurfaceExtents (mod, out); // lighting info @@ -527,7 +610,7 @@ Mod_LoadFaces (bsp_t *bsp) if (i == -1) out->samples = NULL; else - out->samples = loadmodel->lightdata + (i * mod_lightmap_bytes); + out->samples = brush->lightdata + (i * mod_lightmap_bytes); // set the drawing flags flag if (!out->texinfo->texture || !out->texinfo->texture->name) @@ -536,8 +619,8 @@ Mod_LoadFaces (bsp_t *bsp) if (!strncmp (out->texinfo->texture->name, "sky", 3)) { // sky out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); if (gl_sky_divide && gl_sky_divide->int_val) - if (mod_funcs) - mod_funcs->Mod_SubdivideSurface (out); + if (mod_funcs && mod_funcs->Mod_SubdivideSurface) + mod_funcs->Mod_SubdivideSurface (mod, out); continue; } @@ -549,41 +632,46 @@ Mod_LoadFaces (bsp_t *bsp) out->extents[i] = 16384; out->texturemins[i] = -8192; } - if (mod_funcs) // cut up polygon for warps - mod_funcs->Mod_SubdivideSurface (out); + if (mod_funcs && mod_funcs->Mod_SubdivideSurface) { + // cut up polygon for warps + mod_funcs->Mod_SubdivideSurface (mod, out); + } continue; } } } static void -Mod_SetParent (mnode_t *node, mnode_t *parent) +Mod_SetParent (mod_brush_t *brush, mnode_t *node, mnode_t *parent) { - node->parent = parent; - if (node->contents < 0) + if (node->contents < 0) { + brush->leaf_parents[(mleaf_t *)node - brush->leafs] = parent; return; - Mod_SetParent (node->children[0], node); - Mod_SetParent (node->children[1], node); + } + brush->node_parents[node - brush->nodes] = parent; + Mod_SetParent (brush, node->children[0], node); + Mod_SetParent (brush, node->children[1], node); } static void -Mod_LoadNodes (bsp_t *bsp) +Mod_LoadNodes (model_t *mod, bsp_t *bsp) { dnode_t *in; int count, i, j, p; mnode_t *out; + mod_brush_t *brush = &mod->brush; in = bsp->nodes; count = bsp->numnodes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, "%i nodes exceeds standard limit of 32767.\n", count); } - loadmodel->nodes = out; - loadmodel->numnodes = count; + brush->nodes = out; + brush->numnodes = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { @@ -592,7 +680,7 @@ Mod_LoadNodes (bsp_t *bsp) } p = in->planenum; - out->plane = loadmodel->planes + p; + out->plane = brush->planes + p; out->firstsurface = in->firstface; out->numsurfaces = in->numfaces; @@ -601,42 +689,46 @@ Mod_LoadNodes (bsp_t *bsp) p = in->children[j]; // this check is for extended bsp 29 files if (p >= 0) { - out->children[j] = loadmodel->nodes + p; + out->children[j] = brush->nodes + p; } else { p = ~p; - if (p < loadmodel->numleafs) { - out->children[j] = (mnode_t *) (loadmodel->leafs + p); + if (p < brush->numleafs) { + out->children[j] = (mnode_t *) (brush->leafs + p); } else { Sys_Printf ("Mod_LoadNodes: invalid leaf index %i " "(file has only %i leafs)\n", p, - loadmodel->numleafs); + brush->numleafs); //map it to the solid leaf - out->children[j] = (mnode_t *)(loadmodel->leafs); + out->children[j] = (mnode_t *)(brush->leafs); } } } } - Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs + size_t size = (brush->numleafs + brush->numnodes) * sizeof (mnode_t *); + brush->node_parents = Hunk_AllocName (size, mod->name); + brush->leaf_parents = brush->node_parents + brush->numnodes; + Mod_SetParent (brush, brush->nodes, NULL); // sets nodes and leafs } static void -Mod_LoadLeafs (bsp_t *bsp) +Mod_LoadLeafs (model_t *mod, bsp_t *bsp) { dleaf_t *in; int count, i, j, p; mleaf_t *out; qboolean isnotmap = true; + mod_brush_t *brush = &mod->brush; in = bsp->leafs; count = bsp->numleafs; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->leafs = out; - loadmodel->numleafs = count; + brush->leafs = out; + brush->numleafs = count; // snprintf(s, sizeof (s), "maps/%s.bsp", // Info_ValueForKey(cl.serverinfo,"map")); - if (!strncmp ("maps/", loadmodel->name, 5)) + if (!strncmp ("maps/", mod->path, 5)) isnotmap = false; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { @@ -647,14 +739,14 @@ Mod_LoadLeafs (bsp_t *bsp) p = in->contents; out->contents = p; - out->firstmarksurface = loadmodel->marksurfaces + in->firstmarksurface; + out->firstmarksurface = brush->marksurfaces + in->firstmarksurface; out->nummarksurfaces = in->nummarksurfaces; p = in->visofs; if (p == -1) out->compressed_vis = NULL; else - out->compressed_vis = loadmodel->visdata + p; + out->compressed_vis = brush->visdata + p; out->efrags = NULL; for (j = 0; j < 4; j++) @@ -673,16 +765,17 @@ Mod_LoadLeafs (bsp_t *bsp) } static void -Mod_LoadClipnodes (bsp_t *bsp) +Mod_LoadClipnodes (model_t *mod, bsp_t *bsp) { dclipnode_t *in; mclipnode_t *out; hull_t *hull; int count, i; + mod_brush_t *brush = &mod->brush; in = bsp->clipnodes; count = bsp->numclipnodes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, @@ -690,15 +783,15 @@ Mod_LoadClipnodes (bsp_t *bsp) count); } - loadmodel->clipnodes = out; - loadmodel->numclipnodes = count; + brush->clipnodes = out; + brush->numclipnodes = count; - hull = &loadmodel->hulls[1]; - loadmodel->hull_list[1] = hull; + hull = &brush->hulls[1]; + brush->hull_list[1] = hull; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = loadmodel->planes; + hull->planes = brush->planes; hull->clip_mins[0] = -16; hull->clip_mins[1] = -16; hull->clip_mins[2] = -24; @@ -706,12 +799,12 @@ Mod_LoadClipnodes (bsp_t *bsp) hull->clip_maxs[1] = 16; hull->clip_maxs[2] = 32; - hull = &loadmodel->hulls[2]; - loadmodel->hull_list[2] = hull; + hull = &brush->hulls[2]; + brush->hull_list[2] = hull; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = loadmodel->planes; + hull->planes = brush->planes; hull->clip_mins[0] = -32; hull->clip_mins[1] = -32; hull->clip_mins[2] = -24; @@ -721,7 +814,7 @@ Mod_LoadClipnodes (bsp_t *bsp) for (i = 0; i < count; i++, out++, in++) { out->planenum = in->planenum; - if (out->planenum < 0 || out->planenum >= loadmodel->numplanes) + if (out->planenum < 0 || out->planenum >= brush->numplanes) Sys_Error ("Mod_LoadClipnodes: planenum out of bounds"); out->children[0] = in->children[0]; out->children[1] = in->children[1]; @@ -746,47 +839,49 @@ Mod_LoadClipnodes (bsp_t *bsp) Replicate the drawing hull structure as a clipping hull */ static void -Mod_MakeHull0 (void) +Mod_MakeHull0 (model_t *mod) { mclipnode_t *out; hull_t *hull; int count, i, j; mnode_t *in, *child; + mod_brush_t *brush = &mod->brush; - hull = &loadmodel->hulls[0]; - loadmodel->hull_list[0] = hull; + hull = &brush->hulls[0]; + brush->hull_list[0] = hull; - in = loadmodel->nodes; - count = loadmodel->numnodes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + in = brush->nodes; + count = brush->numnodes; + out = Hunk_AllocName (count * sizeof (*out), mod->name); hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = loadmodel->planes; + hull->planes = brush->planes; for (i = 0; i < count; i++, out++, in++) { - out->planenum = in->plane - loadmodel->planes; + out->planenum = in->plane - brush->planes; for (j = 0; j < 2; j++) { child = in->children[j]; if (child->contents < 0) out->children[j] = child->contents; else - out->children[j] = child - loadmodel->nodes; + out->children[j] = child - brush->nodes; } } } static void -Mod_LoadMarksurfaces (bsp_t *bsp) +Mod_LoadMarksurfaces (model_t *mod, bsp_t *bsp) { int count, i, j; msurface_t **out; uint32_t *in; + mod_brush_t *brush = &mod->brush; in = bsp->marksurfaces; count = bsp->nummarksurfaces; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, @@ -794,48 +889,50 @@ Mod_LoadMarksurfaces (bsp_t *bsp) count); } - loadmodel->marksurfaces = out; - loadmodel->nummarksurfaces = count; + brush->marksurfaces = out; + brush->nummarksurfaces = count; for (i = 0; i < count; i++) { j = in[i]; - if (j >= loadmodel->numsurfaces) + if (j >= brush->numsurfaces) Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); - out[i] = loadmodel->surfaces + j; + out[i] = brush->surfaces + j; } } static void -Mod_LoadSurfedges (bsp_t *bsp) +Mod_LoadSurfedges (model_t *mod, bsp_t *bsp) { int count, i; int32_t *in; int *out; + mod_brush_t *brush = &mod->brush; in = bsp->surfedges; count = bsp->numsurfedges; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->surfedges = out; - loadmodel->numsurfedges = count; + brush->surfedges = out; + brush->numsurfedges = count; for (i = 0; i < count; i++) out[i] = in[i]; } static void -Mod_LoadPlanes (bsp_t *bsp) +Mod_LoadPlanes (model_t *mod, bsp_t *bsp) { dplane_t *in; int bits, count, i, j; plane_t *out; + mod_brush_t *brush = &mod->brush; in = bsp->planes; count = bsp->numplanes; - out = Hunk_AllocName (count * 2 * sizeof (*out), loadname); + out = Hunk_AllocName (count * 2 * sizeof (*out), mod->name); - loadmodel->planes = out; - loadmodel->numplanes = count; + brush->planes = out; + brush->numplanes = count; for (i = 0; i < count; i++, in++, out++) { bits = 0; @@ -857,12 +954,13 @@ do_checksums (const bsp_t *bsp, void *_mod) int i; model_t *mod = (model_t *) _mod; byte *base; + mod_brush_t *brush = &mod->brush; base = (byte *) bsp->header; // checksum all of the map, except for entities - mod->checksum = 0; - mod->checksum2 = 0; + brush->checksum = 0; + brush->checksum2 = 0; for (i = 0; i < HEADER_LUMPS; i++) { lump_t *lump = bsp->header->lumps + i; int csum; @@ -870,30 +968,30 @@ do_checksums (const bsp_t *bsp, void *_mod) if (i == LUMP_ENTITIES) continue; csum = Com_BlockChecksum (base + lump->fileofs, lump->filelen); - mod->checksum ^= csum; + brush->checksum ^= csum; if (i != LUMP_VISIBILITY && i != LUMP_LEAFS && i != LUMP_NODES) - mod->checksum2 ^= csum; + brush->checksum2 ^= csum; } } static void -recurse_draw_tree (mnode_t *node, int depth) +recurse_draw_tree (mod_brush_t *brush, mnode_t *node, int depth) { if (!node || node->contents < 0) { - if (depth > loadmodel->depth) - loadmodel->depth = depth; + if (depth > brush->depth) + brush->depth = depth; return; } - recurse_draw_tree (node->children[0], depth + 1); - recurse_draw_tree (node->children[1], depth + 1); + recurse_draw_tree (brush, node->children[0], depth + 1); + recurse_draw_tree (brush, node->children[1], depth + 1); } static void -Mod_FindDrawDepth (void) +Mod_FindDrawDepth (mod_brush_t *brush) { - loadmodel->depth = 0; - recurse_draw_tree (loadmodel->nodes, 1); + brush->depth = 0; + recurse_draw_tree (brush, brush->nodes, 1); } void @@ -903,69 +1001,73 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) int i, j; bsp_t *bsp; - loadmodel->type = mod_brush; + mod->type = mod_brush; bsp = LoadBSPMem (buffer, qfs_filesize, do_checksums, mod); // load into heap - Mod_LoadVertexes (bsp); - Mod_LoadEdges (bsp); - Mod_LoadSurfedges (bsp); - Mod_LoadTextures (bsp); - if (mod_funcs) - mod_funcs->Mod_LoadLighting (bsp); - Mod_LoadPlanes (bsp); - Mod_LoadTexinfo (bsp); - Mod_LoadFaces (bsp); - Mod_LoadMarksurfaces (bsp); - Mod_LoadVisibility (bsp); - Mod_LoadLeafs (bsp); - Mod_LoadNodes (bsp); - Mod_LoadClipnodes (bsp); - Mod_LoadEntities (bsp); - Mod_LoadSubmodels (bsp); + Mod_LoadVertexes (mod, bsp); + Mod_LoadEdges (mod, bsp); + Mod_LoadSurfedges (mod, bsp); + Mod_LoadTextures (mod, bsp); + if (mod_funcs && mod_funcs->Mod_LoadLighting) { + mod_funcs->Mod_LoadLighting (mod, bsp); + } + Mod_LoadPlanes (mod, bsp); + Mod_LoadTexinfo (mod, bsp); + Mod_LoadFaces (mod, bsp); + Mod_LoadMarksurfaces (mod, bsp); + Mod_LoadVisibility (mod, bsp); + Mod_LoadLeafs (mod, bsp); + Mod_LoadNodes (mod, bsp); + Mod_LoadClipnodes (mod, bsp); + Mod_LoadEntities (mod, bsp); + Mod_LoadSubmodels (mod, bsp); BSP_Free(bsp); - Mod_MakeHull0 (); + Mod_MakeHull0 (mod); - Mod_FindDrawDepth (); + Mod_FindDrawDepth (&mod->brush); for (i = 0; i < MAX_MAP_HULLS; i++) - Mod_FindClipDepth (&mod->hulls[i]); + Mod_FindClipDepth (&mod->brush.hulls[i]); mod->numframes = 2; // regular and alternate animation // set up the submodels (FIXME: this is confusing) - for (i = 0; i < mod->numsubmodels; i++) { - bm = &mod->submodels[i]; + for (i = 0; i < mod->brush.numsubmodels; i++) { + bm = &mod->brush.submodels[i]; - mod->hulls[0].firstclipnode = bm->headnode[0]; - mod->hull_list[0] = &mod->hulls[0]; + mod->brush.hulls[0].firstclipnode = bm->headnode[0]; + mod->brush.hull_list[0] = &mod->brush.hulls[0]; for (j = 1; j < MAX_MAP_HULLS; j++) { - mod->hulls[j].firstclipnode = bm->headnode[j]; - mod->hulls[j].lastclipnode = mod->numclipnodes - 1; - mod->hull_list[j] = &mod->hulls[j]; + mod->brush.hulls[j].firstclipnode = bm->headnode[j]; + mod->brush.hulls[j].lastclipnode = mod->brush.numclipnodes - 1; + mod->brush.hull_list[j] = &mod->brush.hulls[j]; } - mod->firstmodelsurface = bm->firstface; - mod->nummodelsurfaces = bm->numfaces; + mod->brush.firstmodelsurface = bm->firstface; + mod->brush.nummodelsurfaces = bm->numfaces; VectorCopy (bm->maxs, mod->maxs); VectorCopy (bm->mins, mod->mins); mod->radius = RadiusFromBounds (mod->mins, mod->maxs); - mod->numleafs = bm->visleafs; + mod->brush.numleafs = bm->visleafs; - if (i < mod->numsubmodels - 1) { + if (i < mod->brush.numsubmodels - 1) { // duplicate the basic information - char name[10]; + char name[12]; snprintf (name, sizeof (name), "*%i", i + 1); - loadmodel = Mod_FindName (name); - *loadmodel = *mod; - strcpy (loadmodel->name, name); - mod = loadmodel; + model_t *m = Mod_FindName (name); + *m = *mod; + strcpy (m->path, name); + mod = m; + // make sure clear is called only for the main model + m->clear = 0; + m->data = 0; } } } diff --git a/libs/models/brush/sw_model_brush.c b/libs/models/brush/sw_model_brush.c index c78cd12b4..84080d49d 100644 --- a/libs/models/brush/sw_model_brush.c +++ b/libs/models/brush/sw_model_brush.c @@ -40,30 +40,14 @@ #include "mod_internal.h" - void -sw_Mod_SubdivideSurface (msurface_t *fa) -{ -} - -void -sw_Mod_ProcessTexture (texture_t *tx) -{ -} - -void -sw_Mod_LoadExternalTextures (model_t *mod) -{ -} - -void -sw_Mod_LoadLighting (bsp_t *bsp) +sw_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { mod_lightmap_bytes = 1; if (!bsp->lightdatasize) { - loadmodel->lightdata = NULL; + mod->brush.lightdata = NULL; return; } - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname); - memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize); + mod->brush.lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); + memcpy (mod->brush.lightdata, bsp->lightdata, bsp->lightdatasize); } diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c new file mode 100644 index 000000000..a7b4dc336 --- /dev/null +++ b/libs/models/brush/vulkan_model_brush.c @@ -0,0 +1,446 @@ +/* + vulkan_model_brush.c + + Vulkan support routines for model loading and caching + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +// models are the only shared resource between a client and server running +// on the same machine. + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/image.h" +#include "QF/qendian.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_model.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/staging.h" + +#include "qfalloca.h" +#include "compat.h" +#include "mod_internal.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +static vulktex_t vulkan_notexture = { }; + +static void vulkan_brush_clear (model_t *mod, void *data) +{ + modelctx_t *mctx = data; + vulkan_ctx_t *ctx = mctx->ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + mod_brush_t *brush = &mod->brush; + + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + dfunc->vkDestroyImage (device->dev, tex->tex->image, 0); + dfunc->vkDestroyImageView (device->dev, tex->tex->view, 0); + if (tex->glow) { + dfunc->vkDestroyImage (device->dev, tex->glow->image, 0); + dfunc->vkDestroyImageView (device->dev, tex->glow->view, 0); + } + } + dfunc->vkFreeMemory (device->dev, mctx->texture_memory, 0); +} + +static void +transfer_mips (byte *dst, const void *_src, const texture_t *tx, byte *palette) +{ + const byte *src = _src; + unsigned width = tx->width; + unsigned height = tx->height; + unsigned count, offset; + + for (int i = 0; i < MIPLEVELS; i++) { + // mip offsets are relative to the texture pointer rather than the + // end of the texture struct + offset = tx->offsets[i] - sizeof (texture_t); + count = width * height; + Vulkan_ExpandPalette (dst, src + offset, palette, 2, count); + dst += count * 4; + width >>= 1; + height >>= 1; + } +} + +static void +copy_mips (qfv_packet_t *packet, texture_t *tx, qfv_tex_t *tex, + qfv_devfuncs_t *dfunc) +{ + // base copy + VkBufferImageCopy copy = { + tex->offset, tx->width, tx->height, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {0, 0, 0}, {tx->width, tx->height, 1}, + }; + int is_sky = 0; + int sky_offset = 0; + size_t size = tx->width * tx->height * 4; + int copy_count = MIPLEVELS; + + if (strncmp (tx->name, "sky", 3) == 0) { + if (tx->width == 2 * tx->height) { + copy.imageExtent.width /= 2; + sky_offset = tx->width * 4 / 2; + } + is_sky = 1; + copy_count *= 2; + } + + __auto_type copies = QFV_AllocBufferImageCopy (copy_count, alloca); + copies->size = 0; + + for (int i = 0; i < MIPLEVELS; i++) { + __auto_type c = &copies->a[copies->size++]; + *c = copy; + if (is_sky) { + __auto_type c = &copies->a[copies->size++]; + *c = copy; + c->bufferOffset += sky_offset; + c->imageSubresource.baseArrayLayer = 1; + } + copy.bufferOffset += size; + size >>= 2; + copy.bufferRowLength >>= 1; + copy.bufferImageHeight >>= 1; + copy.imageExtent.width >>= 1; + copy.imageExtent.height >>= 1; + copy.imageSubresource.mipLevel++; + sky_offset >>= 1; + } + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + tex->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + copies->size, copies->a); +} + +static void +load_textures (model_t *mod, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + modelctx_t *mctx = mod->data; + VkImage image = 0; + byte *buffer; + mod_brush_t *brush = &mod->brush; + + size_t image_count = 0; + size_t copy_count = 0; + size_t memsize = 0; + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + tex->tex->offset = memsize; + memsize += QFV_GetImageSize (device, tex->tex->image); + image_count++; + copy_count += MIPLEVELS; + if (strncmp (tx->name, "sky", 3) == 0) { + copy_count += MIPLEVELS; + } + // just so we have one in the end + image = tex->tex->image; + if (tex->glow) { + copy_count += MIPLEVELS; + tex->glow->offset = memsize; + memsize += QFV_GetImageSize (device, tex->glow->image); + image_count++; + } + } + VkDeviceMemory mem; + mem = QFV_AllocImageMemory (device, image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + memsize, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + mem, va (ctx->va_ctx, "memory:%s:texture", mod->name)); + mctx->texture_memory = mem; + + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, + va (ctx->va_ctx, + "brush:%s", mod->name), + memsize, ctx->cmdpool); + qfv_packet_t *packet = QFV_PacketAcquire (stage); + buffer = QFV_PacketExtend (packet, memsize); + + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; + byte *palette = vid.palette32; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + + dfunc->vkBindImageMemory (device->dev, tex->tex->image, mem, + tex->tex->offset); + VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D; + if (strncmp (tx->name, "sky", 3) == 0) { + palette = alloca (256 * 4); + memcpy (palette, vid.palette32, 256 * 4); + // sky's black is transparent + // this hits both layers, but so long as the screen is cleared + // to black, no one should notice :) + palette[3] = 0; + type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + } + tex->tex->view = QFV_CreateImageView (device, tex->tex->image, + type, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, + tex->tex->view, + va (ctx->va_ctx, "iview:%s:%s:tex", + mod->name, tx->name)); + transfer_mips (buffer + tex->tex->offset, tx + 1, tx, palette); + if (tex->glow) { + dfunc->vkBindImageMemory (device->dev, tex->glow->image, mem, + tex->glow->offset); + // skys are unlit so never have a glow texture thus glow + // textures are always simple 2D + tex->glow->view = QFV_CreateImageView (device, tex->tex->image, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, + tex->glow->view, + va (ctx->va_ctx, "iview:%s:%s:glow", + mod->name, tx->name)); + transfer_mips (buffer + tex->glow->offset, tex->glow->memory, tx, + palette); + } + } + + // base barrier + VkImageMemoryBarrier barrier; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + __auto_type barriers = QFV_AllocImageBarrierSet (image_count, malloc); + barriers->size = 0; + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + __auto_type b = &barriers->a[barriers->size++]; + *b = barrier; + b->image = tex->tex->image; + if (tex->glow) { + b = &barriers->a[barriers->size++]; + *b = barrier; + b->image = tex->glow->image; + } + } + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + barriers->size, barriers->a); + for (int i = 0, j = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + __auto_type b = &barriers->a[j++]; + b->oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + b->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + b->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + b->dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + copy_mips (packet, tx, tex->tex, dfunc); + if (tex->glow) { + b = &barriers->a[j++]; + b->oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + b->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + b->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + b->dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + copy_mips (packet, tx, tex->glow, dfunc); + } + } + + stages=imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + barriers->size, barriers->a); + QFV_PacketSubmit (packet); + QFV_DestroyStagingBuffer (stage); + free (barriers); +} + +void +Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + if (!tx) { + modelctx_t *mctx = Hunk_AllocName (sizeof (modelctx_t), mod->name); + mctx->ctx = ctx; + mod->clear = vulkan_brush_clear; + mod->data = mctx; + + r_notexture_mip->render = &vulkan_notexture; + load_textures (mod, ctx); + return; + } + + vulktex_t *tex = tx->render; + tex->texture = tx; + tex->tex = (qfv_tex_t *) (tex + 1); + VkExtent3D extent = { tx->width, tx->height, 1 }; + + int layers = 1; + if (strncmp (tx->name, "sky", 3) == 0) { + layers = 2; + // the sky texture is normally 2 side-by-side squares, but + // some maps have just a single square + if (tx->width == 2 * tx->height) { + extent.width /= 2; + } + } + + tex->tex->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + extent, 4, layers, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, + tex->tex->image, + va (ctx->va_ctx, "image:%s:%s:tex", mod->name, + tx->name)); + if (layers > 1) { + // skys are unlit, so no fullbrights + return; + } + + const char *name = va (ctx->va_ctx, "fb_%s", tx->name); + int size = (tx->width * tx->height * 85) / 64; + int fullbright_mark = Hunk_LowMark (); + byte *pixels = Hunk_AllocName (size, name); + + if (!Mod_CalcFullbright ((byte *) (tx + 1), pixels, size)) { + Hunk_FreeToLowMark (fullbright_mark); + return; + } + tex->glow = tex->tex + 1; + tex->glow->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + extent, 4, 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, + tex->glow->image, + va (ctx->va_ctx, "image:%s:%s:glow", mod->name, + tx->name)); + // store the pointer to the fullbright data: memory will never be set to + // actual device memory because all of the textures will be loaded in one + // big buffer + tex->glow->memory = (VkDeviceMemory) pixels; +} + +void +Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, vulkan_ctx_t *ctx) +{ + mod_brush_t *brush = &mod->brush; + + mod_lightmap_bytes = 3; + if (!bsp->lightdatasize) { + brush->lightdata = NULL; + return; + } + + byte d; + byte *in, *out, *data; + size_t i; + int ver; + QFile *lit_file; + + brush->lightdata = 0; + if (mod_lightmap_bytes > 1) { + // LordHavoc: check for a .lit file to load + dstring_t *litfilename = dstring_new (); + dstring_copystr (litfilename, mod->name); + QFS_StripExtension (litfilename->str, litfilename->str); + dstring_appendstr (litfilename, ".lit"); + lit_file = QFS_VOpenFile (litfilename->str, 0, mod->vpath); + data = (byte *) QFS_LoadHunkFile (lit_file); + if (data) { + if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' + && data[3] == 'T') { + ver = LittleLong (((int32_t *) data)[1]); + if (ver == 1) { + Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str); + brush->lightdata = data + 8; + } else { + Sys_MaskPrintf (SYS_DEV, + "Unknown .lit file version (%d)\n", ver); + } + } else { + Sys_MaskPrintf (SYS_DEV, "Corrupt .lit file (old version?)\n"); + } + } + dstring_delete (litfilename); + } + if (brush->lightdata || !bsp->lightdatasize) { + return; + } + // LordHavoc: oh well, expand the white lighting data + brush->lightdata = Hunk_AllocName (bsp->lightdatasize * 3, mod->name); + in = bsp->lightdata; + out = brush->lightdata; + + for (i = 0; i < bsp->lightdatasize ; i++) { + d = *in++; + *out++ = d; + *out++ = d; + *out++ = d; + } +} diff --git a/libs/models/clip_hull.c b/libs/models/clip_hull.c index f47c1886d..0a01b62f1 100644 --- a/libs/models/clip_hull.c +++ b/libs/models/clip_hull.c @@ -36,6 +36,7 @@ #include "QF/clip_hull.h" #include "QF/model.h" +#include "mod_internal.h" VISIBLE clip_hull_t * MOD_Alloc_Hull (int nodes, int planes) diff --git a/libs/models/fullbright.c b/libs/models/fullbright.c new file mode 100644 index 000000000..8d76b9db4 --- /dev/null +++ b/libs/models/fullbright.c @@ -0,0 +1,64 @@ +/* + fullbright.c + + fullbright skin handling + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +// models are the only shared resource between a client and server running +// on the same machine. + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "mod_internal.h" + +VISIBLE int +Mod_CalcFullbright (const byte *in, byte *out, int pixels) +{ + byte fb = 0; + + while (pixels-- > 0) { + byte pix = *in++; + if (pix >= 256 - 32) { + fb = 1; + *out++ = pix; + } else { + *out++ = 0; + } + } + return fb; +} + +VISIBLE void +Mod_ClearFullbright (const byte *in, byte *out, int pixels) +{ + while (pixels-- > 0) { + byte pix = *in++; + if (pix >= 256 - 32) { + *out++ = 0; + } else { + *out++ = pix; + } + } +} diff --git a/libs/models/gl_model_fullbright.c b/libs/models/gl_model_fullbright.c index f556c5dd7..6635cbef5 100644 --- a/libs/models/gl_model_fullbright.c +++ b/libs/models/gl_model_fullbright.c @@ -38,45 +38,33 @@ #include "QF/qendian.h" #include "QF/sys.h" -#include "r_local.h" - - -VISIBLE int -Mod_CalcFullbright (byte *in, byte *out, int pixels) -{ - int fb = 0; - - while (pixels--) { - if (*in >= 256 - 32) { - fb = 1; - *out++ = *in++; - } else { - *out++ = 255; - in++; - } - } - return fb; -} +#include "mod_internal.h" int -Mod_Fullbright (byte *skin, int width, int height, char *name) +Mod_Fullbright (byte *skin, int width, int height, const char *name) { - byte *ptexels; + byte *texels; int pixels; int texnum = 0; pixels = width * height; -// ptexels = Hunk_Alloc(s); - ptexels = malloc (pixels); - SYS_CHECKMEM (ptexels); + texels = malloc (pixels); + SYS_CHECKMEM (texels); // Check for fullbright pixels - if (Mod_CalcFullbright (skin, ptexels, pixels)) { + if (Mod_CalcFullbright (skin, texels, pixels)) { + //FIXME black should be transparent for fullbrights (or just fix + //fullbright rendering in gl) Sys_MaskPrintf (SYS_DEV, "FB Model ID: '%s'\n", name); - texnum = GL_LoadTexture (name, width, height, ptexels, true, true, 1); + for (int i = 0; i < pixels; i++) { + if (!texels[i]) { + texels[i] = 255; + } + } + texnum = GL_LoadTexture (name, width, height, texels, true, true, 1); } - free (ptexels); + free (texels); return texnum; } diff --git a/libs/models/gl_skin.c b/libs/models/gl_skin.c index 063100866..ae9c9ac37 100644 --- a/libs/models/gl_skin.c +++ b/libs/models/gl_skin.c @@ -72,7 +72,8 @@ do_fb_skin (glskin_t *s) { int size = s->tex->width * s->tex->height; - s->fb_tex = realloc (s->fb_tex, field_offset(tex_t, data[size])); + s->fb_tex = realloc (s->fb_tex, sizeof (tex_t) + size); + s->fb_tex->data = (byte *) (s->fb_tex + 1); s->fb_tex->width = s->tex->width; s->fb_tex->height = s->tex->height; s->fb_tex->format = tex_palette; @@ -87,7 +88,8 @@ gl_Skin_SetPlayerSkin (int width, int height, const byte *data) glskin_t *s; s = &player_skin; - s->tex = realloc (s->tex, field_offset(tex_t, data[size])); + s->tex = realloc (s->tex, sizeof (tex_t) + size); + s->tex->data = (byte *) (s->tex + 1); s->tex->width = width; s->tex->height = height; s->tex->format = tex_palette; diff --git a/libs/models/iqm/Makefile.am b/libs/models/iqm/Makefile.am deleted file mode 100644 index 71f54f576..000000000 --- a/libs/models/iqm/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= @iqm_libs@ -EXTRA_LTLIBRARIES=libiqm_gl.la libiqm_glsl.la libiqm_sw.la - -iqm_src= model_iqm.c -gl_src= gl_model_iqm.c -glsl_src= glsl_model_iqm.c -sw_src= sw_model_iqm.c - -libiqm_gl_la_SOURCES= $(gl_src) $(iqm_src) - -libiqm_glsl_la_SOURCES= $(glsl_src) $(iqm_src) - -libiqm_sw_la_SOURCES= $(sw_src) $(iqm_src) - -EXTRA_DIST= $(gl_src) $(glsl_src) $(sw_src) $(iqm_src) diff --git a/libs/models/iqm/Makemodule.am b/libs/models/iqm/Makemodule.am new file mode 100644 index 000000000..cc362050d --- /dev/null +++ b/libs/models/iqm/Makemodule.am @@ -0,0 +1,27 @@ +noinst_LTLIBRARIES += @iqm_libs@ +EXTRA_LTLIBRARIES += \ + libs/models/iqm/libiqm_gl.la \ + libs/models/iqm/libiqm_glsl.la \ + libs/models/iqm/libiqm_sw.la \ + libs/models/iqm/libiqm_vulkan.la + +iqm_src= libs/models/iqm/model_iqm.c +iqm_gl_src= libs/models/iqm/gl_model_iqm.c +iqm_glsl_src= libs/models/iqm/glsl_model_iqm.c +iqm_sw_src= libs/models/iqm/sw_model_iqm.c +iqm_vulkan_src= libs/models/iqm/vulkan_model_iqm.c + +libs_models_iqm_libiqm_gl_la_SOURCES= $(iqm_gl_src) $(iqm_src) + +libs_models_iqm_libiqm_glsl_la_SOURCES= $(iqm_glsl_src) $(iqm_src) + +libs_models_iqm_libiqm_sw_la_SOURCES= $(iqm_sw_src) $(iqm_src) + +libs_models_iqm_libiqm_vulkan_la_SOURCES= $(iqm_vulkan_src) $(iqm_src) + +EXTRA_DIST += \ + $(iqm_gl_src) \ + $(iqm_glsl_src) \ + $(iqm_sw_src) \ + $(iqm_vulkan_src) \ + $(iqm_src) diff --git a/libs/models/iqm/gl_model_iqm.c b/libs/models/iqm/gl_model_iqm.c index e2e877d1d..fc9c50f1a 100644 --- a/libs/models/iqm/gl_model_iqm.c +++ b/libs/models/iqm/gl_model_iqm.c @@ -56,7 +56,7 @@ static byte null_texture[] = { }; static void -gl_iqm_clear (model_t *mod) +gl_iqm_clear (model_t *mod, void *data) { iqm_t *iqm = (iqm_t *) mod->aliashdr; gliqm_t *gl = (gliqm_t *) iqm->extra_data; @@ -80,7 +80,7 @@ gl_iqm_load_textures (iqm_t *iqm) for (i = 0; i < iqm->num_meshes; i++) { dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str)))) + if ((tex = LoadImage (va (0, "textures/%s", str->str), 1))) gl->textures[i] = GL_LoadTexture (str->str, tex->width, tex->height, tex->data, true, false, diff --git a/libs/models/iqm/glsl_model_iqm.c b/libs/models/iqm/glsl_model_iqm.c index 5e1a26030..c8a82a112 100644 --- a/libs/models/iqm/glsl_model_iqm.c +++ b/libs/models/iqm/glsl_model_iqm.c @@ -68,7 +68,7 @@ static byte null_normmap[] = { }; static void -glsl_iqm_clear (model_t *mod) +glsl_iqm_clear (model_t *mod, void *data) { iqm_t *iqm = (iqm_t *) mod->aliashdr; glsliqm_t *glsl = (glsliqm_t *) iqm->extra_data; @@ -102,12 +102,12 @@ glsl_iqm_load_textures (iqm_t *iqm) for (i = 0; i < iqm->num_meshes; i++) { dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str)))) + if ((tex = LoadImage (va (0, "textures/%s", str->str), 1))) glsl->textures[i] = GLSL_LoadRGBATexture (str->str, tex->width, tex->height, tex->data); else glsl->textures[i] = GLSL_LoadRGBATexture ("", 2, 2, null_texture); - if ((tex = LoadImage (va ("textures/%s_norm", str->str)))) + if ((tex = LoadImage (va (0, "textures/%s_norm", str->str), 1))) glsl->normmaps[i] = GLSL_LoadRGBATexture (str->str, tex->width, tex->height, tex->data); else diff --git a/libs/models/iqm/model_iqm.c b/libs/models/iqm/model_iqm.c index 6eabf7117..1091ee7d9 100644 --- a/libs/models/iqm/model_iqm.c +++ b/libs/models/iqm/model_iqm.c @@ -118,7 +118,6 @@ get_joints (const iqmheader *hdr, byte *buffer) { iqmjoint *joint; uint32_t i, j; - float t; if (hdr->ofs_joints + hdr->num_joints * sizeof (iqmjoint) > hdr->filesize) return 0; @@ -135,10 +134,6 @@ get_joints (const iqmheader *hdr, byte *buffer) joint[i].translate[j] = LittleFloat (joint[i].translate[j]); for (j = 0; j < 4; j++) joint[i].rotate[j] = LittleFloat (joint[i].rotate[j]); - // iqm quaternions use xyzw but QF quaternions use wxyz - t = joint[i].rotate[3]; - memmove (&joint[i].rotate[1], &joint[i].rotate[0], 3 * sizeof (float)); - joint[i].rotate[0] = t; for (j = 0; j < 3; j++) joint[i].scale[j] = LittleFloat (joint[i].scale[j]); } @@ -442,19 +437,18 @@ load_iqm_anims (model_t *mod, const iqmheader *hdr, byte *buffer) if (p->mask & 0x004) translation[2] += *framedata++ * p->channelscale[2]; - // QF's quaternions are wxyz while IQM's quaternions are xyzw - rotation[1] = p->channeloffset[3]; + rotation[0] = p->channeloffset[3]; if (p->mask & 0x008) - rotation[1] += *framedata++ * p->channelscale[3]; - rotation[2] = p->channeloffset[4]; + rotation[0] += *framedata++ * p->channelscale[3]; + rotation[1] = p->channeloffset[4]; if (p->mask & 0x010) - rotation[2] += *framedata++ * p->channelscale[4]; - rotation[3] = p->channeloffset[5]; + rotation[1] += *framedata++ * p->channelscale[4]; + rotation[2] = p->channeloffset[5]; if (p->mask & 0x020) - rotation[3] += *framedata++ * p->channelscale[5]; - rotation[0] = p->channeloffset[6]; + rotation[2] += *framedata++ * p->channelscale[5]; + rotation[3] = p->channeloffset[6]; if (p->mask & 0x040) - rotation[0] += *framedata++ * p->channelscale[6]; + rotation[3] += *framedata++ * p->channelscale[6]; scale[0] = p->channeloffset[7]; if (p->mask & 0x080) @@ -503,25 +497,25 @@ Mod_LoadIQM (model_t *mod, void *buffer) uint32_t *swap; if (!strequal (hdr->magic, IQM_MAGIC)) - Sys_Error ("%s: not an IQM", loadname); + Sys_Error ("%s: not an IQM", mod->path); // Byte swap the header. Everything is the same type, so no problem :) for (swap = &hdr->version; swap <= &hdr->ofs_extensions; swap++) *swap = LittleLong (*swap); //if (hdr->version < 1 || hdr->version > IQM_VERSION) if (hdr->version != IQM_VERSION) - Sys_Error ("%s: unable to handle iqm version %d", loadname, + Sys_Error ("%s: unable to handle iqm version %d", mod->path, hdr->version); if (hdr->filesize != (uint32_t) qfs_filesize) - Sys_Error ("%s: invalid filesize", loadname); + Sys_Error ("%s: invalid filesize", mod->path); iqm = calloc (1, sizeof (iqm_t)); iqm->text = malloc (hdr->num_text); memcpy (iqm->text, (byte *) buffer + hdr->ofs_text, hdr->num_text); mod->aliashdr = (aliashdr_t *) iqm; mod->type = mod_iqm; if (hdr->num_meshes && !load_iqm_meshes (mod, hdr, (byte *) buffer)) - Sys_Error ("%s: error loading meshes", loadname); + Sys_Error ("%s: error loading meshes", mod->path); if (hdr->num_anims && !load_iqm_anims (mod, hdr, (byte *) buffer)) - Sys_Error ("%s: error loading anims", loadname); + Sys_Error ("%s: error loading anims", mod->path); m_funcs->Mod_IQMFinish (mod); } @@ -606,7 +600,7 @@ Mod_IQMBuildBlendPalette (iqm_t *iqm, int *size) } num_blends = iqm->num_joints; - blend_hash = Hash_NewTable (1023, 0, 0, 0); + blend_hash = Hash_NewTable (1023, 0, 0, 0, 0); Hash_SetHashCompare (blend_hash, blend_get_hash, blend_compare); for (i = 0; i < iqm->num_verts; i++) { diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index 2a32ecca0..b715bb5da 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -53,12 +53,11 @@ #include "mod_internal.h" #include "r_internal.h" -static tex_t null_texture = { - 2, 2, tex_palette, 0, {15, 15, 15, 15} -}; +static byte null_data[] = {15, 15, 15, 15}; +static tex_t null_texture = { 2, 2, tex_palette, 1, 0, null_data }; static void -sw_iqm_clear (model_t *mod) +sw_iqm_clear (model_t *mod, void *data) { iqm_t *iqm = (iqm_t *) mod->aliashdr; swiqm_t *sw = (swiqm_t *) iqm->extra_data; @@ -81,59 +80,6 @@ sw_iqm_clear (model_t *mod) Mod_FreeIQM (iqm); } -static byte -convert_color (byte *rgb) -{ - //FIXME slow! - int dist[3]; - int d, bestd = 256 * 256 * 3, bestc = -1; - int i; - - for (i = 0; i < 256; i++) { - VectorSubtract (vid.basepal + i * 3, rgb, dist); - d = DotProduct (dist, dist); - if (d < bestd) { - bestd = d; - bestc = i; - } - } - return bestc; -} - -static tex_t * -convert_tex (tex_t *tex) -{ - tex_t *new; - int pixels; - int bpp = 3; - int i; - - pixels = tex->width * tex->height; - new = malloc (field_offset (tex_t, data[pixels])); - new->width = tex->width; - new->height = tex->height; - new->format = tex_palette; - new->palette = 0; - switch (tex->format) { - case tex_palette: - case tex_l: // will not work as expected - case tex_a: // will not work as expected - memcpy (new->data, tex->data, pixels); - break; - case tex_la: // will not work as expected - for (i = 0; i < pixels; i++) - new->data[i] = tex->data[i * 2]; - break; - case tex_rgba: - bpp = 4; - case tex_rgb: - for (i = 0; i < pixels; i++) - new->data[i] = convert_color (tex->data + i * bpp); - break; - } - return new; -} - static inline void convert_coord (byte *tc, int size) { @@ -153,7 +99,7 @@ sw_iqm_load_textures (iqm_t *iqm) bytes = (iqm->num_verts + 7) / 8; done_verts = alloca (bytes); memset (done_verts, 0, bytes); - sw->skins = malloc (iqm->num_meshes * sizeof (tex_t)); + sw->skins = malloc (iqm->num_meshes * sizeof (tex_t *)); for (i = 0; i < iqm->num_meshes; i++) { for (j = 0; j < i; j++) { if (iqm->meshes[j].material == iqm->meshes[i].material) { @@ -165,8 +111,8 @@ sw_iqm_load_textures (iqm_t *iqm) continue; dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str)))) - tex = sw->skins[i] = convert_tex (tex); + if ((tex = LoadImage (va (0, "textures/%s", str->str), 1))) + tex = sw->skins[i] = ConvertImage (tex, vid.basepal); else tex = sw->skins[i] = &null_texture; for (j = 0; j < (int) iqm->meshes[i].num_triangles * 3; j++) { diff --git a/libs/models/iqm/vulkan_model_iqm.c b/libs/models/iqm/vulkan_model_iqm.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/models/model.c b/libs/models/model.c index bac0223de..4c2d4ac30 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -39,6 +39,7 @@ #endif #include "QF/cvar.h" +#include "QF/darray.h" #include "QF/iqm.h" #include "QF/model.h" #include "QF/qendian.h" @@ -48,16 +49,13 @@ #include "QF/plugin/vid_render.h" #include "compat.h" +#include "mod_internal.h" vid_model_funcs_t *mod_funcs; -model_t *loadmodel; -char *loadname; // for hunk tags - #define MOD_BLOCK 16 // allocate 16 models at a time -model_t **mod_known; -int mod_numknown; -int mod_maxknown; +static struct DARRAY_TYPE (model_t *) mod_known = {0, 0, MOD_BLOCK}; +static size_t mod_numknown; VISIBLE texture_t *r_notexture_mip; @@ -75,7 +73,6 @@ Mod_Init (void) int m, x, y; int mip0size = 16*16, mip1size = 8*8, mip2size = 4*4, mip3size = 2*2; - memset (mod_novis, 0xff, sizeof (mod_novis)); r_notexture_mip = Hunk_AllocName (sizeof (texture_t) + mip0size + mip1size + mip2size + mip3size, "notexture"); @@ -118,45 +115,46 @@ Mod_Init_Cvars (void) VISIBLE void Mod_ClearAll (void) { - int i; + size_t i; model_t **mod; - for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { + for (i = 0, mod = mod_known.a; i < mod_numknown; i++, mod++) { + //FIXME this seems to be correct but need to double check the behavior + //with alias models if (!(*mod)->needload && (*mod)->clear) { - (*mod)->clear (*mod); - } else { - if ((*mod)->type != mod_alias) - (*mod)->needload = true; - if ((*mod)->type == mod_sprite) - (*mod)->cache.data = 0; + (*mod)->clear (*mod, (*mod)->data); } + if ((*mod)->type != mod_alias) + (*mod)->needload = true; + if ((*mod)->type == mod_sprite) + (*mod)->cache.data = 0; } } model_t * Mod_FindName (const char *name) { - int i; + size_t i; model_t **mod; if (!name[0]) Sys_Error ("Mod_FindName: empty name"); // search the currently loaded models - for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) - if (!strcmp ((*mod)->name, name)) + for (i = 0, mod = mod_known.a; i < mod_numknown; i++, mod++) + if (!strcmp ((*mod)->path, name)) break; if (i == mod_numknown) { - if (mod_numknown == mod_maxknown) { - mod_maxknown += MOD_BLOCK; - mod_known = realloc (mod_known, mod_maxknown * sizeof (model_t *)); - mod = mod_known + mod_numknown; - *mod = calloc (MOD_BLOCK, sizeof (model_t)); - for (i = 1; i < MOD_BLOCK; i++) - mod[i] = mod[0] + i; + if (mod_numknown == mod_known.size) { + model_t *block = calloc (MOD_BLOCK, sizeof (model_t)); + for (i = 0; i < MOD_BLOCK; i++) { + DARRAY_APPEND (&mod_known, &block[i]); + } + mod = &mod_known.a[mod_numknown]; } - strcpy ((*mod)->name, name); + memset ((*mod), 0, sizeof (model_t)); + strncpy ((*mod)->path, name, sizeof (*mod)->path - 1); (*mod)->needload = true; mod_numknown++; Cache_Add (&(*mod)->cache, *mod, Mod_CallbackLoad); @@ -171,17 +169,17 @@ Mod_RealLoadModel (model_t *mod, qboolean crash, cache_allocator_t allocator) uint32_t *buf; // load the file - buf = (uint32_t *) QFS_LoadFile (QFS_FOpenFile (mod->name), 0); + buf = (uint32_t *) QFS_LoadFile (QFS_FOpenFile (mod->path), 0); if (!buf) { if (crash) - Sys_Error ("Mod_LoadModel: %s not found", mod->name); + Sys_Error ("Mod_LoadModel: %s not found", mod->path); return NULL; } - if (loadname) - free (loadname); - loadname = QFS_FileBase (mod->name); - loadmodel = mod; + char *name = QFS_FileBase (mod->path); + strncpy (mod->name, name, sizeof (mod->name - 1)); + mod->name[sizeof (mod->name) - 1] = 0; + free (name); // fill it in mod->vpath = qfs_foundfile.vpath; @@ -202,17 +200,17 @@ Mod_RealLoadModel (model_t *mod, qboolean crash, cache_allocator_t allocator) break; case IDHEADER_MDL: // Type 6: Quake 1 .mdl case HEADER_MDL16: // QF Type 6 extended for 16bit precision - if (strequal (mod->name, "progs/grenade.mdl")) { + if (strequal (mod->path, "progs/grenade.mdl")) { mod->fullbright = 0; mod->shadow_alpha = 255; - } else if (strnequal (mod->name, "progs/flame", 11) - || strnequal (mod->name, "progs/bolt", 10)) { + } else if (strnequal (mod->path, "progs/flame", 11) + || strnequal (mod->path, "progs/bolt", 10)) { mod->fullbright = 1; mod->shadow_alpha = 0; } - if (strnequal (mod->name, "progs/v_", 8)) { + if (strnequal (mod->path, "progs/v_", 8)) { mod->min_light = 0.12; - } else if (strequal (mod->name, "progs/player.mdl")) { + } else if (strequal (mod->path, "progs/player.mdl")) { mod->min_light = 0.04; } if (mod_funcs) @@ -231,10 +229,6 @@ Mod_RealLoadModel (model_t *mod, qboolean crash, cache_allocator_t allocator) default: // Version 29: Quake 1 .bsp // Version 38: Quake 2 .bsp Mod_LoadBrushModel (mod, buf); - - if (gl_textures_external && gl_textures_external->int_val - && mod_funcs && mod_funcs->Mod_LoadExternalTextures) - mod_funcs->Mod_LoadExternalTextures (mod); break; } free (buf); @@ -306,12 +300,12 @@ Mod_TouchModel (const char *name) VISIBLE void Mod_Print (void) { - int i; + size_t i; model_t **mod; Sys_Printf ("Cached models:\n"); - for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { - Sys_Printf ("%8p : %s\n", (*mod)->cache.data, (*mod)->name); + for (i = 0, mod = mod_known.a; i < mod_numknown; i++, mod++) { + Sys_Printf ("%8p : %s\n", (*mod)->cache.data, (*mod)->path); } } diff --git a/libs/models/null_model.c b/libs/models/null_model.c index 18cb987c1..6f482cc01 100644 --- a/libs/models/null_model.c +++ b/libs/models/null_model.c @@ -48,26 +48,11 @@ Mod_LoadSpriteModel (model_t *mod, void *buf) { } -void -Mod_ProcessTexture (texture_t *tx) -{ -} - void Mod_LoadExternalSkins (model_t *mod) { } -void -Mod_LoadExternalTextures (model_t *mod) -{ -} - -void -Mod_SubdivideSurface (msurface_t *fa) -{ -} - viddef_t vid; VISIBLE void diff --git a/libs/models/skin.c b/libs/models/skin.c index 14c21cd81..e5a0353f5 100644 --- a/libs/models/skin.c +++ b/libs/models/skin.c @@ -177,14 +177,14 @@ Skin_SetSkin (skin_t *skin, int cmap, const char *skinname) break; } - file = QFS_FOpenFile (va ("skins/%s.pcx", name)); + file = QFS_FOpenFile (va (0, "skins/%s.pcx", name)); if (!file) { Sys_Printf ("Couldn't load skin %s\n", name); free (name); name = 0; break; } - tex = LoadPCX (file, 0, r_data->vid->palette); + tex = LoadPCX (file, 0, r_data->vid->palette, 1); Qclose (file); if (!tex || tex->width > 320 || tex->height > 200) { Sys_Printf ("Bad skin %s\n", name); @@ -193,7 +193,8 @@ Skin_SetSkin (skin_t *skin, int cmap, const char *skinname) tex = 0; break; } - out = malloc (field_offset (tex_t, data[PLAYER_WIDTH*PLAYER_HEIGHT])); + out = malloc (sizeof (tex_t) + PLAYER_WIDTH*PLAYER_HEIGHT); + out->data = (byte *) (out + 1); out->width = PLAYER_WIDTH; out->height = PLAYER_HEIGHT; out->format = tex_palette; @@ -242,6 +243,66 @@ skin_free (void *_sb, void *unused) void Skin_Init (void) { - skin_cache = Hash_NewTable (127, skin_getkey, skin_free, 0); + skin_cache = Hash_NewTable (127, skin_getkey, skin_free, 0, 0); m_funcs->Skin_InitTranslations (); } + +VISIBLE int +Skin_CalcTopColors (const byte *in, byte *out, int pixels) +{ + byte tc = 0; + + while (pixels-- > 0) { + byte pix = *in++; + if (pix >= TOP_RANGE && pix < TOP_RANGE + 16) { + tc = 1; + *out++ = pix - TOP_RANGE; + } else { + *out++ = 0; + } + } + return tc; +} + +VISIBLE int +Skin_CalcBottomColors (const byte *in, byte *out, int pixels) +{ + byte bc = 0; + + while (pixels-- > 0) { + byte pix = *in++; + if (pix >= BOTTOM_RANGE && pix < BOTTOM_RANGE + 16) { + bc = 1; + *out++ = pix - BOTTOM_RANGE; + } else { + *out++ = 0; + } + } + return bc; +} + +VISIBLE void +Skin_ClearTopColors (const byte *in, byte *out, int pixels) +{ + while (pixels-- > 0) { + byte pix = *in++; + if (pix >= TOP_RANGE && pix < TOP_RANGE + 16) { + *out++ = 0; + } else { + *out++ = pix; + } + } +} + +VISIBLE void +Skin_ClearBottomColors (const byte *in, byte *out, int pixels) +{ + while (pixels-- > 0) { + byte pix = *in++; + if (pix >= BOTTOM_RANGE && pix < BOTTOM_RANGE + 16) { + *out++ = 0; + } else { + *out++ = pix; + } + } +} diff --git a/libs/models/sprite/Makefile.am b/libs/models/sprite/Makefile.am deleted file mode 100644 index 3c6c023d1..000000000 --- a/libs/models/sprite/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= @sprite_libs@ -EXTRA_LTLIBRARIES=libsprite_gl.la libsprite_glsl.la libsprite_sw.la - -sprite_src= model_sprite.c -gl_src= gl_model_sprite.c -glsl_src= glsl_model_sprite.c -sw_src= sw_model_sprite.c - -libsprite_gl_la_SOURCES= $(gl_src) $(sprite_src) - -libsprite_glsl_la_SOURCES= $(glsl_src) $(sprite_src) - -libsprite_sw_la_SOURCES= $(sw_src) $(sprite_src) - -EXTRA_DIST= $(gl_src) $(glsl_src) $(sw_src) $(sprite_src) diff --git a/libs/models/sprite/Makemodule.am b/libs/models/sprite/Makemodule.am new file mode 100644 index 000000000..2021eb370 --- /dev/null +++ b/libs/models/sprite/Makemodule.am @@ -0,0 +1,27 @@ +noinst_LTLIBRARIES += @sprite_libs@ +EXTRA_LTLIBRARIES += \ + libs/models/sprite/libsprite_gl.la \ + libs/models/sprite/libsprite_glsl.la \ + libs/models/sprite/libsprite_sw.la \ + libs/models/sprite/libsprite_vulkan.la + +sprite_src= libs/models/sprite/model_sprite.c +sprite_gl_src= libs/models/sprite/gl_model_sprite.c +sprite_glsl_src= libs/models/sprite/glsl_model_sprite.c +sprite_sw_src= libs/models/sprite/sw_model_sprite.c +sprite_vulkan_src= libs/models/sprite/vulkan_model_sprite.c + +libs_models_sprite_libsprite_gl_la_SOURCES= $(sprite_gl_src) $(sprite_src) + +libs_models_sprite_libsprite_glsl_la_SOURCES= $(sprite_glsl_src) $(sprite_src) + +libs_models_sprite_libsprite_sw_la_SOURCES= $(sprite_sw_src) $(sprite_src) + +libs_models_sprite_libsprite_vulkan_la_SOURCES= $(sprite_vulkan_src) $(sprite_src) + +EXTRA_DIST += \ + $(sprite_gl_src) \ + $(sprite_glsl_src) \ + $(sprite_sw_src) \ + $(sprite_vulkan_src) \ + $(sprite_src) diff --git a/libs/models/sprite/gl_model_sprite.c b/libs/models/sprite/gl_model_sprite.c index 647b5f687..2abef1dfc 100644 --- a/libs/models/sprite/gl_model_sprite.c +++ b/libs/models/sprite/gl_model_sprite.c @@ -44,12 +44,13 @@ #include "mod_internal.h" void -gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +gl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) { tex_t *targa; const char *name; - targa = LoadImage (name = va ("%s_%i", loadmodel->name, framenum)); + targa = LoadImage (name = va (0, "%s_%i", mod->path, framenum), 1); if (targa) { if (targa->format < 4) pspriteframe->gl_texturenum = GL_LoadTexture (name, diff --git a/libs/models/sprite/glsl_model_sprite.c b/libs/models/sprite/glsl_model_sprite.c index 66e1318e2..b5781124f 100644 --- a/libs/models/sprite/glsl_model_sprite.c +++ b/libs/models/sprite/glsl_model_sprite.c @@ -47,7 +47,7 @@ #include "mod_internal.h" static void -glsl_sprite_clear (model_t *m) +glsl_sprite_clear (model_t *m, void *data) { int i, j; msprite_t *sprite = (msprite_t *) m->cache.data; @@ -71,12 +71,13 @@ glsl_sprite_clear (model_t *m) } void -glsl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +glsl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) { const char *name; - loadmodel->clear = glsl_sprite_clear; - name = va ("%s_%i", loadmodel->name, framenum); + mod->clear = glsl_sprite_clear; + name = va (0, "%s_%i", mod->path, framenum); pspriteframe->gl_texturenum = GLSL_LoadQuakeTexture (name, pspriteframe->width, pspriteframe->height, pspriteframe->pixels); diff --git a/libs/models/sprite/model_sprite.c b/libs/models/sprite/model_sprite.c index ce962fec4..e4806bf6e 100644 --- a/libs/models/sprite/model_sprite.c +++ b/libs/models/sprite/model_sprite.c @@ -42,7 +42,8 @@ #include "mod_internal.h" static void * -Mod_LoadSpriteFrame (void *pin, mspriteframe_t **ppframe, int framenum) +Mod_LoadSpriteFrame (model_t *mod, void *pin, mspriteframe_t **ppframe, + int framenum) { dspriteframe_t *pinframe; int width, height, size, origin[2]; @@ -54,7 +55,7 @@ Mod_LoadSpriteFrame (void *pin, mspriteframe_t **ppframe, int framenum) height = LittleLong (pinframe->height); size = width * height; - pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size, loadname); + pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size, mod->name); memset (pspriteframe, 0, sizeof (mspriteframe_t) + size); @@ -72,13 +73,14 @@ Mod_LoadSpriteFrame (void *pin, mspriteframe_t **ppframe, int framenum) memcpy (pspriteframe->pixels, (byte *) (pinframe + 1), size); - m_funcs->Mod_SpriteLoadTexture (pspriteframe, framenum); + m_funcs->Mod_SpriteLoadTexture (mod, pspriteframe, framenum); return (void *) ((byte *) pinframe + sizeof (dspriteframe_t) + size); } static void * -Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) +Mod_LoadSpriteGroup (model_t *mod, void *pin, mspriteframe_t **ppframe, + int framenum) { dspritegroup_t *pingroup; dspriteinterval_t *pin_intervals; @@ -92,7 +94,8 @@ Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) numframes = LittleLong (pingroup->numframes); pspritegroup = Hunk_AllocName (field_offset (mspritegroup_t, - frames[numframes]), loadname); + frames[numframes]), + mod->name); pspritegroup->numframes = numframes; @@ -100,7 +103,7 @@ Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) pin_intervals = (dspriteinterval_t *) (pingroup + 1); - poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + poutintervals = Hunk_AllocName (numframes * sizeof (float), mod->name); pspritegroup->intervals = poutintervals; @@ -117,7 +120,7 @@ Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) for (i = 0; i < numframes; i++) { ptemp = - Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i], + Mod_LoadSpriteFrame (mod, ptemp, &pspritegroup->frames[i], framenum * 100 + i); } @@ -136,14 +139,14 @@ Mod_LoadSpriteModel (model_t *mod, void *buffer) version = LittleLong (pin->version); if (version != SPR_VERSION) - Sys_Error ("%s has wrong version number " - "(%i should be %i)", mod->name, version, SPR_VERSION); + Sys_Error ("%s has wrong version number (%i should be %i)", + mod->path, version, SPR_VERSION); numframes = LittleLong (pin->numframes); size = field_offset (msprite_t, frames[numframes]); - psprite = Hunk_AllocName (size, loadname); + psprite = Hunk_AllocName (size, mod->name); mod->cache.data = psprite; @@ -175,11 +178,11 @@ Mod_LoadSpriteModel (model_t *mod, void *buffer) if (frametype == SPR_SINGLE) { pframetype = (dspriteframetype_t *) - Mod_LoadSpriteFrame (pframetype + 1, + Mod_LoadSpriteFrame (mod, pframetype + 1, &psprite->frames[i].frameptr, i); } else { pframetype = (dspriteframetype_t *) - Mod_LoadSpriteGroup (pframetype + 1, + Mod_LoadSpriteGroup (mod, pframetype + 1, &psprite->frames[i].frameptr, i); } } diff --git a/libs/models/sprite/sw_model_sprite.c b/libs/models/sprite/sw_model_sprite.c index 9d3f25bd2..8dc5a5461 100644 --- a/libs/models/sprite/sw_model_sprite.c +++ b/libs/models/sprite/sw_model_sprite.c @@ -31,6 +31,7 @@ #include "mod_internal.h" void -sw_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +sw_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) { } diff --git a/libs/models/sprite/vulkan_model_sprite.c b/libs/models/sprite/vulkan_model_sprite.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/models/test/Makefile.am b/libs/models/test/Makefile.am deleted file mode 100644 index 2718f5ddd..000000000 --- a/libs/models/test/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CPPFLAGS= -I$(srcdir) -I$(top_srcdir)/include - -check_PROGRAMS=testclip testcontents testportals -EXTRA_DIST= trace-id.c trace-qf-bad.c hulls.h main.c - -test_libs= \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/util/libQFutil.la - -testclip_SOURCES= testclip.c hulls.c -testclip_LDADD= $(test_libs) -testclip_DEPENDENCIES= $(test_libs) - -testcontents_SOURCES= testcontents.c hulls.c -testcontents_LDADD= $(test_libs) -testcontents_DEPENDENCIES= $(test_libs) - -testportals_SOURCES= testportals.c hulls.c -testportals_LDADD= $(test_libs) -testportals_DEPENDENCIES= $(test_libs) - -TESTS=$(check_PROGRAMS) diff --git a/libs/models/test/Makemodule.am b/libs/models/test/Makemodule.am new file mode 100644 index 000000000..15cbe5e35 --- /dev/null +++ b/libs/models/test/Makemodule.am @@ -0,0 +1,36 @@ +libs_model_tests = \ + libs/models/test/testclip \ + libs/models/test/testcontents \ + libs/models/test/testportals + +TESTS += $(libs_model_tests) + +check_PROGRAMS += $(libs_model_tests) + +EXTRA_DIST += \ + libs/models/test/trace-id.c \ + libs/models/test/trace-qf-bad.c \ + libs/models/test/hulls.h \ + libs/models/test/main.c + +test_libs= \ + libs/models/libQFmodels.la \ + libs/util/libQFutil.la + +libs_models_test_testclip_SOURCES= \ + libs/models/test/testclip.c \ + libs/models/test/hulls.c +libs_models_test_testclip_LDADD= $(test_libs) +libs_models_test_testclip_DEPENDENCIES= $(test_libs) + +libs_models_test_testcontents_SOURCES= \ + libs/models/test/testcontents.c \ + libs/models/test/hulls.c +libs_models_test_testcontents_LDADD= $(test_libs) +libs_models_test_testcontents_DEPENDENCIES= $(test_libs) + +libs_models_test_testportals_SOURCES= \ + libs/models/test/testportals.c \ + libs/models/test/hulls.c +libs_models_test_testportals_LDADD= $(test_libs) +libs_models_test_testportals_DEPENDENCIES= $(test_libs) diff --git a/libs/models/test/testclip.c b/libs/models/test/testclip.c index 6b6672e4b..f0f774c1e 100644 --- a/libs/models/test/testclip.c +++ b/libs/models/test/testclip.c @@ -6,6 +6,7 @@ #include "QF/va.h" #include "getopt.h" +#include "mod_internal.h" #include "world.h" #include "hulls.h" @@ -323,9 +324,9 @@ run_test (test_t *test) err = 1; if (test->desc) - desc = va ("(%d) %s", (int)(long)(test - tests), test->desc); + desc = va (0, "(%d) %s", (int)(long)(test - tests), test->desc); else - desc = va ("test #%d", (int)(long)(test - tests)); + desc = va (0, "test #%d", (int)(long)(test - tests)); if (verbose >= 0 || err) { if (output) puts(""); diff --git a/libs/models/test/testcontents.c b/libs/models/test/testcontents.c index 605ed7a6c..17b20f3ae 100644 --- a/libs/models/test/testcontents.c +++ b/libs/models/test/testcontents.c @@ -145,9 +145,9 @@ run_test (test_t *test) res = 1; if (test->desc) - desc = va ("(%d) %s", (int)(long)(test - tests), test->desc); + desc = va (0, "(%d) %s", (int)(long)(test - tests), test->desc); else - desc = va ("test #%d", (int)(long)(test - tests)); + desc = va (0, "test #%d", (int)(long)(test - tests)); if (verbose >= 0 || !res) { if (output) puts(""); diff --git a/libs/models/test/testportals.c b/libs/models/test/testportals.c index 1cc2f50ec..facfa2914 100644 --- a/libs/models/test/testportals.c +++ b/libs/models/test/testportals.c @@ -170,9 +170,9 @@ nodeleaf_bail: MOD_FreeBrushes (test->hull); if (test->desc) - desc = va ("(%d) %s", (int)(long)(test - tests), test->desc); + desc = va (0, "(%d) %s", (int)(long)(test - tests), test->desc); else - desc = va ("test #%d", (int)(long)(test - tests)); + desc = va (0, "test #%d", (int)(long)(test - tests)); if (verbose >= 0 || err) { if (output) puts(""); diff --git a/libs/models/vulkan_skin.c b/libs/models/vulkan_skin.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/models/winding.c b/libs/models/winding.c index d065224f7..62ae9fcb8 100644 --- a/libs/models/winding.c +++ b/libs/models/winding.c @@ -40,10 +40,6 @@ #define BOGUS (18000.0) -/** \addtogroup qfbsp_winding -*/ -//@{ - int c_activewindings, c_peakwindings; winding_t * @@ -326,5 +322,3 @@ FreeWinding (winding_t *w) c_activewindings--; free (w); } - -//@} diff --git a/libs/net/Makefile.am b/libs/net/Makefile.am deleted file mode 100644 index 69f2fbb6c..000000000 --- a/libs/net/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= nc nm -AM_CFLAGS= @PREFER_NON_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= libnet_chan.la libnet_main.la - -nc_libs=nc/libnc.la -libnet_chan_la_LDFLAGS= @STATIC@ -libnet_chan_la_LIBADD= $(nc_libs) -libnet_chan_la_DEPENDENCIES=$(nc_libs) -libnet_chan_la_SOURCES= net_chan.c - -nm_libs=nm/libnm.la -libnet_main_la_LDFLAGS= @STATIC@ -libnet_main_la_LIBADD= $(nm_libs) -libnet_main_la_DEPENDENCIES=$(nm_libs) -libnet_main_la_SOURCES= net_main.c diff --git a/libs/net/Makemodule.am b/libs/net/Makemodule.am new file mode 100644 index 000000000..05d0d0136 --- /dev/null +++ b/libs/net/Makemodule.am @@ -0,0 +1,14 @@ + +noinst_LTLIBRARIES += libs/net/libnet_chan.la libs/net/libnet_main.la + +include libs/net/nc/Makemodule.am +include libs/net/nm/Makemodule.am + +libs_net_libnet_chan_la_LDFLAGS= @STATIC@ +libs_net_libnet_chan_la_SOURCES= libs/net/net_chan.c ${nc_src} +EXTRA_libs_net_libnet_chan_la_SOURCES = $(ipv4_src) $(ipv6_src) + +nm_libs=nm/libnm.la +libs_net_libnet_main_la_LDFLAGS= @STATIC@ +libs_net_libnet_main_la_SOURCES= libs/net/net_main.c ${nm_src} +EXTRA_libs_net_libnet_main_la_SOURCES = $(nm_extra) diff --git a/libs/net/nc/Makefile.am b/libs/net/nc/Makefile.am deleted file mode 100644 index 08b0cb810..000000000 --- a/libs/net/nc/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_NON_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= libnc.la - -ipv6_src= net_udp6.c -ipv4_src= net_udp.c -if NETTYPE_IPV6 -ipvX_src= $(ipv6_src) -else -ipvX_src= $(ipv4_src) -endif -libnc_la_SOURCES= $(ipvX_src) -libnc_la_LDFLAGS= @STATIC@ -EXTRA_libnc_la_SOURCES= $(ipv4_src) $(ipv6_src) diff --git a/libs/net/nc/Makemodule.am b/libs/net/nc/Makemodule.am new file mode 100644 index 000000000..ae51d29e2 --- /dev/null +++ b/libs/net/nc/Makemodule.am @@ -0,0 +1,8 @@ +ipv6_src= libs/net/nc/net_udp6.c +ipv4_src= libs/net/nc/net_udp.c +if NETTYPE_IPV6 +ipvX_src= $(ipv6_src) +else +ipvX_src= $(ipv4_src) +endif +nc_src= $(ipvX_src) diff --git a/libs/net/nc/net_udp.c b/libs/net/nc/net_udp.c index 051785c5e..337bb914e 100644 --- a/libs/net/nc/net_udp.c +++ b/libs/net/nc/net_udp.c @@ -403,6 +403,17 @@ NET_GetLocalAddress (void) Sys_Printf ("IP address %s\n", NET_AdrToString (net_local_adr)); } +static void +NET_shutdown (void *data) +{ +#ifdef _WIN32 + closesocket (net_socket); + WSACleanup (); +#else + close (net_socket); +#endif +} + void NET_Init (int port) { @@ -416,6 +427,7 @@ NET_Init (int port) if (r) Sys_Error ("Winsock initialization failed."); #endif /* _WIN32 */ + Sys_RegisterShutdown (NET_shutdown, 0); net_socket = UDP_OpenSocket (port); @@ -431,14 +443,3 @@ NET_Init (int port) Sys_Printf ("UDP (IPv4) Initialized\n"); } - -void -NET_Shutdown (void) -{ -#ifdef _WIN32 - closesocket (net_socket); - WSACleanup (); -#else - close (net_socket); -#endif -} diff --git a/libs/net/nc/net_udp6.c b/libs/net/nc/net_udp6.c index bad834082..c04092a83 100644 --- a/libs/net/nc/net_udp6.c +++ b/libs/net/nc/net_udp6.c @@ -600,8 +600,8 @@ NET_Init (int port) Sys_Printf ("UDP (IPv6) Initialized\n"); } -void -NET_Shutdown (void) +static void +NET_shutdown (void) { #ifdef _WIN32 closesocket (net_socket); diff --git a/libs/net/net_chan.c b/libs/net/net_chan.c index 88f7ad08e..61f125117 100644 --- a/libs/net/net_chan.c +++ b/libs/net/net_chan.c @@ -257,12 +257,16 @@ Netchan_Transmit (netchan_t *chan, int length, byte *data) if (net_nochoke) chan->cleartime = *net_realtime; - if (showpackets->int_val & 1) + if (showpackets->int_val & 1) { Sys_Printf ("--> s=%i(%i) a=%i(%i) %-4i %i\n", chan->outgoing_sequence, send_reliable, chan->incoming_sequence, chan->incoming_reliable_sequence, send.cursize, chan->outgoing_sequence - chan->incoming_sequence); + if (showpackets->int_val & 4) { + SZ_Dump (&send); + } + } } qboolean @@ -289,9 +293,13 @@ Netchan_Process (netchan_t *chan) sequence &= ~(1 << 31); sequence_ack &= ~(1 << 31); - if (showpackets->int_val & 2) + if (showpackets->int_val & 2) { Sys_Printf ("<-- s=%i(%i) a=%i(%i) %i\n", sequence, reliable_message, sequence_ack, reliable_ack, net_message->message->cursize); + if (showpackets->int_val & 8) { + SZ_Dump (net_message->message); + } + } // get a rate estimation #if 0 // FIXME: Dead code diff --git a/libs/net/net_main.c b/libs/net/net_main.c index 7c235f4a9..996bb10f7 100644 --- a/libs/net/net_main.c +++ b/libs/net/net_main.c @@ -718,6 +718,33 @@ NET_SendToAll (sizebuf_t *data, double blocktime) //============================================================================= +static void +NET_shutdown (void *data) +{ + qsocket_t *sock; + + SetNetTime (); + + for (sock = net_activeSockets; sock; sock = sock->next) + NET_Close (sock); + +// +// shutdown the drivers +// + for (net_driverlevel = 0; net_driverlevel < net_numdrivers; + net_driverlevel++) { + if (net_drivers[net_driverlevel].initialized == true) { + net_drivers[net_driverlevel].Shutdown (); + net_drivers[net_driverlevel].initialized = false; + } + } + + if (vcrFile) { + Sys_Printf ("Closing vcrfile.\n"); + Qclose (vcrFile); + } +} + void NET_Init (void) { @@ -725,6 +752,8 @@ NET_Init (void) int controlSocket; qsocket_t *s; + Sys_RegisterShutdown (NET_shutdown, 0); + if (COM_CheckParm ("-playback")) { net_numdrivers = 1; net_drivers[0].Init = VCR_Init; @@ -790,33 +819,6 @@ NET_Init (void) Sys_MaskPrintf (SYS_NET, "TCP/IP address %s\n", my_tcpip_address); } -void -NET_Shutdown (void) -{ - qsocket_t *sock; - - SetNetTime (); - - for (sock = net_activeSockets; sock; sock = sock->next) - NET_Close (sock); - -// -// shutdown the drivers -// - for (net_driverlevel = 0; net_driverlevel < net_numdrivers; - net_driverlevel++) { - if (net_drivers[net_driverlevel].initialized == true) { - net_drivers[net_driverlevel].Shutdown (); - net_drivers[net_driverlevel].initialized = false; - } - } - - if (vcrFile) { - Sys_Printf ("Closing vcrfile.\n"); - Qclose (vcrFile); - } -} - static PollProcedure *pollProcedureList = NULL; diff --git a/libs/net/nm/Makefile.am b/libs/net/nm/Makefile.am deleted file mode 100644 index cfdaae275..000000000 --- a/libs/net/nm/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_NON_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= libnm.la - -if SYSTYPE_WIN32 -net_sources= net_win.c net_wins.c -else -net_sources= net_bsd.c net_udp.c -endif -libnm_la_SOURCES= net_dgrm.c net_loop.c net_vcr.c $(net_sources) -libnm_la_LDFLAGS= @STATIC@ - - -EXTRA_libnm_la_SOURCES= \ - net_bsd.c net_win.c net_wins.c net_udp.c diff --git a/libs/net/nm/Makemodule.am b/libs/net/nm/Makemodule.am new file mode 100644 index 000000000..002b24b02 --- /dev/null +++ b/libs/net/nm/Makemodule.am @@ -0,0 +1,8 @@ +if SYSTYPE_WIN32 +net_sources= libs/net/nm/net_win.c libs/net/nm/net_wins.c +else +net_sources= libs/net/nm/net_bsd.c libs/net/nm/net_udp.c +endif +nm_src= libs/net/nm/net_dgrm.c libs/net/nm/net_loop.c libs/net/nm/net_vcr.c $(net_sources) + +nm_extra = libs/net/nm/net_bsd.c libs/net/nm/net_win.c libs/net/nm/net_wins.c libs/net/nm/net_udp.c diff --git a/libs/net/nm/net_dgrm.c b/libs/net/nm/net_dgrm.c index 7f7e302c7..20160e228 100644 --- a/libs/net/nm/net_dgrm.c +++ b/libs/net/nm/net_dgrm.c @@ -104,7 +104,7 @@ NET_Ban_f (void) { char addrStr[32]; //FIXME: overflow char maskStr[32]; //FIXME: overflow - void (*print) (const char *fmt, ...); + __attribute__((format(printf, 1, 2))) void (*print) (const char *fmt, ...); if (cmd_source == src_command) { if (!sv.active) { @@ -262,7 +262,7 @@ Datagram_CanSendMessage (qsocket_t *sock) } -qboolean +__attribute__((const)) qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock) { return true; diff --git a/libs/net/nm/net_loop.c b/libs/net/nm/net_loop.c index 0323b760d..0624688b9 100644 --- a/libs/net/nm/net_loop.c +++ b/libs/net/nm/net_loop.c @@ -42,7 +42,7 @@ qboolean localconnectpending = false; qsocket_t *loop_client = NULL; qsocket_t *loop_server = NULL; -int +__attribute__((pure)) int Loop_Init (void) { if (cls.state == ca_dedicated) @@ -240,7 +240,7 @@ Loop_SendUnreliableMessage (qsocket_t * sock, sizebuf_t *data) } -qboolean +__attribute__((pure)) qboolean Loop_CanSendMessage (qsocket_t * sock) { if (!sock->driverdata) @@ -249,7 +249,7 @@ Loop_CanSendMessage (qsocket_t * sock) } -qboolean +__attribute__((const)) qboolean Loop_CanSendUnreliableMessage (qsocket_t * sock) { return true; diff --git a/libs/net/nm/net_udp.c b/libs/net/nm/net_udp.c index 84f01a3a9..41cf8b9ec 100644 --- a/libs/net/nm/net_udp.c +++ b/libs/net/nm/net_udp.c @@ -387,7 +387,7 @@ PartialIPAddress (const char *in, netadr_t *hostaddr) { char *buff; char *b; - int addr, mask, num, port, run; + unsigned addr, mask, num, port, run; buff = nva (".%s", in); b = buff; @@ -407,7 +407,7 @@ PartialIPAddress (const char *in, netadr_t *hostaddr) } if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) goto error; - if (num < 0 || num > 255) + if (num > 255) goto error; mask <<= 8; addr = (addr << 8) + num; @@ -433,7 +433,7 @@ error: return -1; } -int +__attribute__((const)) int UDP_Connect (int socket, netadr_t *addr) { return 0; @@ -651,7 +651,7 @@ UDP_GetAddrFromName (const char *name, netadr_t *addr) return 0; } -int +__attribute__((pure)) int UDP_AddrCompare (netadr_t *addr1, netadr_t *addr2) { if (addr1->family != addr2->family) @@ -666,7 +666,7 @@ UDP_AddrCompare (netadr_t *addr1, netadr_t *addr2) return 0; } -int +__attribute__((pure)) int UDP_GetSocketPort (netadr_t *addr) { return ntohs (addr->port); diff --git a/libs/net/nm/net_vcr.c b/libs/net/nm/net_vcr.c index 603257813..f997d3034 100644 --- a/libs/net/nm/net_vcr.c +++ b/libs/net/nm/net_vcr.c @@ -166,14 +166,14 @@ VCR_SearchForHosts (qboolean xmit) } -qsocket_t * +__attribute__((const)) qsocket_t * VCR_Connect (const char *host) { return NULL; } -qsocket_t * +qsocket_t * VCR_CheckNewConnections (void) { qsocket_t *sock; diff --git a/libs/qw/Makefile.am b/libs/qw/Makefile.am deleted file mode 100644 index 48a58fa72..000000000 --- a/libs/qw/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LIBRARIES= libqw.a - -libqw_a_SOURCES= \ - msg_backbuf.c msg_ucmd.c diff --git a/libs/qw/Makemodule.am b/libs/qw/Makemodule.am new file mode 100644 index 000000000..42834b43a --- /dev/null +++ b/libs/qw/Makemodule.am @@ -0,0 +1,4 @@ +noinst_LIBRARIES += libs/qw/libqw.a + +libs_qw_libqw_a_SOURCES= \ + libs/qw/msg_backbuf.c libs/qw/msg_ucmd.c diff --git a/libs/ruamoko/Makefile.am b/libs/ruamoko/Makefile.am deleted file mode 100644 index 64c65e972..000000000 --- a/libs/ruamoko/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(FNM_FLAGS) - -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined -rua_libs= \ - $(top_builddir)/libs/gamecode/libQFgamecode.la \ - $(top_builddir)/libs/util/libQFutil.la - -lib_LTLIBRARIES= libQFruamoko.la - -libQFruamoko_la_LDFLAGS= $(lib_ldflags) -libQFruamoko_la_LIBADD= $(rua_libs) -libQFruamoko_la_DEPENDENCIES= $(rua_libs) -libQFruamoko_la_SOURCES= \ - pr_cmds.c \ - rua_cbuf.c rua_cmd.c rua_cvar.c rua_file.c rua_hash.c rua_init.c \ - rua_math.c rua_msgbuf.c rua_obj.c rua_plist.c rua_qfile.c rua_qfs.c \ - rua_script.c rua_set.c rua_string.c diff --git a/libs/ruamoko/Makemodule.am b/libs/ruamoko/Makemodule.am new file mode 100644 index 000000000..c3ed37383 --- /dev/null +++ b/libs/ruamoko/Makemodule.am @@ -0,0 +1,26 @@ +ruamoko_rua_libs= \ + libs/gamecode/libQFgamecode.la \ + libs/util/libQFutil.la + +lib_LTLIBRARIES += libs/ruamoko/libQFruamoko.la + +libs_ruamoko_libQFruamoko_la_LDFLAGS= $(lib_ldflags) +libs_ruamoko_libQFruamoko_la_LIBADD= $(ruamoko_rua_libs) +libs_ruamoko_libQFruamoko_la_DEPENDENCIES= $(ruamoko_rua_libs) +libs_ruamoko_libQFruamoko_la_SOURCES= \ + libs/ruamoko/pr_cmds.c \ + libs/ruamoko/rua_cbuf.c \ + libs/ruamoko/rua_cmd.c \ + libs/ruamoko/rua_cvar.c \ + libs/ruamoko/rua_hash.c \ + libs/ruamoko/rua_init.c \ + libs/ruamoko/rua_math.c \ + libs/ruamoko/rua_msgbuf.c \ + libs/ruamoko/rua_obj.c \ + libs/ruamoko/rua_plist.c \ + libs/ruamoko/rua_qfile.c \ + libs/ruamoko/rua_qfs.c \ + libs/ruamoko/rua_runtime.c \ + libs/ruamoko/rua_script.c \ + libs/ruamoko/rua_set.c \ + libs/ruamoko/rua_string.c diff --git a/libs/ruamoko/pr_cmds.c b/libs/ruamoko/pr_cmds.c index 8352228d4..8836de8c9 100644 --- a/libs/ruamoko/pr_cmds.c +++ b/libs/ruamoko/pr_cmds.c @@ -255,7 +255,7 @@ PF_Find (progs_t *pr) int i; // ev_vector int e, f; etype_t type; - ddef_t *field_def; + pr_def_t *field_def; edict_t *ed; e = P_EDICTNUM (pr, 0); @@ -306,7 +306,7 @@ PF_Find (progs_t *pr) } } - RETURN_EDICT (pr, *pr->edicts); + RETURN_EDICT (pr, EDICT_NUM (pr, 0)); } /* @@ -401,7 +401,7 @@ PF_nextent (progs_t *pr) while (1) { i++; if (i == *pr->num_edicts) { - RETURN_EDICT (pr, *pr->edicts); + RETURN_EDICT (pr, EDICT_NUM (pr, 0)); return; } ent = EDICT_NUM (pr, i); @@ -521,18 +521,6 @@ PF_vtos (progs_t *pr) RETURN_STRING (pr, string); } -/* - float (string s) strlen -*/ -static void -PF_strlen (progs_t *pr) -{ - const char *s; - - s = P_GSTRING (pr, 0); - R_FLOAT (pr) = strlen(s); -} - /* float (string char, string s) charcount */ @@ -565,24 +553,6 @@ PF_charcount (progs_t *pr) # define INT_WIDTH 20 #endif -#define MAX_ARG 7 -/* - string (...) sprintf -*/ -static void -PF_sprintf (progs_t *pr) -{ - const char *fmt = P_GSTRING (pr, 0); - int count = pr->pr_argc - 1; - pr_type_t **args = pr->pr_params + 1; - dstring_t *dstr; - - dstr = dstring_newstr (); - PR_Sprintf (pr, dstr, "PF_sprintf", fmt, count, args); - RETURN_STRING (pr, dstr->str); - dstring_delete (dstr); -} - /* string () gametype */ @@ -596,12 +566,12 @@ static void PF_PR_SetField (progs_t *pr) { edict_t *ent = P_EDICT (pr, 0); - ddef_t *field = PR_FindField (pr, P_GSTRING (pr, 1)); + pr_def_t *field = PR_FindField (pr, P_GSTRING (pr, 1)); const char *value = P_GSTRING (pr, 2); R_INT (pr) = 0; if (field) - R_INT (pr) = ED_ParseEpair (pr, ent->v, field, value); + R_INT (pr) = ED_ParseEpair (pr, &E_fld (ent, 0), field, value); } static void @@ -640,9 +610,7 @@ static builtin_t builtins[] = { {"stof", PF_stof, 81}, - {"strlen", PF_strlen, QF 100}, {"charcount", PF_charcount, QF 101}, - {"sprintf", PF_sprintf, QF 109}, {"ftoi", PF_ftoi, QF 110}, {"itof", PF_itof, QF 111}, {"itos", PF_itos, QF 112}, diff --git a/libs/ruamoko/rua_cmd.c b/libs/ruamoko/rua_cmd.c index a18e2805e..8efcfb2a5 100644 --- a/libs/ruamoko/rua_cmd.c +++ b/libs/ruamoko/rua_cmd.c @@ -162,7 +162,8 @@ RUA_Cmd_Init (progs_t *pr, int secure) PR_Resources_Register (pr, "Cmd", res, bi_cmd_clear); if (!bi_cmds) - bi_cmds = Hash_NewTable (1021, bi_cmd_get_key, bi_cmd_free, 0); + bi_cmds = Hash_NewTable (1021, bi_cmd_get_key, bi_cmd_free, 0, + pr->hashlink_freelist); PR_RegisterBuiltins (pr, builtins); } diff --git a/libs/ruamoko/rua_cvar.c b/libs/ruamoko/rua_cvar.c index 18275988e..dbb652817 100644 --- a/libs/ruamoko/rua_cvar.c +++ b/libs/ruamoko/rua_cvar.c @@ -140,7 +140,7 @@ bi_Cvar_SetInteger (progs_t *pr) if (!var) var = Cvar_FindAlias (varname); if (var) - Cvar_Set (var, va ("%d", val)); + Cvar_Set (var, va (0, "%d", val)); } static void @@ -153,7 +153,7 @@ bi_Cvar_SetFloat (progs_t *pr) if (!var) var = Cvar_FindAlias (varname); if (var) - Cvar_Set (var, va ("%g", val)); + Cvar_Set (var, va (0, "%g", val)); } static void @@ -166,7 +166,7 @@ bi_Cvar_SetVector (progs_t *pr) if (!var) var = Cvar_FindAlias (varname); if (var) - Cvar_Set (var, va ("%g %g %g", val[0], val[1], val[2])); + Cvar_Set (var, va (0, "%g %g %g", val[0], val[1], val[2])); } static void diff --git a/libs/ruamoko/rua_file.c b/libs/ruamoko/rua_file.c deleted file mode 100644 index 95d21682c..000000000 --- a/libs/ruamoko/rua_file.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - bi_file.c - - CSQC file builtins - - Copyright (C) 1996-1997 Id Software, Inc. - - 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: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#ifdef HAVE_FNMATCH_H -# define model_t sunmodel_t -# include -# undef model_t -#else -# ifdef _WIN32 -# include "fnmatch.h" -# endif -#endif - -#ifndef HAVE_FNMATCH_PROTO -int fnmatch (const char *__pattern, const char *__string, int __flags); -#endif - -#include "QF/cvar.h" -#include "QF/progs.h" -#include "QF/quakefs.h" -#include "QF/va.h" -#include "QF/zone.h" - -#include "rua_internal.h" - -static const char *file_ban_list[] = { - "default.cfg{,.gz}", - "demo1.dem{,.gz}", - "demo2.dem{,.gz}", - "demo3.dem{,.gz}", - "end1.bin{,.gz}", - "end2.bin{,.gz}", - "gfx.wad{,.gz}", - "progs.dat{,.gz}", - "quake.rc{,.gz}", - 0, -}; - -static const char *dir_ban_list[] = { - "gfx", - "maps", - "progs", - "skins", - "sound", - 0, -}; - -static int -file_readable (char *path) -{ - char t; - char *p = strchr (path, '/'); - const char **match; - - if (p) { - t = *p; - *p = 0; - for (match = dir_ban_list; *match; match++) { - if (fnmatch (*match, path, FNM_PATHNAME) == 0) { - *p = t; - return 0; - } - } - } else { - for (match = file_ban_list; *match; match++) { - if (fnmatch (*match, path, FNM_PATHNAME) == 0) { - return 0; - } - } - } - return 1; -} - -static int -file_writeable (char *path) -{ - return file_readable (path); -} - -static void -bi_File_Open (progs_t *pr) -{ - QFile *file; - const char *pth = P_GSTRING (pr, 0); - const char *mode = P_GSTRING (pr, 1); - char *path; - char *p; - int do_write = 0; - int do_read = 0; - - p = strchr (mode, 'r'); - if (p) { - do_read |= 1; - if (p[1] == '+') - do_write |= 1; - } - - p = strchr (mode, 'w'); - if (p) { - do_write |= 1; - if (p[1] == '+') - do_read |= 1; - } - - p = strchr (mode, 'a'); - if (p) { - do_write |= 1; - if (p[1] == '+') - do_read |= 1; - } - - path = QFS_CompressPath (pth); - //printf ("'%s' '%s'\n", P_GSTRING (pr, 0), path); - if (!path[0]) - goto error; - if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path [2] == 0)) - goto error; - if (path[strlen (path) - 1] =='/') - goto error; - if (!do_read && !do_write) - goto error; - if (do_read && !file_readable (path)) - goto error; - if (do_write && !file_writeable (path)) - goto error; - - file = QFS_Open (va ("%s/%s", qfs_gamedir->dir.def, path), mode); - if (!file) - goto error; - free (path); - if ((R_INT (pr) = QFile_AllocHandle (pr, file))) - return; - Qclose (file); -error: - free (path); - R_INT (pr) = 0; -} - -static builtin_t builtins[] = { - {"File_Open", bi_File_Open, -1}, - {0} -}; - -void -RUA_File_Init (progs_t *pr, int secure) -{ - PR_RegisterBuiltins (pr, builtins); -} diff --git a/libs/ruamoko/rua_hash.c b/libs/ruamoko/rua_hash.c index cc6d2b8c6..6448e0b1c 100644 --- a/libs/ruamoko/rua_hash.c +++ b/libs/ruamoko/rua_hash.c @@ -64,31 +64,31 @@ typedef struct { static bi_hashtab_t * table_new (hash_resources_t *res) { - PR_RESNEW (bi_hashtab_t, res->table_map); + return PR_RESNEW (res->table_map); } static void table_free (hash_resources_t *res, bi_hashtab_t *table) { - PR_RESFREE (bi_hashtab_t, res->table_map, table); + PR_RESFREE (res->table_map, table); } static void table_reset (hash_resources_t *res) { - PR_RESRESET (bi_hashtab_t, res->table_map); + PR_RESRESET (res->table_map); } static inline bi_hashtab_t * table_get (hash_resources_t *res, int index) { - PR_RESGET(res->table_map, index); + return PR_RESGET(res->table_map, index); } -static inline int +static inline int __attribute__((pure)) table_index (hash_resources_t *res, bi_hashtab_t *table) { - PR_RESINDEX(res->table_map, table); + return PR_RESINDEX(res->table_map, table); } static const char * @@ -98,6 +98,7 @@ bi_get_key (const void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->gk); return PR_GetString (ht->pr, R_STRING (ht->pr)); } @@ -109,6 +110,7 @@ bi_get_hash (const void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->gh); return R_INT (ht->pr); } @@ -121,6 +123,7 @@ bi_compare (const void *key1, const void *key2, void *_ht) P_INT (ht->pr, 0) = (intptr_t) (key1); P_INT (ht->pr, 1) = (intptr_t) (key2); P_INT (ht->pr, 2) = ht->ud; + ht->pr->pr_argc = 3; PR_ExecuteProgram (ht->pr, ht->cmp); return R_INT (ht->pr); } @@ -132,6 +135,7 @@ bi_free (void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->f); } @@ -158,7 +162,7 @@ bi_Hash_NewTable (progs_t *pr) gk = ht->gk ? bi_get_key : 0; f = ht->f ? bi_free : 0; - ht->tab = Hash_NewTable (tsize, gk, f, ht); + ht->tab = Hash_NewTable (tsize, gk, f, ht, pr->hashlink_freelist); R_INT (pr) = table_index (res, ht); } diff --git a/libs/ruamoko/rua_init.c b/libs/ruamoko/rua_init.c index ab973b569..6e4333998 100644 --- a/libs/ruamoko/rua_init.c +++ b/libs/ruamoko/rua_init.c @@ -39,13 +39,13 @@ static void (*init_funcs[])(progs_t *, int) = { RUA_Cbuf_Init, RUA_Cmd_Init, RUA_Cvar_Init, - RUA_File_Init, RUA_Hash_Init, RUA_Math_Init, RUA_MsgBuf_Init, RUA_Plist_Init, RUA_QFile_Init, RUA_QFS_Init, + RUA_Runtime_Init, RUA_Script_Init, RUA_Set_Init, RUA_String_Init, @@ -56,7 +56,6 @@ RUA_Init (progs_t *pr, int secure) { size_t i; - PR_Resources_Init (pr); for (i = 0; i < sizeof (init_funcs) / sizeof (init_funcs[0]); i++) init_funcs[i] (pr, secure); } diff --git a/libs/ruamoko/rua_math.c b/libs/ruamoko/rua_math.c index 0cc5e5636..a81d33356 100644 --- a/libs/ruamoko/rua_math.c +++ b/libs/ruamoko/rua_math.c @@ -42,55 +42,55 @@ #include "rua_internal.h" static void -bi_sin (progs_t *pr) +bi_sinf (progs_t *pr) { R_FLOAT (pr) = sinf (P_FLOAT (pr, 0)); } static void -bi_cos (progs_t *pr) +bi_cosf (progs_t *pr) { R_FLOAT (pr) = cosf (P_FLOAT (pr, 0)); } static void -bi_tan (progs_t *pr) +bi_tanf (progs_t *pr) { R_FLOAT (pr) = tanf (P_FLOAT (pr, 0)); } static void -bi_asin (progs_t *pr) +bi_asinf (progs_t *pr) { R_FLOAT (pr) = asinf (P_FLOAT (pr, 0)); } static void -bi_acos (progs_t *pr) +bi_acosf (progs_t *pr) { R_FLOAT (pr) = acosf (P_FLOAT (pr, 0)); } static void -bi_atan (progs_t *pr) +bi_atanf (progs_t *pr) { R_FLOAT (pr) = atanf (P_FLOAT (pr, 0)); } static void -bi_atan2 (progs_t *pr) +bi_atan2f (progs_t *pr) { R_FLOAT (pr) = atan2f (P_FLOAT (pr, 0), P_FLOAT (pr, 1)); } static void -bi_log (progs_t *pr) +bi_logf (progs_t *pr) { R_FLOAT (pr) = logf (P_FLOAT (pr, 0)); } static void -bi_log2 (progs_t *pr) +bi_log2f (progs_t *pr) { #ifdef HAVE_LOG2F R_FLOAT (pr) = log2f (P_FLOAT (pr, 0)); @@ -100,95 +100,259 @@ bi_log2 (progs_t *pr) } static void -bi_log10 (progs_t *pr) +bi_log10f (progs_t *pr) { R_FLOAT (pr) = log10f (P_FLOAT (pr, 0)); } static void -bi_pow (progs_t *pr) +bi_powf (progs_t *pr) { R_FLOAT (pr) = powf (P_FLOAT (pr, 0), P_FLOAT (pr, 1)); } static void -bi_sqrt (progs_t *pr) +bi_sqrtf (progs_t *pr) { R_FLOAT (pr) = sqrtf (P_FLOAT (pr, 0)); } static void -bi_cbrt (progs_t *pr) +bi_cbrtf (progs_t *pr) { R_FLOAT (pr) = cbrtf (P_FLOAT (pr, 0)); } static void -bi_hypot (progs_t *pr) +bi_hypotf (progs_t *pr) { R_FLOAT (pr) = hypotf (P_FLOAT (pr, 0), P_FLOAT (pr, 1)); } static void -bi_sinh (progs_t *pr) +bi_sinhf (progs_t *pr) { R_FLOAT (pr) = sinhf (P_FLOAT (pr, 0)); } static void -bi_cosh (progs_t *pr) +bi_coshf (progs_t *pr) { R_FLOAT (pr) = coshf (P_FLOAT (pr, 0)); } static void -bi_tanh (progs_t *pr) +bi_tanhf (progs_t *pr) { R_FLOAT (pr) = tanhf (P_FLOAT (pr, 0)); } static void -bi_asinh (progs_t *pr) +bi_asinhf (progs_t *pr) { double y = P_FLOAT (pr, 0); R_FLOAT (pr) = logf (y + sqrtf (y * y + 1)); } static void -bi_acosh (progs_t *pr) +bi_acoshf (progs_t *pr) { double y = P_FLOAT (pr, 0); R_FLOAT (pr) = logf (y + sqrtf (y * y - 1)); } static void -bi_atanh (progs_t *pr) +bi_atanhf (progs_t *pr) { double y = P_FLOAT (pr, 0); R_FLOAT (pr) = logf ((1 + y) / (1 - y)) / 2; } +static void +bi_floor (progs_t *pr) +{ + R_DOUBLE (pr) = floor (P_DOUBLE (pr, 0)); +} + +static void +bi_ceil (progs_t *pr) +{ + R_DOUBLE (pr) = ceil (P_DOUBLE (pr, 0)); +} + +static void +bi_fabs (progs_t *pr) +{ + R_DOUBLE (pr) = fabs (P_DOUBLE (pr, 0)); +} + +static void +bi_sin (progs_t *pr) +{ + R_DOUBLE (pr) = sin (P_DOUBLE (pr, 0)); +} + +static void +bi_cos (progs_t *pr) +{ + R_DOUBLE (pr) = cos (P_DOUBLE (pr, 0)); +} + +static void +bi_tan (progs_t *pr) +{ + R_DOUBLE (pr) = tan (P_DOUBLE (pr, 0)); +} + +static void +bi_asin (progs_t *pr) +{ + R_DOUBLE (pr) = asin (P_DOUBLE (pr, 0)); +} + +static void +bi_acos (progs_t *pr) +{ + R_DOUBLE (pr) = acos (P_DOUBLE (pr, 0)); +} + +static void +bi_atan (progs_t *pr) +{ + R_DOUBLE (pr) = atan (P_DOUBLE (pr, 0)); +} + +static void +bi_atan2 (progs_t *pr) +{ + R_DOUBLE (pr) = atan2 (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1)); +} + +static void +bi_log (progs_t *pr) +{ + R_DOUBLE (pr) = log (P_DOUBLE (pr, 0)); +} + +static void +bi_log2 (progs_t *pr) +{ + R_DOUBLE (pr) = log (P_DOUBLE (pr, 0)) / M_LOG2E; +} + +static void +bi_log10 (progs_t *pr) +{ + R_DOUBLE (pr) = log10 (P_DOUBLE (pr, 0)); +} + +static void +bi_pow (progs_t *pr) +{ + R_DOUBLE (pr) = pow (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1)); +} + +static void +bi_sqrt (progs_t *pr) +{ + R_DOUBLE (pr) = sqrt (P_DOUBLE (pr, 0)); +} + +static void +bi_cbrt (progs_t *pr) +{ + R_DOUBLE (pr) = cbrt (P_DOUBLE (pr, 0)); +} + +static void +bi_hypot (progs_t *pr) +{ + R_DOUBLE (pr) = hypot (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1)); +} + +static void +bi_sinh (progs_t *pr) +{ + R_DOUBLE (pr) = sinh (P_DOUBLE (pr, 0)); +} + +static void +bi_cosh (progs_t *pr) +{ + R_DOUBLE (pr) = cosh (P_DOUBLE (pr, 0)); +} + +static void +bi_tanh (progs_t *pr) +{ + R_DOUBLE (pr) = tanh (P_DOUBLE (pr, 0)); +} + +static void +bi_asinh (progs_t *pr) +{ + double y = P_DOUBLE (pr, 0); + R_DOUBLE (pr) = log (y + sqrt (y * y + 1)); +} + +static void +bi_acosh (progs_t *pr) +{ + double y = P_DOUBLE (pr, 0); + R_DOUBLE (pr) = log (y + sqrt (y * y - 1)); +} + +static void +bi_atanh (progs_t *pr) +{ + double y = P_DOUBLE (pr, 0); + R_DOUBLE (pr) = log ((1 + y) / (1 - y)) / 2; +} + static builtin_t builtins[] = { - {"sin", bi_sin, -1}, - {"cos", bi_cos, -1}, - {"tan", bi_tan, -1}, - {"asin", bi_asin, -1}, - {"acos", bi_acos, -1}, - {"atan", bi_atan, -1}, - {"atan2", bi_atan2, -1}, - {"log", bi_log, -1}, - {"log2", bi_log2, -1}, - {"log10", bi_log10, -1}, - {"pow", bi_pow, -1}, - {"sqrt", bi_sqrt, -1}, - {"cbrt", bi_cbrt, -1}, - {"hypot", bi_hypot, -1}, - {"sinh", bi_sinh, -1}, - {"cosh", bi_cosh, -1}, - {"tanh", bi_tanh, -1}, - {"asinh", bi_asinh, -1}, - {"acosh", bi_acosh, -1}, - {"atanh", bi_atanh, -1}, + {"sin|f", bi_sinf, -1}, + {"cos|f", bi_cosf, -1}, + {"tan|f", bi_tanf, -1}, + {"asin|f", bi_asinf, -1}, + {"acos|f", bi_acosf, -1}, + {"atan|f", bi_atanf, -1}, + {"atan2|ff",bi_atan2f, -1}, + {"log|f", bi_logf, -1}, + {"log2|f", bi_log2f, -1}, + {"log10|f", bi_log10f, -1}, + {"pow|ff", bi_powf, -1}, + {"sqrt|f", bi_sqrtf, -1}, + {"cbrt|f", bi_cbrtf, -1}, + {"hypot|ff",bi_hypotf, -1}, + {"sinh|f", bi_sinhf, -1}, + {"cosh|f", bi_coshf, -1}, + {"tanh|f", bi_tanhf, -1}, + {"asinh|f", bi_asinhf, -1}, + {"acosh|f", bi_acoshf, -1}, + {"atanh|f", bi_atanhf, -1}, + {"floor|d", bi_floor, -1}, // float version in pr_cmds + {"ceil|d", bi_ceil, -1}, // float version in pr_cmds + {"fabs|d", bi_fabs, -1}, // float version in pr_cmds + {"sin|d", bi_sin, -1}, + {"cos|d", bi_cos, -1}, + {"tan|d", bi_tan, -1}, + {"asin|d", bi_asin, -1}, + {"acos|d", bi_acos, -1}, + {"atan|d", bi_atan, -1}, + {"atan2|dd",bi_atan2, -1}, + {"log|d", bi_log, -1}, + {"log2|d", bi_log2, -1}, + {"log10|d", bi_log10, -1}, + {"pow|dd", bi_pow, -1}, + {"sqrt|d", bi_sqrt, -1}, + {"cbrt|d", bi_cbrt, -1}, + {"hypot|dd",bi_hypot, -1}, + {"sinh|d", bi_sinh, -1}, + {"cosh|d", bi_cosh, -1}, + {"tanh|d", bi_tanh, -1}, + {"asinh|d", bi_asinh, -1}, + {"acosh|d", bi_acosh, -1}, + {"atanh|d", bi_atanh, -1}, {0} }; diff --git a/libs/ruamoko/rua_msgbuf.c b/libs/ruamoko/rua_msgbuf.c index 9b026c90f..e16525053 100644 --- a/libs/ruamoko/rua_msgbuf.c +++ b/libs/ruamoko/rua_msgbuf.c @@ -58,32 +58,32 @@ typedef struct { static msgbuf_t * msgbuf_new (msgbuf_resources_t *res) { - PR_RESNEW (msgbuf_t, res->msgbuf_map); + return PR_RESNEW (res->msgbuf_map); } static void msgbuf_free (progs_t *pr, msgbuf_resources_t *res, msgbuf_t *msgbuf) { PR_Zone_Free (pr, msgbuf->sizebuf.data); - PR_RESFREE (msgbuf_t, res->msgbuf_map, msgbuf); + PR_RESFREE (res->msgbuf_map, msgbuf); } static void msgbuf_reset (msgbuf_resources_t *res) { - PR_RESRESET (msgbuf_t, res->msgbuf_map); + PR_RESRESET (res->msgbuf_map); } static inline msgbuf_t * msgbuf_get (msgbuf_resources_t *res, int index) { - PR_RESGET(res->msgbuf_map, index); + return PR_RESGET(res->msgbuf_map, index); } -static inline int +static inline int __attribute__((pure)) msgbuf_index (msgbuf_resources_t *res, msgbuf_t *msgbuf) { - PR_RESINDEX(res->msgbuf_map, msgbuf); + return PR_RESINDEX(res->msgbuf_map, msgbuf); } static void @@ -358,8 +358,7 @@ static void bi_MsgBuf_ReadCoordAngleV (progs_t *pr) { msgbuf_t *mb = get_msgbuf (pr, __FUNCTION__, P_INT (pr, 0)); - MSG_ReadCoordAngleV (&mb->msg, P_GPOINTER (pr, 1)->vector_var, - P_GPOINTER (pr, 2)->vector_var); + MSG_ReadCoordAngleV (&mb->msg, P_VECTOR (pr, 1), P_VECTOR (pr, 2)); } static void diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index ed3a1d78b..a901823b0 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -56,11 +56,75 @@ #include "compat.h" #include "rua_internal.h" +#define always_inline inline __attribute__((__always_inline__)) + typedef struct obj_list_s { struct obj_list_s *next; void *data; } obj_list; +typedef struct dtable_s { + size_t size; + func_t *imp; +} dtable_t; + +typedef struct probj_resources_s { + progs_t *pr; + unsigned selector_index; + unsigned selector_index_max; + obj_list **selector_sels; + string_t *selector_names; + PR_RESMAP (dtable_t) dtables; + func_t obj_forward; + pr_sel_t *forward_selector; + dstring_t *msg; + hashtab_t *selector_hash; + hashtab_t *classes; + hashtab_t *protocols; + hashtab_t *load_methods; + obj_list *unresolved_classes; + obj_list *unclaimed_categories; + obj_list *uninitialized_statics; + obj_list *unclaimed_proto_list; + obj_list *module_list; + obj_list *class_tree_list; +} probj_t; + +static dtable_t * +dtable_new (probj_t *probj) +{ + return PR_RESNEW (probj->dtables); +} + +static void +dtable_reset (probj_t *probj) +{ + PR_RESRESET (probj->dtables); +} + +static inline dtable_t * +dtable_get (probj_t *probj, int index) +{ + return PR_RESGET (probj->dtables, index); +} + +static inline int __attribute__((pure)) +dtable_index (probj_t *probj, dtable_t *dtable) +{ + return PR_RESINDEX (probj->dtables, dtable); +} + +static always_inline dtable_t * __attribute__((pure)) +get_dtable (probj_t *probj, const char *name, int index) +{ + dtable_t *dtable = dtable_get (probj, index); + + if (!dtable) { + PR_RunError (probj->pr, "invalid dtable index in %s", name); + } + return dtable; +} + static obj_list *obj_list_free_list; static obj_list * @@ -144,7 +208,7 @@ class_tree_new (void) } static int -class_is_subclass_of_class (progs_t *pr, pr_class_t *class, +class_is_subclass_of_class (probj_t *probj, pr_class_t *class, pr_class_t *superclass) { while (class) { @@ -152,20 +216,22 @@ class_is_subclass_of_class (progs_t *pr, pr_class_t *class, return 1; if (!class->super_class) break; - class = Hash_Find (pr->classes, PR_GetString (pr, class->super_class)); + class = Hash_Find (probj->classes, + PR_GetString (probj->pr, class->super_class)); } return 0; } static class_tree * -create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, +create_tree_of_subclasses_inherited_from (probj_t *probj, pr_class_t *bottom, pr_class_t *upper) { + progs_t *pr = probj->pr; const char *super_class = PR_GetString (pr, bottom->super_class); pr_class_t *superclass; class_tree *tree, *prev; - superclass = bottom->super_class ? Hash_Find (pr->classes, super_class) + superclass = bottom->super_class ? Hash_Find (probj->classes, super_class) : 0; tree = prev = class_tree_new (); prev->class = bottom; @@ -174,7 +240,7 @@ create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, tree->class = superclass; tree->subclasses = list_cons (prev, tree->subclasses); super_class = PR_GetString (pr, superclass->super_class); - superclass = (superclass->super_class ? Hash_Find (pr->classes, + superclass = (superclass->super_class ? Hash_Find (probj->classes, super_class) : 0); prev = tree; @@ -183,16 +249,17 @@ create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, } static class_tree * -_obj_tree_insert_class (progs_t *pr, class_tree *tree, pr_class_t *class) +_obj_tree_insert_class (probj_t *probj, class_tree *tree, pr_class_t *class) { + progs_t *pr = probj->pr; obj_list *subclasses; class_tree *new_tree; if (!tree) - return create_tree_of_subclasses_inherited_from (pr, class, 0); + return create_tree_of_subclasses_inherited_from (probj, class, 0); if (class == tree->class) return tree; - if ((class->super_class ? Hash_Find (pr->classes, + if ((class->super_class ? Hash_Find (probj->classes, PR_GetString (pr, class->super_class)) : 0) == tree->class) { @@ -209,32 +276,32 @@ _obj_tree_insert_class (progs_t *pr, class_tree *tree, pr_class_t *class) tree->subclasses = list_cons (node, tree->subclasses); return tree; } - if (!class_is_subclass_of_class (pr, class, tree->class)) + if (!class_is_subclass_of_class (probj, class, tree->class)) return 0; for (subclasses = tree->subclasses; subclasses; subclasses = subclasses->next) { pr_class_t *aclass = ((class_tree *)subclasses->data)->class; - if (class_is_subclass_of_class (pr, class, aclass)) { - subclasses->data = _obj_tree_insert_class (pr, subclasses->data, + if (class_is_subclass_of_class (probj, class, aclass)) { + subclasses->data = _obj_tree_insert_class (probj, subclasses->data, class); return tree; } } - new_tree = create_tree_of_subclasses_inherited_from (pr, class, + new_tree = create_tree_of_subclasses_inherited_from (probj, class, tree->class); tree->subclasses = list_cons (new_tree, tree->subclasses); return tree; } static void -obj_tree_insert_class (progs_t *pr, pr_class_t *class) +obj_tree_insert_class (probj_t *probj, pr_class_t *class) { obj_list *list_node; class_tree *tree; - list_node = pr->class_tree_list; + list_node = probj->class_tree_list; while (list_node) { - tree = _obj_tree_insert_class (pr, list_node->data, class); + tree = _obj_tree_insert_class (probj, list_node->data, class); if (tree) { list_node->data = tree; break; @@ -243,73 +310,82 @@ obj_tree_insert_class (progs_t *pr, pr_class_t *class) } } if (!list_node) { - tree = _obj_tree_insert_class (pr, 0, class); - pr->class_tree_list = list_cons (tree, pr->class_tree_list); + tree = _obj_tree_insert_class (probj, 0, class); + probj->class_tree_list = list_cons (tree, probj->class_tree_list); } } static void -obj_create_classes_tree (progs_t *pr, pr_module_t *module) +obj_create_classes_tree (probj_t *probj, pr_module_t *module) { + progs_t *pr = probj->pr; pr_symtab_t *symtab = &G_STRUCT (pr, pr_symtab_t, module->symtab); int i; for (i = 0; i < symtab->cls_def_cnt; i++) { pr_class_t *class = &G_STRUCT (pr, pr_class_t, symtab->defs[i]); - obj_tree_insert_class (pr, class); + obj_tree_insert_class (probj, class); } } static void -obj_destroy_class_tree_node (progs_t *pr, class_tree *tree, int level) +obj_destroy_class_tree_node (probj_t *probj, class_tree *tree, int level) { tree->subclasses = (obj_list *) class_tree_free_list; class_tree_free_list = tree; } static void -obj_preorder_traverse (progs_t *pr, class_tree *tree, int level, - void (*func) (progs_t *, class_tree *, int)) +obj_preorder_traverse (probj_t *probj, class_tree *tree, int level, + void (*func) (probj_t *, class_tree *, int)) { obj_list *node; - func (pr, tree, level); + func (probj, tree, level); for (node = tree->subclasses; node; node = node->next) - obj_preorder_traverse (pr, node->data, level + 1, func); + obj_preorder_traverse (probj, node->data, level + 1, func); } static void -obj_postorder_traverse (progs_t *pr, class_tree *tree, int level, - void (*func) (progs_t *, class_tree *, int)) +obj_postorder_traverse (probj_t *probj, class_tree *tree, int level, + void (*func) (probj_t *, class_tree *, int)) { obj_list *node; for (node = tree->subclasses; node; node = node->next) - obj_postorder_traverse (pr, node->data, level + 1, func); - func (pr, tree, level); + obj_postorder_traverse (probj, node->data, level + 1, func); + func (probj, tree, level); } static const char * -selector_get_key (const void *s, void *_pr) +selector_get_key (const void *s, void *_probj) { - progs_t *pr = (progs_t *) _pr; - return PR_GetString (pr, pr->selector_names[(intptr_t) s]); + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, probj->selector_names[(intptr_t) s]); } static const char * -class_get_key (const void *c, void *pr) +class_get_key (const void *c, void *_probj) { - return PR_GetString ((progs_t *)pr, ((pr_class_t *)c)->name); + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, ((pr_class_t *)c)->name); +} + +static const char * +protocol_get_key (const void *p, void *_probj) +{ + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, ((pr_protocol_t *)p)->protocol_name); } static uintptr_t -load_methods_get_hash (const void *m, void *pr) +load_methods_get_hash (const void *m, void *_probj) { return (uintptr_t) m; } static int -load_methods_compare (const void *m1, const void *m2, void *pr) +load_methods_compare (const void *m1, const void *m2, void *_probj) { return m1 == m2; } @@ -323,8 +399,9 @@ sel_eq (pr_sel_t *s1, pr_sel_t *s2) } static int -object_is_instance (progs_t *pr, pr_id_t *object) +object_is_instance (probj_t *probj, pr_id_t *object) { + progs_t *pr = probj->pr; pr_class_t *class; if (object) { @@ -335,8 +412,9 @@ object_is_instance (progs_t *pr, pr_id_t *object) } static string_t -object_get_class_name (progs_t *pr, pr_id_t *object) +object_get_class_name (probj_t *probj, pr_id_t *object) { + progs_t *pr = probj->pr; pr_class_t *class; if (object) { @@ -356,8 +434,9 @@ object_get_class_name (progs_t *pr, pr_id_t *object) //==================================================================== static void -finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) +finish_class (probj_t *probj, pr_class_t *class, pointer_t object_ptr) { + progs_t *pr = probj->pr; pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); pr_class_t *val; @@ -365,7 +444,7 @@ finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) if (class->super_class) { const char *super_class = PR_GetString (pr, class->super_class); const char *class_name = PR_GetString (pr, class->name); - val = Hash_Find (pr->classes, super_class); + val = Hash_Find (probj->classes, super_class); if (!val) PR_Error (pr, "broken class %s: super class %s not found", class_name, super_class); @@ -384,39 +463,39 @@ finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) //==================================================================== static int -add_sel_name (progs_t *pr, const char *name) +add_sel_name (probj_t *probj, const char *name) { - int ind = ++pr->selector_index; + int ind = ++probj->selector_index; int size, i; - if (pr->selector_index >= pr->selector_index_max) { - size = pr->selector_index_max + 128; - pr->selector_sels = realloc (pr->selector_sels, - size * sizeof (obj_list *)); - pr->selector_names = realloc (pr->selector_names, - size * sizeof (string_t)); - for (i = pr->selector_index_max; i < size; i++) { - pr->selector_sels[i] = 0; - pr->selector_names[i] = 0; + if (probj->selector_index >= probj->selector_index_max) { + size = probj->selector_index_max + 128; + probj->selector_sels = realloc (probj->selector_sels, + size * sizeof (obj_list *)); + probj->selector_names = realloc (probj->selector_names, + size * sizeof (string_t)); + for (i = probj->selector_index_max; i < size; i++) { + probj->selector_sels[i] = 0; + probj->selector_names[i] = 0; } - pr->selector_index_max = size; + probj->selector_index_max = size; } - pr->selector_names[ind] = PR_SetString (pr, name); + probj->selector_names[ind] = PR_SetString (probj->pr, name); return ind; } static pr_sel_t * -sel_register_typed_name (progs_t *pr, const char *name, const char *types, +sel_register_typed_name (probj_t *probj, const char *name, const char *types, pr_sel_t *sel) { + progs_t *pr = probj->pr; intptr_t index; int is_new = 0; obj_list *l; - Sys_MaskPrintf (SYS_RUA_OBJ, " Registering SEL %s %s\n", name, types); - index = (intptr_t) Hash_Find (pr->selector_hash, name); + index = (intptr_t) Hash_Find (probj->selector_hash, name); if (index) { - for (l = pr->selector_sels[index]; l; l = l->next) { + for (l = probj->selector_sels[index]; l; l = l->next) { pr_sel_t *s = l->data; if (!types || !s->sel_types) { if (!s->sel_types && !types) { @@ -435,7 +514,9 @@ sel_register_typed_name (progs_t *pr, const char *name, const char *types, } } } else { - index = add_sel_name (pr, name); + Sys_MaskPrintf (SYS_RUA_OBJ, " Registering SEL %s %s\n", + name, types); + index = add_sel_name (probj, name); is_new = 1; } if (!sel) @@ -446,11 +527,11 @@ sel_register_typed_name (progs_t *pr, const char *name, const char *types, l = obj_list_new (); l->data = sel; - l->next = pr->selector_sels[index]; - pr->selector_sels[index] = l; + l->next = probj->selector_sels[index]; + probj->selector_sels[index] = l; if (is_new) - Hash_Add (pr->selector_hash, (void *) index); + Hash_Add (probj->selector_hash, (void *) index); done: Sys_MaskPrintf (SYS_RUA_OBJ, " %d @ %x\n", sel->sel_id, PR_SetPointer (pr, sel)); @@ -458,40 +539,91 @@ done: } static pr_sel_t * -sel_register_name (progs_t *pr, const char *name) +sel_register_name (probj_t *probj, const char *name) { - return sel_register_typed_name (pr, name, "", 0); + return sel_register_typed_name (probj, name, "", 0); } static void -register_selectors_from_list (progs_t *pr, pr_method_list_t *method_list) +obj_register_selectors_from_description_list (probj_t *probj, + pr_method_description_list_t *method_list) { + progs_t *pr = probj->pr; + int i; + + if (!method_list) { + return; + } + for (i = 0; i < method_list->count; i++) { + pr_method_description_t *method = &method_list->list[i]; + const char *name = PR_GetString (pr, method->name); + const char *types = PR_GetString (pr, method->types); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); + method->name = PR_SetPointer (pr, sel); + } +} + +static void +obj_register_selectors_from_list (probj_t *probj, + pr_method_list_t *method_list) +{ + progs_t *pr = probj->pr; int i; for (i = 0; i < method_list->method_count; i++) { pr_method_t *method = &method_list->method_list[i]; const char *name = PR_GetString (pr, method->method_name); const char *types = PR_GetString (pr, method->method_types); - pr_sel_t *sel = sel_register_typed_name (pr, name, types, 0); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); method->method_name = PR_SetPointer (pr, sel); } } static void -obj_register_selectors_from_class (progs_t *pr, pr_class_t *class) +obj_register_selectors_from_class (probj_t *probj, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list = &G_STRUCT (pr, pr_method_list_t, class->methods); while (method_list) { - register_selectors_from_list (pr, method_list); + obj_register_selectors_from_list (probj, method_list); method_list = &G_STRUCT (pr, pr_method_list_t, method_list->method_next); } } +static void obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos); + static void -obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) +obj_init_protocol (probj_t *probj, pr_class_t *proto_class, + pr_protocol_t *proto) { + progs_t *pr = probj->pr; + + if (!proto->class_pointer) { + const char *protocol_name = PR_GetString (pr, proto->protocol_name); + proto->class_pointer = PR_SetPointer (pr, proto_class); + obj_register_selectors_from_description_list (probj, + &G_STRUCT (pr, pr_method_description_list_t, + proto->instance_methods)); + obj_register_selectors_from_description_list (probj, + &G_STRUCT (pr, pr_method_description_list_t, + proto->class_methods)); + if (!Hash_Find (probj->protocols, protocol_name)) { + Hash_Add (probj->protocols, proto); + } + obj_init_protocols (probj, &G_STRUCT (pr, pr_protocol_list_t, + proto->protocol_list)); + } else { + if (proto->class_pointer != PR_SetPointer (pr, proto_class)) + PR_RunError (pr, "protocol broken"); + } +} + +static void +obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos) +{ + progs_t *pr = probj->pr; pr_class_t *proto_class; pr_protocol_t *proto; int i; @@ -499,28 +631,23 @@ obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) if (!protos) return; - if (!(proto_class = Hash_Find (pr->classes, "Protocol"))) { - pr->unclaimed_proto_list = list_cons (protos, - pr->unclaimed_proto_list); + if (!(proto_class = Hash_Find (probj->classes, "Protocol"))) { + probj->unclaimed_proto_list = list_cons (protos, + probj->unclaimed_proto_list); return; } for (i = 0; i < protos->count; i++) { proto = &G_STRUCT (pr, pr_protocol_t, protos->list[i]); - if (!proto->class_pointer) { - proto->class_pointer = PR_SetPointer (pr, proto_class); - obj_init_protocols (pr, &G_STRUCT (pr, pr_protocol_list_t, - proto->protocol_list)); - } else { - if (proto->class_pointer != PR_SetPointer (pr, proto_class)) - PR_RunError (pr, "protocol broken"); - } + obj_init_protocol (probj, proto_class, proto); } } static void -class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) +class_add_method_list (probj_t *probj, pr_class_t *class, + pr_method_list_t *list) { + progs_t *pr = probj->pr; int i; for (i = 0; i < list->method_count; i++) { @@ -528,7 +655,7 @@ class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) if (method->method_name) { const char *name = PR_GetString (pr, method->method_name); const char *types = PR_GetString (pr, method->method_types); - pr_sel_t *sel = sel_register_typed_name (pr, name, types, 0); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); method->method_name = PR_SetPointer (pr, sel); } } @@ -538,7 +665,7 @@ class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) } static void -obj_class_add_protocols (progs_t *pr, pr_class_t *class, +obj_class_add_protocols (probj_t *probj, pr_class_t *class, pr_protocol_list_t *protos) { if (!protos) @@ -549,50 +676,54 @@ obj_class_add_protocols (progs_t *pr, pr_class_t *class, } static void -finish_category (progs_t *pr, pr_category_t *category, pr_class_t *class) +finish_category (probj_t *probj, pr_category_t *category, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list; pr_protocol_list_t *protocol_list; if (category->instance_methods) { method_list = &G_STRUCT (pr, pr_method_list_t, category->instance_methods); - class_add_method_list (pr, class, method_list); + class_add_method_list (probj, class, method_list); } if (category->class_methods) { pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); method_list = &G_STRUCT (pr, pr_method_list_t, category->class_methods); - class_add_method_list (pr, meta, method_list); + class_add_method_list (probj, meta, method_list); } if (category->protocols) { protocol_list = &G_STRUCT (pr, pr_protocol_list_t, category->protocols); - obj_init_protocols (pr, protocol_list); - obj_class_add_protocols (pr, class, protocol_list); + obj_init_protocols (probj, protocol_list); + obj_class_add_protocols (probj, class, protocol_list); } } static void -obj_send_message_in_list (progs_t *pr, pr_method_list_t *method_list, +obj_send_message_in_list (probj_t *probj, pr_method_list_t *method_list, pr_class_t *class, pr_sel_t *op) { + progs_t *pr = probj->pr; int i; if (!method_list) return; - obj_send_message_in_list (pr, &G_STRUCT (pr, pr_method_list_t, - method_list->method_next), + obj_send_message_in_list (probj, &G_STRUCT (pr, pr_method_list_t, + method_list->method_next), class, op); for (i = 0; i < method_list->method_count; i++) { pr_method_t *mth = &method_list->method_list[i]; if (mth->method_name && sel_eq (&G_STRUCT (pr, pr_sel_t, mth->method_name), op) - && !Hash_FindElement (pr->load_methods, (void *) (intptr_t) mth->method_imp)) { - Hash_AddElement (pr->load_methods, (void *) (intptr_t) mth->method_imp); - + && !Hash_FindElement (probj->load_methods, + (void *) (intptr_t) mth->method_imp)) { + Hash_AddElement (probj->load_methods, + (void *) (intptr_t) mth->method_imp); + //FIXME need to wrap in save/restore params? PR_ExecuteProgram (pr, mth->method_imp); break; } @@ -600,58 +731,62 @@ obj_send_message_in_list (progs_t *pr, pr_method_list_t *method_list, } static void -send_load (progs_t *pr, class_tree *tree, int level) +send_load (probj_t *probj, class_tree *tree, int level) { - pr_sel_t *load_sel = sel_register_name (pr, "load"); + progs_t *pr = probj->pr; + pr_sel_t *load_sel = sel_register_name (probj, "load"); pr_class_t *class = tree->class; pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); pr_method_list_t *method_list = &G_STRUCT (pr, pr_method_list_t, meta->methods); - obj_send_message_in_list (pr, method_list, class, load_sel); + obj_send_message_in_list (probj, method_list, class, load_sel); } static void -obj_send_load (progs_t *pr) +obj_send_load (probj_t *probj) { + progs_t *pr = probj->pr; obj_list *m; - if (pr->unresolved_classes) { - pr_class_t *class = pr->unresolved_classes->data; + if (probj->unresolved_classes) { + pr_class_t *class = probj->unresolved_classes->data; const char *super_class = PR_GetString (pr, class->super_class); - while (Hash_Find (pr->classes, super_class)) { - list_remove (&pr->unresolved_classes); - if (pr->unresolved_classes) { - class = pr->unresolved_classes->data; + while (Hash_Find (probj->classes, super_class)) { + list_remove (&probj->unresolved_classes); + if (probj->unresolved_classes) { + class = probj->unresolved_classes->data; super_class = PR_GetString (pr, class->super_class); } else { break; } } - if (pr->unresolved_classes) + if (probj->unresolved_classes) return; } //XXX constant string stuff here (see init.c in libobjc source) - for (m = pr->module_list; m; m = m->next) - obj_create_classes_tree (pr, m->data); - while (pr->class_tree_list) { - obj_preorder_traverse (pr, pr->class_tree_list->data, 0, send_load); - obj_postorder_traverse (pr, pr->class_tree_list->data, 0, + for (m = probj->module_list; m; m = m->next) + obj_create_classes_tree (probj, m->data); + while (probj->class_tree_list) { + obj_preorder_traverse (probj, probj->class_tree_list->data, 0, + send_load); + obj_postorder_traverse (probj, probj->class_tree_list->data, 0, obj_destroy_class_tree_node); - list_remove (&pr->class_tree_list); + list_remove (&probj->class_tree_list); } //XXX callback - //for (m = pr->module_list; m; m = m->next) - // obj_create_classes_tree (pr, m->data); - obj_list_free (pr->module_list); - pr->module_list = 0; + //for (m = probj->module_list; m; m = m->next) + // obj_create_classes_tree (probj, m->data); + obj_list_free (probj->module_list); + probj->module_list = 0; } static pr_method_t * -obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) +obj_find_message (probj_t *probj, pr_class_t *class, pr_sel_t *selector) { + progs_t *pr = probj->pr; pr_class_t *c = class; pr_method_list_t *method_list; pr_method_t *method; @@ -661,7 +796,7 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) string_t *names; if (dev & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf ("Searching for %s\n", PR_GetString (pr, names[selector->sel_id])); } @@ -680,13 +815,13 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) i < method_list->method_count; i++, method++) { sel = &G_STRUCT (pr, pr_sel_t, method->method_name); if (developer->int_val & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf (" %s\n", PR_GetString (pr, names[sel->sel_id])); } if (sel->sel_id == selector->sel_id) { if (dev & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf ("found %s: %x\n", PR_GetString (pr, names[selector->sel_id]), method->method_imp); @@ -703,13 +838,14 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) } static void -obj_send_initialize (progs_t *pr, pr_class_t *class) +obj_send_initialize (probj_t *probj, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list; pr_method_t *method; pr_sel_t *sel; pr_class_t *class_pointer; - pr_sel_t *selector = sel_register_name (pr, "initialize"); + pr_sel_t *selector = sel_register_name (probj, "initialize"); int i; if (PR_CLS_ISINITIALIZED (class)) @@ -718,8 +854,8 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) PR_CLS_SETINITIALIZED (class); PR_CLS_SETINITIALIZED (class_pointer); if (class->super_class) - obj_send_initialize (pr, &G_STRUCT (pr, pr_class_t, - class->super_class)); + obj_send_initialize (probj, &G_STRUCT (pr, pr_class_t, + class->super_class)); method_list = &G_STRUCT (pr, pr_method_list_t, class_pointer->methods); while (method_list) { @@ -728,12 +864,12 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) sel = &G_STRUCT (pr, pr_sel_t, method->method_name); if (sel->sel_id == selector->sel_id) { PR_PushFrame (pr); - PR_SaveParams (pr); + __auto_type params = PR_SaveParams (pr); // param 0 is known to be the class pointer P_POINTER (pr, 1) = method->method_name; // pr->pr_argc is known to be 2 PR_ExecuteProgram (pr, method->method_imp); - PR_RestoreParams (pr); + PR_RestoreParams (pr, params); PR_PopFrame (pr); return; } @@ -743,57 +879,159 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) } } -static func_t -get_imp (progs_t *pr, pr_class_t *class, pr_sel_t *sel) +static void +obj_install_methods_in_dtable (probj_t *probj, pr_class_t *class, + pr_method_list_t *method_list) { - pr_method_t *method = obj_find_message (pr, class, sel); + progs_t *pr = probj->pr; + dtable_t *dtable; - return method ? method->method_imp : 0; + if (!method_list) { + return; + } + if (method_list->method_next) { + obj_install_methods_in_dtable (probj, class, + &G_STRUCT (pr, pr_method_list_t, + method_list->method_next)); + } + + dtable = get_dtable (probj, __FUNCTION__, class->dtable); + for (int i = 0; i < method_list->method_count; i++) { + pr_method_t *method = &method_list->method_list[i]; + pr_sel_t *sel = &G_STRUCT (pr, pr_sel_t, method->method_name); + if (sel->sel_id < dtable->size) { + dtable->imp[sel->sel_id] = method->method_imp; + } + } +} + +static void +obj_install_dispatch_table_for_class (probj_t *probj, pr_class_t *class) +{ + progs_t *pr = probj->pr; + pr_class_t *super = &G_STRUCT (pr, pr_class_t, class->super_class); + dtable_t *dtable; + + Sys_MaskPrintf (SYS_RUA_OBJ, " install dispatch for class %s %x %d\n", + PR_GetString (pr, class->name), + class->methods, + PR_CLS_ISMETA(class)); + + if (super && !super->dtable) { + obj_install_dispatch_table_for_class (probj, super); + } + + dtable = dtable_new (probj); + class->dtable = dtable_index (probj, dtable); + dtable->size = probj->selector_index + 1; + dtable->imp = calloc (dtable->size, sizeof (func_t)); + if (super) { + dtable_t *super_dtable = get_dtable (probj, __FUNCTION__, + super->dtable); + memcpy (dtable->imp, super_dtable->imp, + super_dtable->size * sizeof (*dtable->imp)); + } + obj_install_methods_in_dtable (probj, class, + &G_STRUCT (pr, pr_method_list_t, + class->methods)); +} + +static inline dtable_t * +obj_check_dtable_installed (probj_t *probj, pr_class_t *class) +{ + if (!class->dtable) { + obj_install_dispatch_table_for_class (probj, class); + } + return get_dtable (probj, __FUNCTION__, class->dtable); } static func_t -obj_msg_lookup (progs_t *pr, pr_id_t *receiver, pr_sel_t *op) +get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel) { + func_t imp = 0; + + if (class->dtable) { + dtable_t *dtable = get_dtable (probj, __FUNCTION__, class->dtable); + if (sel->sel_id < dtable->size) { + imp = dtable->imp[sel->sel_id]; + } + } + if (!imp) { + if (!class->dtable) { + obj_install_dispatch_table_for_class (probj, class); + imp = get_imp (probj, class, sel); + } else { + imp = probj->obj_forward; + } + } + return imp; +} + +static int +obj_reponds_to (probj_t *probj, pr_id_t *obj, pr_sel_t *sel) +{ + progs_t *pr = probj->pr; + pr_class_t *class; + dtable_t *dtable; + func_t imp = 0; + + class = &G_STRUCT (pr, pr_class_t, obj->class_pointer); + dtable = obj_check_dtable_installed (probj, class); + + if (sel->sel_id < dtable->size) { + imp = dtable->imp[sel->sel_id]; + } + return imp != 0; +} + +static func_t +obj_msg_lookup (probj_t *probj, pr_id_t *receiver, pr_sel_t *op) +{ + progs_t *pr = probj->pr; pr_class_t *class; if (!receiver) return 0; class = &G_STRUCT (pr, pr_class_t, receiver->class_pointer); if (PR_CLS_ISCLASS (class)) { if (!PR_CLS_ISINITIALIZED (class)) - obj_send_initialize (pr, class); + obj_send_initialize (probj, class); } else if (PR_CLS_ISMETA (class) && PR_CLS_ISCLASS ((pr_class_t *) receiver)) { if (!PR_CLS_ISINITIALIZED ((pr_class_t *) receiver)) - obj_send_initialize (pr, (pr_class_t *) receiver); + obj_send_initialize (probj, (pr_class_t *) receiver); } - return get_imp (pr, class, op); + return get_imp (probj, class, op); } static func_t -obj_msg_lookup_super (progs_t *pr, pr_super_t *super, pr_sel_t *op) +obj_msg_lookup_super (probj_t *probj, pr_super_t *super, pr_sel_t *op) { + progs_t *pr = probj->pr; pr_class_t *class; if (!super->self) return 0; class = &G_STRUCT (pr, pr_class_t, super->class); - return get_imp (pr, class, op); + return get_imp (probj, class, op); } static void -obj_verror (progs_t *pr, pr_id_t *object, int code, const char *fmt, int count, +obj_verror (probj_t *probj, pr_id_t *object, int code, const char *fmt, int count, pr_type_t **args) { + progs_t *pr = probj->pr; + __auto_type class = &G_STRUCT (pr, pr_class_t, object->class_pointer); dstring_t *dstr = dstring_newstr (); PR_Sprintf (pr, dstr, "obj_verror", fmt, count, args); - PR_RunError (pr, "%s", dstr->str); + PR_RunError (pr, "%s: %s", PR_GetString (pr, class->name), dstr->str); } static void -dump_ivars (progs_t *pr, pointer_t _ivars) +dump_ivars (probj_t *probj, pointer_t _ivars) { + progs_t *pr = probj->pr; pr_ivar_list_t *ivars; int i; @@ -808,9 +1046,55 @@ dump_ivars (progs_t *pr, pointer_t _ivars) } } +static void +obj_init_statics (probj_t *probj) +{ + progs_t *pr = probj->pr; + obj_list **cell = &probj->uninitialized_statics; + pointer_t *ptr; + pointer_t *inst; + + Sys_MaskPrintf (SYS_RUA_OBJ, "Initializing statics\n"); + while (*cell) { + int initialized = 1; + + for (ptr = (*cell)->data; *ptr; ptr++) { + __auto_type statics = &G_STRUCT (pr, pr_static_instances_t, *ptr); + const char *class_name = PR_GetString (pr, statics->class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); + + Sys_MaskPrintf (SYS_RUA_OBJ, " %s %p\n", class_name, class); + if (!class) { + initialized = 0; + continue; + } + + if (strcmp (class_name, "Protocol") == 0) { + // protocols are special + for (inst = statics->instances; *inst; inst++) { + obj_init_protocol (probj, class, + &G_STRUCT (pr, pr_protocol_t, *inst)); + } + } else { + for (inst = statics->instances; *inst; inst++) { + pr_id_t *id = &G_STRUCT (pr, pr_id_t, *inst); + id->class_pointer = PR_SetPointer (pr, class); + } + } + } + + if (initialized) { + list_remove (cell); + } else { + cell = &(*cell)->next; + } + } +} + static void rua___obj_exec_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_module_t *module = &P_STRUCT (pr, pr_module_t, 0); pr_symtab_t *symtab; pr_sel_t *sel; @@ -825,22 +1109,25 @@ rua___obj_exec_class (progs_t *pr) return; Sys_MaskPrintf (SYS_RUA_OBJ, "Initializing %s module\n" "symtab @ %x : %d selector%s @ %x, " - "%d class%s and %d categor%s\n", + "%d class%s and %d categor%s\n" + "static instance lists: %s\n", PR_GetString (pr, module->name), module->symtab, symtab->sel_ref_cnt, symtab->sel_ref_cnt == 1 ? "" : "s", symtab->refs, symtab->cls_def_cnt, symtab->cls_def_cnt == 1 ? "" : "es", symtab->cat_def_cnt, - symtab->cat_def_cnt == 1 ? "y" : "ies"); + symtab->cat_def_cnt == 1 ? "y" : "ies", + symtab->defs[symtab->cls_def_cnt + + symtab->cat_def_cnt] ? "yes" : "no"); - pr->module_list = list_cons (module, pr->module_list); + probj->module_list = list_cons (module, probj->module_list); sel = &G_STRUCT (pr, pr_sel_t, symtab->refs); for (i = 0; i < symtab->sel_ref_cnt; i++) { const char *name, *types; name = PR_GetString (pr, sel->sel_id); types = PR_GetString (pr, sel->sel_types); - sel_register_typed_name (pr, name, types, sel); + sel_register_typed_name (probj, name, types, sel); sel++; } @@ -860,7 +1147,7 @@ rua___obj_exec_class (progs_t *pr) class->instance_size, class->ivars); if (developer->int_val & SYS_RUA_OBJ) - dump_ivars (pr, class->ivars); + dump_ivars (probj, class->ivars); Sys_MaskPrintf (SYS_RUA_OBJ, " instance methods: %x\n", class->methods); Sys_MaskPrintf (SYS_RUA_OBJ, " protocols: %x\n", class->protocols); @@ -870,30 +1157,31 @@ rua___obj_exec_class (progs_t *pr) meta->instance_size, meta->ivars); if (developer->int_val & SYS_RUA_OBJ) - dump_ivars (pr, meta->ivars); + dump_ivars (probj, meta->ivars); class->subclass_list = 0; - Hash_Add (pr->classes, class); + Hash_Add (probj->classes, class); - obj_register_selectors_from_class (pr, class); - obj_register_selectors_from_class (pr, meta); + obj_register_selectors_from_class (probj, class); + obj_register_selectors_from_class (probj, meta); if (class->protocols) { pr_protocol_list_t *protocol_list; protocol_list = &G_STRUCT (pr, pr_protocol_list_t, class->protocols); - obj_init_protocols (pr, protocol_list); + obj_init_protocols (probj, protocol_list); } - if (class->super_class && !Hash_Find (pr->classes, super_class)) - pr->unresolved_classes = list_cons (class, pr->unresolved_classes); + if (class->super_class && !Hash_Find (probj->classes, super_class)) + probj->unresolved_classes = list_cons (class, + probj->unresolved_classes); } for (i = 0; i < symtab->cat_def_cnt; i++, ptr++) { pr_category_t *category = &G_STRUCT (pr, pr_category_t, *ptr); const char *class_name = PR_GetString (pr, category->class_name); - pr_class_t *class = Hash_Find (pr->classes, class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); Sys_MaskPrintf (SYS_RUA_OBJ, "Category %s (%s) @ %x\n", PR_GetString (pr, category->class_name), @@ -906,55 +1194,155 @@ rua___obj_exec_class (progs_t *pr) category->protocols); if (class) { - finish_category (pr, category, class); + finish_category (probj, category, class); } else { - pr->unclaimed_categories = list_cons (category, - pr->unclaimed_categories); + probj->unclaimed_categories + = list_cons (category, probj->unclaimed_categories); } } - for (cell = &pr->unclaimed_categories; *cell; ) { + if (*ptr) { + Sys_MaskPrintf (SYS_RUA_OBJ, "Static instances lists: %x\n", *ptr); + probj->uninitialized_statics + = list_cons (&G_STRUCT (pr, pointer_t, *ptr), + probj->uninitialized_statics); + } + if (probj->uninitialized_statics) { + obj_init_statics (probj); + } + + for (cell = &probj->unclaimed_categories; *cell; ) { pr_category_t *category = (*cell)->data; const char *class_name = PR_GetString (pr, category->class_name); - pr_class_t *class = Hash_Find (pr->classes, class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); if (class) { list_remove (cell); - finish_category (pr, category, class); + finish_category (probj, category, class); } else { cell = &(*cell)->next; } } - if (pr->unclaimed_proto_list && Hash_Find (pr->classes, "Protocol")) { - for (cell = &pr->unclaimed_proto_list; *cell; ) { - obj_init_protocols (pr, (*cell)->data); + if (probj->unclaimed_proto_list + && Hash_Find (probj->classes, "Protocol")) { + for (cell = &probj->unclaimed_proto_list; *cell; ) { + obj_init_protocols (probj, (*cell)->data); list_remove (cell); } } Sys_MaskPrintf (SYS_RUA_OBJ, "Finished initializing %s module\n", PR_GetString (pr, module->name)); - obj_send_load (pr); + obj_send_load (probj); Sys_MaskPrintf (SYS_RUA_OBJ, "Leaving %s module init\n", PR_GetString (pr, module->name)); } +static void +rua___obj_forward (progs_t *pr) +{ + probj_t *probj = pr->pr_objective_resources; + pr_id_t *obj = &P_STRUCT (pr, pr_id_t, 0); + pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); + pr_sel_t *fwd_sel = probj->forward_selector; + pr_sel_t *err_sel; + pr_class_t *class =&G_STRUCT (pr, pr_class_t, obj->class_pointer); + func_t imp; + + if (!fwd_sel) { + //FIXME sel_register_typed_name is really not the way to go about + //looking for a selector by name + fwd_sel = sel_register_typed_name (probj, "forward::", "", 0); + probj->forward_selector = fwd_sel; + } + if (obj_reponds_to (probj, obj, fwd_sel)) { + imp = get_imp (probj, class, fwd_sel); + // forward:(SEL) sel :(@va_list) args + // args is full param list + //FIXME oh for a stack + size_t parm_size = pr->pr_param_size * sizeof(pr_type_t); + size_t size = pr->pr_argc * parm_size; + string_t args_block = PR_AllocTempBlock (pr, size); + + int argc = pr->pr_argc; + __auto_type argv = (pr_type_t *) PR_GetString (pr, args_block); + // can't memcpy all params because 0 and 1 could be anywhere + memcpy (argv + 0, &P_INT (pr, 0), 4 * sizeof (pr_type_t)); + memcpy (argv + 4, &P_INT (pr, 1), 4 * sizeof (pr_type_t)); + memcpy (argv + 8, &P_INT (pr, 2), (argc - 2) * parm_size); + + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, fwd_sel); + P_POINTER (pr, 2) = PR_SetPointer (pr, sel); + P_PACKED (pr, pr_va_list_t, 3).count = argc; + P_PACKED (pr, pr_va_list_t, 3).list = PR_SetPointer (pr, argv); + PR_PushTempString (pr, args_block); + PR_CallFunction (pr, imp); + return; + } + //FIXME ditto + err_sel = sel_register_typed_name (probj, "doesNotRecognize:", "", 0); + if (obj_reponds_to (probj, obj, err_sel)) { + imp = get_imp (probj, class, err_sel); + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); + P_POINTER (pr, 2) = PR_SetPointer (pr, sel); + pr->pr_argc = 3; + PR_CallFunction (pr, imp); + return; + } + + dsprintf (probj->msg, "(%s) %s does not recognize %s", + PR_CLS_ISMETA (class) ? "class" : "instance", + PR_GetString (pr, class->name), + PR_GetString (pr, probj->selector_names[sel->sel_id])); + + //FIXME ditto + err_sel = sel_register_typed_name (probj, "error:", "", 0); + if (obj_reponds_to (probj, obj, err_sel)) { + imp = get_imp (probj, class, err_sel); + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); + P_POINTER (pr, 2) = PR_SetTempString (pr, probj->msg->str); + pr->pr_argc = 3; + PR_CallFunction (pr, imp); + return; + } + + PR_RunError (pr, "%s", probj->msg->str); +} + +static void +rua___obj_responds_to (progs_t *pr) +{ + probj_t *probj = pr->pr_objective_resources; + pr_id_t *obj = &P_STRUCT (pr, pr_id_t, 0); + pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); + + R_INT (pr) = obj_reponds_to (probj, obj, sel); +} + static void rua_obj_error (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); int code = P_INT (pr, 1); const char *fmt = P_GSTRING (pr, 2); int count = pr->pr_argc - 3; pr_type_t **args = &pr->pr_params[3]; - obj_verror (pr, object, code, fmt, count, args); + obj_verror (probj, object, code, fmt, count, args); } static void rua_obj_verror (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); int code = P_INT (pr, 1); const char *fmt = P_GSTRING (pr, 2); @@ -965,12 +1353,13 @@ rua_obj_verror (progs_t *pr) for (i = 0; i < val->count; i++) args[i] = params + i * pr->pr_param_size; - obj_verror (pr, object, code, fmt, val->count, args); + obj_verror (probj, object, code, fmt, val->count, args); } static void rua_obj_set_error_handler (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //func_t func = P_INT (pr, 0); //arglist //XXX @@ -980,40 +1369,62 @@ rua_obj_set_error_handler (progs_t *pr) static void rua_obj_msg_lookup (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = obj_msg_lookup (pr, receiver, op); + R_INT (pr) = obj_msg_lookup (probj, receiver, op); } static void rua_obj_msg_lookup_super (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = obj_msg_lookup_super (pr, super, _cmd); + R_INT (pr) = obj_msg_lookup_super (probj, super, _cmd); } static void rua_obj_msg_sendv (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; + pointer_t obj = P_POINTER (pr, 0); pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); + pointer_t sel = P_POINTER (pr, 1); pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - pr_va_list_t *args = (pr_va_list_t *) &P_POINTER (pr, 2); - pr_type_t *params = G_GPOINTER (pr, args->list); - int count = args->count; - func_t imp = obj_msg_lookup (pr, receiver, op); + func_t imp = obj_msg_lookup (probj, receiver, op); - count = bound (0, count, 6); - if (count && pr_boundscheck->int_val) + __auto_type args = &P_PACKED (pr, pr_va_list_t, 2); + int count = args->count; + pr_type_t *params = G_GPOINTER (pr, args->list); + + if (count < 2 || count > MAX_PARMS) { + PR_RunError (pr, "bad args count in obj_msg_sendv: %d", count); + } + if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, args->list, count * pr->pr_param_size); - if (!imp) + } + + if (!imp) { PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, receiver)), - PR_GetString (pr, pr->selector_names[op->sel_id])); - if (count) - memcpy (pr->pr_params[2], params, count * 4 * pr->pr_param_size); + PR_GetString (pr, object_get_class_name (probj, receiver)), + PR_GetString (pr, probj->selector_names[op->sel_id])); + } + + pr->pr_argc = count; + // skip over the first two parameters because receiver and op will + // replace them + count -= 2; + params += 2 * pr->pr_param_size; + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = obj; + P_POINTER (pr, 1) = sel; + if (count) { + memcpy (&P_INT (pr, 2), params, + count * sizeof (pr_type_t) * pr->pr_param_size); + } PR_CallFunction (pr, imp); } @@ -1078,7 +1489,7 @@ rua_obj_realloc (progs_t *pr) static void rua_obj_calloc (progs_t *pr) { - int size = P_INT (pr, 0) * sizeof (pr_type_t); + int size = P_INT (pr, 0) * P_INT (pr, 1) * sizeof (pr_type_t); void *mem = PR_Zone_Malloc (pr, size); memset (mem, 0, size); @@ -1096,6 +1507,7 @@ rua_obj_free (progs_t *pr) static void rua_obj_get_uninstalled_dtable (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //XXX PR_RunError (pr, "%s, not implemented", __FUNCTION__); } @@ -1103,6 +1515,7 @@ rua_obj_get_uninstalled_dtable (progs_t *pr) static void rua_obj_msgSend (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &P_STRUCT (pr, pr_id_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); func_t imp; @@ -1113,11 +1526,11 @@ rua_obj_msgSend (progs_t *pr) } if (!_cmd) PR_RunError (pr, "null selector"); - imp = obj_msg_lookup (pr, self, _cmd); + imp = obj_msg_lookup (probj, self, _cmd); if (!imp) PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); PR_CallFunction (pr, imp); } @@ -1125,16 +1538,17 @@ rua_obj_msgSend (progs_t *pr) static void rua_obj_msgSend_super (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); func_t imp; - imp = obj_msg_lookup_super (pr, super, _cmd); + imp = obj_msg_lookup_super (probj, super, _cmd); if (!imp) { pr_id_t *self = &G_STRUCT (pr, pr_id_t, super->self); PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); } pr->pr_params[0] = pr->pr_real_params[0]; P_POINTER (pr, 0) = super->self; @@ -1144,10 +1558,11 @@ rua_obj_msgSend_super (progs_t *pr) static void rua_obj_get_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); pr_class_t *class; - class = Hash_Find (pr->classes, name); + class = Hash_Find (probj->classes, name); if (!class) PR_RunError (pr, "could not find class %s", name); RETURN_POINTER (pr, class); @@ -1156,16 +1571,18 @@ rua_obj_get_class (progs_t *pr) static void rua_obj_lookup_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); pr_class_t *class; - class = Hash_Find (pr->classes, name); + class = Hash_Find (probj->classes, name); RETURN_POINTER (pr, class); } static void rua_obj_next_class (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //XXX PR_RunError (pr, "%s, not implemented", __FUNCTION__); } @@ -1175,10 +1592,11 @@ rua_obj_next_class (progs_t *pr) static void rua_sel_get_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 0); - if (sel->sel_id > 0 && sel->sel_id <= pr->selector_index) - R_STRING (pr) = pr->selector_names[sel->sel_id]; + if (sel->sel_id > 0 && sel->sel_id <= probj->selector_index) + R_STRING (pr) = probj->selector_names[sel->sel_id]; else R_STRING (pr) = 0; } @@ -1194,25 +1612,28 @@ rua_sel_get_type (progs_t *pr) static void rua_sel_get_uid (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); - RETURN_POINTER (pr, sel_register_typed_name (pr, name, "", 0)); + RETURN_POINTER (pr, sel_register_typed_name (probj, name, "", 0)); } static void rua_sel_register_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); - RETURN_POINTER (pr, sel_register_typed_name (pr, name, "", 0)); + RETURN_POINTER (pr, sel_register_typed_name (probj, name, "", 0)); } static void rua_sel_is_mapped (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; // FIXME might correspond to a string pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 0); - R_INT (pr) = sel->sel_id > 0 && sel->sel_id <= pr->selector_index; + R_INT (pr) = sel->sel_id > 0 && sel->sel_id <= probj->selector_index; } //==================================================================== @@ -1220,20 +1641,22 @@ rua_sel_is_mapped (progs_t *pr) static void rua_class_get_class_method (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *aSel = &P_STRUCT (pr, pr_sel_t, 1); pr_method_t *method; class = &G_STRUCT (pr, pr_class_t, class->class_pointer); - method = obj_find_message (pr, class, aSel); + method = obj_find_message (probj, class, aSel); RETURN_POINTER (pr, method); } static void rua_class_get_instance_method (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *aSel = &P_STRUCT (pr, pr_sel_t, 1); - pr_method_t *method = obj_find_message (pr, class, aSel); + pr_method_t *method = obj_find_message (probj, class, aSel); RETURN_POINTER (pr, method); } @@ -1277,12 +1700,14 @@ class_create_instance (progs_t *pr, pr_class_t *class) { int size = (class->instance_size + 1) * sizeof (pr_type_t); pr_type_t *mem; - pr_id_t *id; + pr_id_t *id = 0; - mem = PR_Zone_Malloc (pr, size); - // redundant memset (id, 0, size); - id = (pr_id_t *) (mem + 1); - id->class_pointer = PR_SetPointer (pr, class); + mem = PR_Zone_TagMalloc (pr, size, class->name); + if (mem) { + memset (mem, 0, size); + id = (pr_id_t *) (mem + 1); + id->class_pointer = PR_SetPointer (pr, class); + } return id; } @@ -1363,6 +1788,7 @@ rua_class_get_gc_object_type (progs_t *pr) static void rua_class_ivar_set_gcinvisible (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //pr_class_t *impostor = &P_STRUCT (pr, pr_class_t, 0); //const char *ivarname = P_GSTRING (pr, 1); //int gcInvisible = P_INT (pr, 2); @@ -1377,16 +1803,17 @@ rua_method_get_imp (progs_t *pr) { pr_method_t *method = &P_STRUCT (pr, pr_method_t, 0); - R_INT (pr) = method->method_imp; + R_INT (pr) = method ? method->method_imp : 0; } static void rua_get_imp (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = get_imp (pr, class, sel); + R_INT (pr) = get_imp (probj, class, sel); } //==================================================================== @@ -1407,9 +1834,11 @@ rua_object_copy (progs_t *pr) pr_id_t *id; id = class_create_instance (pr, class); - memcpy (id, object, sizeof (pr_type_t) * class->instance_size); - // copy the retain count - ((pr_type_t *) id)[-1] = ((pr_type_t *) object)[-1]; + if (id) { + memcpy (id, object, sizeof (pr_type_t) * class->instance_size); + // copy the retain count + ((pr_type_t *) id)[-1] = ((pr_type_t *) object)[-1]; + } RETURN_POINTER (pr, id); } @@ -1476,9 +1905,10 @@ rua_object_get_meta_class (progs_t *pr) static void rua_object_get_class_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - R_STRING (pr) = object_get_class_name (pr, object); + R_STRING (pr) = object_get_class_name (probj, object); } static void @@ -1496,9 +1926,10 @@ rua_object_is_class (progs_t *pr) static void rua_object_is_instance (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - R_INT (pr) = object_is_instance (pr, object); + R_INT (pr) = object_is_instance (probj, object); } static void @@ -1524,6 +1955,7 @@ rua__i_Object__hash (progs_t *pr) static void rua__i_Object_error_error_ (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &P_STRUCT (pr, pr_id_t, 0); const char *fmt = P_GSTRING (pr, 2); dstring_t *dstr = dstring_new (); @@ -1531,37 +1963,113 @@ rua__i_Object_error_error_ (progs_t *pr) pr_type_t **args = &pr->pr_params[3]; dsprintf (dstr, "error: %s (%s)\n%s", - PR_GetString (pr, object_get_class_name (pr, self)), - object_is_instance (pr, self) ? "instance" : "class", fmt); - obj_verror (pr, self, 0, dstr->str, count, args); + PR_GetString (pr, object_get_class_name (probj, self)), + object_is_instance (probj, self) ? "instance" : "class", fmt); + obj_verror (probj, self, 0, dstr->str, count, args); +} + +static int +obj_protocol_conformsToProtocol (probj_t *probj, pr_protocol_t *proto, + pr_protocol_t *protocol) +{ + progs_t *pr = probj->pr; + + pr_protocol_list_t *proto_list; + + if (!proto || !protocol) { + return 0; + } + if (proto == protocol) { + return 1; + } + if (proto->protocol_name == protocol->protocol_name + || strcmp (PR_GetString (pr, proto->protocol_name), + PR_GetString (pr, protocol->protocol_name)) == 0) { + return 1; + } + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto->protocol_list); + while (proto_list) { + Sys_MaskPrintf (SYS_RUA_OBJ, "%x %x %d\n", + PR_SetPointer (pr, proto_list), proto_list->next, + proto_list->count); + for (int i = 0; i < proto_list->count; i++) { + proto = &G_STRUCT (pr, pr_protocol_t, proto_list->list[i]); + if (proto == protocol + || obj_protocol_conformsToProtocol (probj, proto, protocol)) { + return 1; + } + } + + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto_list->next); + } + return 0; } static void rua__c_Object__conformsToProtocol_ (progs_t *pr) { - //pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - //pr_protocol_t *proto = &P_STRUCT (pr, pr_protocol_t, 2); - //... - //XXX - PR_RunError (pr, "%s, not implemented", __FUNCTION__); + probj_t *probj = pr->pr_objective_resources; + // class points to _OBJ_CLASS_foo, and class->class_pointer points to + // _OBJ_METACLASS_foo + pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); + // protocol->class_pointer must point to _OBJ_CLASS_Protocol (ie, if + // protocol is not actually a protocol, then the class cannot conform + // to it) + pr_protocol_t *protocol = &P_STRUCT (pr, pr_protocol_t, 2); + pr_protocol_list_t *proto_list; + + if (!class || !protocol) { + goto not_conforms; + } + if (protocol->class_pointer != PR_SetPointer (pr, + Hash_Find (probj->classes, + "Protocol"))) { + goto not_conforms; + } + proto_list = &G_STRUCT (pr, pr_protocol_list_t, class->protocols); + while (proto_list) { + Sys_MaskPrintf (SYS_RUA_OBJ, "%x %x %d\n", + PR_SetPointer (pr, proto_list), proto_list->next, + proto_list->count); + for (int i = 0; i < proto_list->count; i++) { + __auto_type proto = &G_STRUCT (pr, pr_protocol_t, + proto_list->list[i]); + if (proto == protocol + || obj_protocol_conformsToProtocol (probj, proto, protocol)) { + goto conforms; + } + } + + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto_list->next); + } +not_conforms: + Sys_MaskPrintf (SYS_RUA_OBJ, "does not conform\n"); + R_INT (pr) = 0; + return; +conforms: + Sys_MaskPrintf (SYS_RUA_OBJ, "conforms\n"); + R_INT (pr) = 1; + return; } static void rua_PR_FindGlobal (progs_t *pr) { const char *name = P_GSTRING (pr, 0); - ddef_t *def; + pr_def_t *def; R_POINTER (pr) = 0; def = PR_FindGlobal (pr, name); if (def) - R_POINTER (pr) = def->ofs; //FIXME def's can't access > 32k + R_POINTER (pr) = def->ofs; } //==================================================================== static builtin_t obj_methods [] = { {"__obj_exec_class", rua___obj_exec_class, -1}, + {"__obj_forward", rua___obj_forward, -1}, + {"__obj_responds_to", rua___obj_responds_to, -1}, {"obj_error", rua_obj_error, -1}, {"obj_verror", rua_obj_verror, -1}, @@ -1631,20 +2139,21 @@ static builtin_t obj_methods [] = { static int rua_init_finish (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t **class_list, **class; - class_list = (pr_class_t **) Hash_GetList (pr->classes); + class_list = (pr_class_t **) Hash_GetList (probj->classes); if (*class_list) { pr_class_t *object_class; pointer_t object_ptr; - object_class = Hash_Find (pr->classes, "Object"); + object_class = Hash_Find (probj->classes, "Object"); if (object_class && !object_class->super_class) object_ptr = (pr_type_t *)object_class - pr->pr_globals; else PR_Error (pr, "root class Object not found"); for (class = class_list; *class; class++) - finish_class (pr, *class, object_ptr); + finish_class (probj, *class, object_ptr); } free (class_list); @@ -1652,59 +2161,91 @@ rua_init_finish (progs_t *pr) } static int -rua_init_runtime (progs_t *pr) +rua_obj_init_runtime (progs_t *pr) { - ddef_t *def; - unsigned i; - - if (!pr->selector_hash) - pr->selector_hash = Hash_NewTable (1021, selector_get_key, 0, pr); - else - Hash_FlushTable (pr->selector_hash); - pr->selector_index = 0; - for (i = 0; i < pr->selector_index_max; i++) { - obj_list_free (pr->selector_sels[i]); - pr->selector_sels[i] = 0; - pr->selector_names[i] = 0; - } - - if (!pr->classes) - pr->classes = Hash_NewTable (1021, class_get_key, 0, pr); - else - Hash_FlushTable (pr->classes); - - if (!pr->load_methods) { - pr->load_methods = Hash_NewTable (1021, 0, 0, pr); - Hash_SetHashCompare (pr->load_methods, load_methods_get_hash, - load_methods_compare); - } else { - Hash_FlushTable (pr->load_methods); - } - - pr->unresolved_classes = 0; - pr->unclaimed_categories = 0; - pr->unclaimed_proto_list = 0; - pr->module_list = 0; - pr->class_tree_list = 0; + probj_t *probj = pr->pr_objective_resources; + pr_def_t *def; + dfunction_t *obj_forward; if ((def = PR_FindField (pr, ".this"))) pr->fields.this = def->ofs; + probj->obj_forward = 0; + if ((obj_forward = PR_FindFunction (pr, "__obj_forward"))) { + probj->obj_forward = (intptr_t) (obj_forward - pr->pr_functions); + } + PR_AddLoadFinishFunc (pr, rua_init_finish); return 1; } +static void +rua_obj_cleanup (progs_t *pr, void *data) +{ + unsigned i; + + __auto_type probj = (probj_t *) data; + pr->pr_objective_resources = probj; + + Hash_FlushTable (probj->selector_hash); + probj->selector_index = 0; + for (i = 0; i < probj->selector_index_max; i++) { + obj_list_free (probj->selector_sels[i]); + probj->selector_sels[i] = 0; + probj->selector_names[i] = 0; + } + + for (i = 0; i < probj->dtables._size; i++) { + /* dtable_get expects a handle, but a handle is the ones-compliment + * negative of the index. + */ + dtable_t *dtable = dtable_get (probj, ~i); + if (!dtable->imp) { + break; + } + free (dtable->imp); + } + dtable_reset (probj); + + Hash_FlushTable (probj->classes); + Hash_FlushTable (probj->protocols); + Hash_FlushTable (probj->load_methods); + probj->unresolved_classes = 0; + probj->unclaimed_categories = 0; + probj->unclaimed_proto_list = 0; + probj->module_list = 0; + probj->class_tree_list = 0; +} + void RUA_Obj_Init (progs_t *pr, int secure) { + probj_t *probj = calloc (1, sizeof (*probj)); + + probj->pr = pr; + probj->selector_hash = Hash_NewTable (1021, selector_get_key, 0, probj, + pr->hashlink_freelist); + probj->classes = Hash_NewTable (1021, class_get_key, 0, probj, + pr->hashlink_freelist); + probj->protocols = Hash_NewTable (1021, protocol_get_key, 0, probj, + pr->hashlink_freelist); + probj->load_methods = Hash_NewTable (1021, 0, 0, probj, + pr->hashlink_freelist); + probj->msg = dstring_newstr(); + Hash_SetHashCompare (probj->load_methods, load_methods_get_hash, + load_methods_compare); + + PR_Resources_Register (pr, "RUA_ObjectiveQuakeC", probj, rua_obj_cleanup); + PR_RegisterBuiltins (pr, obj_methods); - PR_AddLoadFunc (pr, rua_init_runtime); + PR_AddLoadFunc (pr, rua_obj_init_runtime); } func_t RUA_Obj_msg_lookup (progs_t *pr, pointer_t _self, pointer_t __cmd) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &G_STRUCT (pr, pr_id_t, _self); pr_sel_t *_cmd = &G_STRUCT (pr, pr_sel_t, __cmd); func_t imp; @@ -1713,11 +2254,25 @@ RUA_Obj_msg_lookup (progs_t *pr, pointer_t _self, pointer_t __cmd) return 0; if (!_cmd) PR_RunError (pr, "null selector"); - imp = obj_msg_lookup (pr, self, _cmd); + imp = obj_msg_lookup (probj, self, _cmd); if (!imp) PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); return imp; } + +int +RUA_obj_increment_retaincount (progs_t *pr) +{ + rua_obj_increment_retaincount (pr); + return R_INT (pr); +} + +int +RUA_obj_decrement_retaincount (progs_t *pr) +{ + rua_obj_decrement_retaincount (pr); + return R_INT (pr); +} diff --git a/libs/ruamoko/rua_plist.c b/libs/ruamoko/rua_plist.c index 0fdb1ff8d..afccba62e 100644 --- a/libs/ruamoko/rua_plist.c +++ b/libs/ruamoko/rua_plist.c @@ -40,8 +40,8 @@ #include #include "QF/hash.h" +#include "QF/plist.h" #include "QF/progs.h" -#include "QF/qfplist.h" #include "rua_internal.h" @@ -63,31 +63,31 @@ typedef struct { static bi_plist_t * plist_new (plist_resources_t *res) { - PR_RESNEW (bi_plist_t, res->plist_map); + return PR_RESNEW (res->plist_map); } static void plist_free (plist_resources_t *res, bi_plist_t *plist) { - PR_RESFREE (bi_plist_t, res->plist_map, plist); + PR_RESFREE (res->plist_map, plist); } static void plist_reset (plist_resources_t *res) { - PR_RESRESET (bi_plist_t, res->plist_map); + PR_RESRESET (res->plist_map); } static inline bi_plist_t * plist_get (plist_resources_t *res, unsigned index) { - PR_RESGET(res->plist_map, index); + return PR_RESGET(res->plist_map, index); } -static inline int +static inline int __attribute__((pure)) plist_index (plist_resources_t *res, bi_plist_t *plist) { - PR_RESINDEX(res->plist_map, plist); + return PR_RESINDEX(res->plist_map, plist); } static void @@ -195,7 +195,7 @@ bi_PL_GetFromFile (progs_t *pr) Qread (file, buf, len); buf[len] = 0; - plitem = PL_GetPropertyList (buf); + plitem = PL_GetPropertyList (buf, pr->hashlink_freelist); R_INT (pr) = plist_retain (res, plitem); } @@ -204,7 +204,8 @@ static void bi_PL_GetPropertyList (progs_t *pr) { plist_resources_t *res = PR_Resources_Find (pr, "plist"); - plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0)); + plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0), + pr->hashlink_freelist); R_INT (pr) = plist_retain (res, plitem); } @@ -229,6 +230,15 @@ bi_PL_Type (progs_t *pr) R_INT (pr) = PL_Type (plist->plitem); } +static void +bi_PL_Line (progs_t *pr) +{ + int handle = P_INT (pr, 0); + bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle); + + R_INT (pr) = PL_Line (plist->plitem); +} + static void bi_PL_String (progs_t *pr) { @@ -364,7 +374,7 @@ static void bi_PL_NewDictionary (progs_t *pr) { plist_resources_t *res = PR_Resources_Find (pr, "plist"); - plitem_t *plitem = PL_NewDictionary (); + plitem_t *plitem = PL_NewDictionary (pr->hashlink_freelist); R_INT (pr) = plist_retain (res, plitem); } @@ -432,6 +442,7 @@ static builtin_t builtins[] = { {"PL_GetPropertyList", bi_PL_GetPropertyList, -1}, {"PL_WritePropertyList", bi_PL_WritePropertyList, -1}, {"PL_Type", bi_PL_Type, -1}, + {"PL_Line", bi_PL_Line, -1}, {"PL_String", bi_PL_String, -1}, {"PL_ObjectForKey", bi_PL_ObjectForKey, -1}, {"PL_RemoveObjectForKey", bi_PL_RemoveObjectForKey, -1}, @@ -455,7 +466,7 @@ void RUA_Plist_Init (progs_t *pr, int secure) { plist_resources_t *res = calloc (1, sizeof (plist_resources_t)); - res->plist_tab = Hash_NewTable (1021, 0, 0, 0); + res->plist_tab = Hash_NewTable (1021, 0, 0, 0, pr->hashlink_freelist); Hash_SetHashCompare (res->plist_tab, plist_get_hash, plist_compare); PR_Resources_Register (pr, "plist", res, bi_plist_clear); diff --git a/libs/ruamoko/rua_qfile.c b/libs/ruamoko/rua_qfile.c index 057ff0ef6..8c6c45ef1 100644 --- a/libs/ruamoko/rua_qfile.c +++ b/libs/ruamoko/rua_qfile.c @@ -38,9 +38,7 @@ #include "QF/dstring.h" #include "QF/progs.h" -#include "QF/quakefs.h" -#include "QF/va.h" -#include "QF/zone.h" +#include "QF/quakeio.h" #include "rua_internal.h" @@ -58,31 +56,31 @@ typedef struct { static qfile_t * handle_new (qfile_resources_t *res) { - PR_RESNEW (qfile_t, res->handle_map); + return PR_RESNEW (res->handle_map); } static void handle_free (qfile_resources_t *res, qfile_t *handle) { - PR_RESFREE (qfile_t, res->handle_map, handle); + PR_RESFREE (res->handle_map, handle); } static void handle_reset (qfile_resources_t *res) { - PR_RESRESET (qfile_t, res->handle_map); + PR_RESRESET (res->handle_map); } static inline qfile_t * handle_get (qfile_resources_t *res, int index) { - PR_RESGET(res->handle_map, index); + return PR_RESGET(res->handle_map, index); } -static inline int +static inline int __attribute__((pure)) handle_index (qfile_resources_t *res, qfile_t *handle) { - PR_RESINDEX(res->handle_map, handle); + return PR_RESINDEX(res->handle_map, handle); } static void diff --git a/libs/ruamoko/rua_qfs.c b/libs/ruamoko/rua_qfs.c index 35d69d0c8..4a3eebb59 100644 --- a/libs/ruamoko/rua_qfs.c +++ b/libs/ruamoko/rua_qfs.c @@ -146,7 +146,8 @@ bi_QFS_WriteFile (progs_t *pr) int count = P_INT (pr, 2); check_buffer (pr, buf, count, "QFS_WriteFile"); - QFS_WriteFile (va ("%s/%s", qfs_gamedir->dir.def, filename), buf, count); + QFS_WriteFile (va (0, "%s/%s", qfs_gamedir->dir.def, filename), buf, + count); } static void @@ -181,6 +182,12 @@ bi_QFS_FilelistFree (progs_t *pr) PR_Zone_Free (pr, list); } +static void +bi_QFS_GetDirectory (progs_t *pr) +{ + RETURN_STRING (pr, qfs_gamedir->dir.def); +} + static builtin_t builtins[] = { {"QFS_Open", bi_QFS_Open, -1}, {"QFS_WOpen", bi_QFS_WOpen, -1}, @@ -190,6 +197,7 @@ static builtin_t builtins[] = { {"QFS_WriteFile", bi_QFS_WriteFile, -1}, {"QFS_Filelist", bi_QFS_Filelist, -1}, {"QFS_FilelistFree", bi_QFS_FilelistFree, -1}, + {"QFS_GetDirectory", bi_QFS_GetDirectory, -1}, {0} }; diff --git a/libs/ruamoko/rua_runtime.c b/libs/ruamoko/rua_runtime.c new file mode 100644 index 000000000..24a8a894d --- /dev/null +++ b/libs/ruamoko/rua_runtime.c @@ -0,0 +1,81 @@ +/* + bi_runtime.c + + QuakeC runtime api + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/4/1 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#if defined(_WIN32) && defined(HAVE_MALLOC_H) +#include +#endif + +#include "QF/progs.h" + +#include "rua_internal.h" + +static void +bi_va_copy (progs_t *pr) +{ + __auto_type src_args = (pr_va_list_t *) &P_POINTER (pr, 0); + __auto_type src_list = &G_STRUCT (pr, pr_type_t, src_args->list); + size_t parm_size = pr->pr_param_size * sizeof(pr_type_t); + size_t size = src_args->count * parm_size; + string_t dst_list_block = 0; + pr_type_t *dst_list = 0; + + if (size) { + dst_list_block = PR_AllocTempBlock (pr, size); + dst_list = (pr_type_t *) PR_GetString (pr, dst_list_block); + } + + memcpy (dst_list, src_list, size); + R_PACKED (pr, pr_va_list_t).count = src_args->count; + R_PACKED (pr, pr_va_list_t).list = PR_SetPointer (pr, dst_list); +} + +static builtin_t builtins[] = { + {"va_copy", bi_va_copy, -1}, + {0} +}; + +void +RUA_Runtime_Init (progs_t *pr, int secure) +{ + PR_RegisterBuiltins (pr, builtins); +} diff --git a/libs/ruamoko/rua_script.c b/libs/ruamoko/rua_script.c index c6fae5750..4723bfcbe 100644 --- a/libs/ruamoko/rua_script.c +++ b/libs/ruamoko/rua_script.c @@ -48,7 +48,6 @@ typedef struct { script_t script; string_t dstr; progs_t *pr; - string_t err_msg; } rua_script_t; typedef struct { @@ -58,31 +57,31 @@ typedef struct { static rua_script_t * script_new (script_resources_t *res) { - PR_RESNEW (rua_script_t, res->scripts); + return PR_RESNEW (res->scripts); } static void script_free (script_resources_t *res, rua_script_t *script) { - PR_RESFREE (rua_script_t, res->scripts, script); + PR_RESFREE (res->scripts, script); } static void script_reset (script_resources_t *res) { - PR_RESRESET (rua_script_t, res->scripts); + PR_RESRESET (res->scripts); } static inline rua_script_t * script_get (script_resources_t *res, int index) { - PR_RESGET(res->scripts, index); + return PR_RESGET(res->scripts, index); } -static inline int +static inline int __attribute__((pure)) script_index (script_resources_t *res, rua_script_t *script) { - PR_RESINDEX(res->scripts, script); + return PR_RESINDEX(res->scripts, script); } static void @@ -92,13 +91,6 @@ bi_script_clear (progs_t *pr, void *data) script_reset (res); } -static void -bi_script_error (script_t *_script, const char *msg) -{ - rua_script_t *script = (rua_script_t *)_script; - script->err_msg = PR_SetString (script->pr, msg); -} - static void bi_Script_New (progs_t *pr) { @@ -110,7 +102,6 @@ bi_Script_New (progs_t *pr) script->dstr = PR_NewMutableString (pr); script->script.token = PR_GetMutableString (pr, script->dstr); - script->script.error = bi_script_error; script->pr = pr; R_INT (pr) = script_index (res, script); } @@ -180,8 +171,8 @@ bi_Script_Error (progs_t *pr) if (!script) PR_RunError (pr, "invalid script handle"); - R_STRING (pr) = script->err_msg; - script->err_msg = 0; + R_STRING (pr) = PR_SetString (pr, script->script.error); + script->script.error = 0; } static void diff --git a/libs/ruamoko/rua_set.c b/libs/ruamoko/rua_set.c index 0fdd964e7..343e0ced0 100644 --- a/libs/ruamoko/rua_set.c +++ b/libs/ruamoko/rua_set.c @@ -77,61 +77,61 @@ typedef struct { static bi_set_t * res_set_new (set_resources_t *res) { - PR_RESNEW (bi_set_t, res->set_map); + return PR_RESNEW (res->set_map); } static void res_set_free (set_resources_t *res, bi_set_t *set) { - PR_RESFREE (bi_set_t, res->set_map, set); + PR_RESFREE (res->set_map, set); } static void res_set_reset (set_resources_t *res) { - PR_RESRESET (bi_set_t, res->set_map); + PR_RESRESET (res->set_map); } static inline bi_set_t * res_set_get (set_resources_t *res, int index) { - PR_RESGET(res->set_map, index); + return PR_RESGET(res->set_map, index); } -static inline int +static inline int __attribute__((pure)) res_set_index (set_resources_t *res, bi_set_t *set) { - PR_RESINDEX(res->set_map, set); + return PR_RESINDEX(res->set_map, set); } static bi_set_iter_t * res_set_iter_new (set_resources_t *res) { - PR_RESNEW (bi_set_iter_t, res->set_iter_map); + return PR_RESNEW (res->set_iter_map); } static void res_set_iter_free (set_resources_t *res, bi_set_iter_t *set_iter) { - PR_RESFREE (bi_set_iter_t, res->set_iter_map, set_iter); + PR_RESFREE (res->set_iter_map, set_iter); } static void res_set_iter_reset (set_resources_t *res) { - PR_RESRESET (bi_set_iter_t, res->set_iter_map); + PR_RESRESET (res->set_iter_map); } static inline bi_set_iter_t * res_set_iter_get (set_resources_t *res, int index) { - PR_RESGET(res->set_iter_map, index); + return PR_RESGET(res->set_iter_map, index); } -static inline int +static inline int __attribute__((pure)) res_set_iter_index (set_resources_t *res, bi_set_iter_t *set_iter) { - PR_RESINDEX(res->set_iter_map, set_iter); + return PR_RESINDEX(res->set_iter_map, set_iter); } static bi_set_t * @@ -392,7 +392,7 @@ bi_set_first (progs_t *pr) res->set_iters->prev = &set_iter->next; res->set_iters = set_iter; - set_iter->iter = iter;; + set_iter->iter = iter; R_INT (pr) = res_set_iter_index (res, set_iter); } diff --git a/libs/ruamoko/rua_string.c b/libs/ruamoko/rua_string.c index 7f233e362..754d1627e 100644 --- a/libs/ruamoko/rua_string.c +++ b/libs/ruamoko/rua_string.c @@ -38,6 +38,7 @@ # include #endif #include +#include #include "qfalloca.h" @@ -50,6 +51,48 @@ #include "rua_internal.h" +static void +bi_strlen (progs_t *pr) +{ + const char *s; + + s = P_GSTRING (pr, 0); + R_INT (pr) = strlen(s); +} + +static void +bi_sprintf (progs_t *pr) +{ + const char *fmt = P_GSTRING (pr, 0); + int count = pr->pr_argc - 1; + pr_type_t **args = pr->pr_params + 1; + dstring_t *dstr; + + dstr = dstring_newstr (); + PR_Sprintf (pr, dstr, "bi_sprintf", fmt, count, args); + RETURN_STRING (pr, dstr->str); + dstring_delete (dstr); +} + +static void +bi_vsprintf (progs_t *pr) +{ + const char *fmt = P_GSTRING (pr, 0); + __auto_type args = &P_PACKED (pr, pr_va_list_t, 1); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + dstring_t *dstr; + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + dstr = dstring_newstr (); + PR_Sprintf (pr, dstr, "bi_vsprintf", fmt, args->count, list); + RETURN_STRING (pr, dstr->str); + dstring_delete (dstr); +} + static void bi_str_new (progs_t *pr) { @@ -62,6 +105,26 @@ bi_str_free (progs_t *pr) PR_FreeString (pr, P_STRING (pr, 0)); } +static void +bi_str_hold (progs_t *pr) +{ + string_t str = P_STRING (pr, 0); + PR_HoldString (pr, str); + R_STRING (pr) = str; +} + +static void +bi_str_valid (progs_t *pr) +{ + R_INT (pr) = PR_StringValid (pr, P_STRING (pr, 0)); +} + +static void +bi_str_mutable (progs_t *pr) +{ + R_INT (pr) = PR_StringMutable (pr, P_STRING (pr, 0)); +} + static void bi_str_copy (progs_t *pr) { @@ -112,6 +175,10 @@ bi_str_mid (progs_t *pr) end = size; if (pos < 0 || pos >= size || end <= pos) return; + if (end == size) { + R_STRING (pr) = str + pos - pr->pr_strings; + return; + } temp = alloca (end - pos + 1); strncpy (temp, str + pos, end - pos); temp[end - pos] = 0; @@ -125,20 +192,114 @@ bi_str_str (progs_t *pr) const char *needle = P_GSTRING (pr, 1); char *res = strstr (haystack, needle); - R_STRING (pr) = 0; - if (res) - R_STRING (pr) = res - pr->pr_strings; + R_INT (pr) = -1; + if (res) { + R_INT (pr) = res - haystack; + } +} + +static void +bi_str_char (progs_t *pr) +{ + const char *str = P_GSTRING (pr, 0); + int ind = P_INT (pr, 1); + + if (ind < 0) { + PR_RunError (pr, "negative index to str_char"); + } + R_INT (pr) = str[ind]; +} + +static void +bi_str_quote (progs_t *pr) +{ + const char *str = P_GSTRING (pr, 0); + // can have up to 4 chars per char (a -> \x61) + char *quote = alloca (strlen (str) * 4 + 1); + char *q = quote; + char c; + int h; + + while ((c = *str++)) { + if (c >= ' ' && c < 127 && c != '\"') { + *q++ = c; + } else { + *q++ = '\\'; + switch (c) { + case '\a': c = 'a'; break; + case '\b': c = 'b'; break; + case '\f': c = 'f'; break; + case '\n': c = 'n'; break; + case '\r': c = 'r'; break; + case '\t': c = 't'; break; + case '\"': c = '\"'; break; + default: + *q++ = 'x'; + h = (c & 0xf0) >> 4; + *q++ = h > 9 ? h + 'a' - 10 : h + '0'; + h = (c & 0x0f); + c = h > 9 ? h + 'a' - 10 : h + '0'; + break; + } + *q++ = c; + } + } + *q++ = 0; + + RETURN_STRING (pr, quote); +} + +static void +bi_str_lower (progs_t *pr) +{ + const char *str = P_GSTRING (pr, 0); + char *lower = alloca (strlen (str) + 1); + char *l = lower; + byte c; + + while ((c = *str++)) { + *l++ = tolower (c); + } + *l++ = 0; + + RETURN_STRING (pr, lower); +} + +static void +bi_str_upper (progs_t *pr) +{ + const char *str = P_GSTRING (pr, 0); + char *upper = alloca (strlen (str) + 1); + char *l = upper; + byte c; + + while ((c = *str++)) { + *l++ = toupper (c); + } + *l++ = 0; + + RETURN_STRING (pr, upper); } static builtin_t builtins[] = { + {"strlen", bi_strlen, -1}, + {"sprintf", bi_sprintf, -1}, + {"vsprintf", bi_vsprintf, -1}, {"str_new", bi_str_new, -1}, {"str_free", bi_str_free, -1}, + {"str_hold", bi_str_hold, -1}, + {"str_valid", bi_str_valid, -1}, + {"str_mutable", bi_str_mutable, -1}, {"str_copy", bi_str_copy, -1}, {"str_cat", bi_str_cat, -1}, {"str_clear", bi_str_clear, -1}, {"str_mid|*i", bi_str_mid, -1}, {"str_mid|*ii", bi_str_mid, -1}, {"str_str", bi_str_str, -1}, + {"str_char", bi_str_char, -1}, + {"str_quote", bi_str_quote, -1}, + {"str_lower", bi_str_lower, -1}, + {"str_upper", bi_str_upper, -1}, {0} }; diff --git a/libs/util/Makefile.am b/libs/util/Makefile.am deleted file mode 100644 index 0c6421450..000000000 --- a/libs/util/Makefile.am +++ /dev/null @@ -1,59 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= . test - -AM_CFLAGS= @PREFER_PIC@ -CCASFLAGS+= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(Z_CFLAGS) $(FNM_FLAGS) - -lib_LTLIBRARIES= libQFutil.la - -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined - -if ASM_ARCH -asm= libasm.la -else -asm= -endif - -noinst_LTLIBRARIES= $(asm) -#EXTRA_LTLIBRARIES= libasm.la - -libasm_la_SOURCES= math.S sys_ia32.S - - -dirent_src= dirent.c -fnmatch_src= fnmatch.c -getopt_src= getopt.c getopt1.c - -if BUILD_DIRENT -dirent= $(dirent_src) -else -dirent= -endif - -if BUILD_FNMATCH -fnmatch= $(fnmatch_src) -else -fnmatch= -endif - -if BUILD_GETOPT -getopt= $(getopt_src) -else -getopt= -endif - -libQFutil_la_LDFLAGS= $(lib_ldflags) -libQFutil_la_LIBADD= $(asm) $(Z_LIBS) $(DL_LIBS) $(WIN32_LIBS) -libQFutil_la_DEPENDENCIES= $(asm) -libQFutil_la_SOURCES= \ - bspfile.c buildnum.c cbuf.c checksum.c cmd.c crc.c cvar.c dstring.c \ - fendian.c hash.c idparse.c info.c link.c llist.c \ - mathlib.c mdfour.c mersenne.c msg.c pakfile.c plugin.c qargs.c qendian.c \ - qfplist.c quakefs.c quakeio.c riff.c script.c segtext.c set.c sizebuf.c \ - string.c sys.c va.c ver_check.c vrect.c wad.c wadfile.c zone.c \ - $(dirent) $(fnmatch) $(getopt) - -EXTRA_DIST= $(fnmatch_src) $(getopt_src) diff --git a/libs/util/Makemodule.am b/libs/util/Makemodule.am new file mode 100644 index 000000000..95ce152b9 --- /dev/null +++ b/libs/util/Makemodule.am @@ -0,0 +1,99 @@ +include libs/util/test/Makemodule.am + +lib_LTLIBRARIES += libs/util/libQFutil.la + +if ASM_ARCH +util_asm= libs/util/libasm.la +else +util_asm= +endif + +noinst_LTLIBRARIES += $(util_asm) +#EXTRA_LTLIBRARIES += libasm.la + +libs_util_libasm_la_SOURCES = libs/util/math.S libs/util/sys_ia32.S + + +dirent_src= libs/util/dirent.c +fnmatch_src= libs/util/fnmatch.c +getopt_src= libs/util/getopt.c libs/util/getopt1.c + +if BUILD_DIRENT +dirent= $(dirent_src) +else +dirent= +endif + +if BUILD_FNMATCH +fnmatch= $(fnmatch_src) +else +fnmatch= +endif + +if BUILD_GETOPT +getopt= $(getopt_src) +else +getopt= +endif + +libs_util_libQFutil_la_LDFLAGS= $(lib_ldflags) +libs_util_libQFutil_la_LIBADD= $(util_asm) $(Z_LIBS) $(DL_LIBS) $(WIN32_LIBS) +libs_util_libQFutil_la_DEPENDENCIES= $(util_asm) +libs_util_libQFutil_la_SOURCES= \ + libs/util/bspfile.c \ + libs/util/buildnum.c \ + libs/util/cbuf.c \ + libs/util/cexpr-lex.l \ + libs/util/cexpr-parse.y \ + libs/util/cexpr-type.c \ + libs/util/cexpr-vars.c \ + libs/util/checksum.c \ + libs/util/cmd.c \ + libs/util/cmem.c \ + libs/util/crc.c \ + libs/util/cvar.c \ + libs/util/dstring.c \ + libs/util/fendian.c \ + libs/util/hash.c \ + libs/util/idparse.c \ + libs/util/info.c \ + libs/util/link.c \ + libs/util/llist.c \ + libs/util/mathlib.c \ + libs/util/mdfour.c \ + libs/util/mersenne.c \ + libs/util/msg.c \ + libs/util/pakfile.c \ + libs/util/plist.c \ + libs/util/plugin.c \ + libs/util/qargs.c \ + libs/util/qendian.c \ + libs/util/quakefs.c \ + libs/util/quakeio.c \ + libs/util/riff.c \ + libs/util/script.c \ + libs/util/segtext.c \ + libs/util/set.c \ + libs/util/simd.c \ + libs/util/sizebuf.c \ + libs/util/string.c \ + libs/util/sys.c \ + libs/util/txtbuffer.c \ + libs/util/va.c \ + libs/util/ver_check.c \ + libs/util/vrect.c \ + libs/util/wad.c \ + libs/util/wadfile.c \ + libs/util/zone.c \ + $(dirent) $(fnmatch) $(getopt) + +BUILT_SOURCES += \ + libs/util/cexpr-lex.c \ + libs/util/cexpr-parse.c + +libs/util/cexpr-parse.c: libs/util/cexpr-parse.y + $(AM_V_YACC)$(YACCCOMPILE) $< -o $@ +libs/util/cexpr-lex.c: libs/util/cexpr-lex.l libs/util/cexpr-parse.h + $(AM_V_LEX)$(LEXCOMPILE) -o$@ $< + +EXTRA_DIST += $(fnmatch_src) $(getopt_src) diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l new file mode 100644 index 000000000..3fafef8e6 --- /dev/null +++ b/libs/util/cexpr-lex.l @@ -0,0 +1,302 @@ +/* + cexpr-lex.l + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +%option bison-bridge +%option reentrant +%option prefix="cexpr_yy" +%option noyywrap + +%{ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include +#include + +#include "QF/cmem.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/plist.h" +#include "QF/sys.h" + +#define CEXPR_YYDEBUG 1 + +#include "QF/cexpr.h" +#include "libs/util/cexpr-parse.h" + +#define YY_NO_INPUT +#define YY_NO_UNPUT + +#define YYSTYPE CEXPR_YYSTYPE +#define YY_EXTRA_TYPE exprctx_t * + +exprctx_t *cexpr_yyget_extra (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_lineno (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_column (yyscan_t yyscanner) __attribute__((pure)); +YYSTYPE *cexpr_yyget_lval (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_debug (yyscan_t yyscanner) __attribute__((pure)); +char *cexpr_yyget_text (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_leng (yyscan_t yyscanner) __attribute__((pure)); +FILE *cexpr_yyget_out (yyscan_t yyscanner) __attribute__((pure)); +FILE *cexpr_yyget_in (yyscan_t yyscanner) __attribute__((pure)); + +static exprval_t *parse_int (const char *str, exprctx_t *context); +static exprval_t *parse_uint (const char *str, exprctx_t *context); +static exprval_t *parse_size_t (const char *str, exprctx_t *context); +static exprval_t *parse_float (const char *str, exprctx_t *context); +static exprval_t *parse_double (const char *str, exprctx_t *context); +static exprsym_t *parse_name (const char *str, exprctx_t *context); +static exprval_t *parse_variable (const char *str, exprctx_t *context); + +VISIBLE void +cexpr_error(exprctx_t *ctx, const char *fmt, ...) +{ + va_list args; + dstring_t *string; + + ctx->errors++; + + string = dstring_new (); + + va_start (args, fmt); + dvsprintf (string, fmt, args); + va_end (args); + + if (ctx->messages) { + PL_Message (ctx->messages, ctx->item, "%s", string->str); + } else { + Sys_Printf ("%s\n", string->str); + } + dstring_delete (string); +} + +%} + +s [ \t] +m [\-+] +D [0-9] +B [01] +X [0-9a-fA-F] +ID [a-zA-Z_][a-zA-Z_0-9]* +FLOAT ({D}+|{D}*\.{D}+|{D}+\.{D}*)([eE]{m}?{D}+)? +FLOATf {FLOAT}[fF] +FLOATd {FLOAT}[dD] +INT ({D}+|0[xX]{X}+|0[bB]{B}) +STRING \"(\\.|[^"\\])*\" + +%% +%{ + __auto_type context = yyget_extra (yyscanner); +%} + +{INT}+[uU] { + yylval->value = parse_uint (yytext, context); + return VALUE; + } + +{INT}+ { + yylval->value = parse_int (yytext, context); + return VALUE; + } + +{INT}+[zZ] { + yylval->value = parse_size_t (yytext, context); + return VALUE; + } + +{FLOAT} { + yylval->value = parse_double (yytext, context); + return VALUE; + } +{FLOATf} { + yylval->value = parse_float (yytext, context); + return VALUE; + } +{FLOATd} { + yylval->value = parse_double (yytext, context); + return VALUE; + } + +{ID} { + yylval->symbol = parse_name (yytext, context); + return NAME; + } + +\${ID} { + yylval->value = parse_variable (yytext + 1, context); + return VALUE; + } + +{STRING} { + } +@ return '@'; + +'(\\[^xX0-7\r\n]|[^'\r\n]|\\[xX][0-9A-Fa-f]+|\\[0-7]+)*' { + } + +[+\-*/&|^%]= { + } + +"%%=" { + } + +"<<=" { + } + +">>=" { + } + +[!(){}.*/&|^~+\-=\[\];,#%?:] { + return yytext[0]; + } + +"%%" { + } + +"<<" return SHL; +">>" return SHR; + +"&&" return AND; +"||" return OR; +"==" return EQ; +"!=" return NE; +"<=" return LE; +">=" return GE; +"<" return LT; +">" return GT; + +"++" { + } + +"--" { + } + +<*>\r*\n { + } + +<*>{s}* /* skip */ + +<*>. cexpr_error (context, "all your typo are belong to us"); + +%% + +VISIBLE int +cexpr_eval_string (const char *str, exprctx_t *context) +{ + int status; + yyscan_t scanner; + cexpr_yypstate *ps = cexpr_yypstate_new (); + + yylex_init_extra (context, &scanner); + yy_scan_string (str, scanner); + + context->errors = 0; + do { + CEXPR_YYSTYPE lval; + int token = yylex (&lval, scanner); + status = cexpr_yypush_parse (ps, token, &lval, scanner, context); + } while (status == YYPUSH_MORE); + + yylex_destroy (scanner); + cexpr_yypstate_delete (ps); + return status || context->errors; +} + +static exprval_t *parse_int (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_int, context); + *(int *) val->value = strtoimax (str, 0, 0); + return val; +} + +static exprval_t *parse_uint (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_uint, context); + *(unsigned *) val->value = strtoumax (str, 0, 0); + return val; +} + +static exprval_t *parse_size_t (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_size_t, context); + *(unsigned *) val->value = strtoumax (str, 0, 0); + return val; +} + +static exprval_t *parse_float (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_float, context); + *(float *) val->value = strtof (str, 0); + return val; +} + +static exprval_t *parse_double (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_double, context); + *(double *) val->value = strtod (str, 0); + return val; +} + +static exprsym_t * +parse_name (const char *name, exprctx_t *context) +{ + exprtab_t *symtab = context->symtab; + + if (!symtab) { + return 0; + } + __auto_type sym = (exprsym_t *) Hash_Find (symtab->tab, name); + return sym; +} + +static exprval_t * +parse_variable (const char *name, exprctx_t *context) +{ + exprval_t *val = 0; + if (strcmp (name, "cvars") == 0) { + val = cexpr_cvar_struct (context); + } else { + exprtab_t *symtab = context->external_variables; + __auto_type sym = (exprsym_t *) Hash_Find (symtab->tab, name); + if (sym) { + val = cexpr_value_reference (sym->type, sym->value, context); + } else { + //val = cexpr_cvar (name, context); + } + } + if (!val) { + cexpr_error (context, "undefined variable %s", name); + } + return val; +} diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y new file mode 100644 index 000000000..fca9171af --- /dev/null +++ b/libs/util/cexpr-parse.y @@ -0,0 +1,419 @@ +/* + cexpr-parse.y + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +%define api.prefix {cexpr_yy} +%define api.pure full +%define api.push-pull push +%define parse.trace +%parse-param {void *scanner} {exprctx_t *context} + +%{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/cmem.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/plist.h" +#include "QF/sys.h" + +#include "QF/cexpr.h" + +static void assign_expr (exprval_t *dst, const exprval_t *src, + exprctx_t *context); +static exprval_t *binary_expr (int op, const exprval_t *a, const exprval_t *b, + exprctx_t *context); +static exprval_t *field_expr (const exprval_t *a, const exprval_t *b, + exprctx_t *context); +static exprval_t *index_expr (const exprval_t *a, const exprval_t *b, + exprctx_t *context); +static exprval_t *unary_expr (int op, const exprval_t *val, + exprctx_t *context); +static exprval_t *vector_expr (exprlist_t *list, exprctx_t *context); +static exprval_t *function_expr (exprsym_t *fsym, exprlist_t *list, + exprctx_t *context); +static exprlist_t *expr_item (exprval_t *val, exprctx_t *context); + +static void +yyerror (void *scanner, exprctx_t *context, const char *s) +{ + cexpr_error (context, "%s before %s", s, cexpr_yyget_text (scanner)); +} + +%} + +%left COMMA +%right '=' ASX +%right '?' ':' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQ NE +%left LE GE LT GT + +%left SHL SHR +%left '+' '-' +%left '*' '/' '%' MOD +%right SIZEOF UNARY INCOP +%left HYPERUNARY +%left '.' '(' '[' + +%token NAME +%token VALUE + +%type expr field uexpr +%type opt_arg_list arg_list arg_expr + +%union { + int op; + exprsym_t *symbol; + exprval_t *value; + exprlist_t *list; + const char *string; +} + +%% + +start + : expr { assign_expr (context->result, $1, context); } + ; + +uexpr + : NAME + { + if ($1) { + $$ = (exprval_t *) cmemalloc (context->memsuper, sizeof (*$$)); + $$->type = $1->type; + $$->value = $1->value; + } else { + cexpr_error (context, "undefined identifier %s", + cexpr_yyget_text (scanner)); + } + } + | VALUE + | '[' arg_list ']' { $$ = vector_expr ($2, context); } + | '(' expr ')' { $$ = $2; } + | NAME '(' opt_arg_list ')' { $$ = function_expr ($1, $3, context); } + | uexpr '.' field { $$ = field_expr ($1, $3, context); } + | uexpr '[' expr ']' { $$ = index_expr ($1, $3, context); } + | '+' uexpr %prec UNARY { $$ = $2; } + | '-' uexpr %prec UNARY { $$ = unary_expr ('-', $2, context); } + | '!' uexpr %prec UNARY { $$ = unary_expr ('!', $2, context); } + | '~' uexpr %prec UNARY { $$ = unary_expr ('~', $2, context); } + ; + +expr + : uexpr + | expr SHL expr { $$ = binary_expr (SHL, $1, $3, context); } + | expr SHR expr { $$ = binary_expr (SHR, $1, $3, context); } + | expr '+' expr { $$ = binary_expr ('+', $1, $3, context); } + | expr '-' expr { $$ = binary_expr ('-', $1, $3, context); } + | expr '*' expr { $$ = binary_expr ('*', $1, $3, context); } + | expr '/' expr { $$ = binary_expr ('/', $1, $3, context); } + | expr '&' expr { $$ = binary_expr ('&', $1, $3, context); } + | expr '|' expr { $$ = binary_expr ('|', $1, $3, context); } + | expr '^' expr { $$ = binary_expr ('^', $1, $3, context); } + | expr '%' expr { $$ = binary_expr ('%', $1, $3, context); } + | expr MOD expr { $$ = binary_expr (MOD, $1, $3, context); } + ; + +field + : NAME + { + exprctx_t *ctx = context; + const char *name = cexpr_yyget_text (scanner); + size_t size = strlen (name) + 1; + //FIXME reuse strings + $$ = (exprval_t *) cmemalloc (ctx->memsuper, sizeof (exprval_t)); + $$->type = &cexpr_field; + $$->value = cmemalloc (ctx->memsuper, size); + memcpy ($$->value, name, size); + } + ; + +opt_arg_list + : { $$ = 0; } + | arg_list { $$ = $1; } + ; + +arg_list + : arg_expr + | arg_list ',' arg_expr + { + $3-> next = $1; + $$ = $3; + } + +arg_expr + : expr { $$ = expr_item ($1, context); } + ; + +%% + +static void +assign_expr (exprval_t *dst, const exprval_t *src, exprctx_t *context) +{ + binop_t *binop; + if (!src) { + return; + } + if (dst->type == &cexpr_exprval) { + *(exprval_t **) dst->value = (exprval_t *) src; + return; + } + binop = cexpr_find_cast (dst->type, src->type); + if (binop && binop->op) { + binop->func (dst, src, dst, context); + } else { + if (dst->type != src->type) { + cexpr_error (context, + "type mismatch in expression result: %s = %s", + dst->type->name, src->type->name); + return; + } + memcpy (dst->value, src->value, dst->type->size); + } +} + +static exprval_t * +binary_expr (int op, const exprval_t *a, const exprval_t *b, + exprctx_t *context) +{ + binop_t *binop; + + for (binop = a->type->binops; binop->op; binop++) { + exprtype_t *otype = binop->other; + if (!otype) { + otype = a->type; + } + if (binop->op == op && otype == b->type) { + break; + } + } + exprtype_t *rtype = binop->result; + if (!rtype) { + rtype = a->type; + } + exprval_t *result = cexpr_value (rtype, context); + if (!binop->op) { + cexpr_error (context, "invalid binary expression: %s %c %s", + a->type->name, op, b->type->name); + memset (result->value, 0, rtype->size); + } else { + binop->func (a, b, result, context); + } + return result; +} + +static exprval_t * +field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) +{ + binop_t *binop; + exprval_t *result = 0; + + if (!a) { + return 0; + } + + for (binop = a->type->binops; binop->op; binop++) { + if (binop->op == '.' && binop->other == b->type) { + break; + } + } + if (!binop->op) { + cexpr_error (context, "invalid binary expression: %s.%s", + a->type->name, b->type->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + } else { + exprval_t c = { 0, &result }; + binop->func (a, b, &c, context); + } + return result; +} + +static exprval_t * +index_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) +{ + binop_t *binop; + exprval_t *result = 0; + + if (!a || !b) { + return 0; + } + for (binop = a->type->binops; binop->op; binop++) { + if (binop->op == '[' && binop->other == b->type) { + break; + } + } + if (!binop->op) { + cexpr_error (context, "invalid index expression: %s.%s", + a->type->name, b->type->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + } else { + exprval_t c = { 0, &result }; + binop->func (a, b, &c, context); + } + return result; +} + +static exprval_t * +unary_expr (int op, const exprval_t *val, exprctx_t *context) +{ + unop_t *unop; + + for (unop = val->type->unops; unop->op; unop++) { + if (unop->op == op) { + break; + } + } + exprtype_t *rtype = unop->result; + if (!rtype) { + rtype = val->type; + } + exprval_t *result = cexpr_value (rtype, context); + if (!unop->op) { + cexpr_error (context, "invalid unary expression: %c %s", + op, val->type->name); + } else { + unop->func (val, result, context); + } + return result; +} + +exprval_t * +vector_expr (exprlist_t *list, exprctx_t *context) +{ + exprlist_t *l; + exprval_t *val = cexpr_value (&cexpr_vector, context); + float *vector = val->value; + int i; + exprlist_t *rlist = 0; + + // list is built in reverse order, so need to reverse it to make converting + // to an array easier + while (list) { + exprlist_t *t = list->next; + list->next = rlist; + rlist = list; + list = t; + } + list = rlist; + + for (i = 0; i < 4 && list; i++, list = l) { + exprval_t dst = { &cexpr_float, &vector[i] }; + exprval_t *src = list->value; + binop_t *cast = cexpr_find_cast (&cexpr_float, src->type); + if (cast) { + cast->func (&dst, src, &dst, context); + } else { + cexpr_error (context, "invalid vector expression type: [%d] %s", + i, val->type->name); + } + l = list->next; + cmemfree (context->memsuper, list); + } + if (i == 4 && list) { + cexpr_error (context, "excess elements in vector expression"); + } + for ( ; i < 4; i++) { + vector[i] = 0; + } + return val; +} + +static exprval_t *function_expr (exprsym_t *fsym, exprlist_t *list, + exprctx_t *context) +{ + exprlist_t *l; + int num_args = 0; + exprfunc_t *func = 0; + exprval_t *result; + + for (l = list; l; l = l->next) { + num_args++; + } + __auto_type args = (const exprval_t **) alloca (num_args * sizeof (exprval_t *)); + __auto_type types = (exprtype_t **) alloca (num_args * sizeof (exprtype_t *)); + for (num_args = 0; list; list = l, num_args++) { + args[num_args] = list->value; + types[num_args] = list->value->type; + l = list->next; + cmemfree (context->memsuper, list); + } + if (fsym->type != &cexpr_function) { + cexpr_error (context, "invalid function %s", fsym->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + return result; + } + for (exprfunc_t *f = fsym->value; f->result; f++) { + if (f->num_params == num_args + && memcmp (f->param_types, types, + num_args * sizeof (exprtype_t *)) == 0) { + func = f; + break; + } + } + if (!func) { + dstring_t *argstr = dstring_newstr(); + for (int i = 0; i < num_args; i++) { + dasprintf (argstr, "%s%s", types[i]->name, + i + 1 < num_args ? ", ": ""); + } + cexpr_error (context, "no overload for %s(%s)", fsym->name, + argstr->str); + dstring_delete (argstr); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + return result; + } + result = cexpr_value (func->result, context); + func->func (args, result, context); + return result; +} + +static exprlist_t * +expr_item (exprval_t *val, exprctx_t *context) +{ + __auto_type item = (exprlist_t *) cmemalloc (context->memsuper, + sizeof (exprlist_t)); + item->next = 0; + item->value = val; + return item; +} diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c new file mode 100644 index 000000000..7ee34f5c2 --- /dev/null +++ b/libs/util/cexpr-type.c @@ -0,0 +1,730 @@ +/* + cexpr-type.c + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "QF/cexpr.h" +#include "QF/cmem.h" +#include "QF/mathlib.h" +#include "QF/plist.h" +#include "QF/simd/vec4f.h" + +#include "libs/util/cexpr-parse.h" + +#define BINOP(pre, opname, type, op) \ +static void \ +pre##_##opname (const exprval_t *a, const exprval_t *b, exprval_t *c, \ + exprctx_t *ctx) \ +{ \ + (*(type *) c->value) = (*(type *) a->value) op (*(type *) b->value); \ +} + +#define UNOP(pre, opname, type, op) \ +static void \ +pre##_##opname (const exprval_t *a, exprval_t *b, exprctx_t *ctx) \ +{ \ + (*(type *) b->value) = op (*(type *) a->value); \ +} + +BINOP(int, shl, int, <<) +BINOP(int, shr, int, >>) +BINOP(int, add, int, +) +BINOP(int, sub, int, -) +BINOP(int, mul, int, *) +BINOP(int, div, int, /) +BINOP(int, band, int, &) +BINOP(int, bor, int, |) +BINOP(int, xor, int, ^) +BINOP(int, rem, int, %) + +UNOP(int, pos, int, +) +UNOP(int, neg, int, -) +UNOP(int, tnot, int, !) +UNOP(int, bnot, int, ~) + +static void +int_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for integers: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + int a = *(int *) val1->value; + int b = *(int *) val2->value; + int c = a % b; + // % is really remainder and so has the same sign rules + // as division: -5 % 3 = -2, so need to add b (3 here) + // if c's sign is incorrect, but only if c is non-zero + int mask = (a ^ b) >> 31; + mask &= ~(!!c + 0) + 1; // +0 to convert bool to int (gcc) + *(int *) result->value = c + (mask & b); +} + +binop_t int_binops[] = { + { SHL, &cexpr_int, &cexpr_int, int_shl }, + { SHR, &cexpr_int, &cexpr_int, int_shr }, + { '+', &cexpr_int, &cexpr_int, int_add }, + { '-', &cexpr_int, &cexpr_int, int_sub }, + { '*', &cexpr_int, &cexpr_int, int_mul }, + { '/', &cexpr_int, &cexpr_int, int_div }, + { '&', &cexpr_int, &cexpr_int, int_band }, + { '|', &cexpr_int, &cexpr_int, int_bor }, + { '^', &cexpr_int, &cexpr_int, int_xor }, + { '%', &cexpr_int, &cexpr_int, int_rem }, + { MOD, &cexpr_int, &cexpr_int, int_mod }, + { '=', &cexpr_plitem, &cexpr_int, cexpr_cast_plitem }, + {} +}; + +unop_t int_unops[] = { + { '+', &cexpr_int, int_pos }, + { '-', &cexpr_int, int_neg }, + { '!', &cexpr_int, int_tnot }, + { '~', &cexpr_int, int_bnot }, + {} +}; + +exprtype_t cexpr_int = { + "int", + sizeof (int), + int_binops, + int_unops, +}; + +BINOP(uint, shl, unsigned, <<) +BINOP(uint, shr, unsigned, >>) +BINOP(uint, add, unsigned, +) +BINOP(uint, sub, unsigned, -) +BINOP(uint, mul, unsigned, *) +BINOP(uint, div, unsigned, /) +BINOP(uint, band, unsigned, &) +BINOP(uint, bor, unsigned, |) +BINOP(uint, xor, unsigned, ^) +BINOP(uint, rem, unsigned, %) + +static void +uint_cast_int (const exprval_t *val1, const exprval_t *src, exprval_t *result, + exprctx_t *ctx) +{ + *(unsigned *) result->value = *(int *) src->value; +} + +UNOP(uint, pos, unsigned, +) +UNOP(uint, neg, unsigned, -) +UNOP(uint, tnot, unsigned, !) +UNOP(uint, bnot, unsigned, ~) + +binop_t uint_binops[] = { + { SHL, &cexpr_uint, &cexpr_uint, uint_shl }, + { SHR, &cexpr_uint, &cexpr_uint, uint_shr }, + { '+', &cexpr_uint, &cexpr_uint, uint_add }, + { '-', &cexpr_uint, &cexpr_uint, uint_sub }, + { '*', &cexpr_uint, &cexpr_uint, uint_mul }, + { '/', &cexpr_uint, &cexpr_uint, uint_div }, + { '&', &cexpr_uint, &cexpr_uint, uint_band }, + { '|', &cexpr_uint, &cexpr_uint, uint_bor }, + { '^', &cexpr_uint, &cexpr_uint, uint_xor }, + { '%', &cexpr_uint, &cexpr_uint, uint_rem }, + { MOD, &cexpr_uint, &cexpr_uint, uint_rem }, + { '=', &cexpr_int, &cexpr_uint, uint_cast_int }, + { '=', &cexpr_plitem, &cexpr_uint, cexpr_cast_plitem }, + {} +}; + +unop_t uint_unops[] = { + { '+', &cexpr_uint, uint_pos }, + { '-', &cexpr_uint, uint_neg }, + { '!', &cexpr_uint, uint_tnot }, + { '~', &cexpr_uint, uint_bnot }, + {} +}; + +exprtype_t cexpr_uint = { + "uint", + sizeof (unsigned), + uint_binops, + uint_unops, +}; + +BINOP(size_t, shl, unsigned, <<) +BINOP(size_t, shr, unsigned, >>) +BINOP(size_t, add, unsigned, +) +BINOP(size_t, sub, unsigned, -) +BINOP(size_t, mul, unsigned, *) +BINOP(size_t, div, unsigned, /) +BINOP(size_t, band, unsigned, &) +BINOP(size_t, bor, unsigned, |) +BINOP(size_t, xor, unsigned, ^) +BINOP(size_t, rem, unsigned, %) + +static void +size_t_cast_int (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx) +{ + int val = *(int *) src->value; + if (val < 0) { + PL_Message (ctx->messages, ctx->item, "int value clamped to 0: %d", + val); + val = 0; + } + *(size_t *) result->value = val; +} + +static void +size_t_cast_uint (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx) +{ + *(size_t *) result->value = *(unsigned *) src->value; +} + +UNOP(size_t, pos, unsigned, +) +UNOP(size_t, neg, unsigned, -) +UNOP(size_t, tnot, unsigned, !) +UNOP(size_t, bnot, unsigned, ~) + +binop_t size_t_binops[] = { + { SHL, &cexpr_size_t, &cexpr_size_t, size_t_shl }, + { SHR, &cexpr_size_t, &cexpr_size_t, size_t_shr }, + { '+', &cexpr_size_t, &cexpr_size_t, size_t_add }, + { '-', &cexpr_size_t, &cexpr_size_t, size_t_sub }, + { '*', &cexpr_size_t, &cexpr_size_t, size_t_mul }, + { '/', &cexpr_size_t, &cexpr_size_t, size_t_div }, + { '&', &cexpr_size_t, &cexpr_size_t, size_t_band }, + { '|', &cexpr_size_t, &cexpr_size_t, size_t_bor }, + { '^', &cexpr_size_t, &cexpr_size_t, size_t_xor }, + { '%', &cexpr_size_t, &cexpr_size_t, size_t_rem }, + { MOD, &cexpr_size_t, &cexpr_size_t, size_t_rem }, + { '=', &cexpr_int, &cexpr_size_t, size_t_cast_int }, + { '=', &cexpr_uint, &cexpr_size_t, size_t_cast_uint }, + { '=', &cexpr_plitem, &cexpr_size_t, cexpr_cast_plitem }, + {} +}; + +unop_t size_t_unops[] = { + { '+', &cexpr_size_t, size_t_pos }, + { '-', &cexpr_size_t, size_t_neg }, + { '!', &cexpr_size_t, size_t_tnot }, + { '~', &cexpr_size_t, size_t_bnot }, + {} +}; + +exprtype_t cexpr_size_t = { + "size_t", + sizeof (size_t), + size_t_binops, + size_t_unops, +}; + +BINOP(float, add, float, +) +BINOP(float, sub, float, -) +BINOP(float, mul, float, *) +BINOP(float, div, float, /) + +static void +float_rem (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + float a = *(float *) val1->value; + float b = *(float *) val2->value; + *(float *) result->value = a - b * truncf (a / b); +} + +static void +float_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for floats: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + float a = *(float *) val1->value; + float b = *(float *) val2->value; + *(float *) result->value = a - b * floorf (a / b); +} + +static void +float_mul_vec4f (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + float s = *(float *) val1->value; + __auto_type v = (vec4f_t *) val2->value; + __auto_type r = (vec4f_t *) result->value; + *r = s * *v; +} + +static void +float_div_quat (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + float a = *(float *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = a * qconjf (b) / dotf (b, b); +} + +static void +float_cast_int (const exprval_t *val1, const exprval_t *src, exprval_t *result, + exprctx_t *ctx) +{ + *(float *) result->value = *(int *) src->value; +} + +UNOP(float, pos, float, +) +UNOP(float, neg, float, -) +UNOP(float, tnot, float, !) + +binop_t float_binops[] = { + { '+', &cexpr_float, &cexpr_float, float_add }, + { '-', &cexpr_float, &cexpr_float, float_sub }, + { '*', &cexpr_float, &cexpr_float, float_mul }, + { '*', &cexpr_vector, &cexpr_vector, float_mul_vec4f }, + { '*', &cexpr_quaternion, &cexpr_quaternion, float_mul_vec4f }, + { '/', &cexpr_float, &cexpr_float, float_div }, + { '/', &cexpr_quaternion, &cexpr_quaternion, float_div_quat }, + { '%', &cexpr_float, &cexpr_float, float_rem }, + { MOD, &cexpr_float, &cexpr_float, float_mod }, + { '=', &cexpr_int, &cexpr_float, float_cast_int }, + { '=', &cexpr_plitem, &cexpr_float, cexpr_cast_plitem }, + {} +}; + +unop_t float_unops[] = { + { '+', &cexpr_float, float_pos }, + { '-', &cexpr_float, float_neg }, + { '!', &cexpr_float, float_tnot }, + {} +}; + +exprtype_t cexpr_float = { + "float", + sizeof (float), + float_binops, + float_unops, +}; + +BINOP(double, add, double, +) +BINOP(double, sub, double, -) +BINOP(double, mul, double, *) +BINOP(double, div, double, /) + +static void +double_rem (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + double a = *(double *) val1->value; + double b = *(double *) val2->value; + *(double *) result->value = a - b * truncf (a / b); +} + +static void +double_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for doubles: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + double a = *(double *) val1->value; + double b = *(double *) val2->value; + *(double *) result->value = a - b * floorf (a / b); +} + +UNOP(double, pos, double, +) +UNOP(double, neg, double, -) +UNOP(double, tnot, double, !) + +binop_t double_binops[] = { + { '+', &cexpr_double, &cexpr_double, double_add }, + { '-', &cexpr_double, &cexpr_double, double_sub }, + { '*', &cexpr_double, &cexpr_double, double_mul }, + { '/', &cexpr_double, &cexpr_double, double_div }, + { '%', &cexpr_double, &cexpr_double, double_rem }, + { MOD, &cexpr_double, &cexpr_double, double_mod }, + { '=', &cexpr_plitem, &cexpr_double, cexpr_cast_plitem }, + {} +}; + +unop_t double_unops[] = { + { '+', &cexpr_double, double_pos }, + { '-', &cexpr_double, double_neg }, + { '!', &cexpr_double, double_tnot }, + {} +}; + +exprtype_t cexpr_double = { + "double", + sizeof (double), + double_binops, + double_unops, +}; + +BINOP(vector, add, vec4f_t, +) +BINOP(vector, sub, vec4f_t, -) +BINOP(vector, mul, vec4f_t, *) +BINOP(vector, div, vec4f_t, /) + +static void +vector_quaternion_mul (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = vqmulf (a, b); +} + +static void +vector_rem (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = a - b * vtruncf (a / b); +} + +static void +vector_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for doubles: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = a - b * vfloorf (a / b); +} + +static void +vector_swizzle (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ +#define m(x) (1 << ((x) - 'a')) +#define v(x, mask) (((x) & 0x60) == 0x60 && (m(x) & (mask))) +#define vind(x) ((x) & 3) +#define cind(x) (-(((x) >> 3) ^ (x)) & 3) + const int color = m('r') | m('g') | m('b') | m('a'); + const int vector = m('x') | m('y') | m('z') | m('w'); + float *vec = val1->value; + const char *name = val2->value; + exprval_t *val = 0; + + if (v (name[0], vector) && v (name[1], vector) + && v (name[2], vector) && v (name[3], vector) && !name[4]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + res[1] = vec[vind (name[1])]; + res[2] = vec[vind (name[2])]; + res[3] = vec[vind (name[3])]; + } else if (v (name[0], color) && v (name[1], color) + && v (name[2], color) && v (name[3], color) && !name[4]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + res[1] = vec[cind (name[1])]; + res[2] = vec[cind (name[2])]; + res[3] = vec[cind (name[3])]; + } else if (v (name[0], vector) && v (name[1], vector) + && v (name[2], vector) && !name[3]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + res[1] = vec[vind (name[1])]; + res[2] = vec[vind (name[2])]; + res[3] = 0; + } else if (v (name[0], color) && v (name[1], color) + && v (name[2], color) && !name[3]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + res[1] = vec[cind (name[1])]; + res[2] = vec[cind (name[2])]; + res[3] = 0; + } else if (v (name[0], vector) && v (name[1], vector) && !name[2]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + res[1] = vec[vind (name[1])]; + res[2] = 0; + res[3] = 0; + } else if (v (name[0], color) && v (name[1], color) && !name[2]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + res[1] = vec[cind (name[1])]; + res[2] = 0; + res[3] = 0; + } else if (v (name[0], vector) && !name[1]) { + val = cexpr_value (&cexpr_float, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + } else if (v (name[0], color) && !name[1]) { + val = cexpr_value (&cexpr_float, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + } + *(exprval_t **) result->value = val; +} + +UNOP(vector, pos, vec4f_t, +) +UNOP(vector, neg, vec4f_t, -) + +static void +vector_tnot (const exprval_t *val, exprval_t *result, exprctx_t *ctx) +{ + vec4f_t v = *(vec4f_t *) val->value; + __auto_type c = (vec4i_t *) result->value; + *c = v != 0; +} + +binop_t vector_binops[] = { + { '+', &cexpr_vector, &cexpr_vector, vector_add }, + { '-', &cexpr_vector, &cexpr_vector, vector_sub }, + { '*', &cexpr_vector, &cexpr_vector, vector_mul }, + { '*', &cexpr_quaternion, &cexpr_vector, vector_quaternion_mul }, + { '/', &cexpr_vector, &cexpr_vector, vector_div }, + { '%', &cexpr_vector, &cexpr_vector, vector_rem }, + { MOD, &cexpr_vector, &cexpr_vector, vector_mod }, + { '.', &cexpr_field, &cexpr_exprval, vector_swizzle }, + {} +}; + +unop_t vector_unops[] = { + { '+', &cexpr_vector, vector_pos }, + { '-', &cexpr_vector, vector_neg }, + { '!', &cexpr_vector, vector_tnot }, + {} +}; + +exprtype_t cexpr_vector = { + "vector", + sizeof (vec4f_t), + vector_binops, + vector_unops, +}; + +static void +quaternion_mul (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = qmulf (a, b); +} + +static void +quaternion_vector_mul (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = qvmulf (a, b); +} + +binop_t quaternion_binops[] = { + { '+', &cexpr_quaternion, &cexpr_quaternion, vector_add }, + { '-', &cexpr_quaternion, &cexpr_quaternion, vector_sub }, + { '*', &cexpr_quaternion, &cexpr_quaternion, quaternion_mul }, + { '*', &cexpr_vector, &cexpr_vector, quaternion_vector_mul }, + {} +}; + +unop_t quaternion_unops[] = { + { '+', &cexpr_vector, vector_pos }, + { '-', &cexpr_vector, vector_neg }, + { '!', &cexpr_vector, vector_tnot }, + {} +}; + +exprtype_t cexpr_quaternion = { + "quaterion", + sizeof (vec4f_t), + quaternion_binops, + quaternion_unops, +}; + +exprtype_t cexpr_exprval = { + "exprval", + sizeof (exprval_t *), + 0, // can't actually do anything with an exprval + 0, +}; + +exprtype_t cexpr_field = { + "field", + 0, // has no size of its own, rather, it's the length of the name + 0, // can't actually do anything with a field + 0, +}; + +exprtype_t cexpr_function = { + "function", + 0, // has no size of its own + 0, // can't actually do anything with a function other than call + 0, +}; + +void +cexpr_cast_plitem (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx) +{ + plitem_t *item = *(plitem_t **) src->value; + const char *str = PL_String (item); + if (!str) { + cexpr_error (ctx, "not a string object: %d", PL_Line (item)); + return; + } + + exprctx_t ectx = *ctx; + ectx.result = result; + cexpr_eval_string (str, &ectx); + ctx->errors += ectx.errors; + if (ectx.errors) { + cexpr_error (ctx, "could not convert: %d", PL_Line (item)); + } +} + +static void +plitem_field (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type dict = *(plitem_t **) a->value; + __auto_type key = (const char *) b->value; + + if (PL_Type (dict) != QFDictionary) { + cexpr_error(ctx, "not a dictionary object"); + return; + } + plitem_t *item = PL_ObjectForKey (dict, key); + exprval_t *val = 0; + if (!item) { + cexpr_error (ctx, "key not found: %s", key); + } else { + val = cexpr_value (&cexpr_plitem, ctx); + *(plitem_t **) val->value = item; + } + *(exprval_t **) c->value = val; +} + +static void +plitem_index (const exprval_t *a, int index, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type array = *(plitem_t **) a->value; + + if (PL_Type (array) != QFArray) { + cexpr_error(ctx, "not an array object"); + return; + } + plitem_t *item = PL_ObjectAtIndex (array, index); + exprval_t *val = 0; + if (!item) { + cexpr_error (ctx, "invalid index: %d", index); + } else { + val = cexpr_value (&cexpr_plitem, ctx); + *(plitem_t **) val->value = item; + } + *(exprval_t **) c->value = val; +} + +static void +plitem_int (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + int index = *(int *) b->value; + plitem_index (a, index, c, ctx); +} + +static void +plitem_uint (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + int index = *(unsigned *) b->value; + plitem_index (a, index, c, ctx); +} + +static void +plitem_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + int index = *(size_t *) b->value; + plitem_index (a, index, c, ctx); +} + +binop_t plitem_binops[] = { + { '.', &cexpr_field, &cexpr_plitem, plitem_field }, + { '[', &cexpr_int, &cexpr_plitem, plitem_int }, + { '[', &cexpr_uint, &cexpr_plitem, plitem_uint }, + { '[', &cexpr_size_t, &cexpr_plitem, plitem_size_t }, + {} +}; + +exprtype_t cexpr_plitem = { + "plitem", + sizeof (plitem_t *), + plitem_binops, + 0, +}; + +VISIBLE binop_t * +cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) +{ + binop_t *binop = 0; + + for (binop = dst_type->binops; binop && binop->op; binop++) { + if (binop->op == '=' && binop->other == src_type) { + break; + } + } + if (binop && binop->op) { + return binop; + } + return 0; +} + +VISIBLE int +cexpr_parse_enum (exprenum_t *enm, const char *str, const exprctx_t *ctx, + void *data) +{ + exprval_t result = { enm->type, data }; + exprctx_t context = *ctx; + context.symtab = enm->symtab; + context.result = &result; + return cexpr_eval_string (str, &context); +} diff --git a/libs/util/cexpr-vars.c b/libs/util/cexpr-vars.c new file mode 100644 index 000000000..9b390b523 --- /dev/null +++ b/libs/util/cexpr-vars.c @@ -0,0 +1,169 @@ +/* + cexpr-vars.c + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +#include "QF/cexpr.h" +#include "QF/cmem.h" +#include "QF/cvar.h" +#include "QF/hash.h" + +#include "libs/util/cexpr-parse.h" + +VISIBLE void +cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type symtab = (exprtab_t *) a->type->data; + __auto_type name = (const char *) b->value; + __auto_type field = (exprsym_t *) Hash_Find (symtab->tab, name); + exprval_t *val = 0; + if (field) { + val = cmemalloc (ctx->memsuper, sizeof (exprval_t)); + val->type = field->type; + val->value = a->value + (ptrdiff_t) field->value; + } else { + cexpr_error (ctx, "%s has no field %s", a->type->name, name); + } + *(exprval_t **) c->value = val; +} + +VISIBLE binop_t cexpr_struct_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cexpr_struct_getfield }, + {} +}; + +VISIBLE void +cexpr_struct_pointer_getfield (const exprval_t *a, const exprval_t *b, + exprval_t *c, exprctx_t *ctx) +{ + // "dereference" the pointer + exprval_t struct_val = { a->type, *(void **) a->value }; + cexpr_struct_getfield (&struct_val, b, c, ctx); +} + +VISIBLE binop_t cexpr_struct_pointer_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cexpr_struct_pointer_getfield }, + {} +}; + +static void +cvar_get (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) +{ + __auto_type name = (const char *) b->value; + exprval_t *var = cexpr_cvar (name, ctx); + if (!var) { + cexpr_error (ctx, "unknown cvar %s", name); + } + *(exprval_t **) c->value = var; +} + +static binop_t cvar_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cvar_get }, + {} +}; + +static exprtype_t cvar_type = { + "cvar", + sizeof (void *), // ref to struct (will always be 0) + cvar_binops, + 0, +}; + +VISIBLE exprval_t * +cexpr_cvar (const char *name, exprctx_t *ctx) +{ + cvar_t *var = Cvar_FindVar (name); + if (!var) { + var = Cvar_FindAlias (name); + } + if (!var) { + return 0; + } + + exprtype_t *type = ctx->result->type; + binop_t *cast = cexpr_find_cast (type, &cexpr_int); + + exprval_t *val = 0; + if (cast || val->type == &cexpr_int || val->type == &cexpr_uint) { + val = cexpr_value (type, ctx); + *(int *) val->value = var->int_val; + } else if (val->type == &cexpr_float) { + val = cexpr_value (type, ctx); + *(float *) val->value = var->value; + } else if (val->type == &cexpr_double) { + val = cexpr_value (type, ctx); + //FIXME cvars need to support double values + *(double *) val->value = var->value; + } + return val; +} + +VISIBLE exprval_t * +cexpr_cvar_struct (exprctx_t *ctx) +{ + exprval_t *cvars = cexpr_value (&cvar_type, ctx); + *(void **) cvars->value = 0; + return cvars; +} + +static const char *expr_getkey (const void *s, void *unused) +{ + __auto_type sym = (exprsym_t *) s; + return sym->name; +} + +void cexpr_init_symtab (exprtab_t *symtab, exprctx_t *ctx) +{ + exprsym_t *sym; + + symtab->tab = Hash_NewTable (61, expr_getkey, 0, 0, ctx->hashlinks); + for (sym = symtab->symbols; sym->name; sym++) { + Hash_Add (symtab->tab, sym); + } +} + +VISIBLE exprval_t * +cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx) +{ + __auto_type ref = (exprval_t *) cmemalloc (ctx->memsuper, + sizeof (exprval_t)); + ref->type = type; + ref->value = data; + return ref; +} + +VISIBLE exprval_t * +cexpr_value (exprtype_t *type, exprctx_t *ctx) +{ + exprval_t *val = cexpr_value_reference (type, 0, ctx); + val->value = cmemalloc (ctx->memsuper, type->size); + return val; +} diff --git a/libs/util/cmd.c b/libs/util/cmd.c index dcdbe6855..812fb55b6 100644 --- a/libs/util/cmd.c +++ b/libs/util/cmd.c @@ -118,6 +118,8 @@ Cmd_Command (cbuf_args_t *args) if (cmd) { if (cmd->function) { cmd->function (); + } else if (cmd->datafunc) { + cmd->datafunc (cmd->data); } return 0; } @@ -133,10 +135,9 @@ Cmd_Command (cbuf_args_t *args) return 0; } -/* Registers a command and handler function */ -VISIBLE int -Cmd_AddCommand (const char *cmd_name, xcommand_t function, - const char *description) +static int +add_command (const char *cmd_name, xcommand_t func, xdatacmd_t datafunc, + void *data, const char *description) { cmd_function_t *cmd; cmd_function_t **c; @@ -152,7 +153,9 @@ Cmd_AddCommand (const char *cmd_name, xcommand_t function, cmd = calloc (1, sizeof (cmd_function_t)); SYS_CHECKMEM (cmd); cmd->name = cmd_name; - cmd->function = function; + cmd->function = func; + cmd->datafunc = datafunc; + cmd->data = data; cmd->description = description; Hash_Add (cmd_hash, cmd); for (c = &cmd_functions; *c; c = &(*c)->next) @@ -163,6 +166,22 @@ Cmd_AddCommand (const char *cmd_name, xcommand_t function, return 1; } +/* Registers a command and handler function */ +VISIBLE int +Cmd_AddCommand (const char *cmd_name, xcommand_t function, + const char *description) +{ + return add_command (cmd_name, function, 0, 0, description); +} + +/* Registers a command and handler function with data */ +VISIBLE int +Cmd_AddDataCommand (const char *cmd_name, xdatacmd_t function, + void *data, const char *description) +{ + return add_command (cmd_name, 0, function, data, description); +} + /* Unregisters a command */ VISIBLE int Cmd_RemoveCommand (const char *name) @@ -583,9 +602,11 @@ Cmd_StuffCmds_f (void) VISIBLE void Cmd_Init_Hash (void) { - cmd_hash = Hash_NewTable (1021, cmd_get_key, 0, 0); - cmd_alias_hash = Hash_NewTable (1021, cmd_alias_get_key, cmd_alias_free, 0); - cmd_provider_hash = Hash_NewTable(1021, cmd_provider_get_key, cmd_provider_free, 0); + cmd_hash = Hash_NewTable (1021, cmd_get_key, 0, 0, 0); + cmd_alias_hash = Hash_NewTable (1021, cmd_alias_get_key, + cmd_alias_free, 0, 0); + cmd_provider_hash = Hash_NewTable(1021, cmd_provider_get_key, + cmd_provider_free, 0, 0); } VISIBLE void diff --git a/libs/util/cmem.c b/libs/util/cmem.c new file mode 100644 index 000000000..1879f7ea3 --- /dev/null +++ b/libs/util/cmem.c @@ -0,0 +1,413 @@ +/* + cmem.c + + Cache-line aligned memory allocator + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#include + +#include "QF/alloc.h" +#include "QF/cmem.h" + +static size_t __attribute__((const)) +ilog2 (size_t x) +{ + size_t l = 0; + while (x >>= 1) { + l++; + } + return l; +} + +memsuper_t * +new_memsuper (void) +{ + memsuper_t *super = aligned_alloc (MEM_LINE_SIZE, sizeof (*super)); + memset (super, 0, sizeof (*super)); + super->page_size = sysconf (_SC_PAGESIZE); + super->page_mask = (super->page_size - 1); + return super; +} + +void +delete_memsuper (memsuper_t *super) +{ + while (super->memblocks) { + memblock_t *t = super->memblocks; + super->memblocks = super->memblocks->next; + free (t->mem); + } + free (super); +} + +static void +link_free_line (memsuper_t *super, memline_t *line) +{ + size_t ind = ilog2 (line->size) - 6; + if (super->free_lines[ind]) { + super->free_lines[ind]->free_prev = &line->free_next; + } + line->free_next = super->free_lines[ind]; + line->free_prev = &super->free_lines[ind]; + super->free_lines[ind] = line; +} + +static void +unlink_free_line (memline_t *line) +{ + if (line->free_next) { + line->free_next->free_prev = line->free_prev; + } + *line->free_prev = line->free_next; +} + +static void +unlink_line (memline_t *line) +{ + if (line->block_next) { + line->block_next->block_prev = line->block_prev; + } + *line->block_prev = line->block_next; + + unlink_free_line (line); +} + +static memblock_t * +init_block (memsuper_t *super, void *mem, size_t alloc_size) +{ + size_t size = super->page_size; + size_t mask = super->page_mask; + size_t ptr = (size_t) mem; + memblock_t *block; + + block = (memblock_t *) (((ptr + size) & ~mask) - sizeof (memblock_t)); + memset (block, 0, sizeof (memblock_t)); + + if (super->memblocks) { + super->memblocks->prev = &block->next; + } + block->next = super->memblocks; + block->prev = &super->memblocks; + super->memblocks = block; + + block->mem = mem; + block->pre_size = (size_t) block - (size_t) mem; + block->post_size = alloc_size - block->pre_size - sizeof (memblock_t); + if (!((size_t) mem & mask) && block->pre_size) { + // can't use the first cache line of the page as it would be + // indistinguishable from a large block + block->pre_size -= MEM_LINE_SIZE; + } + if (block->pre_size) { + memline_t *line = (memline_t *) ((size_t) block - block->pre_size); + + line->block = block; + line->size = block->pre_size; + + line->block_next = 0; + line->block_prev = &block->free_lines; + block->free_lines = line; + + link_free_line (super, line); + } + return block; +} + +static memblock_t * +block_alloc (memsuper_t *super, size_t size) +{ + memblock_t *block; + memblock_t *best = 0; + size_t best_size = ~0u; + + for (block = super->memblocks; block; block = block->next) { + if (block->post_free && block->post_size >= size + && block->post_size < best_size) { + best = block; + best_size = block->post_size; + } + } + if (best) { + best->post_free = 0; + return best; + } + + size_t page_size = super->page_size; + size_t alloc_size = sizeof (memblock_t) + page_size + size; + void *mem = aligned_alloc (MEM_LINE_SIZE, alloc_size); + block = init_block (super, mem, alloc_size); + return block; +} + +static void * +alloc_line (memline_t *line, size_t size) +{ + void *mem = line; + + if (line->size > size) { + // split the line block and insert the new block into the list + memline_t *split = (memline_t *)((size_t) line + size); + split->block = line->block; + split->size = line->size - size; + line->size = size; + + split->block_next = line->block_next; + if (split->block_next) { + split->block_next->block_prev = &split->block_next; + } + line->block_next = split; + split->block_prev = &line->block_next; + + split->free_next = line->free_next; + if (split->free_next) { + split->free_next->free_prev = &split->free_next; + } + line->free_next = split; + split->free_prev = &line->free_next; + } + line->block->pre_allocated += line->size; + unlink_line (line); + return mem; +} + +static void +line_free (memsuper_t *super, memblock_t *block, void *mem) +{ + //FIXME right now, can free only single lines (need allocated lines to + // have a control block) + size_t size = MEM_LINE_SIZE; + memline_t **l; + memline_t *line = 0; + + block->pre_allocated -= size; + + for (l = &block->free_lines; *l; l = &(*l)->block_next) { + line = *l; + if (line->block_next && line->block_next < line) { + *(int *)0 = 0; + } + if ((size_t) mem + size < (size_t) line) { + // line to be freed is below the free line + break; + } + if ((size_t) mem + size == (size_t) line) { + // line to be freed is immediately below the free line + // merge with the free line by "allocating" the line and then + // "freeing" it with the line to be freed + size += line->size; + unlink_line (line); // does not modify line->block_next + line = line->block_next; + break; + } + if ((size_t) line + line->size == (size_t) mem) { + // line to be freed is immediately above the free line + // merge with the free line by growing the line + line->size += size; + if (line->block_next + && (size_t) line->block_next == (size_t) mem + size) { + // the line to be freed connects two free lines + line->size += line->block_next->size; + unlink_line (line->block_next); + } + // the line changed size so needs to be relinked in the super + unlink_free_line (line); + link_free_line (super, line); + return; + } + if ((size_t) mem >= (size_t) line + && (size_t) mem < (size_t) line + line->size) { + *(int *) 0 = 0; + } + line = 0; + } + memline_t *memline = (memline_t *) mem; + memline->block_next = line; + if (memline->block_next) { + memline->block_next->block_prev = &memline->block_next; + } + memline->block_prev = l; + memline->size = size; + memline->block = block; + *l = memline; + link_free_line (super, memline); +} + +static memsline_t * +sline_new (memsuper_t *super, size_t size_ind) +{ + size_t size = 4 << size_ind; + size_t free_loc = (sizeof (memsline_t) + size - 1) & ~(size - 1); + memsline_t *sline = cmemalloc (super, MEM_LINE_SIZE); + sline->size = size_ind; + sline->list = free_loc >> 2; + while (free_loc + size < MEM_LINE_SIZE) { + *(uint16_t *)((size_t) sline + free_loc) = free_loc + size; + free_loc += size; + } + *(uint16_t *)((size_t) sline + free_loc) = 0; + if (super->last_freed[size_ind]) { + super->last_freed[size_ind]->prev = (size_t) &sline->next >> 6; + } + sline->next = super->last_freed[size_ind]; + sline->prev = (size_t) &super->last_freed[size_ind] >> 6; + super->last_freed[size_ind] = sline; + return sline; +} + +void * +cmemalloc (memsuper_t *super, size_t size) +{ + size_t ind = 0; + // allocation sizes start at 4 (sizeof(float)) and go up in powers of two + while ((4u << ind) < size) { + ind++; + } + // round size up + if (size > MEM_LINE_SIZE * 8 || size > super->page_size / 8) { + // the object is large enough it could cause excessive fragmentation, + memblock_t *block = block_alloc (super, 4 << ind); + if (!block) { + return 0; + } + return block + 1; + } else { + size = 4 << ind; + if (size >= MEM_LINE_SIZE) { + // whole cache lines are required for this object + // convert from byte log2 to cache-line log2 + ind -= 4; + memline_t *line = 0; + + while (!line && ind < MAX_CACHE_LINES) { + line = super->free_lines[ind++]; + } + while (line && line->size < size) { + line = line->free_next; + } + if (!line) { + // need a new line, one that doesn't make me fe... wrong song + void *mem; + /* The cache-line pool is page aligned for two reasons: + * 1) so it fits exactly within a page + * 2) the control block can be found easily + * And the reason the pool is exactly one page large is so no + * allocated line is ever page-aligned as that would make the + * line indistinguishable from a large block. + */ + mem = aligned_alloc (super->page_size, super->page_size); + // sets super->free_lines, the block is guarnateed to be big + // enough to hold the requested allocation as otherwise a full + // block allocation would have been used + memblock_t *block = init_block (super, mem, super->page_size); + line = block->free_lines; + } + return alloc_line (line, size); + } else { + void *mem = 0; + memsline_t **sline = &super->last_freed[ind]; + if (!*sline) { + *sline = sline_new (super, ind); + } + if (*sline) { + size_t list = (*sline)->list << 2; + mem = (void *) ((size_t) *sline + list); + (*sline)->list = *(uint16_t *) mem >> 2; + if (!(*sline)->list) { + // the sub-line is full, so remove it from the free + // list. Freeing a block from the line will add it back + // to the list + memsline_t *s = *sline; + if ((*sline)->next) { + (*sline)->next->prev = (*sline)->prev; + } + *sline = (*sline)->next; + s->next = 0; + s->prev = 0; + } + } + return mem; + } + } + return 0; +} + +static void +unlink_block (memblock_t *block) +{ + if (block->pre_size) { + if (!block->free_lines || block->free_lines->block_next) { + *(int *) 0 = 0; + } + unlink_line (block->free_lines); + } + if (block->next) { + block->next->prev = block->prev; + } + *block->prev = block->next; +} + +void +cmemfree (memsuper_t *super, void *mem) +{ + memsline_t **super_sline; + memsline_t *sline; + memblock_t *block; + + if ((size_t) mem & (MEM_LINE_SIZE - 1)) { + // sub line block + sline = (memsline_t *) ((size_t) mem & ~(MEM_LINE_SIZE - 1)); + *(uint16_t *) mem = sline->list << 2; + sline->list = ((size_t) mem & (MEM_LINE_SIZE - 1)) >> 2; + super_sline = &super->last_freed[sline->size]; + if (*super_sline != sline) { + if (sline->next) { + sline->next->prev = sline->prev; + } + if (sline->prev) { + *(memsline_t **) (size_t)(sline->prev << 6) = sline->next; + } + + if (*super_sline) { + (*super_sline)->prev = (size_t) &sline->next >> 6; + } + sline->next = *super_sline; + sline->prev = (size_t) super_sline >> 6; + (*super_sline) = sline; + } + return; + } else if ((size_t) mem & super->page_mask) { + // cache line + size_t page_size = super->page_size; + size_t page_mask = super->page_mask; + block = (memblock_t *) (((size_t) mem + page_size) & ~page_mask) - 1; + line_free (super, block, mem); + } else { + // large block + block = (memblock_t *) mem - 1; + block->post_free = 1; + } + if (!block->pre_allocated && (!block->post_size || block->post_free)) { + unlink_block (block); + free (block->mem); + } +} diff --git a/libs/util/cvar.c b/libs/util/cvar.c index 32e3af26a..afcfeef33 100644 --- a/libs/util/cvar.c +++ b/libs/util/cvar.c @@ -37,6 +37,7 @@ # include #endif +#include #include #include @@ -263,25 +264,27 @@ Cvar_Set (cvar_t *var, const char *value) } changed = !strequal (var->string, value); - free ((char*)var->string); // free the old value string + if (changed) { + free ((char*)var->string); // free the old value string - var->string = strdup (value); - var->value = atof (var->string); - var->int_val = atoi (var->string); - VectorZero (var->vec); - vals = sscanf (var->string, "%f %f %f", - &var->vec[0], &var->vec[1], &var->vec[2]); - if (vals == 1) - var->vec[2] = var->vec[1] = var->vec[0]; + var->string = strdup (value); + var->value = atof (var->string); + var->int_val = atoi (var->string); + VectorZero (var->vec); + vals = sscanf (var->string, "%f %f %f", + &var->vec[0], &var->vec[1], &var->vec[2]); + if (vals == 1) + var->vec[2] = var->vec[1] = var->vec[0]; - if (changed && var->callback) - var->callback (var); + if (var->callback) + var->callback (var); + } } VISIBLE void Cvar_SetValue (cvar_t *var, float value) { - Cvar_Set (var, va ("%g", value)); + Cvar_Set (var, va (0, "%g", value)); } /* @@ -327,6 +330,82 @@ Cvar_WriteVariables (QFile *f) Qprintf (f, "seta %s \"%s\"\n", var->name, var->string); } +// XXX make sure in sync with SYS_* in sys.h +static const char *developer_flags[] = { + "dev", + "warn", + "vid", + "fs_nf", + "fs_f", + "fs", + "net", + "rua_obj", + "rua_msg", + "snd", + "glt", + "glsl", + "skin", + "model", + "vulkan", + 0 +}; + +static int +parse_developer_flag (const char *flag) +{ + const char **devflag; + char *end; + int val; + + val = strtol (flag, &end, 0); + if (!*end) { + return val; + } + for (devflag = developer_flags; *devflag; devflag++) { + if (!strcmp (*devflag, flag)) { + return 1 << (devflag - developer_flags); + } + } + return 0; +} + +static void +developer_f (cvar_t *var) +{ + char *buf = alloca (strlen (var->string) + 1); + const char *s; + char *b; + char c; + int parse = 0; + + for (s = var->string; *s; s++) { + if (isalpha (*s) || *s == '|') { + parse = 1; + break; + } + } + if (!parse) { + return; + } + var->int_val = 0; + for (s = var->string, b = buf; (c = *s++); ) { + if (isspace (c)) { + continue; + } + if (c == '|') { + *b = 0; + var->int_val |= parse_developer_flag (buf); + b = buf; + continue; + } + *b++ = c; + } + if (b != buf) { + *b = 0; + var->int_val |= parse_developer_flag (buf); + } +} + static void set_cvar (const char *cmd, int orflags) { @@ -356,8 +435,8 @@ set_cvar (const char *cmd, int orflags) Cvar_SetFlags (var, var->flags | orflags); } } else { - var = Cvar_Get (var_name, value, CVAR_USER_CREATED | orflags, NULL, - USER_CVAR); + Cvar_Get (var_name, value, CVAR_USER_CREATED | orflags, NULL, + USER_CVAR); } } @@ -529,7 +608,7 @@ Cvar_CvarList_f (void) showhelp++; } for (var = cvar_vars, i = 0; var; var = var->next, i++) { - flags = va ("%c%c%c%c", + flags = va (0, "%c%c%c%c", var->flags & CVAR_ROM ? 'r' : ' ', var->flags & CVAR_ARCHIVE ? '*' : ' ', var->flags & CVAR_USERINFO ? 'u' : ' ', @@ -580,14 +659,14 @@ calias_get_key (const void *c, void *unused) VISIBLE void Cvar_Init_Hash (void) { - cvar_hash = Hash_NewTable (1021, cvar_get_key, cvar_free, 0); - calias_hash = Hash_NewTable (1021, calias_get_key, calias_free, 0); + cvar_hash = Hash_NewTable (1021, cvar_get_key, cvar_free, 0, 0); + calias_hash = Hash_NewTable (1021, calias_get_key, calias_free, 0, 0); } VISIBLE void Cvar_Init (void) { - developer = Cvar_Get ("developer", "0", CVAR_NONE, NULL, + developer = Cvar_Get ("developer", "0", CVAR_NONE, developer_f, "set to enable extra debugging information"); Cmd_AddCommand ("set", Cvar_Set_f, "Set the selected variable, useful on " diff --git a/libs/util/dstring.c b/libs/util/dstring.c index 4e43a0aae..fb495403c 100644 --- a/libs/util/dstring.c +++ b/libs/util/dstring.c @@ -299,7 +299,7 @@ dstring_clearstr (dstring_t *dstr) dstr->str[0] = 0; } -static int +static __attribute__((format(printf, 3, 0))) char * _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) { int size; @@ -325,20 +325,20 @@ _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) } dstr->size = size + offs + 1; dstr->str[dstr->size - 1] = 0; - return size; + return dstr->str; } -VISIBLE int +VISIBLE char * dvsprintf (dstring_t *dstr, const char *fmt, va_list args) { return _dvsprintf (dstr, 0, fmt, args); } -VISIBLE int +VISIBLE char * dsprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; - int ret; + char *ret; va_start (args, fmt); ret = _dvsprintf (dstr, 0, fmt, args); @@ -347,7 +347,7 @@ dsprintf (dstring_t *dstr, const char *fmt, ...) return ret; } -VISIBLE int +VISIBLE char * davsprintf (dstring_t *dstr, const char *fmt, va_list args) { int offs = 0; @@ -357,11 +357,11 @@ davsprintf (dstring_t *dstr, const char *fmt, va_list args) return _dvsprintf (dstr, offs, fmt, args); } -VISIBLE int +VISIBLE char * dasprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; - int ret; + char *ret; int offs = 0; if (dstr->size) diff --git a/libs/util/hash.c b/libs/util/hash.c index 587e4a24d..13c090132 100644 --- a/libs/util/hash.c +++ b/libs/util/hash.c @@ -45,11 +45,11 @@ #include "compat.h" -typedef struct hashlink_s { +struct hashlink_s { struct hashlink_s *next; struct hashlink_s **prev; void *data; -} hashlink_t; +}; struct hashtab_s { size_t tab_size; @@ -60,38 +60,39 @@ struct hashtab_s { uintptr_t (*get_hash)(const void*,void*); const char *(*get_key)(const void*,void*); void (*free_ele)(void*,void*); + hashlink_t **hashlink_freelist; hashlink_t *tab[1]; // variable size }; -static hashlink_t *free_hashlinks; - static hashlink_t * -new_hashlink (void) +new_hashlink (hashlink_t **free_hashlinks) { hashlink_t *link; - if (!free_hashlinks) { + if (!*free_hashlinks) { int i; - if (!(free_hashlinks = calloc (1024, sizeof (hashlink_t)))) + if (!(*free_hashlinks = calloc (1024, sizeof (hashlink_t)))) return 0; - for (i = 0, link = free_hashlinks; i < 1023; i++, link++) + for (i = 0, link = *free_hashlinks; i < 1023; i++, link++) link->next = link + 1; link->next = 0; } - link = free_hashlinks; - free_hashlinks = link->next; + link = *free_hashlinks; + *free_hashlinks = link->next; link->next = 0; return link; } static void -free_hashlink (hashlink_t *link) +free_hashlink (hashlink_t *link, hashlink_t **free_hashlinks) { - link->next = free_hashlinks; - free_hashlinks = link; + link->next = *free_hashlinks; + *free_hashlinks = link; } +static hashlink_t *default_hashlink_freelist; + VISIBLE unsigned long Hash_String (const char *str) { @@ -183,7 +184,8 @@ get_index (uintptr_t hash, size_t size, size_t bits) VISIBLE hashtab_t * Hash_NewTable (int tsize, const char *(*gk)(const void*,void*), - void (*f)(void*,void*), void *ud) + void (*f)(void*,void*), void *ud, + hashlink_t **hashlink_freelist) { hashtab_t *tab = calloc (1, field_offset (hashtab_t, tab[tsize])); if (!tab) @@ -192,6 +194,10 @@ Hash_NewTable (int tsize, const char *(*gk)(const void*,void*), tab->user_data = ud; tab->get_key = gk; tab->free_ele = f; + if (!hashlink_freelist) { + hashlink_freelist = &default_hashlink_freelist; + } + tab->hashlink_freelist = hashlink_freelist; while (tsize) { tab->size_bits++; @@ -228,7 +234,7 @@ Hash_FlushTable (hashtab_t *tab) hashlink_t *t = tab->tab[i]->next; void *data = tab->tab[i]->data; - free_hashlink (tab->tab[i]); + free_hashlink (tab->tab[i], tab->hashlink_freelist); tab->tab[i] = t; if (tab->free_ele) tab->free_ele (data, tab->user_data); @@ -242,7 +248,7 @@ Hash_Add (hashtab_t *tab, void *ele) { unsigned long h = Hash_String (tab->get_key(ele, tab->user_data)); size_t ind = get_index (h, tab->tab_size, tab->size_bits); - hashlink_t *lnk = new_hashlink (); + hashlink_t *lnk = new_hashlink (tab->hashlink_freelist); if (!lnk) return -1; @@ -261,7 +267,7 @@ Hash_AddElement (hashtab_t *tab, void *ele) { unsigned long h = tab->get_hash (ele, tab->user_data); size_t ind = get_index (h, tab->tab_size, tab->size_bits); - hashlink_t *lnk = new_hashlink (); + hashlink_t *lnk = new_hashlink (tab->hashlink_freelist); if (!lnk) return -1; @@ -375,7 +381,7 @@ Hash_Del (hashtab_t *tab, const char *key) if (lnk->next) lnk->next->prev = lnk->prev; *lnk->prev = lnk->next; - free_hashlink (lnk); + free_hashlink (lnk, tab->hashlink_freelist); tab->num_ele--; return data; } @@ -398,7 +404,7 @@ Hash_DelElement (hashtab_t *tab, void *ele) if (lnk->next) lnk->next->prev = lnk->prev; *lnk->prev = lnk->next; - free_hashlink (lnk); + free_hashlink (lnk, tab->hashlink_freelist); tab->num_ele--; return data; } diff --git a/libs/util/info.c b/libs/util/info.c index e9e8e9727..9758942a4 100644 --- a/libs/util/info.c +++ b/libs/util/info.c @@ -228,7 +228,7 @@ Info_ParseString (const char *s, int maxsize, int flags) char *key, *value, *end; info = malloc (sizeof (info_t)); - info->tab = Hash_NewTable (61, info_get_key, free_key, 0); + info->tab = Hash_NewTable (61, info_get_key, free_key, 0, 0); info->maxsize = maxsize; info->cursize = 0; diff --git a/libs/util/mathlib.c b/libs/util/mathlib.c index 9f1053025..33eae277d 100644 --- a/libs/util/mathlib.c +++ b/libs/util/mathlib.c @@ -248,25 +248,46 @@ QuatMult (const quat_t q1, const quat_t q2, quat_t out) vec_t s; vec3_t v; - s = q1[0] * q2[0] - DotProduct (q1 + 1, q2 + 1); - CrossProduct (q1 + 1, q2 + 1, v); - VectorMultAdd (v, q1[0], q2 + 1, v); - VectorMultAdd (v, q2[0], q1 + 1, out + 1); - out[0] = s; + s = q1[3] * q2[3] - DotProduct (q1, q2); + CrossProduct (q1, q2, v); + VectorMultAdd (v, q1[3], q2, v); + VectorMultAdd (v, q2[3], q1, out); + out[3] = s; } VISIBLE void QuatMultVec (const quat_t q, const vec3_t v, vec3_t out) { - vec_t s; vec3_t tv; + vec_t dqv, dqq; + vec_t s; - s = -DotProduct (q + 1, v); - CrossProduct (q + 1, v, tv); - VectorMultAdd (tv, q[0], v, tv); - CrossProduct (q + 1, tv, out); - VectorMultSub (out, s, q + 1, out); - VectorMultAdd (out, q[0], tv, out); + s = q[3]; + CrossProduct (q, v, tv); + dqv = DotProduct (q, v); + dqq = DotProduct (q, q); + VectorScale (tv, s, tv); + VectorMultAdd (tv, dqv, q, tv); + VectorScale (tv, 2, tv); + VectorMultAdd (tv, s * s - dqq, v, out); +} + +VISIBLE void +QuatRotation(const vec3_t a, const vec3_t b, quat_t out) +{ + vec_t ma, mb; + vec_t den, mba_mab; + vec3_t t; + + ma = VectorLength(a); + mb = VectorLength(b); + den = 2 * ma * mb; + VectorScale (a, mb, t); + VectorMultAdd(t, ma, b, t); + mba_mab = VectorLength(t); + CrossProduct (a, b, t); + VectorScale(t, 1 / mba_mab, out); + out[3] = mba_mab / den; } VISIBLE void @@ -288,19 +309,19 @@ QuatExp (const quat_t a, quat_t b) vec_t r; vec_t c, s; - VectorCopy (a + 1, n); + VectorCopy (a, n); th = VectorNormalize (n); - r = expf (a[0]); + r = expf (a[3]); c = cosf (th); s = sinf (th); - VectorScale (n, r * s, b + 1); - b[0] = r * c; + VectorScale (n, r * s, b); + b[3] = r * c; } VISIBLE void QuatToMatrix (const quat_t q, vec_t *m, int homogenous, int vertical) { - vec_t aa, ab, ac, ad, bb, bc, bd, cc, cd, dd; + vec_t xx, xy, xz, xw, yy, yz, yw, zz, zw; vec_t *_m[4] = { m + (homogenous ? 0 : 0), m + (homogenous ? 4 : 3), @@ -308,28 +329,26 @@ QuatToMatrix (const quat_t q, vec_t *m, int homogenous, int vertical) m + (homogenous ? 12 : 9), }; - aa = q[0] * q[0]; - ab = q[0] * q[1]; - ac = q[0] * q[2]; - ad = q[0] * q[3]; + xx = 2 * q[0] * q[0]; + xy = 2 * q[0] * q[1]; + xz = 2 * q[0] * q[2]; + xw = 2 * q[0] * q[3]; - bb = q[1] * q[1]; - bc = q[1] * q[2]; - bd = q[1] * q[3]; + yy = 2 * q[1] * q[1]; + yz = 2 * q[1] * q[2]; + yw = 2 * q[1] * q[3]; - cc = q[2] * q[2]; - cd = q[2] * q[3]; - - dd = q[3] * q[3]; + zz = 2 * q[2] * q[2]; + zw = 2 * q[2] * q[3]; if (vertical) { - VectorSet (aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac), _m[0]); - VectorSet (2 * (bc - ad), aa - bb + cc - dd, 2 * (cd + ab), _m[1]); - VectorSet (2 * (bd + ac), 2 * (cd - ab), aa - bb - cc + dd, _m[2]); + VectorSet (1.0f - yy - zz, xy + zw, xz - yw, _m[0]); + VectorSet (xy - zw, 1.0f - xx - zz, yz + xw, _m[1]); + VectorSet (xz + yw, yz - xw, 1.0f - xx - yy, _m[2]); } else { - VectorSet (aa + bb - cc - dd, 2 * (bc - ad), 2 * (bd + ac), _m[0]); - VectorSet (2 * (bc + ad), aa - bb + cc - dd, 2 * (cd - ab), _m[1]); - VectorSet (2 * (bd - ac), 2 * (cd + ab), aa - bb - cc + dd, _m[2]); + VectorSet (1.0f - yy - zz, xy - zw, xz + yw, _m[0]); + VectorSet (xy + zw, 1.0f - xx - zz, yz - xw, _m[1]); + VectorSet (xz - yw, yz + xw, 1.0f - xx - yy, _m[2]); } if (homogenous) { _m[0][3] = 0; @@ -482,6 +501,8 @@ BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, plane_t *p) #endif /* + FIXME these comments are a confused mess (the code is fine) + angles is a left(?) handed system: 'pitch yaw roll' with x (pitch) axis to the right, y (yaw) axis up and z (roll) axis forward. @@ -555,10 +576,10 @@ AngleQuat (const vec3_t angles, quat_t q) sr = sin (alpha); cr = cos (alpha); - QuatSet (cy * cp * cr + sy * sp * sr, - cy * cp * sr - sy * sp * cr, - cy * sp * cr + sy * cp * sr, - sy * cp * cr - cy * sp * sr, + QuatSet (cy * cp * sr - sy * sp * cr, // x + cy * sp * cr + sy * cp * sr, // y + sy * cp * cr - cy * sp * sr, // z + cy * cp * cr + sy * sp * sr, // w q); } @@ -1112,29 +1133,29 @@ Mat3Decompose (const mat3_t mat, quat_t rot, vec3_t shear, vec3_t scale) t = 1 + row[0][0] + row[1][1] + row[2][2]; if (t >= 1e-5) { vec_t s = sqrt (t) * 2; - rot[0] = s / 4; - rot[1] = (row[2][1] - row[1][2]) / s; - rot[2] = (row[0][2] - row[2][0]) / s; - rot[3] = (row[1][0] - row[0][1]) / s; + rot[0] = (row[2][1] - row[1][2]) / s; + rot[1] = (row[0][2] - row[2][0]) / s; + rot[2] = (row[1][0] - row[0][1]) / s; + rot[3] = s / 4; } else { if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) { vec_t s = sqrt (1 + row[0][0] - row[1][1] - row[2][2]) * 2; - rot[0] = (row[2][1] - row[1][2]) / s; - rot[1] = s / 4; - rot[2] = (row[1][0] + row[0][1]) / s; - rot[3] = (row[0][2] + row[2][0]) / s; + rot[0] = s / 4; + rot[1] = (row[1][0] + row[0][1]) / s; + rot[2] = (row[0][2] + row[2][0]) / s; + rot[3] = (row[2][1] - row[1][2]) / s; } else if (row[1][1] > row[2][2]) { vec_t s = sqrt (1 + row[1][1] - row[0][0] - row[2][2]) * 2; - rot[0] = (row[0][2] - row[2][0]) / s; - rot[1] = (row[1][0] + row[0][1]) / s; - rot[2] = s / 4; - rot[3] = (row[2][1] + row[1][2]) / s; + rot[0] = (row[1][0] + row[0][1]) / s; + rot[1] = s / 4; + rot[2] = (row[2][1] + row[1][2]) / s; + rot[3] = (row[0][2] - row[2][0]) / s; } else { vec_t s = sqrt (1 + row[2][2] - row[0][0] - row[1][1]) * 2; - rot[0] = (row[1][0] - row[0][1]) / s; - rot[1] = (row[0][2] + row[2][0]) / s; - rot[2] = (row[2][1] + row[1][2]) / s; - rot[3] = s / 4; + rot[0] = (row[0][2] + row[2][0]) / s; + rot[1] = (row[2][1] + row[1][2]) / s; + rot[2] = s / 4; + rot[3] = (row[1][0] - row[0][1]) / s; } } return 1; @@ -1256,7 +1277,6 @@ circum_circle (const vec_t **points, int num_points, sphere_t *sphere) VectorMultAdd (sphere->center, bb, ca, sphere->center); VectorMultAdd (sphere->center, cc, ab, sphere->center); VectorAdd (sphere->center, points[0], sphere->center); - sphere->radius = VectorDistance (sphere->center, points[0]); return 1; } return 0; @@ -1283,8 +1303,8 @@ CircumSphere (const vec3_t points[], int num_points, sphere_t *sphere) } static void -closest_point (const vec_t **points, int num_points, const vec3_t x, - vec3_t closest) +closest_affine_point (const vec_t **points, int num_points, const vec3_t x, + vec3_t closest) { vec3_t a, b, n, d; vec_t l; @@ -1311,6 +1331,74 @@ closest_point (const vec_t **points, int num_points, const vec3_t x, } } +static int +test_support_points(const vec_t **points, int *num_points, const vec3_t center) +{ + int in_affine = 0; + int in_convex = 0; + vec3_t v, d, n, a, b; + vec_t nn, dd, vv, dn; + + switch (*num_points) { + case 1: + in_affine = VectorCompare (points[0], center); + // the convex hull and affine hull for a single point are the same + in_convex = in_affine; + break; + case 2: + VectorSubtract (points[1], points[0], v); + VectorSubtract (center, points[0], d); + CrossProduct (v, d, n); + nn = DotProduct (n, n); + dd = DotProduct (d, d); + vv = DotProduct (v, v); + in_affine = nn < 1e-8 * vv * dd; + break; + case 3: + VectorSubtract (points[1], points[0], a); + VectorSubtract (points[2], points[0], b); + VectorSubtract (center, points[0], d); + CrossProduct (a, b, n); + dn = DotProduct (d, n); + dd = DotProduct (d, d); + nn = DotProduct (n, n); + in_affine = dn * dn < 1e-8 * dd * nn; + break; + case 4: + in_affine = 1; + break; + default: + Sys_Error ("Invalid number of points (%d) in test_support_points", + *num_points); + } + + // if in_convex is not true while in_affine is, then need to test as + // there is more than one dimension for the affine hull (a single support + // point is never dropped as it cannot be redundant) + if (in_affine && !in_convex) { + vec_t lambda[4]; + int dropped = 0; + int count = *num_points; + + BarycentricCoords (points, count, center, lambda); + + for (int i = 0; i < count; i++) { + points[i - dropped] = points[i]; + if (lambda[i] < -1e-4) { + dropped++; + (*num_points)--; + } + } + in_convex = !dropped; + if (dropped) { + for (int i = count - dropped; i < count; i++) { + points[i] = 0; + } + } + } + return in_convex; +} + sphere_t SmallestEnclosingBall (const vec3_t points[], int num_points) { @@ -1320,10 +1408,11 @@ SmallestEnclosingBall (const vec3_t points[], int num_points) int num_support; vec_t dist, best_dist; int i; - int itters = 0; + int iters = 0; - if (num_points < 3) { - CircumSphere (points, num_points, &sphere); + if (num_points < 1) { + VectorZero (sphere.center); + sphere.radius = 0; return sphere; } @@ -1332,7 +1421,7 @@ SmallestEnclosingBall (const vec3_t points[], int num_points) VectorCopy (points[0], sphere.center); best_dist = dist = 0; - best = 0; + best = points[0]; for (i = 1; i < num_points; i++) { dist = VectorDistance_fast (points[i], sphere.center); if (dist > best_dist) { @@ -1344,41 +1433,22 @@ SmallestEnclosingBall (const vec3_t points[], int num_points) support[0] = best; sphere.radius = best_dist; // note: radius squared until the end - while (1) { + while (!test_support_points (support, &num_support, sphere.center)) { vec3_t affine; vec3_t center_to_affine, center_to_point; vec_t affine_dist, point_proj, point_dist, bound; vec_t scale = 1; int i; - if (itters++ > 10) + if (iters++ > 10) Sys_Error ("stuck SEB"); best = 0; - if (num_support == 4) { - vec_t lambda[4]; - int dropped = 0; - - BarycentricCoords (support, 4, sphere.center, lambda); - for (i = 0; i < 4; i++) { - support[i - dropped] = support[i]; - if (lambda[i] < 0) { - dropped++; - num_support--; - } - } - if (!dropped) - break; - for (i = 4 - dropped; i < 4; i++) - support[i] = 0; - } - closest_point (support, num_support, sphere.center, affine); + closest_affine_point (support, num_support, sphere.center, affine); VectorSubtract (affine, sphere.center, center_to_affine); affine_dist = DotProduct (center_to_affine, center_to_affine); - if (affine_dist < 1e-2 * sphere.radius) - break; for (i = 0; i < num_points; i++) { - if (points[i] == support [0] || points[i] == support[1] + if (points[i] == support[0] || points[i] == support[1] || points[i] == support[2]) continue; VectorSubtract (points[i], sphere.center, center_to_point); @@ -1396,10 +1466,10 @@ SmallestEnclosingBall (const vec3_t points[], int num_points) } } VectorMultAdd (sphere.center, scale, center_to_affine, sphere.center); - if (!best) - break; - sphere.radius = VectorDistance_fast (sphere.center, best); - support[num_support++] = best; + sphere.radius = VectorDistance_fast (sphere.center, support[0]); + if (best) { + support[num_support++] = best; + } } best_dist = 0; for (i = 0; i < num_points; i++) { diff --git a/libs/util/mdfour.c b/libs/util/mdfour.c index 99f57bef2..61bc46e9a 100644 --- a/libs/util/mdfour.c +++ b/libs/util/mdfour.c @@ -37,7 +37,6 @@ #endif #include "QF/mdfour.h" -#include "QF/uint32.h" /* NOTE: This code makes no attempt to be fast! It assumes that a int is at least 32 bits long @@ -62,12 +61,12 @@ static struct mdfour *m; /* this applies md4 to 64 byte chunks */ static void -mdfour64 (uint32 * M) +mdfour64 (uint32_t * M) { int j; - uint32 AA, BB, CC, DD; - uint32 X[16]; - uint32 A, B, C, D; + uint32_t AA, BB, CC, DD; + uint32_t X[16]; + uint32_t A, B, C, D; for (j = 0; j < 16; j++) X[j] = M[j]; @@ -154,7 +153,7 @@ mdfour64 (uint32 * M) } static void -copy64 (uint32 * M, const unsigned char *in) +copy64 (uint32_t * M, const unsigned char *in) { int i; @@ -164,7 +163,7 @@ copy64 (uint32 * M, const unsigned char *in) } static void -copy4 (unsigned char *out, uint32 x) +copy4 (unsigned char *out, uint32_t x) { out[0] = x & 0xFF; out[1] = (x >> 8) & 0xFF; @@ -186,8 +185,8 @@ static void mdfour_tail (const unsigned char *in, int n) { unsigned char buf[128]; - uint32 M[16]; - uint32 b; + uint32_t M[16]; + uint32_t b; m->totalN += n; @@ -214,7 +213,7 @@ mdfour_tail (const unsigned char *in, int n) VISIBLE void mdfour_update (struct mdfour *md, const unsigned char *in, int n) { - uint32 M[16]; + uint32_t M[16]; if (n == 0) mdfour_tail (in, n); diff --git a/libs/util/pakfile.c b/libs/util/pakfile.c index 5ddbbb9a2..f3f0352ed 100644 --- a/libs/util/pakfile.c +++ b/libs/util/pakfile.c @@ -66,7 +66,7 @@ pack_new (const char *name) free (pack); return 0; } - pack->file_hash = Hash_NewTable (1021, pack_get_key, 0, 0); + pack->file_hash = Hash_NewTable (1021, pack_get_key, 0, 0, 0); if (!pack->file_hash) { free (pack->filename); free (pack); @@ -161,7 +161,7 @@ pack_create (const char *name) pack_del (pack); return 0; } - strncpy (pack->header.id, "PACK", sizeof (pack->header.id)); + memcpy (pack->header.id, "PACK", sizeof (pack->header.id)); Qwrite (pack->handle, &pack->header, sizeof (pack->header)); diff --git a/libs/util/qfplist.c b/libs/util/plist.c similarity index 52% rename from libs/util/qfplist.c rename to libs/util/plist.c index 03a85b5b2..b731f982f 100644 --- a/libs/util/qfplist.c +++ b/libs/util/plist.c @@ -1,5 +1,5 @@ /* - qfplist.c + plist.c Property list management @@ -38,17 +38,20 @@ #include "qfalloca.h" +#include "QF/darray.h" #include "QF/dstring.h" #include "QF/hash.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/qtypes.h" #include "QF/sys.h" +#include "QF/va.h" /* Generic property list item. */ struct plitem_s { pltype_t type; + int line; void *data; }; @@ -61,6 +64,12 @@ struct dictkey_s { }; typedef struct dictkey_s dictkey_t; +struct pldict_s { + hashtab_t *tab; + struct DARRAY_TYPE (dictkey_t *) keys; +}; +typedef struct pldict_s pldict_t; + /* Arrays */ @@ -82,11 +91,13 @@ struct plbinary_s { typedef struct plbinary_s plbinary_t; typedef struct pldata_s { // Unparsed property list string - const char *ptr; - unsigned int end; - unsigned int pos; - unsigned int line; - const char *error; + const char *ptr; + unsigned end; + unsigned pos; + unsigned line; + plitem_t *error; + va_ctx_t *va_ctx; + hashlink_t **hashlinks; } pldata_t; // Ugly defines for fast checking and conversion from char to number @@ -96,6 +107,13 @@ typedef struct pldata_s { // Unparsed property list string : 10 + (inrange((ch), 'a', 'f') ? ((ch) - 'a') \ : ((ch) - 'A'))) +static const char *pl_types[] = { + "dictionary", + "array", + "biinary", + "string", +}; + static byte quotable_bitmap[32]; static inline int is_quotable (byte x) @@ -114,11 +132,11 @@ init_quotables (void) quotable_bitmap[*c / 8] &= ~(1 << (*c % 8)); } -static plitem_t *PL_ParsePropertyListItem (pldata_t *); -static qboolean PL_SkipSpace (pldata_t *); -static char *PL_ParseQuotedString (pldata_t *); -static char *PL_ParseUnquotedString (pldata_t *); -static char *PL_ParseData (pldata_t *, int *); +static plitem_t *pl_parsepropertylistitem (pldata_t *); +static qboolean pl_skipspace (pldata_t *); +static char *pl_parsequotedstring (pldata_t *); +static char *pl_parseunquotedstring (pldata_t *); +static char *pl_parsedata (pldata_t *, int *); static const char * dict_get_key (const void *i, void *unused) @@ -138,7 +156,7 @@ dict_free (void *i, void *unused) } static plitem_t * -PL_NewItem (pltype_t type) +pl_newitem (pltype_t type) { plitem_t *item = calloc (1, sizeof (plitem_t)); item->type = type; @@ -146,10 +164,12 @@ PL_NewItem (pltype_t type) } VISIBLE plitem_t * -PL_NewDictionary (void) +PL_NewDictionary (hashlink_t **hashlinks) { - plitem_t *item = PL_NewItem (QFDictionary); - hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL); + plitem_t *item = pl_newitem (QFDictionary); + pldict_t *dict = malloc (sizeof (pldict_t)); + dict->tab = Hash_NewTable (1021, dict_get_key, dict_free, NULL, hashlinks); + DARRAY_INIT (&dict->keys, 8); item->data = dict; return item; } @@ -157,7 +177,7 @@ PL_NewDictionary (void) VISIBLE plitem_t * PL_NewArray (void) { - plitem_t *item = PL_NewItem (QFArray); + plitem_t *item = pl_newitem (QFArray); plarray_t *array = calloc (1, sizeof (plarray_t)); item->data = array; return item; @@ -166,7 +186,7 @@ PL_NewArray (void) VISIBLE plitem_t * PL_NewData (void *data, size_t size) { - plitem_t *item = PL_NewItem (QFBinary); + plitem_t *item = pl_newitem (QFBinary); plbinary_t *bin = malloc (sizeof (plbinary_t)); item->data = bin; bin->data = data; @@ -175,34 +195,46 @@ PL_NewData (void *data, size_t size) } static plitem_t * -new_string (char *str) +new_string (char *str, int line) { - plitem_t *item = PL_NewItem (QFString); + plitem_t *item = pl_newitem (QFString); item->data = str; + item->line = line; return item; } VISIBLE plitem_t * PL_NewString (const char *str) { - return new_string (strdup (str)); + return new_string (strdup (str), 0); } VISIBLE void PL_Free (plitem_t *item) { + pldict_t *dict; + plarray_t *array; + + if (!item) { + return; + } switch (item->type) { case QFDictionary: - Hash_DelTable (item->data); + dict = item->data; + Hash_DelTable (dict->tab); + DARRAY_CLEAR (&dict->keys); + free (item->data); break; - case QFArray: { - int i = ((plarray_t *) item->data)->numvals; + case QFArray: + { + array = item->data; + int i = array->numvals; while (i-- > 0) { - PL_Free (((plarray_t *) item->data)->values[i]); + PL_Free (array->values[i]); } - free (((plarray_t *) item->data)->values); + free (array->values); free (item->data); } break; @@ -215,102 +247,151 @@ PL_Free (plitem_t *item) case QFString: free (item->data); break; + case QFMultiType: + break; } free (item); } -VISIBLE const char * -PL_String (plitem_t *string) +VISIBLE size_t +PL_BinarySize (const plitem_t *binary) { - if (string->type != QFString) + if (!binary || binary->type != QFBinary) { + return 0; + } + + plbinary_t *bin = (plbinary_t *) binary->data; + return bin->size; +} + +VISIBLE const void * +PL_BinaryData (const plitem_t *binary) +{ + if (!binary || binary->type != QFBinary) { + return 0; + } + + plbinary_t *bin = (plbinary_t *) binary->data; + return bin->data; +} + +VISIBLE const char * +PL_String (const plitem_t *string) +{ + if (!string || string->type != QFString) { return NULL; + } return string->data; } VISIBLE plitem_t * -PL_ObjectForKey (plitem_t *dict, const char *key) +PL_ObjectForKey (const plitem_t *item, const char *key) { - hashtab_t *table = (hashtab_t *) dict->data; - dictkey_t *k; - - if (dict->type != QFDictionary) + if (!item || item->type != QFDictionary) { return NULL; + } - k = (dictkey_t *) Hash_Find (table, key); + pldict_t *dict = (pldict_t *) item->data; + dictkey_t *k = (dictkey_t *) Hash_Find (dict->tab, key); return k ? k->value : NULL; } -VISIBLE plitem_t * -PL_RemoveObjectForKey (plitem_t *dict, const char *key) +VISIBLE const char * +PL_KeyAtIndex (const plitem_t *item, int index) { - hashtab_t *table = (hashtab_t *) dict->data; + if (!item || item->type != QFDictionary) { + return NULL; + } + + pldict_t *dict = (pldict_t *) item->data; + if (index < 0 || (size_t) index >= dict->keys.size) { + return NULL; + } + + return dict->keys.a[index]->key; +} + +VISIBLE plitem_t * +PL_RemoveObjectForKey (const plitem_t *item, const char *key) +{ + if (!item || item->type != QFDictionary) { + return NULL; + } + + pldict_t *dict = (pldict_t *) item->data; dictkey_t *k; plitem_t *value; - if (dict->type != QFDictionary) - return NULL; - - k = (dictkey_t *) Hash_Del (table, key); + k = (dictkey_t *) Hash_Del (dict->tab, key); if (!k) return NULL; value = k->value; k->value = 0; + for (size_t i = 0; i < dict->keys.size; i++) { + if (dict->keys.a[i] == k) { + DARRAY_REMOVE_AT (&dict->keys, i); + break; + } + } dict_free (k, 0); return value; } VISIBLE plitem_t * -PL_D_AllKeys (plitem_t *dict) +PL_D_AllKeys (const plitem_t *item) { - void **list, **l; - dictkey_t *current; - plitem_t *array; - - if (dict->type != QFDictionary) + if (!item || item->type != QFDictionary) { return NULL; + } - if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) - return NULL; + pldict_t *dict = (pldict_t *) item->data; + dictkey_t *current; + plitem_t *array; if (!(array = PL_NewArray ())) return NULL; - while ((current = (dictkey_t *) *l++)) { + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; PL_A_AddObject (array, PL_NewString (current->key)); } - free (list); return array; } VISIBLE int -PL_D_NumKeys (plitem_t *dict) +PL_D_NumKeys (const plitem_t *item) { - if (dict->type != QFDictionary) + if (!item || item->type != QFDictionary) { return 0; - return Hash_NumElements ((hashtab_t *) dict->data); + } + + pldict_t *dict = (pldict_t *) item->data; + return Hash_NumElements (dict->tab); } VISIBLE plitem_t * -PL_ObjectAtIndex (plitem_t *array, int index) +PL_ObjectAtIndex (const plitem_t *array, int index) { - plarray_t *arr = (plarray_t *) array->data; - - if (array->type != QFArray) + if (!array || array->type != QFArray) { return NULL; + } + plarray_t *arr = (plarray_t *) array->data; return index >= 0 && index < arr->numvals ? arr->values[index] : NULL; } VISIBLE qboolean -PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value) +PL_D_AddObject (plitem_t *item, const char *key, plitem_t *value) { + if (!item || item->type != QFDictionary || !value) { + return false; + } + + pldict_t *dict = (pldict_t *) item->data; dictkey_t *k; - if (dict->type != QFDictionary) - return false; - - if ((k = Hash_Find ((hashtab_t *)dict->data, key))) { + if ((k = Hash_Find (dict->tab, key))) { PL_Free ((plitem_t *) k->value); k->value = value; } else { @@ -322,7 +403,8 @@ PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value) k->key = strdup (key); k->value = value; - Hash_Add ((hashtab_t *)dict->data, k); + Hash_Add (dict->tab, k); + DARRAY_APPEND (&dict->keys, k); } return true; } @@ -330,10 +412,11 @@ PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value) VISIBLE qboolean PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index) { - plarray_t *arr; - - if (array->type != QFArray) + if (!array || array->type != QFArray || !item) { return false; + } + + plarray_t *arr; arr = (plarray_t *)array->data; @@ -370,22 +453,24 @@ PL_A_AddObject (plitem_t *array, plitem_t *item) } VISIBLE int -PL_A_NumObjects (plitem_t *array) +PL_A_NumObjects (const plitem_t *array) { - if (array->type != QFArray) + if (!array || array->type != QFArray) { return 0; + } return ((plarray_t *) array->data)->numvals; } VISIBLE plitem_t * PL_RemoveObjectAtIndex (plitem_t *array, int index) { + if (!array || array->type != QFArray) { + return 0; + } + plarray_t *arr; plitem_t *item; - if (array->type != QFArray) - return 0; - arr = (plarray_t *)array->data; if (index < 0 || index >= arr->numvals) @@ -402,7 +487,7 @@ PL_RemoveObjectAtIndex (plitem_t *array, int index) } static qboolean -PL_SkipSpace (pldata_t *pl) +pl_skipspace (pldata_t *pl) { while (pl->pos < pl->end) { char c = pl->ptr[pl->pos]; @@ -420,7 +505,7 @@ PL_SkipSpace (pldata_t *pl) pl->pos++; } if (pl->pos >= pl->end) { - pl->error = "Reached end of string in comment"; + pl->error = PL_NewString ("Reached end of string in comment"); return false; } } else if (pl->ptr[pl->pos + 1] == '*') { // "/*" comments @@ -439,7 +524,7 @@ PL_SkipSpace (pldata_t *pl) pl->pos++; } if (pl->pos >= pl->end) { - pl->error = "Reached end of string in comment"; + pl->error = PL_NewString ("Reached end of string in comment"); return false; } } else { @@ -454,7 +539,7 @@ PL_SkipSpace (pldata_t *pl) } pl->pos++; } - pl->error = "Reached end of string"; + pl->error = PL_NewString ("Reached end of string"); return false; } @@ -475,7 +560,7 @@ make_byte (byte h, byte l) } static char * -PL_ParseData (pldata_t *pl, int *len) +pl_parsedata (pldata_t *pl, int *len) { unsigned start = ++pl->pos; int nibbles = 0, i; @@ -489,7 +574,7 @@ PL_ParseData (pldata_t *pl, int *len) } if (c == '>') { if (nibbles & 1) { - pl->error = "invalid data, missing nibble"; + pl->error = PL_NewString ("invalid data, missing nibble"); return NULL; } *len = nibbles / 2; @@ -499,15 +584,16 @@ PL_ParseData (pldata_t *pl, int *len) pl->ptr[start + i * 2 + 1]); return str; } - pl->error = "invalid character in data"; + pl->error = PL_NewString (va (pl->va_ctx, + "invalid character in data: %02x", c)); return NULL; } - pl->error = "Reached end of string while parsing data"; + pl->error = PL_NewString ("Reached end of string while parsing data"); return NULL; } static char * -PL_ParseQuotedString (pldata_t *pl) +pl_parsequotedstring (pldata_t *pl) { unsigned int start = ++pl->pos; unsigned int escaped = 0; @@ -569,7 +655,7 @@ PL_ParseQuotedString (pldata_t *pl) } if (pl->pos >= pl->end) { - pl->error = "Reached end of string while parsing quoted string"; + pl->error = PL_NewString ("Reached end of string while parsing quoted string"); return NULL; } @@ -660,7 +746,7 @@ PL_ParseQuotedString (pldata_t *pl) } static char * -PL_ParseUnquotedString (pldata_t *pl) +pl_parseunquotedstring (pldata_t *pl) { unsigned int start = pl->pos; char *str; @@ -676,44 +762,45 @@ PL_ParseUnquotedString (pldata_t *pl) } static plitem_t * -PL_ParsePropertyListItem (pldata_t *pl) +pl_parsepropertylistitem (pldata_t *pl) { plitem_t *item = NULL; - if (!PL_SkipSpace (pl)) + if (!pl_skipspace (pl)) return NULL; switch (pl->ptr[pl->pos]) { case '{': { - item = PL_NewDictionary (); + item = PL_NewDictionary (pl->hashlinks); + item->line = pl->line; pl->pos++; - while (PL_SkipSpace (pl) && pl->ptr[pl->pos] != '}') { + while (pl_skipspace (pl) && pl->ptr[pl->pos] != '}') { plitem_t *key; plitem_t *value; - if (!(key = PL_ParsePropertyListItem (pl))) { + if (!(key = pl_parsepropertylistitem (pl))) { PL_Free (item); return NULL; } - if (!(PL_SkipSpace (pl))) { + if (!(pl_skipspace (pl))) { PL_Free (key); PL_Free (item); return NULL; } if (key->type != QFString) { - pl->error = "Key is not a string"; + pl->error = PL_NewString ("Key is not a string"); PL_Free (key); PL_Free (item); return NULL; } if (pl->ptr[pl->pos] != '=') { - pl->error = "Unexpected character (expected '=')"; + pl->error = PL_NewString (va (pl->va_ctx, "Unexpected character %c (expected '=')", pl->ptr[pl->pos])); PL_Free (key); PL_Free (item); return NULL; @@ -721,13 +808,13 @@ PL_ParsePropertyListItem (pldata_t *pl) pl->pos++; // If there is no value, lose the key - if (!(value = PL_ParsePropertyListItem (pl))) { + if (!(value = pl_parsepropertylistitem (pl))) { PL_Free (key); PL_Free (item); return NULL; } - if (!(PL_SkipSpace (pl))) { + if (!(pl_skipspace (pl))) { PL_Free (key); PL_Free (value); PL_Free (item); @@ -737,7 +824,7 @@ PL_ParsePropertyListItem (pldata_t *pl) if (pl->ptr[pl->pos] == ';') { pl->pos++; } else if (pl->ptr[pl->pos] != '}') { - pl->error = "Unexpected character (wanted ';' or '}')"; + pl->error = PL_NewString (va (pl->va_ctx, "Unexpected character %c (wanted ';' or '}')", pl->ptr[pl->pos])); PL_Free (key); PL_Free (value); PL_Free (item); @@ -755,7 +842,7 @@ PL_ParsePropertyListItem (pldata_t *pl) } if (pl->pos >= pl->end) { // Catch the error - pl->error = "Unexpected end of string when parsing dictionary"; + pl->error = PL_NewString ("Unexpected end of string when parsing dictionary"); PL_Free (item); return NULL; } @@ -766,18 +853,19 @@ PL_ParsePropertyListItem (pldata_t *pl) case '(': { item = PL_NewArray (); + item->line = pl->line; pl->pos++; - while (PL_SkipSpace (pl) && pl->ptr[pl->pos] != ')') { + while (pl_skipspace (pl) && pl->ptr[pl->pos] != ')') { plitem_t *value; - if (!(value = PL_ParsePropertyListItem (pl))) { + if (!(value = pl_parsepropertylistitem (pl))) { PL_Free (item); return NULL; } - if (!(PL_SkipSpace (pl))) { + if (!(pl_skipspace (pl))) { PL_Free (value); PL_Free (item); return NULL; @@ -786,14 +874,14 @@ PL_ParsePropertyListItem (pldata_t *pl) if (pl->ptr[pl->pos] == ',') { pl->pos++; } else if (pl->ptr[pl->pos] != ')') { - pl->error = "Unexpected character (wanted ',' or ')')"; + pl->error = PL_NewString (va (pl->va_ctx, "Unexpected character %c (wanted ',' or ')')", pl->ptr[pl->pos])); PL_Free (value); PL_Free (item); return NULL; } if (!PL_A_AddObject (item, value)) { - pl->error = "Unexpected character (too many items in array)"; + pl->error = PL_NewString ("Unexpected character (too many items in array)"); PL_Free (value); PL_Free (item); return NULL; @@ -806,39 +894,43 @@ PL_ParsePropertyListItem (pldata_t *pl) case '<': { int len; - char *str = PL_ParseData (pl, &len); + char *str = pl_parsedata (pl, &len); if (!str) { return NULL; } else { - return PL_NewData (str, len); + item = PL_NewData (str, len); + item->line = pl->line; + return item; } } case '"': { - char *str = PL_ParseQuotedString (pl); + int line = pl->line; + char *str = pl_parsequotedstring (pl); if (!str) { return NULL; } else { - return new_string (str); + return new_string (str, line); } } default: { - char *str = PL_ParseUnquotedString (pl); + int line = pl->line; + char *str = pl_parseunquotedstring (pl); if (!str) { return NULL; } else { - return new_string (str); + return new_string (str, line); } } } // switch } VISIBLE plitem_t * -PL_GetPropertyList (const char *string) +PL_GetPropertyList (const char *string, hashlink_t **hashlinks) { pldata_t *pl = calloc (1, sizeof (pldata_t)); plitem_t *newpl = NULL; @@ -851,13 +943,22 @@ PL_GetPropertyList (const char *string) pl->end = strlen (string); pl->error = NULL; pl->line = 1; + pl->va_ctx = va_create_context (4); + pl->hashlinks = hashlinks; - if ((newpl = PL_ParsePropertyListItem (pl))) { + if ((newpl = pl_parsepropertylistitem (pl))) { + va_destroy_context (pl->va_ctx); free (pl); return newpl; } else { - if (pl && pl->error && pl->error[0]) - Sys_Printf ("plist: %d,%d: %s", pl->line, pl->pos, pl->error); + if (pl && pl->error) { + const char *error = PL_String (pl->error); + if (error[0]) { + Sys_Printf ("plist: %d,%d: %s\n", pl->line, pl->pos, error); + } + PL_Free (pl->error); + } + va_destroy_context (pl->va_ctx); free (pl); return NULL; } @@ -970,26 +1071,26 @@ write_string (dstring_t *dstr, const char *str) } static void -write_item (dstring_t *dstr, plitem_t *item, int level) +write_item (dstring_t *dstr, const plitem_t *item, int level) { - void **list, **l; dictkey_t *current; plarray_t *array; + pldict_t *dict; plbinary_t *binary; int i; switch (item->type) { case QFDictionary: write_string_len (dstr, "{\n", 2); - l = list = Hash_GetList ((hashtab_t *) item->data); - while ((current = (dictkey_t *) *l++)) { + dict = (pldict_t *) item->data; + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; write_tabs (dstr, level + 1); write_string (dstr, current->key); write_string_len (dstr, " = ", 3); write_item (dstr, current->value, level + 1); write_string_len (dstr, ";\n", 2); } - free (list); write_tabs (dstr, level); write_string_len (dstr, "}", 1); break; @@ -1021,19 +1122,332 @@ write_item (dstring_t *dstr, plitem_t *item, int level) } VISIBLE char * -PL_WritePropertyList (plitem_t *pl) +PL_WritePropertyList (const plitem_t *pl) { dstring_t *dstr = dstring_newstr (); - if (!quotable_bitmap[0]) - init_quotables (); - write_item (dstr, pl, 0); - write_string_len (dstr, "\n", 1); + if (pl) { + if (!quotable_bitmap[0]) + init_quotables (); + write_item (dstr, pl, 0); + write_string_len (dstr, "\n", 1); + } return dstring_freeze (dstr); } VISIBLE pltype_t -PL_Type (plitem_t *item) +PL_Type (const plitem_t *item) { return item->type; } + +VISIBLE int +PL_Line (const plitem_t *item) +{ + return item->line; +} + +VISIBLE void +PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...) +{ + va_list args; + dstring_t *va_str; + dstring_t *msg_str; + char *msg; + + va_str = dstring_new (); + msg_str = dstring_new (); + + va_start (args, fmt); + dvsprintf (va_str, fmt, args); + va_end (args); + + if (item) { + msg = dsprintf (msg_str, "%d: %s", item->line, va_str->str); + } else { + msg = dsprintf (msg_str, "internal: %s", va_str->str); + } + PL_A_AddObject (messages, PL_NewString (msg)); + dstring_delete (va_str); + dstring_delete (msg_str); +} + +static int +pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + switch (field->type) { + case QFDictionary: + { + *(hashtab_t **)data = ((pldict_t *)item->data)->tab; + } + return 1; + case QFArray: + { + plarray_t *array = (plarray_t *)item->data; + typedef struct DARRAY_TYPE (plitem_t *) arraydata_t; + arraydata_t *arraydata = DARRAY_ALLOCFIXED(arraydata_t, + array->numvals, + malloc); + memcpy (arraydata->a, array->values, + array->numvals * sizeof (arraydata->a[0])); + } + return 1; + case QFBinary: + { + plbinary_t *binary = (plbinary_t *)item->data; + typedef struct DARRAY_TYPE (byte) bindata_t; + bindata_t *bindata = DARRAY_ALLOCFIXED(bindata_t, + binary->size, malloc); + memcpy (bindata->a, binary->data, binary->size); + *(bindata_t **)data = bindata; + } + return 1; + case QFString: + *(char **)data = (char *)item->data; + return 1; + case QFMultiType: + break; + } + PL_Message (messages, 0, "invalid item type: %d", field->type); + return 0; +} + +VISIBLE int +PL_CheckType (pltype_t field_type, pltype_t item_type) +{ + if (field_type & QFMultiType) { + // field_type is a mask of allowed types + return field_type & (1 << item_type); + } else { + // exact match + return field_type == item_type; + } +} + +VISIBLE void +PL_TypeMismatch (plitem_t *messages, const plitem_t *item, const char *name, + pltype_t field_type, pltype_t item_type) +{ + const int num_types = sizeof (pl_types) / sizeof (pl_types[0]); + if (field_type & QFMultiType) { + PL_Message (messages, item, + "error: %s is the wrong type. Got %s, expected on of:", + name, pl_types[item_type]); + field_type &= ~QFMultiType; + for (int type = 0; field_type && type < num_types; + type++, field_type >>= 1) { + if (field_type & 1) { + PL_Message (messages, item, " %s", pl_types[type]); + } + } + } else { + PL_Message (messages, item, + "error: %s is the wrong type. Got %s, expected %s", name, + pl_types[item_type], pl_types[field_type]); + } +} + +VISIBLE int +PL_ParseStruct (const plfield_t *fields, const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + pldict_t *dict = item->data; + dictkey_t *current; + int result = 1; + plparser_t parser; + + if (item->type != QFDictionary) { + PL_Message (messages, item, "error: not a dictionary object"); + return 0; + } + + + for (size_t i = 0; i < dict->keys.size; i++) { + const plfield_t *f; + current = dict->keys.a[i]; + for (f = fields; f->name; f++) { + if (strcmp (f->name, current->key) == 0) { + plitem_t *item = current->value; + void *flddata = (byte *)data + f->offset; + + if (f->parser) { + parser = f->parser; + } else { + parser = pl_default_parser; + } + if (!PL_CheckType (f->type, item->type)) { + PL_TypeMismatch (messages, item, current->key, + f->type, item->type); + result = 0; + } else { + if (!parser (f, item, flddata, messages, context)) { + result = 0; + } + } + break; + } + } + if (!f->name) { + PL_Message (messages, item, "error: unknown field %s", + current->key); + result = 0; + } + } + return result; +} + +VISIBLE int +PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, + plitem_t *messages, void *context) +{ + int result = 1; + plparser_t parser; + plarray_t *plarray = (plarray_t *) array->data; + plelement_t *element = (plelement_t *) field->data; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr; + plfield_t f = { 0, 0, element->type, element->parser, element->data }; + + if (array->type != QFArray) { + PL_Message (messages, array, "error: not an array object"); + return 0; + } + if (f.parser) { + parser = f.parser; + } else { + parser = pl_default_parser; + } + + arr = DARRAY_ALLOCFIXED_OBJ (arr_t, plarray->numvals * element->stride, + element->alloc, context); + memset (arr->a, 0, arr->size); + // the array is allocated using bytes, but need the actual number of + // elements in the array + arr->size = arr->maxSize = plarray->numvals; + + for (int i = 0; i < plarray->numvals; i++) { + plitem_t *item = plarray->values[i]; + void *eledata = &arr->a[i * element->stride]; + + if (!PL_CheckType (element->type, item->type)) { + char index[16]; + snprintf (index, sizeof(index) - 1, "%d", i); + index[15] = 0; + PL_TypeMismatch (messages, item, index, element->type, item->type); + result = 0; + } else { + if (!parser (&f, item, eledata, messages, context)) { + result = 0; + } + } + } + *(arr_t **) data = arr; + return result; +} + +VISIBLE int +PL_ParseLabeledArray (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + pldict_t *dict = item->data; + dictkey_t *current; + int result = 1; + plparser_t parser; + plelement_t *element = (plelement_t *) field->data; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr; + plfield_t f = { 0, 0, element->type, element->parser, element->data }; + + if (item->type != QFDictionary) { + PL_Message (messages, item, "error: not a dictionary object"); + return 0; + } + if (f.parser) { + parser = f.parser; + } else { + parser = pl_default_parser; + } + + arr = DARRAY_ALLOCFIXED_OBJ (arr_t, dict->keys.size * element->stride, + element->alloc, context); + memset (arr->a, 0, arr->size); + // the array is allocated using bytes, but need the actual number of + // elements in the array + arr->size = arr->maxSize = dict->keys.size; + + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; + plitem_t *item = current->value; + void *eledata = &arr->a[i * element->stride]; + + if (!PL_CheckType (element->type, item->type)) { + char index[16]; + snprintf (index, sizeof(index) - 1, "%zd", i); + index[15] = 0; + PL_TypeMismatch (messages, item, index, element->type, item->type); + result = 0; + } else { + if (!parser (&f, item, eledata, messages, context)) { + result = 0; + } + } + } + *(arr_t **) data = arr; + return result; +} + +VISIBLE int +PL_ParseSymtab (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + pldict_t *dict = item->data; + dictkey_t *current; + int result = 1; + plparser_t parser; + __auto_type tab = (hashtab_t *) data; + + plelement_t *element = (plelement_t *) field->data; + plfield_t f = { 0, 0, element->type, element->parser, element->data }; + + if (item->type != QFDictionary) { + PL_Message (messages, item, "error: not a dictionary object"); + return 0; + } + + if (f.parser) { + parser = f.parser; + } else { + PL_Message (messages, item, "no parser set"); + return 0; + } + + void *obj = element->alloc (context, element->stride); + memset (obj, 0, element->stride); + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; + const char *key = current->key; + plitem_t *item = current->value; + + if (!PL_CheckType (element->type, item->type)) { + PL_TypeMismatch (messages, item, key, element->type, item->type); + result = 0; + continue; + } + f.name = key; + if (Hash_Find (tab, key)) { + PL_Message (messages, item, "duplicate name"); + result = 0; + } else { + if (!parser (&f, item, obj, messages, context)) { + result = 0; + } else { + Hash_Add (tab, obj); + obj = element->alloc (context, element->stride); + memset (obj, 0, element->stride); + } + } + } + Hash_Free (tab, obj); + return result; +} diff --git a/libs/util/plugin.c b/libs/util/plugin.c index 31fa725fd..f625ddd15 100644 --- a/libs/util/plugin.c +++ b/libs/util/plugin.c @@ -98,11 +98,13 @@ loaded_plugin_delete (void *lp, void *unused) static int pi_close_lib (void *handle) { + if (handle) { #if defined(HAVE_DLOPEN) - return (dlclose (handle) == 0); + return (dlclose (handle) == 0); #elif defined (_WIN32) - return (FreeLibrary (handle) == 0); + return (FreeLibrary (handle) == 0); #endif + } return 1; } @@ -239,9 +241,9 @@ VISIBLE void PI_Init (void) { PI_InitCvars (); - registered_plugins = Hash_NewTable (253, plugin_get_key, 0, 0); + registered_plugins = Hash_NewTable (253, plugin_get_key, 0, 0, 0); loaded_plugins = Hash_NewTable(253, loaded_plugin_get_key, - loaded_plugin_delete, 0); + loaded_plugin_delete, 0, 0); Cmd_AddCommand("plugin_load", PI_Plugin_Load_f, "load the plugin of the given type name and name"); Cmd_AddCommand("plugin_unload", PI_Plugin_Unload_f, diff --git a/libs/util/qargs.c b/libs/util/qargs.c index 5ba36b842..7f385e5a1 100644 --- a/libs/util/qargs.c +++ b/libs/util/qargs.c @@ -100,13 +100,13 @@ COM_InitArgv (int argc, const char **argv) safe = false; largv = (const char **) calloc (1, (argc + NUM_SAFE_ARGVS + 1) * - sizeof (const char **)); + sizeof (const char *)); for (com_argc = 0, len = 0; com_argc < argc; com_argc++) { largv[com_argc] = argv[com_argc]; if ((argv[com_argc]) && !strcmp ("-safe", argv[com_argc])) safe = true; - if (com_argc) + if (argv[com_argc]) len += strlen (argv[com_argc]) + 1; } diff --git a/libs/util/qendian.c b/libs/util/qendian.c index 12873af9f..9858823be 100644 --- a/libs/util/qendian.c +++ b/libs/util/qendian.c @@ -41,9 +41,9 @@ */ #ifndef WORDS_BIGENDIAN -VISIBLE qboolean bigendien = false;; +VISIBLE qboolean bigendien = false; #else -VISIBLE qboolean bigendien = true;; +VISIBLE qboolean bigendien = true; #endif diff --git a/libs/util/quakefs.c b/libs/util/quakefs.c index 5131f7194..e209d460a 100644 --- a/libs/util/quakefs.c +++ b/libs/util/quakefs.c @@ -82,9 +82,9 @@ #include "QF/mathlib.h" #include "QF/pak.h" #include "QF/pakfile.h" +#include "QF/plist.h" #include "QF/qargs.h" #include "QF/qendian.h" -#include "QF/qfplist.h" #include "QF/qtypes.h" #include "QF/quakefs.h" #include "QF/sys.h" @@ -252,12 +252,11 @@ static void delete_searchpath (searchpath_t *searchpath) { if (searchpath->pack) { - Qclose (searchpath->pack->handle); - free (searchpath->pack->files); - free (searchpath->pack); + pack_del (searchpath->pack); } - if (searchpath->filename) + if (searchpath->filename) { free (searchpath->filename); + } FREE (searchpaths, searchpath); } @@ -274,8 +273,9 @@ delete_vpath (vpath_t *vpath) { searchpath_t *next; - if (vpath->name) + if (vpath->name) { free (vpath->name); + } while (vpath->user) { next = vpath->user->next; delete_searchpath (vpath->user); @@ -307,7 +307,7 @@ qfs_var_free (void *_v, void *unused) static hashtab_t * qfs_new_vars (void) { - return Hash_NewTable (61, qfs_var_get_key, qfs_var_free, 0); + return Hash_NewTable (61, qfs_var_get_key, qfs_var_free, 0, 0); } static void @@ -359,7 +359,7 @@ qfs_var_subst (const char *string, hashtab_t *vars) dstring_appendsubstr (new, s, (e - s)); break; } - var = va ("%.*s", (int) (e - s) - 1, s + 1); + var = va (0, "%.*s", (int) (e - s) - 1, s + 1); sub = Hash_Find (vars, var); if (sub) dstring_appendstr (new, sub->val); @@ -370,7 +370,7 @@ qfs_var_subst (const char *string, hashtab_t *vars) s = e; while (qfs_isident (*e)) e++; - var = va ("%.*s", (int) (e - s), s); + var = va (0, "%.*s", (int) (e - s), s); sub = Hash_Find (vars, var); if (sub) dstring_appendstr (new, sub->val); @@ -549,7 +549,7 @@ qfs_build_gamedir (const char **list) gamedir_t *gamedir; plitem_t *gdpl; dstring_t *path; - hashtab_t *dirs = Hash_NewTable (31, qfs_dir_get_key, qfs_dir_free, 0); + hashtab_t *dirs = Hash_NewTable (31, qfs_dir_get_key, qfs_dir_free, 0, 0); hashtab_t *vars = qfs_new_vars (); const char *dir = 0; @@ -588,7 +588,7 @@ qfs_build_gamedir (const char **list) gamedir = calloc (1, sizeof (gamedir_t)); path = dstring_newstr (); while (j--) { - const char *name = va ("%s:%s", qfs_game, dir = list[j]); + const char *name = va (0, "%s:%s", qfs_game, dir = list[j]); if (Hash_Find (dirs, name)) continue; gdpl = qfs_find_gamedir (name, dirs); @@ -672,7 +672,7 @@ qfs_load_config (void) buf[len + 2] = 0; if (qfs_gd_plist) PL_Free (qfs_gd_plist); - qfs_gd_plist = PL_GetPropertyList (buf); + qfs_gd_plist = PL_GetPropertyList (buf, 0); free (buf); if (qfs_gd_plist && PL_Type (qfs_gd_plist) == QFDictionary) return; // done @@ -680,7 +680,7 @@ qfs_load_config (void) no_config: if (qfs_gd_plist) PL_Free (qfs_gd_plist); - qfs_gd_plist = PL_GetPropertyList (qfs_default_dirconf); + qfs_gd_plist = PL_GetPropertyList (qfs_default_dirconf, 0); } /* @@ -859,6 +859,7 @@ qfs_findfile_search (const vpath_t *vpath, const searchpath_t *sp, found.ff.realname = strdup (*fn); found.path = strdup (path->str); found.fname_index = fn - fnames; + dstring_delete (path); return &found; } } @@ -1209,7 +1210,7 @@ qfs_file_sort (char **os1, char **os2) s2 = *os2; while (1) { - in1 = in2 = n1 = n2 = 0; + n1 = n2 = 0; if ((in1 = isdigit ((byte) *s1))) n1 = strtol (s1, &s1, 10); @@ -1416,6 +1417,16 @@ qfs_path_cvar (cvar_t *var) free (cpath); } +static void +qfs_shutdown (void *data) +{ + while (qfs_vpaths) { + vpath_t *next = qfs_vpaths->next; + delete_vpath (qfs_vpaths); + qfs_vpaths = next; + } +} + VISIBLE void QFS_Init (const char *game) { @@ -1465,6 +1476,7 @@ QFS_Init (const char *game) } else { QFS_Gamedir (""); } + Sys_RegisterShutdown (qfs_shutdown, 0); } VISIBLE const char * @@ -1661,7 +1673,7 @@ QFS_FilelistAdd (filelist_t *filelist, const char *fname, const char *ext) } str = strdup (fname); - if (ext && (s = strstr(str, va(".%s", ext)))) + if (ext && (s = strstr(str, va (0, ".%s", ext)))) *s = 0; filelist->list[filelist->count++] = str; } @@ -1680,9 +1692,9 @@ qfs_filelistfill_do (filelist_t *list, const searchpath_t *search, const char *c for (i = 0; i < pak->numfiles; i++) { char *name = pak->files[i].name; - if (!fnmatch (va("%s%s*.%s", cp, separator, ext), name, + if (!fnmatch (va (0, "%s%s*.%s", cp, separator, ext), name, FNM_PATHNAME) - || !fnmatch (va("%s%s*.%s.gz", cp, separator, ext), name, + || !fnmatch (va (0, "%s%s*.%s.gz", cp, separator, ext), name, FNM_PATHNAME)) QFS_FilelistAdd (list, name, strip ? ext : 0); } @@ -1690,12 +1702,12 @@ qfs_filelistfill_do (filelist_t *list, const searchpath_t *search, const char *c DIR *dir_ptr; struct dirent *dirent; - dir_ptr = opendir (va ("%s/%s", search->filename, cp)); + dir_ptr = opendir (va (0, "%s/%s", search->filename, cp)); if (!dir_ptr) return; while ((dirent = readdir (dir_ptr))) - if (!fnmatch (va("*.%s", ext), dirent->d_name, 0) - || !fnmatch (va("*.%s.gz", ext), dirent->d_name, 0)) + if (!fnmatch (va (0, "*.%s", ext), dirent->d_name, 0) + || !fnmatch (va (0, "*.%s.gz", ext), dirent->d_name, 0)) QFS_FilelistAdd (list, dirent->d_name, strip ? ext : 0); closedir (dir_ptr); } diff --git a/libs/util/riff.c b/libs/util/riff.c index ce3fb2e22..c4590ce2d 100644 --- a/libs/util/riff.c +++ b/libs/util/riff.c @@ -138,7 +138,6 @@ read_adtl (dstring_t *list_buf, QFile *f, int len) //FIXME list = (riff_list_t *) list_buf->str; while (len) { if (!Rread (f, &ck, sizeof (ck))) { - len = 0; break; } len -= sizeof (ck); @@ -161,7 +160,7 @@ read_adtl (dstring_t *list_buf, QFile *f, int len) chunk = &label->ck; break; default: - data = malloc (sizeof (data)); + data = malloc (sizeof (riff_data_t)); data->ck = ck; data->data = read_data (f, ck.len); chunk = &data->ck; @@ -229,6 +228,7 @@ read_list (riff_d_chunk_t *ck, QFile *f, int len) riff_data_t *data = malloc (sizeof (riff_data_t)); if (!Rread (f, &data->ck, sizeof (data->ck))) { free (data); + len = 0; } else { data->ck.len = LittleLong (data->ck.len); data->data = read_data (f, data->ck.len); @@ -236,7 +236,6 @@ read_list (riff_d_chunk_t *ck, QFile *f, int len) chunk = &data->ck; } } - len = 0; break; } if (chunk) { @@ -392,7 +391,6 @@ riff_read (QFile *f) break; } dstring_append (riff_buf, (char *)&chunk, sizeof (chunk)); - riff = (riff_list_t *) riff_buf->str; chunk = 0; } bail: diff --git a/libs/util/script.c b/libs/util/script.c index eeb1df977..fa8b51ae0 100644 --- a/libs/util/script.c +++ b/libs/util/script.c @@ -34,19 +34,6 @@ #include "QF/dstring.h" #include "QF/script.h" -static void __attribute__ ((format (printf, 2, 3), noreturn)) -script_error (script_t *script, const char *fmt, ...) -{ - va_list args; - - va_start (args, fmt); - fprintf (stderr, "%s:%d: ", script->file, script->line); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); - va_end (args); - exit (1); -} - VISIBLE script_t * Script_New (void) { @@ -69,11 +56,16 @@ Script_Start (script_t *script, const char *file, const char *data) script->file = file; script->p = data; script->unget = false; + script->error = 0; } VISIBLE qboolean Script_TokenAvailable (script_t *script, qboolean crossline) { + if (script->error) { + return false; + } + if (script->unget) return true; skipspace: @@ -111,6 +103,10 @@ Script_GetToken (script_t *script, qboolean crossline) { const char *token_p; + if (script->error) { + return false; + } + if (script->unget) { // is a token allready waiting? script->unget = false; return true; @@ -118,10 +114,7 @@ Script_GetToken (script_t *script, qboolean crossline) if (!Script_TokenAvailable (script, crossline)) { if (!crossline) { - if (script->error) - script->error (script, "line is incomplete"); - else - script_error (script, "line is incomplete"); + script->error = "line is incomplete"; } return false; } @@ -134,18 +127,13 @@ Script_GetToken (script_t *script, qboolean crossline) while (*script->p != '"') { if (!*script->p) { script->line = start_line; - if (script->error) - script->error (script, "EOF inside quoted token"); - else - script_error (script, "EOF inside quoted token"); + script->error = "EOF inside quoted token"; return false; } if (*script->p == '\n') { if (script->no_quote_lines) { - if (script->error) - script->error (script, "EOL inside quoted token"); - else - script_error (script, "EOL inside quoted token"); + script->error = "EOL inside quoted token"; + return false; } script->line++; } @@ -175,11 +163,16 @@ Script_GetToken (script_t *script, qboolean crossline) VISIBLE void Script_UngetToken (script_t *script) { - script->unget = true; + if (!script->error) { + script->unget = true; + } } VISIBLE const char * Script_Token (script_t *script) { + if (script->error) { + return 0; + } return script->token->str; } diff --git a/libs/util/segtext.c b/libs/util/segtext.c index 742983be1..ffee78d77 100644 --- a/libs/util/segtext.c +++ b/libs/util/segtext.c @@ -140,7 +140,7 @@ Segtext_new (const char *source_string) if (!source_string) return 0; text = new_text (); - text->tab = Hash_NewTable (61, segtext_getkey, 0, 0); + text->tab = Hash_NewTable (61, segtext_getkey, 0, 0, 0); src = strdup (source_string); // The first chunk is special in that it holds the pointer to the copied diff --git a/libs/util/set.c b/libs/util/set.c index 4b3b3a033..dfdd55b4e 100644 --- a/libs/util/set.c +++ b/libs/util/set.c @@ -343,7 +343,7 @@ set_everything (set_t *set) return set; } -static inline int +static inline __attribute__((pure)) int _set_is_empty (const set_t *set) { unsigned i; @@ -370,7 +370,7 @@ set_is_everything (const set_t *set) return _set_is_empty (set); } -static int +static __attribute__((pure)) int set_test_n_n (const set_t *s1, const set_t *s2) { unsigned i, end; @@ -394,7 +394,7 @@ set_test_n_n (const set_t *s1, const set_t *s2) return (difference != 0) | ((intersection != 0) << 1); } -static int +static __attribute__((pure)) int set_test_n_i (const set_t *s1, const set_t *s2) { unsigned i, end; @@ -419,7 +419,7 @@ set_test_n_i (const set_t *s1, const set_t *s2) return (difference != 0) | ((intersection != 0) << 1); } -static int +static __attribute__((pure)) int set_test_i_n (const set_t *s1, const set_t *s2) { unsigned i, end; @@ -444,7 +444,7 @@ set_test_i_n (const set_t *s1, const set_t *s2) return (difference != 0) | ((intersection != 0) << 1); } -static int +static __attribute__((pure)) int set_test_i_i (const set_t *s1, const set_t *s2) { unsigned i, end; @@ -470,7 +470,7 @@ set_test_i_i (const set_t *s1, const set_t *s2) return (difference != 0) | ((intersection != 0) << 1); } -static int +static __attribute__((pure)) int set_test (const set_t *s1, const set_t *s2) { if (s1->inverted && s2->inverted) diff --git a/qw/include/cl_tent.h b/libs/util/simd.c similarity index 69% rename from qw/include/cl_tent.h rename to libs/util/simd.c index 71af54705..84acc8798 100644 --- a/qw/include/cl_tent.h +++ b/libs/util/simd.c @@ -1,9 +1,9 @@ /* - client.h + simd.c - Client definitions + SIMD math support - Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -24,15 +24,16 @@ Boston, MA 02111-1307, USA */ - -#ifndef _CL_TENT_H -#define _CL_TENT_H - -void CL_TEnts_Init (void); -void CL_ClearEnts (void); -void CL_ClearTEnts (void); -void CL_Init_Entity (struct entity_s *ent); -void CL_ParseTEnt (void); -void CL_UpdateTEnts (void); - +#ifdef HAVE_CONFIG_H +# include "config.h" #endif + +#include + +#define IMPLEMENT_VEC4F_Funcs +#define IMPLEMENT_VEC4D_Funcs +#define IMPLEMENT_MAT4F_Funcs + +#include "QF/simd/vec4d.h" +#include "QF/simd/vec4f.h" +#include "QF/simd/mat4f.h" diff --git a/libs/util/sizebuf.c b/libs/util/sizebuf.c index 757672367..785287d0c 100644 --- a/libs/util/sizebuf.c +++ b/libs/util/sizebuf.c @@ -99,3 +99,34 @@ SZ_Print (sizebuf_t *buf, const char *data) memcpy (SZ_GetSpace (buf, len), data, len); } + +VISIBLE void +SZ_Dump (sizebuf_t *buf) +{ + int i; + char chars[17], c; + + chars[16] = 0; + for (i = 0; i < buf->cursize; i++) { + if (i % 16 == 0) { + Sys_Printf ("%04x:", i); + } else if (i % 16 == 8) { + Sys_Printf (" "); + } + Sys_Printf (" %02x", buf->data[i]); + c = buf->data[i] & 0x7f; + if (c < ' ') { + c = '.'; + } + chars[i % 16] = c; + if (i % 16 == 15) { + Sys_Printf (" %s\n", chars); + } + } + i %= 16; + if (i) { + chars[i] = 0; + i = 16 - i; + Sys_Printf ("%*s %s\n", i * 3 + (i > 7), "", chars); + } +} diff --git a/libs/util/sys.c b/libs/util/sys.c index 1b6a9c269..db0777f07 100644 --- a/libs/util/sys.c +++ b/libs/util/sys.c @@ -90,8 +90,8 @@ #include "compat.h" -static void Sys_StdPrintf (const char *fmt, va_list args); -static void Sys_ErrPrintf (const char *fmt, va_list args); +static void Sys_StdPrintf (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); +static void Sys_ErrPrintf (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); VISIBLE cvar_t *sys_nostdout; VISIBLE cvar_t *sys_extrasleep; @@ -103,9 +103,23 @@ int sys_checksum; static sys_printf_t sys_std_printf_function = Sys_StdPrintf; static sys_printf_t sys_err_printf_function = Sys_ErrPrintf; +#ifndef _WIN32 +static struct sigaction save_hup; +static struct sigaction save_quit; +static struct sigaction save_trap; +static struct sigaction save_iot; +static struct sigaction save_bus; +#endif +static struct sigaction save_int; +static struct sigaction save_ill; +static struct sigaction save_segv; +static struct sigaction save_term; +static struct sigaction save_fpe; + typedef struct shutdown_list_s { struct shutdown_list_s *next; - void (*func)(void); + void (*func) (void *); + void *data; } shutdown_list_t; typedef struct error_handler_s { @@ -126,18 +140,18 @@ qboolean stdin_ready; /* The translation table between the graphical font and plain ASCII --KB */ VISIBLE const char sys_char_map[256] = { - '\0', '#', '#', '#', '#', '.', '#', '#', - '#', 9, 10, '#', ' ', 13, '.', '.', + 0, '#', '#', '#', '#', '.', '#', '#', + '#', 9, 10, '#', ' ', 13, '.', '.', '[', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '<', '=', '>', - ' ', '!', '"', '#', '$', '%', '&', '\'', + ' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + 'X', 'Y', 'Z', '[','\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', @@ -147,14 +161,14 @@ VISIBLE const char sys_char_map[256] = { '#', '#', ' ', '#', ' ', '>', '.', '.', '[', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '<', '=', '>', - ' ', '!', '"', '#', '$', '%', '&', '\'', + ' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + 'X', 'Y', 'Z', '[','\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', @@ -240,16 +254,20 @@ Sys_FileExists (const char *path) for want of a better name, but it sets the function pointer for the actual implementation of Sys_Printf. */ -VISIBLE void +VISIBLE sys_printf_t Sys_SetStdPrintf (sys_printf_t func) { + sys_printf_t prev = sys_std_printf_function; sys_std_printf_function = func; + return prev; } -VISIBLE void +VISIBLE sys_printf_t Sys_SetErrPrintf (sys_printf_t func) { + sys_printf_t prev = sys_err_printf_function; sys_err_printf_function = func; + return prev; } void @@ -488,7 +506,7 @@ Sys_Shutdown (void) shutdown_list_t *t; while (shutdown_list) { - shutdown_list->func (); + shutdown_list->func (shutdown_list->data); t = shutdown_list; shutdown_list = shutdown_list->next; free (t); @@ -567,7 +585,7 @@ Sys_Error (const char *error, ...) } VISIBLE void -Sys_RegisterShutdown (void (*func) (void)) +Sys_RegisterShutdown (void (*func) (void *), void *data) { shutdown_list_t *p; if (!func) @@ -576,6 +594,7 @@ Sys_RegisterShutdown (void (*func) (void)) if (!p) Sys_Error ("Sys_RegisterShutdown: insufficient memory"); p->func = func; + p->data = data; p->next = shutdown_list; shutdown_list = p; } @@ -593,11 +612,11 @@ Sys_TimeID (void) //FIXME I need a new name, one that doesn't make me feel 3 fee } VISIBLE void -Sys_PageIn (void *ptr, int size) +Sys_PageIn (void *ptr, size_t size) { //may or may not be useful in linux #ifdef _WIN32 byte *x; - int m, n; + size_t m, n; // touch all the memory to make sure it's there. The 16-page skip is to // keep Win 95 from thinking we're trying to page ourselves in (we are @@ -613,6 +632,16 @@ Sys_PageIn (void *ptr, int size) //#endif } +VISIBLE void * +Sys_Alloc (size_t size) +{ + size_t page_size = sysconf (_SC_PAGESIZE); + size_t page_mask = page_size - 1; + size = (size + page_mask) & ~page_mask; + return mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); +} + VISIBLE void Sys_DebugLog (const char *file, const char *fmt, ...) { @@ -798,18 +827,22 @@ Sys_PopSignalHook (void) } } -static void +static void __attribute__((noreturn)) aiee (int sig) { printf ("AIEE, signal %d in shutdown code, giving up\n", sig); - longjmp (aiee_abort, 1); + siglongjmp (aiee_abort, 1); } static void -signal_handler (int sig) +signal_handler (int sig, siginfo_t *info, void *ucontext) { int volatile recover = 0; // volatile for longjump + static volatile int in_signal_handler = 0; + if (in_signal_handler) { + aiee (sig); + } printf ("Received signal %d, exiting...\n", sig); switch (sig) { @@ -817,48 +850,28 @@ signal_handler (int sig) case SIGTERM: #ifndef _WIN32 case SIGHUP: - signal (SIGHUP, SIG_DFL); + sigaction (SIGHUP, &save_hup, 0); #endif - signal (SIGINT, SIG_DFL); - signal (SIGTERM, SIG_DFL); + sigaction (SIGINT, &save_int, 0); + sigaction (SIGTERM, &save_term, 0); Sys_Quit (); default: -#ifndef _WIN32 - signal (SIGQUIT, aiee); - signal (SIGTRAP, aiee); - signal (SIGIOT, aiee); - signal (SIGBUS, aiee); -#endif - signal (SIGILL, aiee); - signal (SIGSEGV, aiee); - signal (SIGFPE, aiee); - - if (!setjmp (aiee_abort)) { + if (!sigsetjmp (aiee_abort, 1)) { if (signal_hook) recover = signal_hook (sig, signal_hook_data); Sys_Shutdown (); } - if (recover) { + if (!recover) { #ifndef _WIN32 - signal (SIGQUIT, signal_handler); - signal (SIGTRAP, signal_handler); - signal (SIGIOT, signal_handler); - signal (SIGBUS, signal_handler); + sigaction (SIGQUIT, &save_quit, 0); + sigaction (SIGTRAP, &save_trap, 0); + sigaction (SIGIOT, &save_iot, 0); + sigaction (SIGBUS, &save_bus, 0); #endif - signal (SIGILL, signal_handler); - signal (SIGSEGV, signal_handler); - signal (SIGFPE, signal_handler); - } else { -#ifndef _WIN32 - signal (SIGQUIT, SIG_DFL); - signal (SIGTRAP, SIG_DFL); - signal (SIGIOT, SIG_DFL); - signal (SIGBUS, SIG_DFL); -#endif - signal (SIGILL, SIG_DFL); - signal (SIGSEGV, SIG_DFL); - signal (SIGFPE, SIG_DFL); + sigaction (SIGILL, &save_ill, 0); + sigaction (SIGSEGV, &save_segv, 0); + sigaction (SIGFPE, &save_fpe, 0); } } } @@ -867,18 +880,21 @@ VISIBLE void Sys_Init (void) { // catch signals + struct sigaction action = {}; + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = signal_handler; #ifndef _WIN32 - signal (SIGHUP, signal_handler); - signal (SIGQUIT, signal_handler); - signal (SIGTRAP, signal_handler); - signal (SIGIOT, signal_handler); - signal (SIGBUS, signal_handler); + sigaction (SIGHUP, &action, &save_hup); + sigaction (SIGQUIT, &action, &save_quit); + sigaction (SIGTRAP, &action, &save_trap); + sigaction (SIGIOT, &action, &save_iot); + sigaction (SIGBUS, &action, &save_bus); #endif - signal (SIGINT, signal_handler); - signal (SIGILL, signal_handler); - signal (SIGSEGV, signal_handler); - signal (SIGTERM, signal_handler); - signal (SIGFPE, signal_handler); + sigaction (SIGINT, &action, &save_int); + sigaction (SIGILL, &action, &save_ill); + sigaction (SIGSEGV, &action, &save_segv); + sigaction (SIGTERM, &action, &save_term); + sigaction (SIGFPE, &action, &save_fpe); Cvar_Init_Hash (); Cmd_Init_Hash (); diff --git a/libs/util/test/Makefile.am b/libs/util/test/Makefile.am deleted file mode 100644 index a7bdb5d4e..000000000 --- a/libs/util/test/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CPPFLAGS= -I$(top_srcdir)/include - -check_PROGRAMS= \ - test-bary test-cs test-dq test-half test-mat3 test-mat4 test-plist \ - test-qfs test-quat test-seb test-seg test-set test-vrect - -test_bary_SOURCES=test-bary.c -test_bary_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_bary_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_cs_SOURCES=test-cs.c -test_cs_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_cs_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_dq_SOURCES=test-dq.c -test_dq_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_dq_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_half_SOURCES=test-half.c -test_half_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_half_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_mat3_SOURCES=test-mat3.c -test_mat3_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_mat3_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_mat4_SOURCES=test-mat4.c -test_mat4_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_mat4_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_plist_SOURCES=test-plist.c -test_plist_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_plist_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_qfs_SOURCES=test-qfs.c -test_qfs_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_qfs_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_quat_SOURCES=test-quat.c -test_quat_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_quat_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_seb_SOURCES=test-seb.c -test_seb_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_seb_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_seg_SOURCES=test-seg.c -test_seg_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_seg_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_set_SOURCES=test-set.c -test_set_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_set_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -test_vrect_SOURCES=test-vrect.c -test_vrect_LDADD=$(top_builddir)/libs/util/libQFutil.la -test_vrect_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la - -TESTS=$(check_PROGRAMS) diff --git a/libs/util/test/Makemodule.am b/libs/util/test/Makemodule.am new file mode 100644 index 000000000..ca777f864 --- /dev/null +++ b/libs/util/test/Makemodule.am @@ -0,0 +1,95 @@ +libs_util_tests = \ + libs/util/test/test-bary \ + libs/util/test/test-cexpr \ + libs/util/test/test-cmem \ + libs/util/test/test-cs \ + libs/util/test/test-darray \ + libs/util/test/test-dq \ + libs/util/test/test-half \ + libs/util/test/test-mat3 \ + libs/util/test/test-mat4 \ + libs/util/test/test-plist \ + libs/util/test/test-qfs \ + libs/util/test/test-quat \ + libs/util/test/test-seb \ + libs/util/test/test-seg \ + libs/util/test/test-set \ + libs/util/test/test-simd \ + libs/util/test/test-txtbuffer \ + libs/util/test/test-vrect + +TESTS += $(libs_util_tests) + +check_PROGRAMS += $(libs_util_tests) + +libs_util_test_test_bary_SOURCES=libs/util/test/test-bary.c +libs_util_test_test_bary_LDADD=libs/util/libQFutil.la +libs_util_test_test_bary_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_cexpr_SOURCES=libs/util/test/test-cexpr.c +libs_util_test_test_cexpr_LDADD=libs/util/libQFutil.la +libs_util_test_test_cexpr_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_cmem_SOURCES=libs/util/test/test-cmem.c +libs_util_test_test_cmem_LDADD=libs/util/libQFutil.la +libs_util_test_test_cmem_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_cs_SOURCES=libs/util/test/test-cs.c +libs_util_test_test_cs_LDADD=libs/util/libQFutil.la +libs_util_test_test_cs_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_darray_SOURCES=libs/util/test/test-darray.c +libs_util_test_test_darray_LDADD=libs/util/libQFutil.la +libs_util_test_test_darray_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_dq_SOURCES=libs/util/test/test-dq.c +libs_util_test_test_dq_LDADD=libs/util/libQFutil.la +libs_util_test_test_dq_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_half_SOURCES=libs/util/test/test-half.c +libs_util_test_test_half_LDADD=libs/util/libQFutil.la +libs_util_test_test_half_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_mat3_SOURCES=libs/util/test/test-mat3.c +libs_util_test_test_mat3_LDADD=libs/util/libQFutil.la +libs_util_test_test_mat3_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_mat4_SOURCES=libs/util/test/test-mat4.c +libs_util_test_test_mat4_LDADD=libs/util/libQFutil.la +libs_util_test_test_mat4_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_plist_SOURCES=libs/util/test/test-plist.c +libs_util_test_test_plist_LDADD=libs/util/libQFutil.la +libs_util_test_test_plist_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_qfs_SOURCES=libs/util/test/test-qfs.c +libs_util_test_test_qfs_LDADD=libs/util/libQFutil.la +libs_util_test_test_qfs_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_quat_SOURCES=libs/util/test/test-quat.c +libs_util_test_test_quat_LDADD=libs/util/libQFutil.la +libs_util_test_test_quat_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_seb_SOURCES=libs/util/test/test-seb.c +libs_util_test_test_seb_LDADD=libs/util/libQFutil.la +libs_util_test_test_seb_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_seg_SOURCES=libs/util/test/test-seg.c +libs_util_test_test_seg_LDADD=libs/util/libQFutil.la +libs_util_test_test_seg_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_set_SOURCES=libs/util/test/test-set.c +libs_util_test_test_set_LDADD=libs/util/libQFutil.la +libs_util_test_test_set_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_simd_SOURCES=libs/util/test/test-simd.c +libs_util_test_test_simd_LDADD=libs/util/libQFutil.la +libs_util_test_test_simd_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_txtbuffer_SOURCES=libs/util/test/test-txtbuffer.c +libs_util_test_test_txtbuffer_LDADD=libs/util/libQFutil.la +libs_util_test_test_txtbuffer_DEPENDENCIES=libs/util/libQFutil.la + +libs_util_test_test_vrect_SOURCES=libs/util/test/test-vrect.c +libs_util_test_test_vrect_LDADD=libs/util/libQFutil.la +libs_util_test_test_vrect_DEPENDENCIES=libs/util/libQFutil.la diff --git a/libs/util/test/test-cexpr.c b/libs/util/test/test-cexpr.c new file mode 100644 index 000000000..338e71bbc --- /dev/null +++ b/libs/util/test/test-cexpr.c @@ -0,0 +1,218 @@ +/* + test-cexpr.c + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/cexpr.h" +#include "QF/cmem.h" +#include "QF/hash.h" +#include "QF/mathlib.h" +#include "QF/simd/vec4f.h" + +int a = 5; +int b = 6; +int c; +float point[4] = { 2, 3, 4, 1 }; // a point, so w = 1 +float normal[4] = { 1, 2, 3, 0 }; // a vector, so w = 0 +float direction[4] = { 4, 5, 6, 0 }; // a vector, so w = 0 +float plane[4]; +float intercept[4]; + +exprtype_t *vector_params[] = { + &cexpr_vector, + &cexpr_vector, +}; + +exprtype_t *int_params[] = { + &cexpr_int, + &cexpr_int, +}; + +exprtype_t *float_params[] = { + &cexpr_float, + &cexpr_float, +}; + +exprtype_t *double_params[] = { + &cexpr_double, + &cexpr_double, +}; + +static void +float_dot (const exprval_t **params, exprval_t *result, exprctx_t *context) +{ + // parameters are reversed! + vec4f_t *a = params[1]->value; + vec4f_t *b = params[0]->value; + vec4f_t *d = result->value; + *d = dotf (*a, *b); +} + +exprfunc_t dot_func[] = { + { &cexpr_vector, 2, vector_params, float_dot}, + {} +}; + +exprfunc_t sin_func[] = { + { &cexpr_float, 1, float_params }, + { &cexpr_double, 1, double_params }, + {} +}; + +exprfunc_t cos_func[] = { + { &cexpr_float, 1, float_params }, + { &cexpr_double, 1, double_params }, + {} +}; + +exprfunc_t atan2_func[] = { + { &cexpr_float, 2, float_params }, + { &cexpr_double, 2, double_params }, + {} +}; + +exprfunc_t int_func[] = { + { &cexpr_int, 1, float_params }, + { &cexpr_int, 1, double_params }, + {} +}; + +exprfunc_t float_func[] = { + { &cexpr_float, 1, int_params }, + { &cexpr_float, 1, double_params }, + {} +}; + +exprfunc_t double_func[] = { + { &cexpr_double, 1, float_params }, + { &cexpr_double, 1, double_params }, + {} +}; + +exprsym_t symbols[] = { + { "a", &cexpr_int, &a }, + { "b", &cexpr_int, &b }, + { "point", &cexpr_vector, &point }, + { "normal", &cexpr_vector, &normal }, + { "plane", &cexpr_vector, &plane }, + { "direction", &cexpr_vector, &direction }, + { "intercept", &cexpr_vector, &intercept }, + { "dot", &cexpr_function, dot_func }, + { "sin", &cexpr_function, sin_func }, + { "cos", &cexpr_function, cos_func }, + { "atan2", &cexpr_function, atan2_func }, + { "float", &cexpr_function, float_func }, + { "double", &cexpr_function, double_func }, + { "int", &cexpr_function, int_func }, + {} +}; +exprval_t test_result = { &cexpr_int, &c }; +exprval_t plane_result = { &cexpr_vector, &plane }; +// a bit hacky, but no l-values +exprval_t dist_result = { &cexpr_float, &plane[3] }; +exprval_t intercept_result = { &cexpr_vector, &intercept }; + +exprtab_t symtab = { + symbols, + 0 +}; + +exprctx_t context = { &test_result, &symtab }; + +#define TEST_BINOP(op) \ + do { \ + c = -4096; \ + cexpr_eval_string ("a " #op " b", &context); \ + printf ("c = a %s b -> %d = %d %s %d\n", #op, c, a, #op, b); \ + if (c != (a op b)) { \ + ret |= 1; \ + } \ + } while (0) + +int +main(int argc, const char **argv) +{ + int ret = 0; + + cexpr_init_symtab (&symtab, &context); + context.memsuper = new_memsuper(); + + TEST_BINOP (<<); + TEST_BINOP (>>); + TEST_BINOP (+); + TEST_BINOP (-); + TEST_BINOP (*); + TEST_BINOP (/); + TEST_BINOP (&); + TEST_BINOP (|); + TEST_BINOP (^); + TEST_BINOP (%); + + context.result = &plane_result; + cexpr_eval_string ("point.wzyx", &context); + if (plane[0] != point[3] || plane[1] != point[2] + || plane[2] != point[1] || plane[3] != point[0]) { + printf ("point.wzyx [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + cexpr_eval_string ("point.zyx", &context); + if (plane[0] != point[2] || plane[1] != point[1] + || plane[2] != point[0] || plane[3] != 0) { + printf ("point.zyx [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + cexpr_eval_string ("point.yx", &context); + if (plane[0] != point[1] || plane[1] != point[0] + || plane[2] != 0 || plane[3] != 0) { + printf ("point.yx [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + cexpr_eval_string ("normal", &context); + context.result = &dist_result; + cexpr_eval_string ("-dot(point, normal).x / 2f", &context); + if (!VectorCompare (normal, plane) + || plane[3] != -DotProduct (normal, point) / 2) { + printf ("plane [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + context.result = &intercept_result; + cexpr_eval_string ("point - direction * dot(point, plane)/dot(direction,plane)", &context); + if (intercept[0] != 0.75 || intercept[1] != 1.4375 + || intercept[2] != 2.125 || intercept[3] != 1) { + printf ("[%.9g, %.9g, %.9g] %.9g\n", VectorExpand (intercept), intercept[3]); + ret |= 1; + } + + Hash_DelTable (symtab.tab); + delete_memsuper (context.memsuper); + return ret; +} diff --git a/libs/util/test/test-cmem.c b/libs/util/test/test-cmem.c new file mode 100644 index 000000000..4f146ccc7 --- /dev/null +++ b/libs/util/test/test-cmem.c @@ -0,0 +1,663 @@ +#include +#include +#include +#include + +#include "QF/cmem.h" +#include "QF/set.h" + +static int +test_block (memsuper_t *super) +{ + size_t size = super->page_size; + void *mem = cmemalloc (super, size); + memblock_t *block; + + if (!mem) { + fprintf (stderr, "could not allocate %zd byte block\n", + super->page_size); + return 0; + } + if ((size_t) mem & super->page_mask) { + fprintf (stderr, "mem not page aligned: %p %zd\n", + mem, super->page_size); + return 0; + } + block = super->memblocks; + if (mem != block + 1) { + fprintf (stderr, "super does not point to mem\n"); + return 0; + } + if (block->post_size < size) { + fprintf (stderr, "block post_size too small: %zd < %zd\n", + block->post_size, size); + return 0; + } + if (block->post_size - size >= super->page_size) { + fprintf (stderr, "block post_size too big: %zd < %zd\n", + block->post_size - size, super->page_size); + return 0; + } + memset (mem, 0, size); // valgrind check + cmemfree (super, mem); + if (super->memblocks) { + fprintf (stderr, "super still points to mem\n"); + return 0; + } + return 1; +} + +static int +check_block (memblock_t *block, int line_count, int allocated) +{ + set_t *visited = set_new (); + size_t free_bytes = 0; + int ret = 1; + int count = 0; + + for (memline_t **l = &block->free_lines; *l; l = &(*l)->block_next) { + memline_t *line = *l; + ptrdiff_t ind = (memline_t *) block - line; + if (ind < 1 || (size_t ) ind > block->pre_size / MEM_LINE_SIZE) { + fprintf (stderr, "line outside of block\n"); + return 0; + } + if (set_is_member (visited, ind)) { + fprintf (stderr, "loop in block free_lines\n"); + return 0; + } + count++; + set_add (visited, ind); + if (!line->size) { + fprintf (stderr, "line with size 0\n"); + ret = 0; + } + if (line->block_next && line->block_next < line) { + fprintf (stderr, "line link in wrong direction\n"); + ret = 0; + } + if ((size_t) line + line->size == (size_t) line->block_next) { + fprintf (stderr, "adjacant free line blocks\n"); + ret = 0; + } + if (line->block_prev != l) { + fprintf (stderr, "line block_prev link incorrect\n"); + ret = 0; + } + if (line->size > block->pre_size) { + fprintf (stderr, "line size too large: %zd / %zd\n", + line->size, block->pre_size); + ret = 0; + } + if (line->size % MEM_LINE_SIZE) { + fprintf (stderr, "bad line size: %zd / %zd\n", + line->size, line->size % MEM_LINE_SIZE); + ret = 0; + } + if (ret) { + free_bytes += line->size; + } + } + if (ret) { + if (free_bytes + block->pre_allocated != block->pre_size) { + fprintf (stderr, "block space mismatch: s: %zd a: %zd f: %zd\n", + block->pre_size, block->pre_allocated, free_bytes); + ret = 0; + } + if (line_count >= 0 && line_count != count) { + fprintf (stderr, "incorrect number of lines: e: %d g: %d\n", + line_count, count); + ret = 0; + } + if (allocated >= 0 && (size_t) allocated != block->pre_allocated) { + fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", + block->pre_allocated, allocated); + } + } + set_delete (visited); + return ret; +} + +static int __attribute__ ((pure)) +check_for_loop (memline_t *line, memline_t **stop) +{ + memline_t *next = line->free_next; + + for (memline_t **l = line->free_prev; l != stop; + l = line->free_prev) { + line = (memline_t *) l; + if (line == next) { + return 1; + } + } + return 0; +} + +static int +check_bins (memsuper_t *super, int mask) +{ + int ret = 1; + for (int i = MAX_CACHE_LINES; i-- > 0; ) { + if (mask >= 0) { + if (mask & (1 << i)) { + if (!super->free_lines[i]) { + fprintf (stderr, "super free_lines[%d] is empty\n", i); + ret = 0; + } + } else { + if (super->free_lines[i]) { + fprintf (stderr, "super free_lines[%d] is occupied\n", i); + ret = 0; + } + } + } + for (memline_t **l = &super->free_lines[i]; *l; l = &(*l)->free_next) { + memline_t *line = *l; + if (line->free_prev != l) { + fprintf (stderr, "super free_lines[%d] has bad prev\n", i); + ret = 0; + break; + } + if (check_for_loop (line, &super->free_lines[i])) { + fprintf (stderr, "super free_lines[%d] loop detected\n", i); + ret = 0; + break; + } + if ((MEM_LINE_SIZE << i) > (int) line->size + || (MEM_LINE_SIZE << (i + 1)) <= (int) line->size) { + fprintf (stderr, "line in wrong i: %d %d %zd\n", + i, MEM_LINE_SIZE << i, line->size); + ret = 0; + } + } + } + return ret; +} + +static int +test_line (memsuper_t *super) +{ + memline_t *line1 = cmemalloc (super, MEM_LINE_SIZE); + memline_t *line2 = cmemalloc (super, MEM_LINE_SIZE); + memline_t *line3 = cmemalloc (super, MEM_LINE_SIZE); + memblock_t *block = super->memblocks; + + if (block->next) { + fprintf (stderr, "too many memblocks\n"); + return 0; + } + if (line1 < (memline_t *) block->mem || line1 >= (memline_t *) block) { + fprintf (stderr, "line1 outside block line pool\n"); + return 0; + } + if (line2 < (memline_t *) block->mem || line2 >= (memline_t *) block) { + fprintf (stderr, "line2 outside block line pool\n"); + return 0; + } + if (line3 < (memline_t *) block->mem || line3 >= (memline_t *) block) { + fprintf (stderr, "line3 outside block line pool\n"); + return 0; + } + if (!((size_t) line1 & super->page_mask)) { + fprintf (stderr, "line1 is page aligned\n"); + return 0; + } + if (!((size_t) line2 & super->page_mask)) { + fprintf (stderr, "line2 is page aligned\n"); + return 0; + } + if (!((size_t) line3 & super->page_mask)) { + fprintf (stderr, "line3 is page aligned\n"); + return 0; + } + if (line1 + 1 != line2 || line2 + 1 != line3) { + fprintf (stderr, "lines not contiguous\n"); + return 0; + } + if (line3 + 1 != block->free_lines) { + fprintf (stderr, "line3 not contiguous with free lines\n"); + return 0; + } + + if (!check_block (block, 1, 3 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 1 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 1 failed\n"); + return 0; + } + + cmemfree (super, line2); + + if (!check_block (block, 2, 2 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 2 failed\n"); + return 0; + } + if (!check_bins (super, 0x21)) { + fprintf (stderr, "bin check 2 failed\n"); + return 0; + } + + if (block->free_lines != line2) { + fprintf (stderr, "block free_lines not pointing to line2\n"); + return 0; + } + if (super->free_lines[0] != line2) { + fprintf (stderr, "super free_lines[0] not pointing to line2\n"); + return 0; + } + + cmemfree (super, line3); + if (!check_block (block, 1, 1 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 3 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 3 failed\n"); + return 0; + } + + if (block->free_lines != line2) { + fprintf (stderr, "free lines not pointing to line2 2\n"); + return 0; + } + + cmemfree (super, line1); + if (super->memblocks) { + fprintf (stderr, "line pool not freed\n"); + return 0; + } + if (!check_bins (super, 0x00)) { + fprintf (stderr, "bins not cleared\n"); + return 0; + } + + line1 = cmemalloc (super, MEM_LINE_SIZE); + line2 = cmemalloc (super, MEM_LINE_SIZE); + line3 = cmemalloc (super, MEM_LINE_SIZE); + block = super->memblocks; + + if (!check_block (block, 1, 3 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 4 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 4 failed\n"); + return 0; + } + + cmemfree (super, line1); + + if (!check_block (block, 2, 2 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 5 failed\n"); + return 0; + } + if (!check_bins (super, 0x21)) { + fprintf (stderr, "bin check 5 failed\n"); + return 0; + } + + cmemfree (super, line2); + + if (!check_block (block, 2, 1 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 6 failed\n"); + return 0; + } + if (!check_bins (super, 0x22)) { + fprintf (stderr, "bin check 6 failed\n"); + return 0; + } + + cmemfree (super, line3); + if (super->memblocks) { + fprintf (stderr, "line pool not freed 2\n"); + return 0; + } + if (!check_bins (super, 0x00)) { + fprintf (stderr, "bins not cleared 2\n"); + return 0; + } + + line1 = cmemalloc (super, MEM_LINE_SIZE); + line2 = cmemalloc (super, MEM_LINE_SIZE); + line3 = cmemalloc (super, MEM_LINE_SIZE); + block = super->memblocks; + + if (!check_block (block, 1, 3 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 7 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 7 failed\n"); + return 0; + } + + cmemfree (super, line3); + + if (!check_block (block, 1, 2 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 8 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 8 failed\n"); + return 0; + } + + cmemfree (super, line2); + + if (!check_block (block, 1, 1 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 9 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 9 failed\n"); + return 0; + } + + cmemfree (super, line1); + if (super->memblocks) { + fprintf (stderr, "line pool not freed 3\n"); + return 0; + } + if (!check_bins (super, 0x00)) { + fprintf (stderr, "bins not cleared 3\n"); + return 0; + } + + return 1; +} + +typedef struct { + size_t size; + int group_id; +} sline_block_t; + +static sline_block_t group_tests[] = { + { 2, 4}, + { 4, 4}, + { 5, 8}, + { 3, 4}, + { 1, 4}, + { 6, 8}, + { 9, 16}, + { 4, 4}, + { 4, 4}, + { 7, 8}, + { 2, 4}, + { 4, 4}, + { 8, 8}, + {13, 16}, + { 3, 4}, + { 1, 4}, + { 8, 8}, + { 8, 8}, + { 4, 4}, + { 4, 4}, + {16, 16}, + {32, 32}, + {32, 33}, +}; +#define num_group_tests (sizeof (group_tests) / sizeof (group_tests[0])) +#define mask(x) (((size_t) (x)) & ~(MEM_LINE_SIZE - 1)) +#define pagemask(x,o,s) (((size_t) (x)) & (o (s)->page_mask)) + +static int +test_sline (memsuper_t *super) +{ + void *mem[num_group_tests]; + int ret = 1; + + for (size_t i = 0; i < num_group_tests; i++) { + mem[i] = cmemalloc (super, group_tests[i].size); + if (!mem[i]) { + fprintf (stderr, "mem[%zd] is null\n", i); + return 0; + } + if (!((size_t) mem[i] % MEM_LINE_SIZE)) { + fprintf (stderr, "mem[%zd] is aligned with chache line\n", i); + ret = 0; + } + } + for (size_t i = 0; i < num_group_tests; i++) { + for (size_t j = i + 1; j < num_group_tests; j++) { + if (mem[i] == mem[j]) { + fprintf (stderr, "mem[%zd] is dupped with %zd\n", i, j); + ret = 0; + } + if (mask (mem[i]) == mask (mem[j])) { + if (group_tests[i].group_id != group_tests[j].group_id) { + fprintf (stderr, "mem[%zd](%d) is grouped with %zd(%d)\n", + i, group_tests[i].group_id, + j, group_tests[j].group_id); + ret = 0; + } + } else { + if (group_tests[i].group_id == group_tests[j].group_id) { + fprintf (stderr, + "mem[%zd](%d) is not grouped with %zd(%d)\n", + i, group_tests[i].group_id, + j, group_tests[j].group_id); + ret = 0; + } + } + if (pagemask (mem[i], ~, super) != pagemask (mem[j], ~, super)) { + fprintf (stderr, + "mem[%zd](%d) is not block grouped with %zd(%d)\n", + i, group_tests[i].group_id, + j, group_tests[j].group_id); + } + } + } + for (size_t i = 0; i < num_group_tests; i++) { + cmemfree (super, mem[i]); + void *newmem = cmemalloc (super, group_tests[i].size); + if (newmem != mem[i]) { + fprintf (stderr, + "%2zd bytes not recycled (%2zd,%2d) (%06zx %06zx)\n", + group_tests[i].size, i, group_tests[i].group_id, + pagemask (mem[i], ~~, super), + pagemask (newmem, ~~, super)); + ret = 0; + } + if (!((size_t) newmem % MEM_LINE_SIZE)) { + fprintf (stderr, "newmem is aligned with chache line %p\n", + newmem); + ret = 0; + } + } + return ret; +} + +static int +test_block_line (memsuper_t *super) +{ + void *mem = cmemalloc (super, 2 * super->page_size); + void *line; + memblock_t *block = super->memblocks; + + if (block + 1 != (memblock_t *) mem) { + fprintf (stderr, "super memblocks do not point to mem\n"); + return 0; + } + if (block->pre_size < MEM_LINE_SIZE) { + // need to figure out a way to guarantee a shared block + fprintf (stderr, "can't allocate line from block\n"); + return 0; + } + if (block->next) { + fprintf (stderr, "excess blocks in super\n"); + return 0; + } + line = cmemalloc (super, MEM_LINE_SIZE); + if (!((size_t) line & super->page_mask)) { + fprintf (stderr, "line is page aligned\n"); + return 0; + } + if (super->memblocks->next) { + // need to figure out a way to guarantee a shared block + fprintf (stderr, "mem and line not in same block\n"); + return 0; + } + cmemfree (super, mem); + if (!super->memblocks) { + fprintf (stderr, "shared block freed\n"); + return 0; + } + if (cmemalloc (super, super->page_size) != mem) { + fprintf (stderr, "block not reused for mem\n"); + return 0; + } + if (super->memblocks != block || super->memblocks->next) { + // need to figure out a way to guarantee a shared block + fprintf (stderr, "blocks corrupt\n"); + return 0; + } + cmemfree (super, line); + if (!super->memblocks) { + fprintf (stderr, "shared block freed 2\n"); + return 0; + } + cmemfree (super, mem); + if (super->memblocks) { + fprintf (stderr, "shared block not freed\n"); + return 0; + } + return 1; +} + +int +main (void) +{ + memsuper_t *super = new_memsuper (); + int i; + + if (sizeof (memsuper_t) != 2 * MEM_LINE_SIZE) { + fprintf (stderr, "memsuper_t not 2 * cache size: %zd\n", + sizeof (memsuper_t)); + return 1; + } + if (sizeof (memline_t) != MEM_LINE_SIZE) { + fprintf (stderr, "memline_t not cache size: %zd\n", + sizeof (memline_t)); + return 1; + } + if (sizeof (memsline_t) != 2 * sizeof (void *)) { + fprintf (stderr, "memsline_t not two pointers: %zd\n", + sizeof (memsline_t)); + return 1; + } + if (sizeof (memblock_t) != MEM_LINE_SIZE) { + fprintf (stderr, "memblock_t not cache size: %zd\n", + sizeof (memblock_t)); + return 1; + } + if ((size_t) super & (MEM_LINE_SIZE - 1)) { + fprintf (stderr, "super block not cache aligned: %p\n", super); + return 1; + } + if (super->page_size != (size_t) sysconf (_SC_PAGESIZE)) { + fprintf (stderr, "page size not equal to system page size: %zd, %zd\n", + super->page_size, sysconf (_SC_PAGESIZE)); + return 1; + } + if (!super->page_size || (super->page_size & (super->page_size - 1))) { + fprintf (stderr, "page size not power of two: %zd\n", + super->page_size); + return 1; + } + if (super->page_mask + 1 != super->page_size) { + fprintf (stderr, "page mask not page size - 1: %zx %zx\n", + super->page_mask, super->page_size); + return 1; + } + if (!super->page_mask || (super->page_mask & (super->page_mask + 1))) { + fprintf (stderr, "page mask not all 1s: %zx\n", + super->page_mask); + return 1; + } + if (super->memblocks) { + fprintf (stderr, "super block list not null\n"); + return 1; + } + for (i = 4; i-- > 0; ) { + if (super->last_freed[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super last_freed not all null\n"); + return 1; + } + for (i = MAX_CACHE_LINES; i-- > 0; ) { + if (super->free_lines[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super free_lines not all null\n"); + return 1; + } + if (!test_block (super)) { + fprintf (stderr, "block tests failed\n"); + return 1; + } + if (super->memblocks) { + fprintf (stderr, "super block list not null 2\n"); + return 1; + } + for (i = 4; i-- > 0; ) { + if (super->last_freed[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super last_freed not all null 2\n"); + return 1; + } + for (i = MAX_CACHE_LINES; i-- > 0; ) { + if (super->free_lines[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super free_lines not all null 2\n"); + return 1; + } + if (!test_line (super)) { + fprintf (stderr, "line tests failed\n"); + return 1; + } + if (super->memblocks) { + fprintf (stderr, "super block list not null 2\n"); + return 1; + } + if (!test_block_line (super)) { + fprintf (stderr, "block-line tests failed\n"); + return 1; + } + for (size_t i = 0; i < 2 * super->page_size / MEM_LINE_SIZE; i++) { + void *line = cmemalloc (super, MEM_LINE_SIZE); + if (!line) { + fprintf (stderr, "could not allocate %d byte line\n", + MEM_LINE_SIZE); + return 1; + } + if ((size_t) line % MEM_LINE_SIZE) { + fprintf (stderr, "line not cache-line aligned: %p %d\n", + line, MEM_LINE_SIZE); + return 1; + } + if (!((size_t) line & super->page_mask)) { + fprintf (stderr, "line is page aligned: %p %zd\n", + line, super->page_size); + return 1; + } + } + if (!test_sline (super)) { + fprintf (stderr, "sub-line tests failed\n"); + return 1; + } + delete_memsuper (super); + return 0; +} diff --git a/libs/util/test/test-darray.c b/libs/util/test/test-darray.c new file mode 100644 index 000000000..59d3a2ddc --- /dev/null +++ b/libs/util/test/test-darray.c @@ -0,0 +1,213 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#define remove remove_renamed +#include +#include +#include + +#include "QF/darray.h" +#include "QF/sys.h" +#undef remove + +typedef int (*test_func) (int a, int b); +typedef struct intarray_s DARRAY_TYPE(int) intarray_t; + +intarray_t intarray = {0, 0, 16, 0}; + +static int +append (int val, int b) +{ + return DARRAY_APPEND (&intarray, val); +} + +static int +check_size (int a, int b) +{ + return intarray.size; +} + +static int +check_maxSize (int a, int b) +{ + return intarray.maxSize; +} + +static int +check_grow (int a, int b) +{ + return intarray.grow; +} + +static int +check_maxSizeGrowth (int a, int b) +{ + return intarray.maxSize % intarray.grow; +} + +static int +check_array (int a, int b) +{ + return !!intarray.a; +} + +static int __attribute__((pure)) +check_value (int index, int b) +{ + if ((size_t) index >= intarray.size) { + Sys_Error ("indexing beyond array"); + } + return intarray.a[index]; +} + +static int +insert_at (int val, int pos) +{ + return DARRAY_INSERT_AT (&intarray, val, pos); +} + +static int +open_at (int pos, int size) +{ + return DARRAY_OPEN_AT (&intarray, pos, size) - intarray.a; +} + +static const char text[] = "Aloy is an awesome huntress."; +static int +open_at2 (int pos, int size) +{ + memcpy(DARRAY_OPEN_AT (&intarray, pos, size), text, size * sizeof (int)); + return strcmp((char*) (intarray.a + pos), text); +} + +static int +remove_at (int pos, int b) +{ + return DARRAY_REMOVE_AT (&intarray, pos); +} + +static int +remove (int pos, int b) +{ + return DARRAY_REMOVE (&intarray); +} + +static int +close_at (int pos, int size) +{ + return DARRAY_CLOSE_AT (&intarray, pos, size); +} + +static int +clear (int a, int b) +{ + DARRAY_CLEAR (&intarray); + return 0; +} + +static int +resize (int size, int b) +{ + DARRAY_RESIZE (&intarray, size); + return 0; +} + +struct { + test_func test; + int param1, param2; + int test_expect; +} tests[] = { + {check_size, 0, 0, 0}, // confirm array empty but can grow + {check_maxSize, 0, 0, 0}, + {check_grow, 0, 0, 16}, + {check_array, 0, 0, 0}, + {append, 5, 0, 5}, // test first append to emtpty array + {check_size, 0, 0, 1}, + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 16}, + {check_array, 0, 0, 1}, + {check_value, 0, 0, 5}, + {append, 42, 0, 42}, // test a second append + {check_size, 0, 0, 2}, + {check_maxSize, 0, 0, 16}, + {check_value, 0, 0, 5}, + {check_value, 1, 0, 42}, + {insert_at, 69, 1, 69}, // test insertions + {insert_at, 96, 0, 96}, + {check_size, 0, 0, 4}, + {check_maxSize, 0, 0, 16}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 5}, + {check_value, 2, 0, 69}, + {check_value, 3, 0, 42}, + {open_at, 2, 14, 2}, // test opening a large hole + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 18}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 5}, + {check_value, 16, 0, 69}, + {check_value, 17, 0, 42}, + {close_at, 1, 15, 5}, // test block removal + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 3}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 69}, + {check_value, 2, 0, 42}, + {remove, 0, 0, 42}, // test "pop" + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 2}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 69}, + {remove_at, 0, 0, 96}, // test remove at + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 1}, + {check_value, 0, 0, 69}, + {insert_at, 71, 1, 71}, // test insertion at end + {resize, 48, 0, 0}, // test resize bigger + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 48}, + {check_size, 0, 0, 48}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 71}, + {resize, 24, 0, 0}, // test resize smaller + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 48}, + {check_size, 0, 0, 24}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 71}, + {open_at2, 1, (sizeof (text) + sizeof (int) - 1) / sizeof (int), 0}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 0x796f6c41}, + {check_value, 9, 0, 71}, + {clear, 0, 0, 0}, // test clearing + {check_size, 0, 0, 0}, + {check_maxSize, 0, 0, 0}, + {check_array, 0, 0, 0}, +}; +#define num_tests (sizeof (tests) / sizeof (tests[0])) +int test_start_line = __LINE__ - num_tests - 2; + +int +main (int argc, const char **argv) +{ + int res = 0; + + size_t i; + + for (i = 0; i < num_tests; i++) { + if (tests[i].test) { + int test_res; + test_res = tests[i].test (tests[i].param1, tests[i].param2); + if (test_res != tests[i].test_expect) { + res |= 1; + printf ("test %d (line %d) failed\n", (int) i, + (int) i + test_start_line); + printf ("expect: %d\n", tests[i].test_expect); + printf ("got : %d\n", test_res); + continue; + } + } + } + return res; +} diff --git a/libs/util/test/test-mat3.c b/libs/util/test/test-mat3.c index 385200750..f852d281a 100644 --- a/libs/util/test/test-mat3.c +++ b/libs/util/test/test-mat3.c @@ -80,7 +80,8 @@ negate: return 1; fail: - printf ("\n\n(%g %g %g)\n", VectorExpand (angles)); + printf ("\ntest_angle\n"); + printf ("(%g %g %g)\n", VectorExpand (angles)); printf (" [%g %g %g %g]\n", QuatExpand (rotation)); printf (" [%g %g %g %g] [%g %g %g] [%g %g %g]\n", QuatExpand (r), VectorExpand (scale), VectorExpand (shear)); @@ -110,7 +111,8 @@ test_transform (const vec3_t angles, const vec3_t scale) return 1; fail: - printf ("\n\n(%g %g %g) (%g %g %g)\n", VectorExpand (angles), + printf ("\ntest_transform\n"); + printf ("(%g %g %g) (%g %g %g)\n", VectorExpand (angles), VectorExpand (scale)); printf (" (%g %g %g)\n", VectorExpand (x)); printf (" (%g %g %g)\n", VectorExpand (y)); @@ -146,7 +148,8 @@ test_transform2 (const vec3_t angles, const vec3_t scale) return 1; fail: - printf ("\n\n(%g %g %g) (%g %g %g) (%g %g %g)\n", + printf ("\ntest_transform2\n"); + printf ("(%g %g %g) (%g %g %g) (%g %g %g)\n", VectorExpand (angles), VectorExpand (scale), VectorExpand (v)); printf (" (%g %g %g)\n", VectorExpand (x)); printf (" (%g %g %g)\n", VectorExpand (y)); @@ -173,7 +176,8 @@ test_inverse (const vec3_t angles, const vec3_t scale) return 1; fail: - printf ("\n\n(%g %g %g) (%g %g %g)\n", + printf ("\ntest_inverse\n"); + printf ("(%g %g %g) (%g %g %g)\n", VectorExpand (angles), VectorExpand (scale)); printf (" [%g %g %g]\n [%g %g %g]\n [%g %g %g]\n\n", Mat3Expand (mat)); printf (" [%g %g %g]\n [%g %g %g]\n [%g %g %g]\n\n", Mat3Expand (inv)); diff --git a/libs/util/test/test-mat4.c b/libs/util/test/test-mat4.c index 623444a0d..1bd7afcc9 100644 --- a/libs/util/test/test-mat4.c +++ b/libs/util/test/test-mat4.c @@ -58,8 +58,8 @@ static vec3_t test_scales[] = { { 3, 1, 2}, { 3, 2, 1}, }; -#define num_translation_tests \ - (sizeof (test_translations) / sizeof (test_translations[0])) +#define num_scale_tests \ + (sizeof (test_scales) / sizeof (test_scales[0])) // return true if a and b are close enough (yay, floats) static int @@ -143,7 +143,8 @@ test_transform2 (const vec3_t angles, const vec3_t scale, vec3_t x, y; quat_t rotation; mat4_t mat; - vec3_t rot, sc, sh, tr; + quat_t rot; + vec3_t sc, sh, tr; VectorCopy (v, x); AngleQuat (angles, rotation); @@ -171,6 +172,9 @@ fail: VectorExpand (translation), VectorExpand (v)); printf (" (%g %g %g)\n", VectorExpand (x)); printf (" (%g %g %g)\n", VectorExpand (y)); + printf (" (%g %g %g %g) (%g %g %g %g) (%g %g %g) (%g %g %g) (%g %g %g)\n", + QuatExpand (rotation), QuatExpand (rot), VectorExpand (sh), + VectorExpand (sc), VectorExpand (tr)); return 0; } @@ -214,33 +218,41 @@ main (int argc, const char **argv) size_t i, j, k; for (i = 0; i < num_angle_tests; i ++) { - if (!test_angle (test_angles[i])) + if (!test_angle (test_angles[i])) { res = 1; + printf("angle test %zd failed\n", i); + } } for (i = 0; i < num_angle_tests; i ++) { - for (j = 0; j < num_translation_tests; j ++) { + for (j = 0; j < num_scale_tests; j ++) { for (k = 0; k < num_translation_tests; k ++) { if (!test_transform (test_angles[i], test_scales[j], - test_translations[k])) + test_translations[k])) { res = 1; + printf("transform test %zd:%zd:%zd failed\n", i, j, k); + } } } } for (i = 0; i < num_angle_tests; i ++) { - for (j = 0; j < num_translation_tests; j ++) { + for (j = 0; j < num_scale_tests; j ++) { for (k = 0; k < num_translation_tests; k ++) { if (!test_transform2 (test_angles[i], test_scales[j], - test_translations[k])) + test_translations[k])) { res = 1; + printf("transform2 test %zd:%zd:%zd failed\n", i, j, k); + } } } } for (i = 0; i < num_angle_tests; i ++) { - for (j = 0; j < num_translation_tests; j ++) { + for (j = 0; j < num_scale_tests; j ++) { for (k = 0; k < num_translation_tests; k ++) { if (!test_inverse (test_angles[i], test_scales[j], - test_translations[k])) + test_translations[k])) { res = 1; + printf("inverse test %zd:%zd:%zd failed\n", i, j, k); + } } } } diff --git a/libs/util/test/test-plist.c b/libs/util/test/test-plist.c index 20ab1e94e..d3ce32715 100644 --- a/libs/util/test/test-plist.c +++ b/libs/util/test/test-plist.c @@ -2,7 +2,7 @@ # include "config.h" #endif #include -#include "QF/qfplist.h" +#include "QF/plist.h" static const char *test_strings[] = { "Guarding the entrance to the Grendal\n" @@ -11,7 +11,7 @@ static const char *test_strings[] = { "of the Shadow cult.\n\n" "For years the Shadow Gate existed in\n" "obscurity but after the cult discovered\n" - "the \3023\354\341\343\353\240\307\341\364\345 in the caves below\n" + "the \302\354\341\343\353\240\307\341\364\345 in the caves below\n" "the empire took notice.\n" "A batallion of Imperial Knights were\n" "sent to the gate to destroy the cult\n" @@ -29,7 +29,7 @@ test_string_io (const char *str) item = PL_NewString (str); saved = PL_WritePropertyList (item); PL_Free (item); - item = PL_GetPropertyList (saved); + item = PL_GetPropertyList (saved, 0); res = PL_String (item); if (!strcmp (str, res)) return 1; diff --git a/libs/util/test/test-quat.c b/libs/util/test/test-quat.c index 58a3e0a2f..cafceb2c8 100644 --- a/libs/util/test/test-quat.c +++ b/libs/util/test/test-quat.c @@ -4,6 +4,15 @@ #include "QF/mathlib.h" +static struct { + quat_t q1; + quat_t q2; + quat_t expect; +} quat_mult_tests[] = { + {{1, 2, 3, 4}, {5, 6, 7, 8}, {24, 48, 48, -6}}, +}; +#define num_quat_mult_tests (sizeof (quat_mult_tests) / sizeof (quat_mult_tests[0])) + //PITCH YAW ROLL static vec3_t test_angles[] = { {0, 0, 0}, @@ -20,6 +29,45 @@ static vec3_t test_angles[] = { }; #define num_angle_tests (sizeof (test_angles) / sizeof (test_angles[0])) +static struct { + vec3_t a; + vec3_t b; + quat_t expect; +} quat_vector_rotation_tests[] = { + {{1, 0, 0}, {1, 0, 0}, {0, 0, 0, 1}}, + {{0, 1, 0}, {0, 1, 0}, {0, 0, 0, 1}}, + {{0, 0, 1}, {0, 0, 1}, {0, 0, 0, 1}}, + {{1, 0, 0}, {8, 0, 0}, {0, 0, 0, 1}}, + {{0, 8, 0}, {0, 1, 0}, {0, 0, 0, 1}}, + {{0, 0, 8}, {0, 0, 8}, {0, 0, 0, 1}}, + {{1, 0, 0}, {-1, 0, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, -1, 0}, {0, 1, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, 0, 1}, {0, 0, -1}, {0, 0, 0, 0}}, // x, y, z = NaN + {{-1, 0, 0}, {8, 0, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, 8, 0}, {0, -1, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, 0, -8}, {0, 0, 8}, {0, 0, 0, 0}}, // x, y, z = NaN + // excessive for float, but if vec_t becomes double... + // 1/50 second orbiting JNSQ Kerbin at 120km altitude. While this has + // nothing to do with quakeforge (yet?), it came up when testing camera + // rotation in KSP and Unity failed miserably. I don't remember the exact + // details, but I could see significant snapping in the rotation (I thought + // it was a few times per second, but these numbers indicate it must have + // been every few seconds). + // The quaternion is unit to 9 sigfigs (a little larger) + {{1720000, 0, 0}, {1719999.9983028059, 76.409082595828366, 0}, {0, 0, 2.22119434e-5, 1}}, + // 1/20 second, same situation + {{1720000, 0, 0}, {1719999.9893925365, 191.02270615971355, 0}, {0, 0, 5.55298575e-5, 1}}, + // 1/5 second, same situation + {{1720000, 0, 0}, {1719999.8302805868, 764.09080107761736, 0}, {0, 0, 2.2211943e-4, 1}}, + // 1/4 second, same situation + {{1720000, 0, 0}, {1719999.7348134194, 955.11348367609469, 0}, {0, 0, 2.77649262e-4, 1}}, + // 1/3 second, same situation. This is (float) 1 ulp in w: about 0.0424 + // degrees. + // The quaternion is unit to 9 sigfigs (a little larger) + {{1720000, 0, 0}, {1719999.5285571995, 1273.4845939975546, 0}, {0, 0, 3.70199094e-4, 0.99999994}}, +}; +#define num_quat_vector_rotation_tests (sizeof (quat_vector_rotation_tests) / sizeof (quat_vector_rotation_tests[0])) + // return true if a and b are close enough (yay, floats) static int compare (vec_t a, vec_t b) @@ -28,60 +76,96 @@ compare (vec_t a, vec_t b) return diff * diff < 0.001; } +static int +test_quat_mult(const quat_t q1, const quat_t q2, const quat_t expect) +{ + int i; + quat_t r; + + QuatMult (q1, q2, r); + + for (i = 0; i < 4; i++) + if (!compare (r[i], expect[i])) + goto fail; + return 1; +fail: + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (q1)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (q2)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (r)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (expect)); + return 0; +} + + +static void +rotate_vec (const quat_t r, const vec3_t v, vec3_t out) +{ + quat_t qv = {0, 0, 0, 0}; + quat_t t; + + VectorCopy (v, qv); + + QuatConj (r, t); + QuatMult (qv, t, t); + QuatMult (r, t, t); + VectorCopy (t, out); +} + static int test_rotation (const vec3_t angles) { int i; vec3_t forward, right, up; - quat_t quat, f, r, u, t; - quat_t qf = {0, 1, 0, 0}; - quat_t qr = {0, 0, -1, 0}; - quat_t qu = {0, 0, 0, 1}; + quat_t quat, conj, f, r, u, t; + quat_t qf = {1, 0, 0, 0}; + quat_t qr = {0, -1, 0, 0}; + quat_t qu = {0, 0, 1, 0}; AngleVectors (angles, forward, right, up); AngleQuat (angles, quat); + QuatConj (quat, conj); // rotate forward vector - QuatConj (quat, t); - QuatMult (qf, t, t); + QuatMult (qf, conj, t); QuatMult (quat, t, f); // rotate right vector - QuatConj (quat, t); - QuatMult (qr, t, t); + QuatMult (qr, conj, t); QuatMult (quat, t, r); // rotate up vector - QuatConj (quat, t); - QuatMult (qu, t, t); + QuatMult (qu, conj, t); QuatMult (quat, t, u); - if (!compare (f[0], 0)) + if (!compare (f[3], 0)) goto fail; for (i = 0; i < 3; i++) - if (!compare (forward[i], f[i + 1])) + if (!compare (forward[i], f[i])) goto fail; - if (!compare (r[0], 0)) + if (!compare (r[3], 0)) goto fail; for (i = 0; i < 3; i++) - if (!compare (right[i], r[i + 1])) + if (!compare (right[i], r[i])) goto fail; - if (!compare (u[0], 0)) + if (!compare (u[3], 0)) goto fail; for (i = 0; i < 3; i++) - if (!compare (up[i], u[i + 1])) + if (!compare (up[i], u[i])) goto fail; return 1; fail: - printf ("\n\n%g %g %g\n\n", angles[0], angles[1], angles[2]); - printf ("%g %g %g\n", forward[0], forward[1], forward[2]); - printf ("%g %g %g\n", right[0], right[1], right[2]); - printf ("%g %g %g\n\n", up[0], up[1], up[2]); + printf ("\ntest_rotation\n"); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand (angles)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (quat)); + printf ("%11.9g %11.9g %11.9g %11.9g\n\n", QuatExpand (conj)); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand (forward)); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand (right)); + printf ("%11.9g %11.9g %11.9g\n\n", VectorExpand (up)); - printf ("%g %g %g %g\n", f[0], f[1], f[2], f[3]); - printf ("%g %g %g %g\n", r[0], r[1], r[2], r[3]); - printf ("%g %g %g %g\n", u[0], u[1], u[2], u[3]); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (f)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (r)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (u)); return 0; } @@ -120,14 +204,186 @@ test_rotation2 (const vec3_t angles) goto fail; return 1; fail: - printf ("\n\n%g %g %g\n\n", angles[0], angles[1], angles[2]); - printf ("%g %g %g\n", forward[0], forward[1], forward[2]); - printf ("%g %g %g\n", right[0], right[1], right[2]); - printf ("%g %g %g\n\n", up[0], up[1], up[2]); + printf ("\ntest_rotation2\n"); + printf ("\n\n%11.9g %11.9g %11.9g\n\n", angles[0], angles[1], angles[2]); + printf ("%11.9g %11.9g %11.9g\n", forward[0], forward[1], forward[2]); + printf ("%11.9g %11.9g %11.9g\n", right[0], right[1], right[2]); + printf ("%11.9g %11.9g %11.9g\n\n", up[0], up[1], up[2]); - printf ("%g %g %g\n", f[0], f[1], f[2]); - printf ("%g %g %g\n", r[0], r[1], r[2]); - printf ("%g %g %g\n", u[0], u[1], u[2]); + printf ("%11.9g %11.9g %11.9g\n", f[0], f[1], f[2]); + printf ("%11.9g %11.9g %11.9g\n", r[0], r[1], r[2]); + printf ("%11.9g %11.9g %11.9g\n", u[0], u[1], u[2]); + return 0; +} + +static int +test_rotation3 (const vec3_t angles) +{ + int i; + quat_t quat; + vec3_t v = {1, 1, 1}; + vec3_t a, b; + + AngleQuat (angles, quat); + QuatMultVec (quat, v, a); + rotate_vec (quat, v, b); + + for (i = 0; i < 3; i++) + if (!compare (a[i], b[i])) + goto fail; + return 1; +fail: + printf ("\ntest_rotation3\n"); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand(a)); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand(b)); + return 0; +} + +// XXX FIXME see usage in test_rotation4. need to investigate whether +// -ffast-math is any real benefit +#define ISNAN(x) (((x) & 0x7f800000) == 0x7f800000 && ((x) & 0x7fffff)) + +static int +test_rotation4 (const vec3_t a, const vec3_t b, const quat_t expect) +{ + int i; + union { int x[4]; vec_t q[4]; } q; + vec_t *quat = q.q; + vec3_t t; + vec_t d = 0; + + VectorZero (t); + + // find the rotation vector between a and b + QuatRotation (a, b, quat); + + if (quat[3] == 0) { + if (expect[3] != 0) { + goto fail; + } + // expect NaN for the vector components because the vectors are + // anti-parallel and thus the rotation axis is undefined + //XXX FIXME(?) still using -ffast-math which implies + // -ffinite-math-only which in turn disables nan/inf checks, so have + // to do it by hand + // if (!(isnan(quat[0]) && isnan(quat[1]) && isnan(quat[2]))) { + if (!(ISNAN(q.x[0]) && ISNAN(q.x[1]) && ISNAN(q.x[2]))) { + goto fail; + } + } else { + // the vectors are not anti-parallel and thus the rotation axis is + // defined, so NaN is invalid + // XXX FIXME see above + //if (isnan(quat[0]) || isnan(quat[1]) || isnan(quat[2])) { + if (ISNAN(q.x[0]) || ISNAN(q.x[1]) || ISNAN(q.x[2])) { + goto fail; + } + for (i = 0; i < 4; i++) { + // yes, float precision will make it difficult to set up expect + // but it is at least consistent (ie, the "errors" are not at all + // random and thus will be the same from run to run) + if (quat[i] != expect[i]) { + goto fail; + } + } + QuatMultVec(quat, a, t); + + d = DotProduct (t, b) / (VectorLength (t) * VectorLength (b)) - 1; + if (d * d > 1e-8) { + goto fail; + } + } + return 1; +fail: + printf ("\ntest_rotation4\n"); + printf ("a: %11.9g %11.9g %11.9g\n", VectorExpand(a)); + printf ("b: %11.9g %11.9g %11.9g\n", VectorExpand(b)); + printf ("q: %11.9g %11.9g %11.9g %11.9g\n", QuatExpand(quat)); + printf ("e: %11.9g %11.9g %11.9g %11.9g\n", QuatExpand(expect)); + printf ("t: %11.9g %11.9g %11.9g\n", VectorExpand(t)); + printf ("d: %11.9g\n", d); + return 0; +} + +#define s05 0.70710678118654757 + +static struct { + quat_t q; + vec_t expect[9]; +} quat_mat_tests[] = { + {{0, 0, 0, 1}, + {1, 0, 0, + 0, 1, 0, + 0, 0, 1}}, + {{1, 0, 0, 0}, + {1, 0, 0, + 0, -1, 0, + 0, 0, -1}}, + {{0, 1, 0, 0}, + {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}}, + {{0, 0, 1, 0}, + {-1, 0, 0, + 0, -1, 0, + 0, 0, 1}}, + {{0.5, 0.5, 0.5, 0.5}, + {0, 0, 1, + 1, 0, 0, + 0, 1, 0}}, + {{s05, 0.0, 0.0, s05}, + {1, 0, 0, + 0, 5.96046448e-8, -0.99999994, + 0, 0.99999994, 5.96046448e-8}}, +}; +#define num_quat_mat_tests (sizeof (quat_mat_tests) / sizeof (quat_mat_tests[0])) + +static int +test_quat_mat(const quat_t q, const quat_t expect) +{ + int i; + vec_t m[9]; + + QuatToMatrix (q, m, 0, 0); + + for (i = 0; i < 9; i++) + if (m[i] != expect[i]) // exact tests here + goto fail; + return 1; +fail: + printf ("\ntest_quat_mat\n"); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (q)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 0), VectorExpand (expect + 0)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 3), VectorExpand (expect + 3)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 6), VectorExpand (expect + 6)); + return 0; +} + +static int +test_quat_mat2(const quat_t q, const quat_t expect) +{ + int i; + vec_t m[9]; + + QuatToMatrix (q, m, 0, 1); + Mat3Transpose (m, m); + + for (i = 0; i < 9; i++) + if (m[i] != expect[i]) // exact tests here + goto fail; + return 1; +fail: + printf ("\ntest_quat_mat\n"); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (q)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 0), VectorExpand (expect + 0)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 3), VectorExpand (expect + 3)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 6), VectorExpand (expect + 6)); return 0; } @@ -137,6 +393,14 @@ main (int argc, const char **argv) int res = 0; size_t i; + for (i = 0; i < num_quat_mult_tests; i ++) { + vec_t *q1 = quat_mult_tests[i].q1; + vec_t *q2 = quat_mult_tests[i].q2; + vec_t *expect = quat_mult_tests[i].expect; + if (!test_quat_mult (q1, q2, expect)) + res = 1; + } + for (i = 0; i < num_angle_tests; i ++) { if (!test_rotation (test_angles[i])) res = 1; @@ -146,5 +410,34 @@ main (int argc, const char **argv) if (!test_rotation2 (test_angles[i])) res = 1; } + + for (i = 0; i < num_angle_tests; i ++) { + if (!test_rotation3 (test_angles[i])) + res = 1; + } + + for (i = 0; i < num_quat_vector_rotation_tests; i++) { + vec_t *a = quat_vector_rotation_tests[i].a; + vec_t *b = quat_vector_rotation_tests[i].b; + vec_t *expect = quat_vector_rotation_tests[i].expect; + if (!test_rotation4 (a, b, expect)) { + res = 1; + } + } + + for (i = 0; i < num_quat_mat_tests; i ++) { + vec_t *q = quat_mat_tests[i].q; + vec_t *expect = quat_mat_tests[i].expect; + if (!test_quat_mat (q, expect)) + res = 1; + } + + for (i = 0; i < num_quat_mat_tests; i ++) { + vec_t *q = quat_mat_tests[i].q; + vec_t *expect = quat_mat_tests[i].expect; + if (!test_quat_mat2 (q, expect)) + res = 1; + } + return res; } diff --git a/libs/util/test/test-seb.c b/libs/util/test/test-seb.c index 801e1ff88..d5e900972 100644 --- a/libs/util/test/test-seb.c +++ b/libs/util/test/test-seb.c @@ -96,7 +96,7 @@ main (int argc, const char **argv) } } end = Sys_DoubleTime (); - printf ("%d itterations in %gs: %g itters/second\n", (int) i, end - start, + printf ("%d iterations in %gs: %g iters/second\n", (int) i, end - start, i / (end - start)); return res; } diff --git a/libs/util/test/test-simd.c b/libs/util/test/test-simd.c new file mode 100644 index 000000000..b14a1be9c --- /dev/null +++ b/libs/util/test/test-simd.c @@ -0,0 +1,593 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include "QF/mathlib.h" +#include "QF/simd/vec4d.h" +#include "QF/simd/vec4f.h" +#include "QF/simd/mat4f.h" + +#define right { 1, 0, 0 } +#define forward { 0, 1, 0 } +#define up { 0, 0, 1 } +#define one { 1, 1, 1, 1 } +#define half { 0.5, 0.5, 0.5, 0.5 } +#define zero { 0, 0, 0, 0 } +#define qident { 0, 0, 0, 1 } +#define qtest { 0.64, 0.48, 0, 0.6 } + +#define nright { -1, 0, 0 } +#define nforward { 0, -1, 0 } +#define nup { 0, 0, -1 } +#define none { -1, -1, -1, -1 } +#define nqident { 0, 0, 0, -1 } + +#define identity \ + { { 1, 0, 0, 0 }, \ + { 0, 1, 0, 0 }, \ + { 0, 0, 1, 0 }, \ + { 0, 0, 0, 1 } } +#define rotate120 \ + { { 0, 1, 0, 0 }, \ + { 0, 0, 1, 0 }, \ + { 1, 0, 0, 0 }, \ + { 0, 0, 0, 1 } } +#define rotate240 \ + { { 0, 0, 1, 0 }, \ + { 1, 0, 0, 0 }, \ + { 0, 1, 0, 0 }, \ + { 0, 0, 0, 1 } } + +#define s05 0.70710678118654757 + +typedef struct { + vec4d_t (*op) (vec4d_t a, vec4d_t b); + vec4d_t a; + vec4d_t b; + vec4d_t expect; + vec4d_t ulp_errors; +} vec4d_test_t; + +typedef struct { + vec4f_t (*op) (vec4f_t a, vec4f_t b); + vec4f_t a; + vec4f_t b; + vec4f_t expect; + vec4f_t ulp_errors; +} vec4f_test_t; + +typedef struct { + void (*op) (mat4f_t c, const mat4f_t a, const mat4f_t b); + mat4f_t a; + mat4f_t b; + mat4f_t expect; + mat4f_t ulp_errors; +} mat4f_test_t; + +typedef struct { + vec4f_t (*op) (const mat4f_t a, vec4f_t b); + mat4f_t a; + vec4f_t b; + vec4f_t expect; + vec4f_t ulp_errors; +} mv4f_test_t; + +typedef struct { + void (*op) (mat4f_t m, vec4f_t q); + vec4f_t q; + mat4f_t expect; + mat4f_t ulp_errors; +} mq4f_test_t; + +static vec4d_t tvtruncd (vec4d_t v, vec4d_t ignore) +{ + return vtruncd (v); +} + +static vec4d_t tvceild (vec4d_t v, vec4d_t ignore) +{ + return vceild (v); +} + +static vec4d_t tvfloord (vec4d_t v, vec4d_t ignore) +{ + return vfloord (v); +} + +static vec4d_t tqconjd (vec4d_t v, vec4d_t ignore) +{ + return qconjd (v); +} + +static vec4f_t tvtruncf (vec4f_t v, vec4f_t ignore) +{ + return vtruncf (v); +} + +static vec4f_t tvceilf (vec4f_t v, vec4f_t ignore) +{ + return vceilf (v); +} + +static vec4f_t tvfloorf (vec4f_t v, vec4f_t ignore) +{ + return vfloorf (v); +} + +static vec4f_t tqconjf (vec4f_t v, vec4f_t ignore) +{ + return qconjf (v); +} + +static vec4d_test_t vec4d_tests[] = { + // 3D dot products + { dotd, right, right, one }, + { dotd, right, forward, zero }, + { dotd, right, up, zero }, + { dotd, forward, right, zero }, + { dotd, forward, forward, one }, + { dotd, forward, up, zero }, + { dotd, up, right, zero }, + { dotd, up, forward, zero }, + { dotd, up, up, one }, + + // one is 4D, so its self dot product is 4 + { dotd, one, one, { 4, 4, 4, 4} }, + { dotd, one, none, {-4, -4, -4, -4} }, + + // 3D cross products + { crossd, right, right, zero }, + { crossd, right, forward, up }, + { crossd, right, up, nforward }, + { crossd, forward, right, nup }, + { crossd, forward, forward, zero }, + { crossd, forward, up, right }, + { crossd, up, right, forward }, + { crossd, up, forward, nright }, + { crossd, up, up, zero }, + // double whammy tests: cross product with an angled vector and + // ensuring that a 4d vector (non-zero w component) does not affect + // the result, including the result's w component remaining zero. + { crossd, right, one, { 0, -1, 1} }, + { crossd, forward, one, { 1, 0, -1} }, + { crossd, up, one, {-1, 1, 0} }, + { crossd, one, right, { 0, 1, -1} }, + { crossd, one, forward, {-1, 0, 1} }, + { crossd, one, up, { 1, -1, 0} }, + // This one fails when optimizing with -mfma (which is why fma is not + // used): ulp errors in z and w + { crossd, qtest, qtest, {0, 0, 0, 0} }, + + { qmuld, qident, qident, qident }, + { qmuld, qident, right, right }, + { qmuld, qident, forward, forward }, + { qmuld, qident, up, up }, + { qmuld, right, qident, right }, + { qmuld, forward, qident, forward }, + { qmuld, up, qident, up }, + { qmuld, right, right, nqident }, + { qmuld, right, forward, up }, + { qmuld, right, up, nforward }, + { qmuld, forward, right, nup }, + { qmuld, forward, forward, nqident }, + { qmuld, forward, up, right }, + { qmuld, up, right, forward }, + { qmuld, up, forward, nright }, + { qmuld, up, up, nqident }, + { qmuld, one, one, { 2, 2, 2, -2 } }, + { qmuld, one, { 2, 2, 2, -2 }, { 0, 0, 0, -8 } }, + // This one fails when optimizing with -mfma (which is why fma is not + // used): ulp error in z + { qmuld, qtest, qtest, {0.768, 0.576, 0, -0.28} }, + + // The one vector is not unit (magnitude 2), so using it as a rotation + // quaternion results in scaling by 4. However, it still has the effect + // of rotating 120 degrees around the axis equidistant from the three + // orthogonal axes such that x->y->z->x + { qvmuld, one, right, { 0, 4, 0, 0 } }, + { qvmuld, one, forward, { 0, 0, 4, 0 } }, + { qvmuld, one, up, { 4, 0, 0, 0 } }, + { qvmuld, one, {1,1,1,0}, { 4, 4, 4, 0 } }, + { qvmuld, one, one, { 4, 4, 4, -2 } }, + // inverse rotation, so x->z->y->x + { vqmuld, right, one, { 0, 0, 4, 0 } }, + { vqmuld, forward, one, { 4, 0, 0, 0 } }, + { vqmuld, up, one, { 0, 4, 0, 0 } }, + { vqmuld, {1,1,1,0}, one, { 4, 4, 4, 0 } }, + { vqmuld, one, one, { 4, 4, 4, -2 } }, + // The half vector is unit. + { qvmuld, half, right, forward }, + { qvmuld, half, forward, up }, + { qvmuld, half, up, right }, + { qvmuld, half, {1,1,1,0}, { 1, 1, 1, 0 } }, + // inverse + { vqmuld, right, half, up }, + { vqmuld, forward, half, right }, + { vqmuld, up, half, forward }, + { vqmuld, {1,1,1,0}, half, { 1, 1, 1, 0 } }, + // one is a 4D vector and qvmuld is meant for 3D vectors. However, it + // seems that the vector's w has no effect on the 3d portion of the + // result, but the result's w is cosine of the full rotation angle + // scaled by quaternion magnitude and vector w + { qvmuld, half, one, { 1, 1, 1, -0.5 } }, + { qvmuld, half, {2,2,2,2}, { 2, 2, 2, -1 } }, + { qvmuld, qtest, right, {0.5392, 0.6144, -0.576, 0} }, + { qvmuld, qtest, forward, {0.6144, 0.1808, 0.768, 0}, + {0, -2.7e-17, 0, 0} }, + { qvmuld, qtest, up, {0.576, -0.768, -0.28, 0} }, + // inverse + { vqmuld, one, half, { 1, 1, 1, -0.5 } }, + { vqmuld, {2,2,2,2}, half, { 2, 2, 2, -1 } }, + { vqmuld, right, qtest, {0.5392, 0.6144, 0.576, 0} }, + { vqmuld, forward, qtest, {0.6144, 0.1808, -0.768, 0}, + {0, -2.7e-17, 0, 0} }, + { vqmuld, up, qtest, {-0.576, 0.768, -0.28, 0} }, + + { qrotd, right, right, qident }, + { qrotd, right, forward, { 0, 0, s05, s05 }, + {0, 0, -1.1e-16, 0} }, + { qrotd, right, up, { 0, -s05, 0, s05 }, + {0, 1.1e-16, 0, 0} }, + { qrotd, forward, right, { 0, 0, -s05, s05 }, + {0, 0, 1.1e-16, 0} }, + { qrotd, forward, forward, qident }, + { qrotd, forward, up, { s05, 0, 0, s05 }, + {-1.1e-16, 0, 0, 0} }, + { qrotd, up, right, { 0, s05, 0, s05 }, + {0, -1.1e-16, 0, 0} }, + { qrotd, up, forward, { -s05, 0, 0, s05 }, + { 1.1e-16, 0, 0, 0} }, + { qrotd, up, up, qident }, + + { tvtruncd, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -1, -2 } }, + { tvceild, { 1.1, 2.9, -1.1, -2.9 }, {}, { 2, 3, -1, -2 } }, + { tvfloord, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -2, -3 } }, + { tqconjd, one, {}, { -1, -1, -1, 1 } }, +}; +#define num_vec4d_tests (sizeof (vec4d_tests) / (sizeof (vec4d_tests[0]))) + +static vec4f_test_t vec4f_tests[] = { + // 3D dot products + { dotf, right, right, one }, + { dotf, right, forward, zero }, + { dotf, right, up, zero }, + { dotf, forward, right, zero }, + { dotf, forward, forward, one }, + { dotf, forward, up, zero }, + { dotf, up, right, zero }, + { dotf, up, forward, zero }, + { dotf, up, up, one }, + + // one is 4D, so its self dot product is 4 + { dotf, one, one, { 4, 4, 4, 4} }, + { dotf, one, none, {-4, -4, -4, -4} }, + + // 3D cross products + { crossf, right, right, zero }, + { crossf, right, forward, up }, + { crossf, right, up, nforward }, + { crossf, forward, right, nup }, + { crossf, forward, forward, zero }, + { crossf, forward, up, right }, + { crossf, up, right, forward }, + { crossf, up, forward, nright }, + { crossf, up, up, zero }, + // double whammy tests: cross product with an angled vector and + // ensuring that a 4d vector (non-zero w component) does not affect + // the result, including the result's w component remaining zero. + { crossf, right, one, { 0, -1, 1} }, + { crossf, forward, one, { 1, 0, -1} }, + { crossf, up, one, {-1, 1, 0} }, + { crossf, one, right, { 0, 1, -1} }, + { crossf, one, forward, {-1, 0, 1} }, + { crossf, one, up, { 1, -1, 0} }, + { crossf, qtest, qtest, {0, 0, 0, 0} }, + + { qmulf, qident, qident, qident }, + { qmulf, qident, right, right }, + { qmulf, qident, forward, forward }, + { qmulf, qident, up, up }, + { qmulf, right, qident, right }, + { qmulf, forward, qident, forward }, + { qmulf, up, qident, up }, + { qmulf, right, right, nqident }, + { qmulf, right, forward, up }, + { qmulf, right, up, nforward }, + { qmulf, forward, right, nup }, + { qmulf, forward, forward, nqident }, + { qmulf, forward, up, right }, + { qmulf, up, right, forward }, + { qmulf, up, forward, nright }, + { qmulf, up, up, nqident }, + { qmulf, one, one, { 2, 2, 2, -2 } }, + { qmulf, one, { 2, 2, 2, -2 }, { 0, 0, 0, -8 } }, + { qmulf, qtest, qtest, {0.768, 0.576, 0, -0.28}, + {0, 6e-8, 0, 3e-8} }, + + // The one vector is not unit (magnitude 2), so using it as a rotation + // quaternion results in scaling by 4. However, it still has the effect + // of rotating 120 degrees around the axis equidistant from the three + // orthogonal axes such that x->y->z->x + { qvmulf, one, right, { 0, 4, 0, 0 } }, + { qvmulf, one, forward, { 0, 0, 4, 0 } }, + { qvmulf, one, up, { 4, 0, 0, 0 } }, + { qvmulf, one, {1,1,1,0}, { 4, 4, 4, 0 } }, + { qvmulf, one, one, { 4, 4, 4, -2 } }, + // inverse rotation, so x->z->y->x + { vqmulf, right, one, { 0, 0, 4, 0 } }, + { vqmulf, forward, one, { 4, 0, 0, 0 } }, + { vqmulf, up, one, { 0, 4, 0, 0 } }, + { vqmulf, {1,1,1,0}, one, { 4, 4, 4, 0 } }, + { vqmulf, one, one, { 4, 4, 4, -2 } }, + // + { qvmulf, qtest, right, {0.5392, 0.6144, -0.576, 0}, + {0, -5.9e-8, -6e-8, 0} }, + { qvmulf, qtest, forward, {0.6144, 0.1808, 0.768, 0}, + {-5.9e-8, 1.5e-8, 0, 0} }, + { qvmulf, qtest, up, {0.576, -0.768, -0.28, 0}, + {6e-8, 0, 3e-8, 0} }, + { vqmulf, right, qtest, {0.5392, 0.6144, 0.576, 0}, + {0, -5.9e-8, 5.9e-8, 0} }, + { vqmulf, forward, qtest, {0.6144, 0.1808, -0.768, 0}, + {-5.9e-8, 1.5e-8, 0, 0} }, + { vqmulf, up, qtest, {-0.576, 0.768, -0.28, 0}, + {-5.9e-8, 0, 3e-8, 0} }, + + { qrotf, right, right, qident }, + { qrotf, right, forward, { 0, 0, s05, s05 } }, + { qrotf, right, up, { 0, -s05, 0, s05 } }, + { qrotf, forward, right, { 0, 0, -s05, s05 } }, + { qrotf, forward, forward, qident }, + { qrotf, forward, up, { s05, 0, 0, s05 } }, + { qrotf, up, right, { 0, s05, 0, s05 } }, + { qrotf, up, forward, { -s05, 0, 0, s05 } }, + { qrotf, up, up, qident }, + + { tvtruncf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -1, -2 } }, + { tvceilf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 2, 3, -1, -2 } }, + { tvfloorf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -2, -3 } }, + { tqconjf, one, {}, { -1, -1, -1, 1 } }, +}; +#define num_vec4f_tests (sizeof (vec4f_tests) / (sizeof (vec4f_tests[0]))) + +static mat4f_test_t mat4f_tests[] = { + { mmulf, identity, identity, identity }, + { mmulf, rotate120, identity, rotate120 }, + { mmulf, identity, rotate120, rotate120 }, + { mmulf, rotate120, rotate120, rotate240 }, + { mmulf, rotate120, rotate240, identity }, + { mmulf, rotate240, rotate120, identity }, +}; +#define num_mat4f_tests (sizeof (mat4f_tests) / (sizeof (mat4f_tests[0]))) + +static mv4f_test_t mv4f_tests[] = { + { mvmulf, identity, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } }, + { mvmulf, identity, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } }, + { mvmulf, identity, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } }, + { mvmulf, identity, { 0, 0, 0, 1 }, { 0, 0, 0, 1 } }, + { mvmulf, rotate120, { 1, 2, 3, 4 }, { 3, 1, 2, 4 } }, + { mvmulf, rotate240, { 1, 2, 3, 4 }, { 2, 3, 1, 4 } }, +}; +#define num_mv4f_tests (sizeof (mv4f_tests) / (sizeof (mv4f_tests[0]))) + +// expect filled in using non-simd QuatToMatrix (has its own tests) +static mq4f_test_t mq4f_tests[] = { + { mat4fquat, { 0, 0, 0, 1 } }, + { mat4fquat, { 0.5, 0.5, 0.5, 0.5 } }, + { mat4fquat, { 0.5, 0.5, -0.5, 0.5 } }, + { mat4fquat, { 0.5, -0.5, 0.5, 0.5 } }, + { mat4fquat, { 0.5, -0.5, -0.5, 0.5 } }, + { mat4fquat, { -0.5, 0.5, 0.5, 0.5 } }, + { mat4fquat, { -0.5, 0.5, -0.5, 0.5 } }, + { mat4fquat, { -0.5, -0.5, 0.5, 0.5 } }, + { mat4fquat, { -0.5, -0.5, -0.5, 0.5 } }, +}; +#define num_mq4f_tests (sizeof (mq4f_tests) / (sizeof (mq4f_tests[0]))) + +static int +run_vec4d_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_vec4d_tests; i++) { + __auto_type test = &vec4d_tests[i]; + vec4d_t result = test->op (test->a, test->b); + vec4d_t expect = test->expect + test->ulp_errors; + vec4l_t res = result != expect; + if (res[0] || res[1] || res[2] || res[3]) { + ret |= 1; + printf ("\nrun_vec4d_tests %zd\n", i); + printf ("a: " VEC4D_FMT "\n", VEC4_EXP(test->a)); + printf ("b: " VEC4D_FMT "\n", VEC4_EXP(test->b)); + printf ("r: " VEC4D_FMT "\n", VEC4_EXP(result)); + printf ("t: " VEC4L_FMT "\n", VEC4_EXP(res)); + printf ("E: " VEC4D_FMT "\n", VEC4_EXP(expect)); + printf ("e: " VEC4D_FMT "\n", VEC4_EXP(test->expect)); + printf ("u: " VEC4D_FMT "\n", VEC4_EXP(test->ulp_errors)); + } + } + return ret; +} + +static int +run_vec4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_vec4f_tests; i++) { + __auto_type test = &vec4f_tests[i]; + vec4f_t result = test->op (test->a, test->b); + vec4f_t expect = test->expect + test->ulp_errors; + vec4i_t res = result != expect; + if (res[0] || res[1] || res[2] || res[3]) { + ret |= 1; + printf ("\nrun_vec4f_tests %zd\n", i); + printf ("a: " VEC4F_FMT "\n", VEC4_EXP(test->a)); + printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b)); + printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result)); + printf ("t: " VEC4I_FMT "\n", VEC4_EXP(res)); + printf ("E: " VEC4F_FMT "\n", VEC4_EXP(expect)); + printf ("e: " VEC4F_FMT "\n", VEC4_EXP(test->expect)); + printf ("u: " VEC4F_FMT "\n", VEC4_EXP(test->ulp_errors)); + } + } + return ret; +} + +static int +run_mat4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_mat4f_tests; i++) { + __auto_type test = &mat4f_tests[i]; + mat4f_t result; + mat4f_t expect; + mat4i_t res = {}; + + test->op (result, test->a, test->b); + maddf (expect, test->expect, test->ulp_errors); + + int fail = 0; + for (int j = 0; j < 4; j++) { + res[j] = result[j] != expect[j]; + fail |= res[j][0] || res[j][1] || res[j][2] || res[j][3]; + } + if (fail) { + ret |= 1; + printf ("\nrun_mat4f_tests %zd\n", i); + printf ("a: " VEC4F_FMT "\n", MAT4_ROW(test->a, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 3)); + printf ("b: " VEC4F_FMT "\n", MAT4_ROW(test->b, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 3)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(result, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 3)); + printf ("t: " VEC4I_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 3)); + printf ("E: " VEC4F_FMT "\n", MAT4_ROW(expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 3)); + printf ("e: " VEC4F_FMT "\n", MAT4_ROW(test->expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 3)); + printf ("u: " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 3)); + } + } + return ret; +} + +static int +run_mv4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_mv4f_tests; i++) { + __auto_type test = &mv4f_tests[i]; + vec4f_t result = test->op (test->a, test->b); + vec4f_t expect = test->expect + test->ulp_errors; + vec4i_t res = result != expect; + + if (res[0] || res[1] || res[2] || res[3]) { + ret |= 1; + printf ("\nrun_mv4f_tests %zd\n", i); + printf ("a: " VEC4F_FMT "\n", MAT4_ROW(test->a, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 3)); + printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b)); + printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result)); + printf ("t: " VEC4I_FMT "\n", VEC4_EXP(res)); + printf ("E: " VEC4F_FMT "\n", VEC4_EXP(expect)); + printf ("e: " VEC4F_FMT "\n", VEC4_EXP(test->expect)); + printf ("u: " VEC4F_FMT "\n", VEC4_EXP(test->ulp_errors)); + } + } + return ret; +} + +static int +run_mq4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_mq4f_tests; i++) { + __auto_type test = &mq4f_tests[i]; + quat_t q; + vec_t m[16]; + memcpy (q, &test->q, sizeof (quat_t)); + QuatToMatrix (q, m, 1, 1); + memcpy (&test->expect, m, sizeof (mat4f_t)); + } + for (size_t i = 0; i < num_mq4f_tests; i++) { + __auto_type test = &mq4f_tests[i]; + mat4f_t result; + mat4f_t expect; + mat4i_t res = {}; + + test->op (result, test->q); + maddf (expect, test->expect, test->ulp_errors); + memcpy (expect, (void *) &test->expect, sizeof (mat4f_t)); + + int fail = 0; + for (int j = 0; j < 4; j++) { + res[j] = result[j] != expect[j]; + fail |= res[j][0] || res[j][1] || res[j][2] || res[j][3]; + } + if (fail) { + ret |= 1; + printf ("\nrun_mq4f_tests %zd\n", i); + printf ("q: " VEC4F_FMT "\n", VEC4_EXP(test->q)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(result, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 3)); + printf ("t: " VEC4I_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 3)); + printf ("E: " VEC4F_FMT "\n", MAT4_ROW(expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 3)); + printf ("e: " VEC4F_FMT "\n", MAT4_ROW(test->expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 3)); + printf ("u: " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 3)); + } + } + return ret; +} + +int +main (void) +{ + int ret = 0; + ret |= run_vec4d_tests (); + ret |= run_vec4f_tests (); + ret |= run_mat4f_tests (); + ret |= run_mv4f_tests (); + ret |= run_mq4f_tests (); + return ret; +} diff --git a/libs/util/test/test-txtbuffer.c b/libs/util/test/test-txtbuffer.c new file mode 100644 index 000000000..44ccebdc9 --- /dev/null +++ b/libs/util/test/test-txtbuffer.c @@ -0,0 +1,240 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +#include "QF/txtbuffer.h" + +static size_t +check_text_ptr (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->text != 0; +} + +static size_t +get_textSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->textSize; +} + +static size_t +get_bufferSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->bufferSize; +} + +static size_t +get_gapOffset (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->gapOffset; +} + +static size_t +get_gapSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->gapSize; +} + +static size_t +insert_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + if (TextBuffer_InsertAt (buffer, offset, txt, length)) { + memset (buffer->text + buffer->gapOffset, 0xff, buffer->gapSize); + return 1; + } + return 0; +} + +static size_t +delete_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + if (TextBuffer_DeleteAt (buffer, offset, length)) { + memset (buffer->text + buffer->gapOffset, 0xff, buffer->gapSize); + return 1; + } + return 0; +} + +static size_t +destroy_buffer (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + TextBuffer_Destroy (buffer); + return 0; +} + +typedef size_t (*test_func) (txtbuffer_t *buffer, size_t offset, + const char *text, size_t length); + +static const char test_text[] = { + "Guarding the entrance to the Grendal\n" + "Gorge is the Shadow Gate, a small keep\n" + "and monastary which was once the home\n" + "of the Shadow cult.\n\n" + "For years the Shadow Gate existed in\n" + "obscurity but after the cult discovered\n" + "the \3023\354\341\343\353\240\307\341\364\345 in the caves below\n" + "the empire took notice.\n" + "A batallion of Imperial Knights were\n" + "sent to the gate to destroy the cult\n" + "and claim the artifact for the King.", +}; +static const char empty[TXTBUFFER_GROW] = { }; + +static size_t +compare_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + //printf("%zd %ld %zd\n", offset, txt - test_text, length); + size_t res = memcmp (buffer->text + offset, txt, length) == 0; + if (!res) { + for (size_t i = 0; i < length; i++) { + //printf ("%02x %02x\n", txt[i] & 0xff, buffer->text[offset + i] & 0xff); + } + } + return res; +} + +#define txtsize (sizeof (test_text) - 1) +#define txtsize0 txtsize +#define bufsize0 (TXTBUFFER_GROW) +#define gapoffs0 txtsize0 +#define gapsize0 (bufsize0 - txtsize0) +#define subtxtlen 200 +#define suboffs 200 +#define txtsize1 (txtsize0 + subtxtlen) +#define bufsize1 (TXTBUFFER_GROW) +#define gapoffs1 (suboffs + subtxtlen) +#define gapsize1 (bufsize1 - txtsize1) +#define deltxtlen 350 +#define deloffs 150 +#define txtsize2 (txtsize + subtxtlen - deltxtlen) +#define bufsize2 (TXTBUFFER_GROW) +#define gapoffs2 (deloffs) +#define gapsize2 (bufsize2 - txtsize2) +#define deltxtrem (txtsize2 - gapoffs2) +#define emptyoffs 370 +#define txtsize3 (txtsize + sizeof (empty)) +#define bufsize3 (2 * TXTBUFFER_GROW) +#define gapoffs3 (emptyoffs + sizeof (empty)) +#define gapsize3 (bufsize3 - txtsize3) +#define txtsize4 (txtsize + 2 * sizeof (empty)) +#define bufsize4 (3 * TXTBUFFER_GROW) +#define gapoffs4 (emptyoffs + sizeof (empty)) +#define gapsize4 (bufsize4 - txtsize4) + +struct { + test_func test; + size_t offset_param; + const char *text_param; + size_t length_param; + int test_expect; +} tests[] = { + { check_text_ptr, 0, 0, 0, 0 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, 0 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, 0 }, + { insert_text, 0, test_text, txtsize, 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize0 }, + { get_gapOffset, 0, 0, 0, gapoffs0 }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { compare_text, 0, test_text, txtsize, 1 }, + { insert_text, suboffs, test_text, subtxtlen, 1 }, + { get_textSize, 0, 0, 0, txtsize1 }, + { get_bufferSize, 0, 0, 0, bufsize1 }, + { get_gapOffset, 0, 0, 0, gapoffs1 }, + { get_gapSize, 0, 0, 0, gapsize1 }, + { compare_text, 0, test_text, txtsize, 0 }, + { compare_text, 0, test_text, suboffs, 1 }, + { compare_text, suboffs, test_text, subtxtlen, 1 }, + { compare_text, gapoffs1 + gapsize1, test_text + subtxtlen, txtsize - subtxtlen, 1 }, + { delete_text, deloffs, 0, deltxtlen, 1 }, + { get_textSize, 0, 0, 0, txtsize2 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, gapoffs2 }, + { get_gapSize, 0, 0, 0, gapsize2 }, + { compare_text, 0, test_text, suboffs, 0 }, + { compare_text, suboffs, test_text, subtxtlen, 0 }, + { compare_text, gapoffs1 + gapsize1, test_text + subtxtlen, txtsize - subtxtlen, 0 }, + { compare_text, 0, test_text, deloffs, 1 }, + { compare_text, gapoffs2 + gapsize2, test_text + txtsize - deltxtrem, deltxtrem, 1 }, + { compare_text, gapoffs2 + gapsize2 - 1, test_text + txtsize - deltxtrem - 1, 1, 0 }, + { delete_text, 0, 0, -1, 1 }, + { check_text_ptr, 0, 0, 0, 1 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, bufsize2 }, + { insert_text, 1, test_text, txtsize, 0 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, bufsize2 }, + { insert_text, 0, test_text, txtsize, 1 }, + { insert_text, 300, 0, 0, 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 300 }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { compare_text, 0, test_text, 300, 1 }, + { compare_text, 300, test_text + 300, 1, 0 }, + { compare_text, 300 + gapsize0, test_text + 300, txtsize - 300, 1 }, + { compare_text, 300 + gapsize0 - 1, test_text + 300 - 1, 1, 0 }, + { insert_text, 350, 0, 0, 1 }, + { compare_text, (emptyoffs - 20) + gapsize0, test_text + (emptyoffs - 20), txtsize - (emptyoffs - 20), 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, (emptyoffs - 20) }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { insert_text, emptyoffs, empty, sizeof (empty), 1 }, + { get_textSize, 0, 0, 0, txtsize3 }, + { get_bufferSize, 0, 0, 0, bufsize3 }, + { get_gapOffset, 0, 0, 0, gapoffs3 }, + { get_gapSize, 0, 0, 0, gapsize3 }, + { insert_text, emptyoffs, empty, sizeof (empty), 1 }, + { get_textSize, 0, 0, 0, txtsize4 }, + { get_bufferSize, 0, 0, 0, bufsize4 }, + { get_gapOffset, 0, 0, 0, gapoffs4 }, + { get_gapSize, 0, 0, 0, gapsize4 }, + { destroy_buffer, 0, 0, 0, 0 }, +}; +#define num_tests (sizeof (tests) / sizeof (tests[0])) +int test_start_line = __LINE__ - num_tests - 2; + +int +main (int argc, const char **argv) +{ + size_t i; + int res = 0; + + txtbuffer_t *buffer = TextBuffer_Create (); + + for (i = 0; i < num_tests; i++) { + if (tests[i].test) { + int test_res; + test_res = tests[i].test (buffer, + tests[i].offset_param, + tests[i].text_param, + tests[i].length_param); + if (test_res != tests[i].test_expect) { + res |= 1; + printf ("test %d (line %d) failed\n", (int) i, + (int) i + test_start_line); + printf ("expect: %d\n", tests[i].test_expect); + printf ("got : %d\n", test_res); + continue; + } + } + } + return res; +} diff --git a/libs/util/test/test-vrect.c b/libs/util/test/test-vrect.c index b1ba859bc..ab2558e8f 100644 --- a/libs/util/test/test-vrect.c +++ b/libs/util/test/test-vrect.c @@ -134,7 +134,7 @@ print_rects (vrect_t *rect) printf ("\n"); } -static int +static __attribute__((pure)) int compare_rects (vrect_t *r1, vrect_t *r2) { if (!r1 && !r2) diff --git a/libs/util/txtbuffer.c b/libs/util/txtbuffer.c new file mode 100644 index 000000000..0edc785b5 --- /dev/null +++ b/libs/util/txtbuffer.c @@ -0,0 +1,209 @@ +/* + txtbuffer.c + + Text buffer + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/qtypes.h" +#include "QF/sys.h" +#include "QF/txtbuffer.h" + +#include "compat.h" + +static txtbuffer_t *txtbuffers_freelist; + +static char * +txtbuffer_open_gap (txtbuffer_t *buffer, size_t offset, size_t length) +{ + size_t len; + char *dst; + char *src; + + if (offset == buffer->gapOffset && length <= buffer->gapSize) { + return buffer->text + buffer->gapOffset; + } + if (length <= buffer->gapSize) { + // no resize needed + if (offset < buffer->gapOffset) { + len = buffer->gapOffset - offset; + dst = buffer->text + buffer->gapOffset + buffer->gapSize - len; + src = buffer->text + offset; + } else { + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + } + memmove (dst, src, len); + } else { + // need to resize the buffer + // grow the buffer by the difference in lengths rounded up to the + // next multiple of TXTBUFFER_GROW + size_t new_size = buffer->bufferSize + length - buffer->gapSize; + new_size = (new_size + TXTBUFFER_GROW - 1) & ~(TXTBUFFER_GROW - 1); + char *new_text = realloc (buffer->text, new_size); + + if (!new_text) { + return 0; + } + buffer->text = new_text; + + if (offset < buffer->gapOffset) { + // move the old post-gap to the end of the new buffer + len = buffer->bufferSize - (buffer->gapOffset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + // move the remaining chunk to after the end of the new gap or + // just before the location of the previous move + len = buffer->gapOffset - offset; + dst -= len; + src = buffer->text + offset; + memmove (dst, src, len); + } else if (offset > buffer->gapOffset) { + // move the old post-offset to the end of the new buffer + len = buffer->bufferSize - (offset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + offset + buffer->gapSize; + memmove (dst, src, len); + // move the old post-gap to offset block to before the new gap + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } else { + // the gap only grew, did not move + len = buffer->bufferSize - (offset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } + buffer->gapSize += new_size - buffer->bufferSize; + buffer->bufferSize = new_size; + } + buffer->gapOffset = offset; + return buffer->text + buffer->gapOffset; +} + +static char * +txtbuffer_delete_text (txtbuffer_t *buffer, size_t offset, size_t length) +{ + size_t len; + char *dst; + char *src; + + if (offset > buffer->gapOffset) { + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } else if (offset + length < buffer->gapOffset) { + len = buffer->gapOffset - (offset + length); + dst = buffer->text + buffer->gapSize + (offset + length); + src = buffer->text + (offset + length); + memmove (dst, src, len); + } + // don't need to do any copying when offset <= gapOffset && + // offset + length >= offset + buffer->gapOffset = offset; + buffer->gapSize += length; + buffer->textSize -= length; + return buffer->text + buffer->gapOffset; +} + +VISIBLE txtbuffer_t * +TextBuffer_Create (void) +{ + txtbuffer_t *buffer; + ALLOC (16, txtbuffer_t, txtbuffers, buffer); + return buffer; +} + +VISIBLE void +TextBuffer_Destroy (txtbuffer_t *buffer) +{ + if (buffer->text) { + free (buffer->text); + } + FREE (txtbuffers, buffer); +} + +VISIBLE char * +TextBuffer_OpenGap (txtbuffer_t *buffer, size_t offset, size_t text_len) +{ + char *dst; + + if (offset > buffer->textSize) { + return 0; + } + dst = txtbuffer_open_gap (buffer, offset, text_len); + if (!dst) { + return 0; + } + return dst; +} + +VISIBLE int +TextBuffer_InsertAt (txtbuffer_t *buffer, size_t offset, + const char *text, size_t text_len) +{ + char *dst; + + if (offset > buffer->textSize) { + return 0; + } + dst = txtbuffer_open_gap (buffer, offset, text_len); + if (!dst) { + return 0; + } + memcpy (dst, text, text_len); + buffer->textSize += text_len; + buffer->gapOffset += text_len; + buffer->gapSize -= text_len; + return 1; +} + +VISIBLE int +TextBuffer_DeleteAt (txtbuffer_t *buffer, size_t offset, size_t len) +{ + if (offset > buffer->textSize) { + return 0; + } + // clamp len to the amount of text beyond offset + if (len > buffer->textSize - offset) { + len = buffer->textSize - offset; + } + txtbuffer_delete_text (buffer, offset, len); + return 1; +} diff --git a/libs/util/va.c b/libs/util/va.c index aa99f7955..c4b83aebb 100644 --- a/libs/util/va.c +++ b/libs/util/va.c @@ -40,27 +40,57 @@ #include "QF/dstring.h" #include "QF/va.h" +struct va_ctx_s { + dstring_t **strings; + int num_strings; + int str_index; +}; -/* - va - - does a varargs printf into a temp buffer, so I don't need to have - varargs versions of all text functions. -*/ -VISIBLE char * -va (const char *fmt, ...) +VISIBLE va_ctx_t * +va_create_context (int buffers) { - va_list args; - static dstring_t *string; + va_ctx_t *ctx; - if (!string) - string = dstring_new (); + ctx = malloc (sizeof (va_ctx_t) + buffers * sizeof (dstring_t *)); + ctx->strings = (dstring_t **) (ctx + 1); + ctx->num_strings = buffers; + ctx->str_index = 0; + + for (int i = 0; i < buffers; i++) { + ctx->strings[i] = dstring_new (); + } + return ctx; +} + +VISIBLE void +va_destroy_context (va_ctx_t *ctx) +{ + for (int i = 0; i < ctx->num_strings; i++) { + dstring_delete (ctx->strings[i]); + } + free (ctx); +} + +VISIBLE char * +va (va_ctx_t *ctx, const char *fmt, ...) +{ + static va_ctx_t *_ctx; + va_list args; + dstring_t *dstr; + + if (!ctx) { + if (!_ctx) { + _ctx = va_create_context (4); + } + ctx = _ctx; + } + dstr = ctx->strings[ctx->str_index++ % ctx->num_strings]; va_start (args, fmt); - dvsprintf (string, fmt, args); + dvsprintf (dstr, fmt, args); va_end (args); - return string->str; + return dstr->str; } VISIBLE char * diff --git a/libs/util/wad.c b/libs/util/wad.c index 3b4355bbb..ffb5414d3 100644 --- a/libs/util/wad.c +++ b/libs/util/wad.c @@ -118,7 +118,7 @@ W_GetLumpinfo (const char *name) return lump_p; } - Sys_Error ("W_GetLumpinfo: %s not found", name); + Sys_MaskPrintf (SYS_WARN, "W_GetLumpinfo: %s not found", name); return NULL; } diff --git a/libs/util/wadfile.c b/libs/util/wadfile.c index d5bf7c7fd..3d8a709ca 100644 --- a/libs/util/wadfile.c +++ b/libs/util/wadfile.c @@ -86,7 +86,7 @@ wad_new (const char *name) free (wad); return 0; } - wad->lump_hash = Hash_NewTable (1021, 0, 0, 0); + wad->lump_hash = Hash_NewTable (1021, 0, 0, 0, 0); if (!wad->lump_hash) { free (wad->filename); free (wad); @@ -182,7 +182,7 @@ wad_create (const char *name) wad_del (wad); return 0; } - strncpy (wad->header.id, "WAD2", sizeof (wad->header.id)); + memcpy (wad->header.id, "WAD2", sizeof (wad->header.id)); Qwrite (wad->handle, &wad->header, sizeof (wad->header)); diff --git a/libs/util/zone.c b/libs/util/zone.c index f5c90a379..ec1b08932 100644 --- a/libs/util/zone.c +++ b/libs/util/zone.c @@ -56,6 +56,7 @@ static qboolean Cache_FreeLRU (void); #define HUNK_SENTINAL 0x1df001ed #define MINFRAGMENT 64 +#define HUNK_ALIGN 64 /* ZONE MEMORY ALLOCATION @@ -337,7 +338,7 @@ Z_Print (memzone_t *zone) zone->size, zone, zone->used); for (block = zone->blocklist.next ; ; block = block->next) { - Sys_Printf ("block:%p size:%7i tag:%3i ofs:%x\n", + Sys_Printf ("block:%p size:%7i tag:%5x ofs:%x\n", block, z_block_size (block), block->tag, z_offset (zone, block)); @@ -413,6 +414,7 @@ typedef struct { int sentinal; int size; // including sizeof(hunk_t), -1 = not allocated char name[8]; + char fill[48]; // pad out to 64 bytes } hunk_t; byte *hunk_base; @@ -436,7 +438,8 @@ Hunk_Check (void) for (h = (hunk_t *) hunk_base; (byte *) h != hunk_base + hunk_low_used;) { if (h->sentinal != HUNK_SENTINAL) Sys_Error ("Hunk_Check: trashed sentinal"); - if (h->size < 16 || h->size + (byte *) h - hunk_base > hunk_size) + if (h->size < (int) sizeof (hunk_t) + || h->size + (byte *) h - hunk_base > hunk_size) Sys_Error ("Hunk_Check: bad size"); h = (hunk_t *) ((byte *) h + h->size); } @@ -449,15 +452,13 @@ Hunk_Check (void) Otherwise, allocations with the same name will be totaled up before printing. */ -/* -static void + +VISIBLE void Hunk_Print (qboolean all) { - char name[9]; hunk_t *h, *next, *endlow, *starthigh, *endhigh; int count, sum, totalblocks; - name[8] = 0; count = 0; sum = 0; totalblocks = 0; @@ -486,7 +487,8 @@ Hunk_Print (qboolean all) // run consistancy checks if (h->sentinal != HUNK_SENTINAL) Sys_Error ("Hunk_Check: trahsed sentinal"); - if (h->size < 16 || h->size + (byte *) h - hunk_base > hunk_size) + if (h->size < (int) sizeof (hunk_t) + || h->size + (byte *) h - hunk_base > hunk_size) Sys_Error ("Hunk_Check: bad size"); next = (hunk_t *) ((byte *) h + h->size); @@ -495,15 +497,14 @@ Hunk_Print (qboolean all) sum += h->size; // print the single block - memcpy (name, h->name, 8); if (all) - Sys_Printf ("%8p :%8i %8s\n", h, h->size, name); + Sys_Printf ("%8p :%8i %8.8s\n", h, h->size, h->name); // print the total if (next == endlow || next == endhigh || strncmp (h->name, next->name, 8)) { if (!all) - Sys_Printf (" :%8i %8s (TOTAL)\n", sum, name); + Sys_Printf (" :%8i %8.8s (TOTAL)\n", sum, h->name); count = 0; sum = 0; } @@ -514,7 +515,7 @@ Hunk_Print (qboolean all) Sys_Printf ("-------------------------\n"); Sys_Printf ("%8i total blocks\n", totalblocks); } -*/ + static void Hunk_FreeToHighMark (int mark) { @@ -551,7 +552,7 @@ Hunk_AllocName (int size, const char *name) if (size < 0) Sys_Error ("Hunk_Alloc: bad size: %i", size); - size = sizeof (hunk_t) + ((size + 15) & ~15); + size = sizeof (hunk_t) + ((size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1)); if (hunk_size - hunk_low_used - hunk_high_used < size) { Hunk_HighMark(); @@ -577,7 +578,8 @@ Hunk_AllocName (int size, const char *name) h->size = size; h->sentinal = HUNK_SENTINAL; - strncpy (h->name, name, 8); + memcpy (h->name, name, 8); + h->name[7] = 0; return (void *) (h + 1); } @@ -606,6 +608,8 @@ Hunk_FreeToLowMark (int mark) static void * Hunk_HighAlloc (int size) { + hunk_t *h; + if (size < 0) Sys_Error ("Hunk_HighAlloc: bad size: %i", size); @@ -617,7 +621,7 @@ Hunk_HighAlloc (int size) Hunk_Check (); #endif - size = ((size + 15) & ~15); + size = sizeof (hunk_t) + ((size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1)); if (hunk_size - hunk_low_used - hunk_high_used < size) { Sys_Printf ("Hunk_HighAlloc: failed on %i bytes\n", size); @@ -626,7 +630,11 @@ Hunk_HighAlloc (int size) hunk_high_used += size; - return (void *) (hunk_base + hunk_size - hunk_high_used); + h = (void *) (hunk_base + hunk_size - hunk_high_used); + h->sentinal = HUNK_SENTINAL; + h->size = size; + h->name[0] = 0; + return h + 1; } /* @@ -639,7 +647,7 @@ Hunk_TempAlloc (int size) { void *buf; - size = (size + 15) & ~15; + size = (size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1); if (hunk_tempactive) { if (hunk_high_used - hunk_tempmark >= size + (int) sizeof (hunk_t)) { @@ -741,7 +749,7 @@ static inline void Cache_UnlinkLRU (cache_system_t * cs) { if (!cs->lru_next || !cs->lru_prev) - Sys_Error ("Cache_UnlinkLRU: NULL link: %s %p %p", + Sys_Error ("Cache_UnlinkLRU: NULL link: %.16s %p %p", cs->name, cs->lru_next, cs->lru_prev); cs->lru_next->lru_prev = cs->lru_prev; @@ -754,7 +762,7 @@ static void Cache_MakeLRU (cache_system_t * cs) { if (cs->lru_next || cs->lru_prev) - Sys_Error ("Cache_MakeLRU: active link: %s %p %p", + Sys_Error ("Cache_MakeLRU: active link: %.16s %p %p", cs->name, cs->lru_next, cs->lru_prev); cache_head.lru_next->lru_prev = cs; @@ -893,7 +901,7 @@ Cache_Print (void) cache_system_t *cd; for (cd = cache_head.next; cd != &cache_head; cd = cd->next) { - Sys_Printf ("%8d : %s\n", (int) cd->size, cd->name); + Sys_Printf ("%8d : %.16s\n", (int) cd->size, cd->name); } } @@ -926,7 +934,7 @@ Cache_Flush (void) while (cache_head.prev != &cache_head) { if (!cache_head.prev->user->data) Sys_Error ("Cache_Flush: user/system out of sync for " - "'%s' with %d size", + "'%.16s' with %d size", cache_head.prev->name, (int) cache_head.prev->size); Cache_Free (cache_head.prev->user); // reclaim the space } @@ -967,7 +975,7 @@ Cache_Free (cache_user_t *c) if (cs->readlock) Sys_Error ("Cache_Free: attempt to free locked block"); - Sys_MaskPrintf (SYS_DEV, "Cache_Free: freeing '%s' %p\n", cs->name, cs); + Sys_MaskPrintf (SYS_DEV, "Cache_Free: freeing '%.16s' %p\n", cs->name, cs); Cache_UnlinkLRU (cs); @@ -1008,7 +1016,7 @@ Cache_Alloc (cache_user_t *c, int size, const char *name) if (size <= 0) Sys_Error ("Cache_Alloc: size %i", size); - size = (size + sizeof (cache_system_t) + 15) & ~15; + size = (size + sizeof (cache_system_t) + HUNK_ALIGN - 1) & ~(HUNK_ALIGN-1); // find memory for it while (1) { diff --git a/libs/video/Makefile.am b/libs/video/Makefile.am deleted file mode 100644 index 25b787b7c..000000000 --- a/libs/video/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= targets renderer - -clean-local: - rm -f *.a diff --git a/libs/video/Makemodule.am b/libs/video/Makemodule.am new file mode 100644 index 000000000..ae3d3ca44 --- /dev/null +++ b/libs/video/Makemodule.am @@ -0,0 +1,2 @@ +include libs/video/renderer/Makemodule.am +include libs/video/targets/Makemodule.am diff --git a/libs/video/renderer/Makefile.am b/libs/video/renderer/Makefile.am deleted file mode 100644 index 2c234fe33..000000000 --- a/libs/video/renderer/Makefile.am +++ /dev/null @@ -1,65 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= @vid_render_dirs@ -DIST_SUBDIRS= gl glsl sw sw32 -AM_CPPFLAGS= -I$(top_srcdir)/include - -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined -plugin_ldflags= @plugin_ldflags@ -avoid-version -module -rpath $(plugindir) -plugin_libadd= @plugin_libadd@ -EXEEXT= - -#lib_LTLIBRARIES= @VID_REND_TARGETS@ -plugin_LTLIBRARIES= @vid_render_plugins@ -noinst_LTLIBRARIES= libQFrenderer.la @vid_render_static_plugins@ - -EXTRA_LTLIBRARIES= \ - vid_render_sw.la vid_render_sw32.la \ - vid_render_gl.la vid_render_glsl.la - -common_sources= \ - crosshair.c noisetextures.c r_alias.c r_bsp.c r_cvar.c r_dyn_textures.c \ - r_efrag.c r_ent.c r_graph.c r_iqm.c r_light.c r_main.c r_part.c \ - r_screen.c vid_common.c - -renderer_libs= \ - @vid_render_static_plugin_libs@ \ - $(top_builddir)/libs/util/libQFutil.la - -libQFrenderer_la_LDFLAGS= @STATIC@ -libQFrenderer_la_LIBADD= $(renderer_libs) -libQFrenderer_la_DEPENDENCIES= $(renderer_libs) -libQFrenderer_la_SOURCES= r_init.c r_progs.c - -gl_libs= \ - gl/libgl.la \ - $(top_builddir)/libs/models/libmodels_gl.la -vid_render_gl_la_LDFLAGS= $(plugin_ldflags) -vid_render_gl_la_LIBADD= $(gl_libs) -vid_render_gl_la_DEPENDENCIES= $(gl_libs) -vid_render_gl_la_SOURCES= $(common_sources) vid_render_gl.c - -glsl_libs= \ - glsl/libglsl.la \ - $(top_builddir)/libs/models/libmodels_glsl.la -vid_render_glsl_la_LDFLAGS= $(plugin_ldflags) -vid_render_glsl_la_LIBADD= $(glsl_libs) -vid_render_glsl_la_DEPENDENCIES=$(glsl_libs) -vid_render_glsl_la_SOURCES= $(common_sources) vid_render_glsl.c - -sw_libs= \ - sw/libsw.la \ - $(top_builddir)/libs/models/libmodels_sw.la -vid_render_sw_la_LDFLAGS= $(plugin_ldflags) -vid_render_sw_la_LIBADD= $(sw_libs) -vid_render_sw_la_DEPENDENCIES= $(sw_libs) -vid_render_sw_la_SOURCES= $(common_sources) vid_render_sw.c - -sw32_libs= \ - sw32/libsw32.la \ - $(top_builddir)/libs/models/libmodels_sw.la -vid_render_sw32_la_LDFLAGS= $(plugin_ldflags) -vid_render_sw32_la_LIBADD= $(sw32_libs) -vid_render_sw32_la_DEPENDENCIES=$(sw32_libs) -vid_render_sw32_la_SOURCES= $(common_sources) vid_render_sw32.c diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am new file mode 100644 index 000000000..54fa0a2e3 --- /dev/null +++ b/libs/video/renderer/Makemodule.am @@ -0,0 +1,421 @@ +include libs/video/renderer/vulkan/test/Makemodule.am +include libs/video/renderer/vulkan/vkgen/Makemodule.am + +#lib_LTLIBRARIES += @VID_REND_TARGETS@ +plugin_LTLIBRARIES += @vid_render_plugins@ +noinst_LTLIBRARIES += \ + libs/video/renderer/libQFrenderer.la \ + @render_libs@ \ + @vid_render_static_plugins@ + +#plugins +EXTRA_LTLIBRARIES += \ + libs/video/renderer/vid_render_sw.la \ + libs/video/renderer/vid_render_sw32.la \ + libs/video/renderer/vid_render_gl.la \ + libs/video/renderer/vid_render_glsl.la \ + libs/video/renderer/vid_render_vulkan.la + +#helper libraries +EXTRA_LTLIBRARIES += \ + libs/video/renderer/librender_sw.la \ + libs/video/renderer/librender_sw32.la \ + libs/video/renderer/librender_gl.la \ + libs/video/renderer/librender_glsl.la \ + libs/video/renderer/librender_vulkan.la + +video_renderer_common_sources = \ + libs/video/renderer/crosshair.c \ + libs/video/renderer/font8x8.c \ + libs/video/renderer/noisetextures.c \ + libs/video/renderer/r_alias.c \ + libs/video/renderer/r_bsp.c \ + libs/video/renderer/r_dyn_textures.c \ + libs/video/renderer/r_efrag.c \ + libs/video/renderer/r_ent.c \ + libs/video/renderer/r_graph.c \ + libs/video/renderer/r_iqm.c \ + libs/video/renderer/r_light.c \ + libs/video/renderer/r_main.c \ + libs/video/renderer/r_part.c \ + libs/video/renderer/vid_common.c + +renderer_libs= \ + @vid_render_static_plugin_libs@ \ + libs/util/libQFutil.la + +libs_video_renderer_libQFrenderer_la_LDFLAGS= @STATIC@ +libs_video_renderer_libQFrenderer_la_LIBADD= $(renderer_libs) +libs_video_renderer_libQFrenderer_la_DEPENDENCIES= $(renderer_libs) +libs_video_renderer_libQFrenderer_la_SOURCES=\ + libs/video/renderer/r_cvar.c \ + libs/video/renderer/r_init.c \ + libs/video/renderer/r_scrap.c \ + libs/video/renderer/r_screen.c \ + libs/video/renderer/r_progs.c + +video_renderer_gl_libs= \ + libs/video/renderer/librender_gl.la \ + libs/models/libmodels_gl.la +libs_video_renderer_vid_render_gl_la_LDFLAGS= $(plugin_ldflags) +libs_video_renderer_vid_render_gl_la_LIBADD= $(video_renderer_gl_libs) +libs_video_renderer_vid_render_gl_la_DEPENDENCIES= $(video_renderer_gl_libs) +libs_video_renderer_vid_render_gl_la_SOURCES=\ + $(video_renderer_common_sources) \ + libs/video/renderer/vid_render_gl.c + +libs_video_renderer_librender_gl_la_SOURCES = \ + libs/video/renderer/gl/gl_draw.c \ + libs/video/renderer/gl/gl_dyn_lights.c \ + libs/video/renderer/gl/gl_dyn_part.c \ + libs/video/renderer/gl/gl_dyn_textures.c \ + libs/video/renderer/gl/gl_fog.c \ + libs/video/renderer/gl/gl_graph.c \ + libs/video/renderer/gl/gl_lightmap.c \ + libs/video/renderer/gl/gl_mod_alias.c \ + libs/video/renderer/gl/gl_mod_iqm.c \ + libs/video/renderer/gl/gl_mod_sprite.c \ + libs/video/renderer/gl/gl_rmain.c \ + libs/video/renderer/gl/gl_rmisc.c \ + libs/video/renderer/gl/gl_rsurf.c \ + libs/video/renderer/gl/gl_screen.c \ + libs/video/renderer/gl/gl_sky.c \ + libs/video/renderer/gl/gl_sky_clip.c \ + libs/video/renderer/gl/gl_textures.c \ + libs/video/renderer/gl/gl_warp.c \ + libs/video/renderer/gl/namehack.h \ + libs/video/renderer/gl/qfgl_ext.c \ + libs/video/renderer/gl/vid_common_gl.c \ + libs/video/renderer/gl/vtxarray.c + +shader_src= libs/video/renderer/glsl/quakeforge.glsl +shader_gen= libs/video/renderer/glsl/quakeforge.slc + +V_SED = $(V_SED_@AM_V@) +V_SED_ = $(V_SED_@AM_DEFAULT_V@) +V_SED_0 = @echo " SED " $@; +V_SED_1 = + +SUFFICES=.frag .vert .spv .spvc .fc .vc .slc .glsl .plist .plc +.glsl.slc: + $(V_SED)sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@.t &&\ + $(am__mv) $@.t $@ + +.plist.plc: + $(V_SED)sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $< > $@.t &&\ + $(am__mv) $@.t $@ + +video_renderer_glsl_libs= \ + libs/video/renderer/librender_glsl.la \ + libs/models/libmodels_glsl.la +libs_video_renderer_vid_render_glsl_la_LDFLAGS= $(plugin_ldflags) +libs_video_renderer_vid_render_glsl_la_LIBADD= $(video_renderer_glsl_libs) +libs_video_renderer_vid_render_glsl_la_DEPENDENCIES=$(video_renderer_glsl_libs) +libs_video_renderer_vid_render_glsl_la_SOURCES=\ + $(video_renderer_common_sources) \ + libs/video/renderer/vid_render_glsl.c + +libs_video_renderer_librender_glsl_la_SOURCES = \ + libs/video/renderer/glsl/glsl_alias.c \ + libs/video/renderer/glsl/glsl_bsp.c \ + libs/video/renderer/glsl/glsl_draw.c \ + libs/video/renderer/glsl/glsl_fog.c \ + libs/video/renderer/glsl/glsl_iqm.c \ + libs/video/renderer/glsl/glsl_lightmap.c \ + libs/video/renderer/glsl/glsl_main.c \ + libs/video/renderer/glsl/glsl_particles.c \ + libs/video/renderer/glsl/glsl_screen.c \ + libs/video/renderer/glsl/glsl_shader.c \ + libs/video/renderer/glsl/glsl_sprite.c \ + libs/video/renderer/glsl/glsl_textures.c \ + libs/video/renderer/glsl/namehack.h \ + libs/video/renderer/glsl/qfglsl.c \ + libs/video/renderer/glsl/quakeforge.glsl \ + libs/video/renderer/glsl/vid_common_glsl.c + +video_renderer_sw_libs= \ + libs/video/renderer/librender_sw.la \ + libs/models/libmodels_sw.la +libs_video_renderer_vid_render_sw_la_LDFLAGS= $(plugin_ldflags) +libs_video_renderer_vid_render_sw_la_LIBADD= $(video_renderer_sw_libs) +libs_video_renderer_vid_render_sw_la_DEPENDENCIES= $(video_renderer_sw_libs) +libs_video_renderer_vid_render_sw_la_SOURCES=\ + $(video_renderer_common_sources) \ + libs/video/renderer/vid_render_sw.c + +libs_video_renderer_librender_sw_la_SOURCES = \ + libs/video/renderer/sw/d_copy.S \ + libs/video/renderer/sw/d_draw.S \ + libs/video/renderer/sw/d_edge.c \ + libs/video/renderer/sw/d_fill.c \ + libs/video/renderer/sw/d_init.c \ + libs/video/renderer/sw/d_modech.c \ + libs/video/renderer/sw/d_part.c \ + libs/video/renderer/sw/d_parta.S \ + libs/video/renderer/sw/d_polysa.S \ + libs/video/renderer/sw/d_polyse.c \ + libs/video/renderer/sw/d_scan.c \ + libs/video/renderer/sw/d_scana.S \ + libs/video/renderer/sw/d_sky.c \ + libs/video/renderer/sw/d_spr8.S \ + libs/video/renderer/sw/d_sprite.c \ + libs/video/renderer/sw/d_surf.c \ + libs/video/renderer/sw/d_vars.c \ + libs/video/renderer/sw/d_varsa.S \ + libs/video/renderer/sw/d_zpoint.c \ + libs/video/renderer/sw/draw.c \ + libs/video/renderer/sw/fpu.c \ + libs/video/renderer/sw/fpua.S \ + libs/video/renderer/sw/nonintel.c \ + libs/video/renderer/sw/screen.c \ + libs/video/renderer/sw/surf8.S \ + libs/video/renderer/sw/sw_graph.c \ + libs/video/renderer/sw/sw_raclip.c \ + libs/video/renderer/sw/sw_raclipa.S \ + libs/video/renderer/sw/sw_ralias.c \ + libs/video/renderer/sw/sw_raliasa.S \ + libs/video/renderer/sw/sw_rbsp.c \ + libs/video/renderer/sw/sw_rdraw.c \ + libs/video/renderer/sw/sw_rdrawa.S \ + libs/video/renderer/sw/sw_redge.c \ + libs/video/renderer/sw/sw_redgea.S \ + libs/video/renderer/sw/sw_riqm.c \ + libs/video/renderer/sw/sw_rmain.c \ + libs/video/renderer/sw/sw_rmisc.c \ + libs/video/renderer/sw/sw_rpart.c \ + libs/video/renderer/sw/sw_rsky.c \ + libs/video/renderer/sw/sw_rsprite.c \ + libs/video/renderer/sw/sw_rsurf.c \ + libs/video/renderer/sw/sw_rvarsa.S \ + libs/video/renderer/sw/transform.S \ + libs/video/renderer/sw/vid_common_sw.c + +video_renderer_sw32_libs= \ + libs/video/renderer/librender_sw32.la \ + libs/models/libmodels_sw.la +libs_video_renderer_vid_render_sw32_la_LDFLAGS= $(plugin_ldflags) +libs_video_renderer_vid_render_sw32_la_LIBADD= $(video_renderer_sw32_libs) +libs_video_renderer_vid_render_sw32_la_DEPENDENCIES=$(video_renderer_sw32_libs) +libs_video_renderer_vid_render_sw32_la_SOURCES=\ + $(video_renderer_common_sources) \ + libs/video/renderer/vid_render_sw32.c + +libs_video_renderer_librender_sw32_la_SOURCES = \ + libs/video/renderer/sw32/d_edge.c \ + libs/video/renderer/sw32/d_fill.c \ + libs/video/renderer/sw32/d_init.c \ + libs/video/renderer/sw32/d_modech.c \ + libs/video/renderer/sw32/d_part.c \ + libs/video/renderer/sw32/d_polyse.c \ + libs/video/renderer/sw32/d_scan.c \ + libs/video/renderer/sw32/d_sky.c \ + libs/video/renderer/sw32/d_sprite.c \ + libs/video/renderer/sw32/d_surf.c \ + libs/video/renderer/sw32/d_vars.c \ + libs/video/renderer/sw32/d_zpoint.c \ + libs/video/renderer/sw32/draw.c \ + libs/video/renderer/sw32/namehack.h \ + libs/video/renderer/sw32/screen.c \ + libs/video/renderer/sw32/sw32_graph.c \ + libs/video/renderer/sw32/sw32_raclip.c \ + libs/video/renderer/sw32/sw32_ralias.c \ + libs/video/renderer/sw32/sw32_rbsp.c \ + libs/video/renderer/sw32/sw32_rdraw.c \ + libs/video/renderer/sw32/sw32_redge.c \ + libs/video/renderer/sw32/sw32_riqm.c \ + libs/video/renderer/sw32/sw32_rmain.c \ + libs/video/renderer/sw32/sw32_rmisc.c \ + libs/video/renderer/sw32/sw32_rpart.c \ + libs/video/renderer/sw32/sw32_rsky.c \ + libs/video/renderer/sw32/sw32_rsprite.c \ + libs/video/renderer/sw32/sw32_rsurf.c \ + libs/video/renderer/sw32/vid_common_sw32.c + +pipeline_src = libs/video/renderer/vulkan/qfpipeline.plist +pipeline_gen = libs/video/renderer/vulkan/qfpipeline.plc +renderpass_src = libs/video/renderer/vulkan/deferred.plist +renderpass_gen = libs/video/renderer/vulkan/deferred.plc + +video_renderer_vulkan_libs = \ + libs/video/renderer/librender_vulkan.la \ + libs/models/libmodels_vulkan.la +libs_video_renderer_vid_render_vulkan_la_LDFLAGS= $(plugin_ldflags) +libs_video_renderer_vid_render_vulkan_la_LIBADD= $(video_renderer_vulkan_libs) +libs_video_renderer_vid_render_vulkan_la_DEPENDENCIES=$(video_renderer_vulkan_libs) +libs_video_renderer_vid_render_vulkan_la_SOURCES = \ + $(video_renderer_common_sources) \ + libs/video/renderer/vid_render_vulkan.c + +libs_video_renderer_librender_vulkan_la_SOURCES = \ + libs/video/renderer/vulkan/barrier.c \ + libs/video/renderer/vulkan/buffer.c \ + libs/video/renderer/vulkan/command.c \ + libs/video/renderer/vulkan/capture.c \ + libs/video/renderer/vulkan/descriptor.c \ + libs/video/renderer/vulkan/device.c \ + libs/video/renderer/vulkan/image.c \ + libs/video/renderer/vulkan/instance.c \ + libs/video/renderer/vulkan/memory.c \ + libs/video/renderer/vulkan/namehack.h \ + libs/video/renderer/vulkan/pipeline.c \ + libs/video/renderer/vulkan/renderpass.c \ + libs/video/renderer/vulkan/scrap.c \ + libs/video/renderer/vulkan/shader.c \ + libs/video/renderer/vulkan/staging.c \ + libs/video/renderer/vulkan/swapchain.c \ + libs/video/renderer/vulkan/util.c \ + libs/video/renderer/vulkan/util.h \ + libs/video/renderer/vulkan/vkparse.c \ + libs/video/renderer/vulkan/vulkan_alias.c \ + libs/video/renderer/vulkan/vulkan_bsp.c \ + libs/video/renderer/vulkan/vulkan_compose.c \ + libs/video/renderer/vulkan/vulkan_draw.c \ + libs/video/renderer/vulkan/vulkan_lighting.c \ + libs/video/renderer/vulkan/vulkan_main.c \ + libs/video/renderer/vulkan/vulkan_matrices.c \ + libs/video/renderer/vulkan/vulkan_particles.c \ + libs/video/renderer/vulkan/vulkan_texture.c \ + libs/video/renderer/vulkan/vulkan_vid_common.c + +libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vkparse_src) + +libs/video/renderer/vulkan/shader.lo: libs/video/renderer/vulkan/shader.c $(vkshader_c) + +libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(vkparse_src) $(pipeline_gen) ${renderpass_gen} + + +qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) +vkparse_cinc = libs/video/renderer/vulkan/vkparse.cinc +vkparse_hinc = libs/video/renderer/vulkan/vkparse.hinc +vkparse_src = \ + $(vkparse_cinc) \ + $(vkparse_hinc) +vkparse_plist = \ + $(srcdir)/libs/video/renderer/vulkan/vkparse.plist + +vkshaderpath = libs/video/renderer/vulkan/shader + +twodv_src = $(vkshaderpath)/twod.vert +twodv_c = $(vkshaderpath)/twod.vert.spvc +twodf_src = $(vkshaderpath)/twod.frag +twodf_c = $(vkshaderpath)/twod.frag.spvc +quakebspv_src = $(vkshaderpath)/quakebsp.vert +quakebspv_c = $(vkshaderpath)/quakebsp.vert.spvc +quakebspf_src = $(vkshaderpath)/quakebsp.frag +quakebspf_c = $(vkshaderpath)/quakebsp.frag.spvc + +bsp_depth_src = $(vkshaderpath)/bsp_depth.vert +bsp_depth_c = $(vkshaderpath)/bsp_depth.vert.spvc +bsp_gbufv_src = $(vkshaderpath)/bsp_gbuf.vert +bsp_gbufv_c = $(vkshaderpath)/bsp_gbuf.vert.spvc +bsp_gbufg_src = $(vkshaderpath)/bsp_gbuf.geom +bsp_gbufg_c = $(vkshaderpath)/bsp_gbuf.geom.spvc +bsp_gbuff_src = $(vkshaderpath)/bsp_gbuf.frag +bsp_gbuff_c = $(vkshaderpath)/bsp_gbuf.frag.spvc +bsp_skyf_src = $(vkshaderpath)/bsp_sky.frag +bsp_skyf_c = $(vkshaderpath)/bsp_sky.frag.spvc +bsp_turbf_src = $(vkshaderpath)/bsp_turb.frag +bsp_turbf_c = $(vkshaderpath)/bsp_turb.frag.spvc +lightingf_src = $(vkshaderpath)/lighting.frag +lightingf_c = $(vkshaderpath)/lighting.frag.spvc +composef_src = $(vkshaderpath)/compose.frag +composef_c = $(vkshaderpath)/compose.frag.spvc +aliasv_src = $(vkshaderpath)/alias.vert +aliasv_c = $(vkshaderpath)/alias.vert.spvc +aliasf_src = $(vkshaderpath)/alias.frag +aliasf_c = $(vkshaderpath)/alias.frag.spvc +alias_depth_src = $(vkshaderpath)/alias_depth.vert +alias_depth_c = $(vkshaderpath)/alias_depth.vert.spvc +alias_gbuf_src = $(vkshaderpath)/alias_gbuf.frag +alias_gbuf_c = $(vkshaderpath)/alias_gbuf.frag.spvc +passthrough_src = $(vkshaderpath)/passthrough.vert +passthrough_c = $(vkshaderpath)/passthrough.vert.spvc +pushcolor_src = $(vkshaderpath)/pushcolor.frag +pushcolor_c = $(vkshaderpath)/pushcolor.frag.spvc + +$(twodv_c): $(twodv_src) + +$(twodf_c): $(twodf_src) + +$(quakebspv_c): $(quakebspv_src) + +$(quakebspf_c): $(quakebspf_src) + +$(bsp_depth_c): $(bsp_depth_src) + +$(bsp_gbufv_c): $(bsp_gbufv_src) + +$(bsp_gbufg_c): $(bsp_gbufg_src) + +$(bsp_gbuff_c): $(bsp_gbuff_src) + +$(bsp_skyf_c): $(bsp_skyf_src) + +$(bsp_turbf_c): $(bsp_turbf_src) + +$(lightingf_c): $(lightingf_src) + +$(composef_c): $(composef_src) + +$(aliasv_c): $(aliasv_src) + +$(alias_depth_c): $(alias_depth_src) + +$(aliasf_c): $(aliasf_src) + +$(alias_gbuf_c): $(alias_gbuf_src) + +$(passthrough_c): $(passthrough_src) + +$(pushcolor_c): $(pushcolor_src) + +vkshader_c = \ + $(twodv_c) \ + $(twodf_c) \ + $(quakebspv_c) \ + $(quakebspf_c) \ + $(bsp_depth_c) \ + $(bsp_gbufv_c) \ + $(bsp_gbufg_c) \ + $(bsp_gbuff_c) \ + $(bsp_skyf_c) \ + $(bsp_turbf_c) \ + $(lightingf_c) \ + $(composef_c) \ + $(aliasv_c) \ + $(alias_depth_c) \ + $(aliasf_c) \ + $(alias_gbuf_c) \ + $(passthrough_c) \ + $(pushcolor_c) + +V_VKGEN = $(V_VKGEN_@AM_V@) +V_VKGEN_ = $(V_VKGEN_@AM_DEFAULT_V@) +V_VKGEN_0 = @echo " VKGEN " $@; +V_VKGEN_1 = + +$(vkparse_cinc): $(vkgen) $(qwaq_curses) $(vkparse_plist) + $(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) $(vkparse_cinc).t $(vkparse_hinc).t &&\ + $(am__mv) $(vkparse_cinc).t $(vkparse_cinc) &&\ + $(am__mv) $(vkparse_hinc).t $(vkparse_hinc) + +$(vkparse_hinc): $(vkparse_cinc) +# do nothing: hinc generated at the same time as cinc + +CLEANFILES += \ + libs/video/renderer/glsl/*.vc \ + libs/video/renderer/glsl/*.fc \ + libs/video/renderer/glsl/*.slc \ + libs/video/renderer/vulkan/*.plc \ + libs/video/renderer/vulkan/*.spv \ + libs/video/renderer/vulkan/*.spvc \ + libs/video/renderer/vulkan/vkgen.sym \ + $(vkparse_src) + +BUILT_SOURCES += $(shader_gen) + +#shader_DATA += \ +# libs/video/renderer/vulkan/passthrough.vert.spv \ +# libs/video/renderer/vulkan/pushcolor.frag.spv + +EXTRA_DIST += $(shader_DATA:.spv=) diff --git a/libs/video/renderer/font8x8.c b/libs/video/renderer/font8x8.c new file mode 100644 index 000000000..ab78882a5 --- /dev/null +++ b/libs/video/renderer/font8x8.c @@ -0,0 +1,336 @@ +/* + r_font8x8.c + + 8x8 bitmap font data. + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/8 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "QF/qtypes.h" +#include "QF/wadfile.h" + +#include "r_internal.h" + +//NOTE: This is packed 8x8 bitmap data, one byte per scanline, 8 scanlines +//per character. Also, it is NOT the quake font, but the IBM charset. +byte font8x8_data[] = { + 0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff, + 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, + 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, + 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x92, 0x10, 0x7C, + 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, + 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, + 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, + 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0x86, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, + 0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00, + 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, + 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, + 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, + 0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0x7C, 0x00, + 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, + 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, + 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, + 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, + 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x7C, 0xC6, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, + 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, + 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3A, 0x00, + 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, + 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, + 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, + 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, + 0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0x7C, 0x0E, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, + 0x7C, 0xC6, 0xE0, 0x78, 0x0E, 0xC6, 0x7C, 0x00, + 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, + 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, + 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, + 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x38, 0x6C, 0x64, 0xF0, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, + 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xD6, 0x00, + 0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, + 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00, + 0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, + 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, + 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, + 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x0C, 0x06, 0x7C, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x7E, 0x81, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0x00, + 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0x78, 0x0C, 0x38, + 0x7E, 0x81, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, + 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7C, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xC6, 0x10, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, + 0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00, + 0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00, + 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00, + 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00, + 0x78, 0x84, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0x84, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00, + 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18, + 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00, + 0xCC, 0xCC, 0x78, 0x30, 0xFC, 0x30, 0xFC, 0x30, + 0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC3, + 0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70, + 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0xF8, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0x00, + 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00, + 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, + 0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00, + 0xC6, 0xCC, 0xD8, 0x36, 0x6B, 0xC2, 0x84, 0x0F, + 0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6D, 0xCF, 0x03, + 0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, + 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0xDB, 0xF6, 0xDB, 0x6F, 0xDB, 0x7E, 0xD7, 0xED, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00, + 0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xCC, 0xF8, 0xC0, + 0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, + 0x00, 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, + 0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00, + 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0, + 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC, + 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00, + 0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00, + 0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0, + 0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00, + 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, + 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00, + 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00, + 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70, + 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C, + 0x58, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, + 0x70, 0x98, 0x30, 0x60, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, + 0xff, 0x99, 0x99, 0xff, 0xff, 0x99, 0x99, 0xff, +}; +#define FONT_WIDTH 8 +#define FONT_HEIGHT 8 +#define FONT_HCHARS 16 +#define FONT_VCHARS 16 +#define FONT_BYTES ((FONT_VCHARS)*(FONT_HCHARS)*(FONT_HEIGHT)*(FONT_WIDTH)) + +qpic_t * +Draw_Font8x8Pic (void) +{ + qpic_t *pic; + byte *data; + byte *out; + int i, j, x, y, ind; + + pic = calloc (1, field_offset (qpic_t, data[FONT_BYTES])); + pic->width = FONT_HCHARS * FONT_WIDTH; + pic->height = FONT_VCHARS * FONT_HEIGHT; + // convert the bitmap data to pixel data in a 16x16 character "image" + // assumes the quake palette where 254 is white, and 255 is transparent + data = font8x8_data; + for (j = 0; j < FONT_VCHARS; j++) { + for (i = 0; i < FONT_HCHARS; i++) { + for (y = 0; y < FONT_HEIGHT; y++) { + byte scanline = *data++; + ind = (j * FONT_HEIGHT + y) * FONT_WIDTH * FONT_HCHARS; + ind += i * FONT_WIDTH; + out = pic->data + ind; + for (x = 0; x < FONT_WIDTH; x++) { + *out++ = 0xff - ((scanline & 0x80) >> 7); + scanline <<= 1; + } + } + } + } + return pic; +} diff --git a/libs/video/renderer/gl/Makefile.am b/libs/video/renderer/gl/Makefile.am deleted file mode 100644 index 041db8546..000000000 --- a/libs/video/renderer/gl/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(GLX_CFLAGS) - -noinst_LTLIBRARIES= libgl.la - -gl_src = \ - gl_draw.c gl_dyn_lights.c gl_dyn_part.c gl_dyn_textures.c \ - gl_fog.c gl_graph.c gl_lightmap.c gl_mod_alias.c gl_mod_iqm.c \ - gl_mod_sprite.c gl_rmain.c gl_rmisc.c gl_rsurf.c gl_screen.c gl_sky.c \ - gl_sky_clip.c gl_textures.c gl_warp.c qfgl_ext.c vid_common_gl.c vtxarray.c - -libgl_la_SOURCES= $(gl_src) - -EXTRA_DIST = $(gl_src) namehack.h diff --git a/libs/video/renderer/gl/gl_draw.c b/libs/video/renderer/gl/gl_draw.c index f988ddf66..d84e8f17e 100644 --- a/libs/video/renderer/gl/gl_draw.c +++ b/libs/video/renderer/gl/gl_draw.c @@ -175,7 +175,7 @@ gl_Draw_PicFromWad (const char *name) tex_t *targa; pic = W_GetLumpName (name); - targa = LoadImage (name); + targa = LoadImage (name, 1); if (targa) { p = malloc (sizeof (qpic_t) + sizeof (glpic_t)); p->width = pic->width; @@ -236,7 +236,7 @@ gl_Draw_CachePic (const char *path, qboolean alpha) // Adjust for endian.. SwapPic (dat); // Check for a .tga first - targa = LoadImage (path); + targa = LoadImage (path, 1); if (targa) { if (targa->format < 4) { gl->texnum = GL_LoadTexture ("", targa->width, targa->height, @@ -256,7 +256,8 @@ gl_Draw_CachePic (const char *path, qboolean alpha) } else Sys_Error ("Draw_CachePic: failed to load %s", path); - strncpy (pic->name, path, sizeof (pic->name)); + memset (pic->name, 0, sizeof (pic->name)); + strncpy (pic->name, path, sizeof (pic->name) - 1); // Now lets mark this cache entry as used.. pic->dirty = false; @@ -352,7 +353,7 @@ gl_Draw_Init (void) // write the version string into the background before turning it into a // texture - image = LoadImage ("gfx/conchars"); + image = LoadImage ("gfx/conchars", 1); if (image) { if (image->format < 4) { char_texture = GL_LoadTexture ("charset", image->width, diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index 5b7f1a63a..13afc1fe9 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -42,6 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/mersenne.h" #include "QF/qargs.h" #include "QF/quakefs.h" @@ -205,12 +206,12 @@ gl_R_ReadPointFile_f (void) vec3_t org; QFile *f; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("%s.pts", mapname); + name = va (0, "%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); @@ -521,12 +522,14 @@ R_RocketTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -555,12 +558,14 @@ R_GrenadeTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -590,12 +595,14 @@ R_BloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 5.0 + qfrandom (10.0); @@ -630,12 +637,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (7.5); @@ -670,12 +679,14 @@ R_WizTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -711,12 +722,14 @@ R_FlameTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -752,12 +765,14 @@ R_VoorTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; int j; vec3_t subtract, old_origin, porg, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -790,7 +805,8 @@ R_GlowTrail_QF (const entity_t *ent, int glow_color) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, (maxlen - dist), subtract); @@ -869,12 +885,14 @@ R_RocketTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -904,12 +922,14 @@ R_GrenadeTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -1143,7 +1163,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) // l = r_maxparticles - numparticles; // } - VectorCopy (ent->origin, org); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { dir [1] = i * 8; @@ -1177,6 +1197,7 @@ R_EntityParticles_ID (const entity_t *ent) float angle, sp, sy, cp, cy; // cr, sr float beamlength = 16.0, dist = 64.0; vec3_t forward, porg; + vec3_t org; if (numparticles + j >= r_maxparticles) { return; @@ -1184,6 +1205,8 @@ R_EntityParticles_ID (const entity_t *ent) j = r_maxparticles - numparticles; } + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + if (!avelocities[0][0]) { for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; @@ -1209,11 +1232,11 @@ R_EntityParticles_ID (const entity_t *ent) forward[1] = cp * sy; forward[2] = -sp; - porg[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + + porg[0] = org[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; - porg[1] = ent->origin[1] + r_avertexnormals[i][1] * dist + + porg[1] = org[1] + r_avertexnormals[i][1] * dist + forward[1] * beamlength; - porg[2] = ent->origin[2] + r_avertexnormals[i][2] * dist + + porg[2] = org[2] + r_avertexnormals[i][2] * dist + forward[2] * beamlength; particle_new (pt_explode, part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.01, 0x6f, 1.0, 0); @@ -1232,7 +1255,8 @@ R_RocketTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, (maxlen - dist), subtract); @@ -1264,7 +1288,8 @@ R_GrenadeTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1291,12 +1316,14 @@ R_BloodTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, subtract, vec, porg; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1322,12 +1349,14 @@ R_SlightBloodTrail_ID (const entity_t *ent) float dist = 6.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1353,12 +1382,14 @@ R_WizTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1390,12 +1421,14 @@ R_FlameTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1427,12 +1460,14 @@ R_VoorTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1471,7 +1506,7 @@ gl_R_DrawParticles (void) qfglDepthMask (GL_FALSE); qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, particleVertexArray); - minparticledist = DotProduct (r_refdef.vieworg, vpn) + + minparticledist = DotProduct (r_refdef.viewposition, vpn) + r_particles_nearclip->value; activeparticles = 0; @@ -1591,6 +1626,27 @@ gl_R_DrawParticles (void) qfglDepthMask (GL_TRUE); } +static void +gl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, + float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); +} + +static void +gl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, float die, + int color, float alpha, float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, + color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -1775,24 +1831,3 @@ gl_R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -gl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); -} - -void -gl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, - color, alpha, ramp); -} diff --git a/libs/video/renderer/gl/gl_fog.c b/libs/video/renderer/gl/gl_fog.c index fe63419b5..0b74d0b80 100644 --- a/libs/video/renderer/gl/gl_fog.c +++ b/libs/video/renderer/gl/gl_fog.c @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "QF/cmd.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/sys.h" @@ -189,32 +189,29 @@ gl_Fog_ParseWorldspawn (plitem_t *worldspawn) calculates fog color for this frame, taking into account fade times */ -float * -gl_Fog_GetColor (void) +void +gl_Fog_GetColor (quat_t fogcolor) { - static float c[4]; float f; int i; if (fade_done > vr_data.realtime) { f = (fade_done - vr_data.realtime) / fade_time; - c[0] = f * old_red + (1.0 - f) * fog_red; - c[1] = f * old_green + (1.0 - f) * fog_green; - c[2] = f * old_blue + (1.0 - f) * fog_blue; - c[3] = 1.0; + fogcolor[0] = f * old_red + (1.0 - f) * fog_red; + fogcolor[1] = f * old_green + (1.0 - f) * fog_green; + fogcolor[2] = f * old_blue + (1.0 - f) * fog_blue; + fogcolor[3] = 1.0; } else { - c[0] = fog_red; - c[1] = fog_green; - c[2] = fog_blue; - c[3] = 1.0; + fogcolor[0] = fog_red; + fogcolor[1] = fog_green; + fogcolor[2] = fog_blue; + fogcolor[3] = 1.0; } //find closest 24-bit RGB value, so solid-colored sky can match the fog //perfectly for (i = 0; i < 3; i++) - c[i] = (float) (rint (c[i] * 255)) / 255.0f; - - return c; + fogcolor[i] = (float) (rint (fogcolor[i] * 255)) / 255.0f; } /* @@ -243,7 +240,10 @@ gl_Fog_GetDensity (void) void gl_Fog_SetupFrame (void) { - qfglFogfv (GL_FOG_COLOR, gl_Fog_GetColor ()); + quat_t fogcolor; + + gl_Fog_GetColor (fogcolor); + qfglFogfv (GL_FOG_COLOR, fogcolor); qfglFogf (GL_FOG_DENSITY, gl_Fog_GetDensity () / 64.0); } @@ -294,8 +294,11 @@ gl_Fog_StartAdditive (void) void gl_Fog_StopAdditive (void) { - if (gl_Fog_GetDensity () > 0) - qfglFogfv (GL_FOG_COLOR, gl_Fog_GetColor ()); + if (gl_Fog_GetDensity () > 0) { + quat_t fogcolor; + gl_Fog_GetColor (fogcolor); + qfglFogfv (GL_FOG_COLOR, fogcolor); + } } //============================================================================== diff --git a/libs/video/renderer/gl/gl_lightmap.c b/libs/video/renderer/gl/gl_lightmap.c index 9dfa3df92..2ea33a8c0 100644 --- a/libs/video/renderer/gl/gl_lightmap.c +++ b/libs/video/renderer/gl/gl_lightmap.c @@ -43,6 +43,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" #include "QF/GL/defines.h" @@ -74,7 +75,7 @@ glRect_t gl_lightmap_rectchange[MAX_LIGHTMAPS]; static int lmshift = 7; -void (*gl_R_BuildLightMap) (msurface_t *surf); +void (*gl_R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); extern void gl_multitexture_f (cvar_t *var); @@ -117,16 +118,22 @@ R_AddDynamicLights_1 (msurface_t *surf) unsigned int sdtable[18]; unsigned int *bl; vec3_t impact, local; + vec4f_t entorigin = { 0, 0, 0, 1 }; smax = (surf->extents[0] >> 4) + 1; smax_bytes = smax * gl_internalformat; tmax = (surf->extents[1] >> 4) + 1; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); + VectorSubtract (r_dlights[lnum].origin, entorigin, local); dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; VectorMultSub (r_dlights[lnum].origin, dist, surf->plane->normal, impact); @@ -182,16 +189,21 @@ R_AddDynamicLights_3 (msurface_t *surf) unsigned int sdtable[18]; unsigned int *bl; vec3_t impact, local; + vec4f_t entorigin = { 0, 0, 0, 1 }; smax = (surf->extents[0] >> 4) + 1; smax_bytes = smax * gl_internalformat; tmax = (surf->extents[1] >> 4) + 1; + if (currententity->transform) { + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); + VectorSubtract (r_dlights[lnum].origin, entorigin, local); dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; VectorMultSub (r_dlights[lnum].origin, dist, surf->plane->normal, impact); @@ -240,7 +252,7 @@ R_AddDynamicLights_3 (msurface_t *surf) } static void -R_BuildLightMap_1 (msurface_t *surf) +R_BuildLightMap_1 (mod_brush_t *brush, msurface_t *surf) { byte *dest; int maps, size, stride, smax, tmax, i, j; @@ -254,7 +266,7 @@ R_BuildLightMap_1 (msurface_t *surf) size = smax * tmax * gl_internalformat; // set to full bright if no light data - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { memset (&blocklights[0], 0xff, size * sizeof(int)); goto store; } @@ -300,7 +312,7 @@ R_BuildLightMap_1 (msurface_t *surf) } static void -R_BuildLightMap_3 (msurface_t *surf) +R_BuildLightMap_3 (mod_brush_t *brush, msurface_t *surf) { byte *dest; int maps, size, stride, smax, tmax, i, j; @@ -314,7 +326,7 @@ R_BuildLightMap_3 (msurface_t *surf) size = smax * tmax * gl_internalformat; // set to full bright if no light data - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { memset (&blocklights[0], 0xff, size * sizeof(int)); goto store; } @@ -365,7 +377,7 @@ R_BuildLightMap_3 (msurface_t *surf) } static void -R_BuildLightMap_4 (msurface_t *surf) +R_BuildLightMap_4 (mod_brush_t *brush, msurface_t *surf) { byte *dest; int maps, size, smax, tmax, i, j, stride; @@ -379,7 +391,7 @@ R_BuildLightMap_4 (msurface_t *surf) size = smax * tmax * gl_internalformat; // set to full bright if no light data - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { memset (&blocklights[0], 0xff, size * sizeof(int)); goto store; } @@ -535,6 +547,7 @@ gl_overbright_f (cvar_t *var) model_t *m; msurface_t *fa; entity_t *ent; + mod_brush_t *brush; if (!var) return; @@ -581,14 +594,15 @@ gl_overbright_f (cvar_t *var) return; for (ent = r_ent_queue; ent; ent = ent->next) { - m = ent->model; + m = ent->renderer.model; if (m->type != mod_brush) continue; - if (m->name[0] == '*') + if (m->path[0] == '*') continue; - for (j = 0, fa = m->surfaces; j < m->numsurfaces; j++, fa++) { + brush = &m->brush; + for (j = 0, fa = brush->surfaces; j < brush->numsurfaces; j++, fa++) { if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) continue; @@ -599,13 +613,13 @@ gl_overbright_f (cvar_t *var) gl_lightmap_rectchange[num].w = BLOCK_WIDTH; gl_lightmap_rectchange[num].h = BLOCK_HEIGHT; - gl_R_BuildLightMap (fa); + gl_R_BuildLightMap (brush, fa); } } - m = r_worldentity.model; + brush = &r_worldentity.renderer.model->brush; - for (i = 0, fa = m->surfaces; i < m->numsurfaces; i++, fa++) { + for (i = 0, fa = brush->surfaces; i < brush->numsurfaces; i++, fa++) { if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) continue; @@ -616,7 +630,7 @@ gl_overbright_f (cvar_t *var) gl_lightmap_rectchange[num].w = BLOCK_WIDTH; gl_lightmap_rectchange[num].h = BLOCK_HEIGHT; - gl_R_BuildLightMap (fa); + gl_R_BuildLightMap (brush, fa); } } @@ -665,7 +679,7 @@ AllocBlock (int w, int h, int *x, int *y) } static void -GL_CreateSurfaceLightmap (msurface_t *surf) +GL_CreateSurfaceLightmap (mod_brush_t *brush, msurface_t *surf) { int smax, tmax; @@ -677,7 +691,7 @@ GL_CreateSurfaceLightmap (msurface_t *surf) surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t); - gl_R_BuildLightMap (surf); + gl_R_BuildLightMap (brush, surf); } /* @@ -690,6 +704,7 @@ GL_BuildLightmaps (model_t **models, int num_models) { int i, j; model_t *m; + mod_brush_t *brush; memset (allocated, 0, sizeof (allocated)); @@ -732,21 +747,22 @@ GL_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->name[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } - r_pcurrentvertbase = m->vertexes; + brush = &m->brush; + r_pcurrentvertbase = brush->vertexes; gl_currentmodel = m; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - if (m->surfaces[i].flags & SURF_DRAWTURB) + for (i = 0; i < brush->numsurfaces; i++) { + if (brush->surfaces[i].flags & SURF_DRAWTURB) continue; - if (gl_sky_divide->int_val && (m->surfaces[i].flags & + if (gl_sky_divide->int_val && (brush->surfaces[i].flags & SURF_DRAWSKY)) continue; - GL_CreateSurfaceLightmap (m->surfaces + i); - GL_BuildSurfaceDisplayList (m->surfaces + i); + GL_CreateSurfaceLightmap (brush, brush->surfaces + i); + GL_BuildSurfaceDisplayList (brush->surfaces + i); } } diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index c74e1815c..3f96b4364 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -43,7 +43,7 @@ #include #include "QF/cvar.h" -#include "QF/locs.h" +#include "QF/entity.h" #include "QF/mathlib.h" #include "QF/qargs.h" #include "QF/render.h" @@ -190,14 +190,16 @@ GL_DrawAliasFrameMulti (vert_order_t *vo) static void GL_DrawAliasShadowTri (const aliashdr_t *paliashdr, const vert_order_t *vo) { - int count = vo->count;; + int count = vo->count; const blended_vert_t *verts = vo->verts; float height, lheight; vec3_t point; const vec_t *scale = paliashdr->mdl.scale; const vec_t *scale_origin = paliashdr->mdl.scale_origin; + vec4f_t entorigin; - lheight = currententity->origin[2] - lightspot[2]; + entorigin = Transform_GetWorldPosition (currententity->transform); + lheight = entorigin[2] - lightspot[2]; height = -lheight + 1.0; qfglBegin (GL_TRIANGLES); @@ -232,8 +234,10 @@ GL_DrawAliasShadow (const aliashdr_t *paliashdr, const vert_order_t *vo) const int *order = vo->order; vec3_t point; const blended_vert_t *verts = vo->verts; + vec4f_t entorigin; - lheight = currententity->origin[2] - lightspot[2]; + entorigin = Transform_GetWorldPosition (currententity->transform); + lheight = entorigin[2] - lightspot[2]; height = -lheight + 1.0; while ((count = *order++)) { @@ -299,14 +303,14 @@ GL_GetAliasFrameVerts16 (aliashdr_t *paliashdr, entity_t *e) if (blend == 0.0) { - verts = verts + e->pose1 * count; + verts = verts + e->animation.pose1 * count; } else if (blend == 1.0) { - verts = verts + e->pose2 * count; + verts = verts + e->animation.pose2 * count; } else { trivertx16_t *verts1, *verts2; - verts1 = verts + e->pose1 * count; - verts2 = verts + e->pose2 * count; + verts1 = verts + e->animation.pose1 * count; + verts2 = verts + e->animation.pose2 * count; for (i = 0, vo_v = vo->verts; i < count; i++, vo_v++, verts1++, verts2++) { @@ -362,14 +366,14 @@ GL_GetAliasFrameVerts (aliashdr_t *paliashdr, entity_t *e) blend = 1.0; if (blend == 0.0) { - verts = verts + e->pose1 * count; + verts = verts + e->animation.pose1 * count; } else if (blend == 1.0) { - verts = verts + e->pose2 * count; + verts = verts + e->animation.pose2 * count; } else { trivertx_t *verts1, *verts2; - verts1 = verts + e->pose1 * count; - verts2 = verts + e->pose2 * count; + verts1 = verts + e->animation.pose1 * count; + verts2 = verts + e->animation.pose2 * count; for (i = 0, vo_v = vo->verts; i < count; i++, vo_v++, verts1++, verts2++) { @@ -413,30 +417,36 @@ gl_R_DrawAliasModel (entity_t *e) dlight_t *l; model_t *model; vec3_t dist, scale; + vec4f_t origin; vert_order_t *vo; - model = e->model; + model = e->renderer.model; radius = model->radius; - if (e->scale != 1.0) - radius *= e->scale; - if (R_CullSphere (e->origin, radius)) + origin = Transform_GetWorldPosition (e->transform); + VectorCopy (Transform_GetWorldScale (e->transform), scale); + //FIXME assumes uniform scale + if (scale[0] != 1.0) { + radius *= scale[0]; + } + if (R_CullSphere (&origin[0], radius)) {//FIXME return; + } - VectorSubtract (r_origin, e->origin, modelorg); + VectorSubtract (r_origin, origin, modelorg); - gl_modelalpha = e->colormod[3]; + gl_modelalpha = e->renderer.colormod[3]; - is_fullbright = (model->fullbright || e->fullbright); - minlight = max (model->min_light, e->min_light); + is_fullbright = (model->fullbright || e->renderer.fullbright); + minlight = max (model->min_light, e->renderer.min_light); - qfglColor4fv (e->colormod); + qfglColor4fv (e->renderer.colormod); if (!is_fullbright) { float lightadj; // get lighting information - R_LightPoint (e->origin); + R_LightPoint (&r_worldentity.renderer.model->brush, &origin[0]);//FIXME lightadj = (ambientcolor[0] + ambientcolor[1] + ambientcolor[2]) / 765.0; @@ -457,7 +467,7 @@ gl_R_DrawAliasModel (entity_t *e) if (gl_vector_light->int_val) { for (l = r_dlights, lnum = 0; lnum < r_maxdlights; lnum++, l++) { if (l->die >= vr_data.realtime) { - VectorSubtract (l->origin, e->origin, dist); + VectorSubtract (l->origin, origin, dist); if ((d = DotProduct (dist, dist)) > // Out of range ((l->radius + radius) * (l->radius + radius))) { continue; @@ -508,7 +518,7 @@ gl_R_DrawAliasModel (entity_t *e) for (l = r_dlights, lnum = 0; lnum < r_maxdlights; lnum++, l++) { if (l->die >= vr_data.realtime) { - VectorSubtract (l->origin, e->origin, dist); + VectorSubtract (l->origin, origin, dist); if ((d = DotProduct (dist, dist)) > (l->radius + radius) * (l->radius + radius)) { @@ -530,24 +540,25 @@ gl_R_DrawAliasModel (entity_t *e) VectorScale (emission, 1.5 / d, emission); } - emission[0] *= e->colormod[0]; - emission[1] *= e->colormod[1]; - emission[2] *= e->colormod[2]; - emission[3] *= e->colormod[3]; + emission[0] *= e->renderer.colormod[0]; + emission[1] *= e->renderer.colormod[1]; + emission[2] *= e->renderer.colormod[2]; + emission[3] *= e->renderer.colormod[3]; qfglColor4fv (emission); } } // locate the proper data - if (!(paliashdr = e->model->aliashdr)) - paliashdr = Cache_Get (&e->model->cache); + if (!(paliashdr = e->renderer.model->aliashdr)) { + paliashdr = Cache_Get (&e->renderer.model->cache); + } gl_c_alias_polys += paliashdr->mdl.numtris; // if the model has a colorised/external skin, use it, otherwise use // the skin embedded in the model data - if (e->skin && e->skin->texnum && !gl_nocolors->int_val) { - skin_t *skin = e->skin; + if (e->renderer.skin && e->renderer.skin->texnum && !gl_nocolors->int_val) { + skin_t *skin = e->renderer.skin; texture = skin->texnum; if (gl_fb_models->int_val) { @@ -556,19 +567,22 @@ gl_R_DrawAliasModel (entity_t *e) } else { maliasskindesc_t *skindesc; - skindesc = R_AliasGetSkindesc (e->skinnum, paliashdr); + skindesc = R_AliasGetSkindesc (e->renderer.skinnum, paliashdr); texture = skindesc->texnum; - if (gl_fb_models->int_val && !is_fullbright) + if (gl_fb_models->int_val && !is_fullbright) { fb_texture = skindesc->fb_texnum; + } } if (paliashdr->mdl.ident == HEADER_MDL16) { // because we multipled by 256 when we loaded the verts, we have to // scale by 1/256 when drawing. - VectorScale (paliashdr->mdl.scale, e->scale / 256.0, scale); + //FIXME see scaling above + VectorScale (paliashdr->mdl.scale, 1 / 256.0, scale); vo = GL_GetAliasFrameVerts16 (paliashdr, e); } else { - VectorScale (paliashdr->mdl.scale, e->scale, scale); + //FIXME see scaling above + VectorScale (paliashdr->mdl.scale, 1, scale); vo = GL_GetAliasFrameVerts (paliashdr, e); } @@ -640,7 +654,7 @@ gl_R_DrawAliasModel (entity_t *e) qfglDisable (GL_NORMALIZE); } - qfglColor4fv (e->colormod); + qfglColor4fv (e->renderer.colormod); qfglBindTexture (GL_TEXTURE_2D, fb_texture); GL_DrawAliasFrameTri (vo); @@ -660,7 +674,7 @@ gl_R_DrawAliasModel (entity_t *e) qfglDisable (GL_NORMALIZE); } - qfglColor4fv (e->colormod); + qfglColor4fv (e->renderer.colormod); qfglBindTexture (GL_TEXTURE_2D, fb_texture); GL_DrawAliasFrame (vo); @@ -678,7 +692,7 @@ gl_R_DrawAliasModel (entity_t *e) // torches, grenades, and lightning bolts do not have shadows if (r_shadows->int_val && model->shadow_alpha) { - mat4_t shadow_mat; + mat4f_t shadow_mat; qfglPushMatrix (); gl_R_RotateForEntity (e); @@ -690,19 +704,19 @@ gl_R_DrawAliasModel (entity_t *e) qfglDepthMask (GL_FALSE); if (gl_modelalpha < 1.0) { - VectorBlend (e->colormod, dark, 0.5, color); + VectorBlend (e->renderer.colormod, dark, 0.5, color); color[3] = gl_modelalpha * (model->shadow_alpha / 255.0); qfglColor4fv (color); } else { color_black[3] = model->shadow_alpha; qfglColor4ubv (color_black); } - shadevector[0] = 1; - shadevector[1] = 0; - shadevector[2] = 1; - VectorNormalize (shadevector); - Mat4Transpose (e->transform, shadow_mat); - Mat4as3MultVec (shadow_mat, shadevector, shadevector); + //FIXME fully vectorize + vec4f_t vec = { 0.707106781, 0, 0.707106781, 0 }; + Transform_GetWorldMatrix (e->transform, shadow_mat); + mat4ftranspose (shadow_mat, shadow_mat); + vec = m3vmulf (shadow_mat, vec); + VectorCopy (vec, shadevector); if (vo->tex_coord) GL_DrawAliasShadowTri (paliashdr, vo); else @@ -722,6 +736,7 @@ gl_R_DrawAliasModel (entity_t *e) qfglDisable (GL_LIGHT0 + used_lights); } - if (!e->model->aliashdr) - Cache_Release (&e->model->cache); + if (!e->renderer.model->aliashdr) { + Cache_Release (&e->renderer.model->cache); + } } diff --git a/libs/video/renderer/gl/gl_mod_iqm.c b/libs/video/renderer/gl/gl_mod_iqm.c index 8a6efaade..f66c2c7ca 100644 --- a/libs/video/renderer/gl/gl_mod_iqm.c +++ b/libs/video/renderer/gl/gl_mod_iqm.c @@ -90,21 +90,19 @@ gl_draw_iqm_frame (iqm_t *iqm, gliqm_t *gl, iqmframe_t *frame, iqmmesh *mesh) void gl_R_DrawIQMModel (entity_t *ent) { - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; gliqm_t *gl = (gliqm_t *) iqm->extra_data; float blend; iqmframe_t *frame; int i; - model = ent->model; blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendPalette (iqm, ent->pose1, ent->pose2, blend, 0, - gl->blend_palette, gl->palette_size); + frame = R_IQMBlendPalette (iqm, ent->animation.pose1, ent->animation.pose2, + blend, 0, gl->blend_palette, gl->palette_size); qfglPushMatrix (); gl_R_RotateForEntity (ent); - qfglScalef (ent->scale, ent->scale, ent->scale); for (i = 0; i < iqm->num_meshes; i++) { qfglBindTexture (GL_TEXTURE_2D, gl->textures[i]); diff --git a/libs/video/renderer/gl/gl_mod_sprite.c b/libs/video/renderer/gl/gl_mod_sprite.c index c5b484ed7..d4b1c1f86 100644 --- a/libs/video/renderer/gl/gl_mod_sprite.c +++ b/libs/video/renderer/gl/gl_mod_sprite.c @@ -41,6 +41,7 @@ #include "QF/GL/defines.h" #include "QF/GL/funcs.h" +#include "QF/entity.h" #include "QF/model.h" #include "QF/render.h" #include "QF/sys.h" @@ -66,8 +67,8 @@ R_GetSpriteFrame (entity_t *currententity) mspriteframe_t *pspriteframe; mspritegroup_t *pspritegroup; - psprite = currententity->model->cache.data; - frame = currententity->frame; + psprite = currententity->renderer.model->cache.data; + frame = currententity->animation.frame; if ((frame >= psprite->numframes) || (frame < 0)) { Sys_MaskPrintf (SYS_DEV, "R_DrawSprite: no such frame %d\n", frame); @@ -82,7 +83,7 @@ R_GetSpriteFrame (entity_t *currententity) numframes = pspritegroup->numframes; fullinterval = pintervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -103,35 +104,28 @@ static void R_DrawSpriteModel_f (entity_t *e) { float modelalpha, color[4]; - float *up, *right; + vec4f_t up = {}, right = {}; + vec4f_t origin, point; msprite_t *psprite; mspriteframe_t *frame; - vec3_t point, point1, point2, v_up; // don't bother culling, it's just a single polygon without a surface cache frame = R_GetSpriteFrame (e); - psprite = e->model->cache.data; + psprite = e->renderer.model->cache.data; if (psprite->type == SPR_ORIENTED) { // bullet marks on walls - up = e->transform + 2 * 4; - right = e->transform + 1 * 4; + up = Transform_Up (e->transform); + right = Transform_Right (e->transform); } else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) { - v_up[0] = 0; - v_up[1] = 0; - v_up[2] = 1; - up = v_up; - right = vright; + up = (vec4f_t) { 0, 0, 1, 0 }; + VectorCopy (vright, right); } else { // normal sprite - up = vup; - right = vright; - } - if (e->scale != 1.0) { - VectorScale (up, e->scale, up); - VectorScale (right, e->scale, right); + VectorCopy (vup, up); + VectorCopy (vright, right); } - VectorCopy (e->colormod, color); - modelalpha = color[3] = e->colormod[3]; + VectorCopy (e->renderer.colormod, color); + modelalpha = color[3] = e->renderer.colormod[3]; if (modelalpha < 1.0) qfglDepthMask (GL_FALSE); @@ -141,23 +135,24 @@ R_DrawSpriteModel_f (entity_t *e) qfglColor4fv (color); - qfglTexCoord2f (0, 1); - VectorMultAdd (e->origin, frame->down, up, point1); - VectorMultAdd (point1, frame->left, right, point); - qfglVertex3fv (point); + origin = Transform_GetWorldPosition (e->transform); + point = origin + frame->down * up + frame->left * right; + qfglTexCoord2f (0, 1); + qfglVertex3fv (&point[0]); + + point = origin + frame->up * up + frame->left * right; qfglTexCoord2f (0, 0); - VectorMultAdd (e->origin, frame->up, up, point2); - VectorMultAdd (point2, frame->left, right, point); - qfglVertex3fv (point); + qfglVertex3fv (&point[0]); + + point = origin + frame->up * up + frame->right * right; qfglTexCoord2f (1, 0); - VectorMultAdd (point2, frame->right, right, point); - qfglVertex3fv (point); + qfglVertex3fv (&point[0]); + point = origin + frame->down * up + frame->right * right; qfglTexCoord2f (1, 1); - VectorMultAdd (point1, frame->right, right, point); - qfglVertex3fv (point); + qfglVertex3fv (&point[0]); qfglEnd (); @@ -169,60 +164,58 @@ static void R_DrawSpriteModel_VA_f (entity_t *e) { unsigned char modelalpha, color[4]; - float *up, *right; + vec4f_t up = {}, right = {}; + vec4f_t origin, point; int i; // unsigned int vacount; msprite_t *psprite; mspriteframe_t *frame; - vec3_t point1, point2, v_up; varray_t2f_c4ub_v3f_t *VA; VA = gl_spriteVertexArray; // FIXME: Despair // don't bother culling, it's just a single polygon without a surface cache frame = R_GetSpriteFrame (e); - psprite = e->model->cache.data; + psprite = e->renderer.model->cache.data; qfglBindTexture (GL_TEXTURE_2D, frame->gl_texturenum); // FIXME: DESPAIR if (psprite->type == SPR_ORIENTED) { // bullet marks on walls - up = e->transform + 2 * 4; - right = e->transform + 1 * 4; + up = Transform_Up (e->transform); + right = Transform_Right (e->transform); } else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) { - v_up[0] = 0; - v_up[1] = 0; - v_up[2] = 1; - up = v_up; - right = vright; + up = (vec4f_t) { 0, 0, 1, 0 }; + VectorCopy (vright, right); } else { // normal sprite - up = vup; - right = vright; - } - if (e->scale != 1.0) { - VectorScale (up, e->scale, up); - VectorScale (right, e->scale, right); + VectorCopy (vup, up); + VectorCopy (vright, right); } - for (i = 0; i < 4; i++) - color[i] = e->colormod[i] * 255; + for (i = 0; i < 4; i++) { + color[i] = e->renderer.colormod[i] * 255; + } memcpy (VA[0].color, color, 4); + memcpy (VA[1].color, color, 4); + memcpy (VA[2].color, color, 4); + memcpy (VA[3].color, color, 4); modelalpha = color[3]; if (modelalpha < 255) qfglDepthMask (GL_FALSE); - VectorMultAdd (e->origin, frame->down, up, point1); - VectorMultAdd (point1, frame->left, right, VA[0].vertex); + origin = Transform_GetWorldPosition (e->transform); - memcpy (VA[1].color, color, 4); - VectorMultAdd (e->origin, frame->up, up, point2); - VectorMultAdd (point2, frame->left, right, VA[1].vertex); + point = origin + frame->down * up + frame->left * right; + VectorCopy (point, VA[0].vertex); - memcpy (VA[2].color, color, 4); - VectorMultAdd (point2, frame->right, right, VA[2].vertex); + point = origin + frame->up * up + frame->left * right; + VectorCopy (point, VA[1].vertex); - memcpy (VA[3].color, color, 4); - VectorMultAdd (point1, frame->right, right, VA[3].vertex); + point = origin + frame->up * up + frame->right * right; + VectorCopy (point, VA[2].vertex); + + point = origin + frame->down * up + frame->right * right; + VectorCopy (point, VA[3].vertex); // VA += 4; // vacount += 4; @@ -243,7 +236,7 @@ gl_R_InitSprites (void) int i; if (r_init) { - if (gl_va_capable) { // 0 == gl_va_capable + if (gl_va_capable) { gl_R_DrawSpriteModel = R_DrawSpriteModel_VA_f; #if 0 diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index 1f9b30696..8bf8ec46a 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -44,7 +44,7 @@ #include "QF/cvar.h" #include "QF/draw.h" -#include "QF/locs.h" +#include "QF/entity.h" #include "QF/mathlib.h" #include "QF/qargs.h" #include "QF/render.h" @@ -74,7 +74,7 @@ qboolean gl_mirror; plane_t *gl_mirror_plane; float gl_r_world_matrix[16]; -static float r_base_world_matrix[16]; +//FIXME static float r_base_world_matrix[16]; //vec3_t gl_shadecolor; // Ender (Extend) Colormod float gl_modelalpha; // Ender (Extend) Alpha @@ -178,7 +178,9 @@ glrmain_init (void) void gl_R_RotateForEntity (entity_t *e) { - qfglMultMatrixf (e->transform); + mat4f_t mat; + Transform_GetWorldMatrix (e->transform, mat); + qfglMultMatrixf (&mat[0][0]); } /* @@ -217,7 +219,7 @@ R_DrawEntitiesOnList (void) } for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_alias) + if (ent->renderer.model->type != mod_alias) continue; currententity = ent; @@ -249,7 +251,7 @@ R_DrawEntitiesOnList (void) } for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_iqm) + if (ent->renderer.model->type != mod_iqm) continue; currententity = ent; @@ -262,7 +264,7 @@ R_DrawEntitiesOnList (void) if (gl_va_capable) qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, gl_spriteVertexArray); for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_sprite) + if (ent->renderer.model->type != mod_sprite) continue; currententity = ent; @@ -279,7 +281,7 @@ R_DrawViewModel (void) || !r_drawviewmodel->int_val || gl_envmap || !r_drawentities->int_val - || !currententity->model) + || !currententity->renderer.model) return; // hack the depth range to prevent view model from poking into walls @@ -342,14 +344,17 @@ gl_R_SetupFrame (void) gl_Fog_SetupFrame (); // build the transformation matrix for the given view angles - VectorCopy (r_refdef.vieworg, r_origin); + VectorCopy (r_refdef.viewposition, r_origin); + + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); R_SetFrustum (); // current viewleaf - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); r_cache_thrash = false; @@ -417,13 +422,19 @@ R_SetupGL (void) qfglMatrixMode (GL_MODELVIEW); qfglLoadIdentity (); - qfglRotatef (-90, 1, 0, 0); // put Z going up - qfglRotatef (90, 0, 0, 1); // put Z going up - qfglRotatef (-r_refdef.viewangles[ROLL], 1, 0, 0); - qfglRotatef (-r_refdef.viewangles[PITCH], 0, 1, 0); - qfglRotatef (-r_refdef.viewangles[YAW], 0, 0, 1); - qfglTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], - -r_refdef.vieworg[2]); + static mat4f_t z_up = { + { 0, 0, -1, 0}, + {-1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 0, 1}, + }; + mat4f_t view; + mat4fquat (view, qconjf (r_refdef.viewrotation)); + mmulf (view, z_up, view); + vec4f_t offset = -r_refdef.viewposition; + offset[3] = 1; + view[3] = mvmulf (view, offset); + qfglLoadMatrixf (&view[0][0]); qfglGetFloatv (GL_MODELVIEW_MATRIX, gl_r_world_matrix); @@ -478,12 +489,12 @@ R_RenderScene (void) static void R_Mirror (void) { - float d; + //float d; // msurface_t *s; // if (!gl_mirror) // FIXME: Broken return; - +/* memcpy (r_base_world_matrix, gl_r_world_matrix, sizeof (r_base_world_matrix)); @@ -549,6 +560,7 @@ R_Mirror (void) r_worldentity.model->textures[gl_mirrortexturenum]->texturechain = NULL; #endif qfglColor3ubv (color_white); +*/ } /* @@ -559,10 +571,12 @@ R_Mirror (void) static void R_RenderView_ (void) { - if (r_norefresh->int_val) + if (r_norefresh->int_val) { return; - if (!r_worldentity.model) + } + if (!r_worldentity.renderer.model) { Sys_Error ("R_RenderView: NULL worldmodel"); + } gl_mirror = false; @@ -580,6 +594,18 @@ R_RenderView_ (void) R_ZGraph (); } +//FIXME static void R_RenderViewFishEye (void); + +void +gl_R_RenderView (void) +{ + R_RenderView_ (); + /*if(!scr_fisheye->int_val) + R_RenderView_ (); + else + R_RenderViewFishEye ();*/ +} +/*FIXME // Algorithm: // Draw up to six views, one in each direction. // Save the picture to cube map texture, use GL_ARB_texture_cube_map. @@ -589,17 +615,6 @@ R_RenderView_ (void) // grid vertices coordinates. // Render view. Fisheye is done. -static void R_RenderViewFishEye (void); - -void -gl_R_RenderView (void) -{ - if(!scr_fisheye->int_val) - R_RenderView_ (); - else - R_RenderViewFishEye (); -} - #define BOX_FRONT 0 #define BOX_RIGHT 1 #define BOX_BEHIND 2 @@ -887,12 +902,12 @@ R_RenderViewFishEye (void) R_SetupGL_Viewport_and_Perspective (); qfglMatrixMode (GL_MODELVIEW); qfglCallList (fisheye_grid); -} +}*/ void gl_R_ClearState (void) { - r_worldentity.model = 0; + r_worldentity.renderer.model = 0; R_ClearEfrags (); R_ClearDlights (); gl_R_ClearParticles (); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index a399c26bd..de34bb203 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -64,6 +64,7 @@ #include "mod_internal.h" #include "r_internal.h" #include "varrays.h" +#include "vid_gl.h" /* R_Envmap_f @@ -73,6 +74,7 @@ static void R_Envmap_f (void) { + /*FIXME update for simd byte buffer[256 * 256 * 4]; qfglDrawBuffer (GL_FRONT); @@ -121,7 +123,7 @@ R_Envmap_f (void) gl_envmap = false; qfglDrawBuffer (GL_BACK); qfglReadBuffer (GL_BACK); - vid.end_rendering (); + gl_ctx->end_rendering ();*/ } void @@ -166,13 +168,13 @@ gl_R_Init (void) } static void -register_textures (model_t *model) +register_textures (mod_brush_t *brush) { int i; texture_t *tex; - for (i = 0; i < model->numtextures; i++) { - tex = model->textures[i]; + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; if (!tex) continue; gl_R_AddTexture (tex); @@ -184,18 +186,20 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) { int i; texture_t *tex; + mod_brush_t *brush; for (i = 0; i < 256; i++) d_lightstylevalue[i] = 264; // normal light value memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; + brush = &worldmodel->brush; R_FreeAllEntities (); // clear out efrags in case the level hasn't been reloaded - for (i = 0; i < r_worldentity.model->numleafs; i++) - r_worldentity.model->leafs[i].efrags = NULL; + for (i = 0; i < brush->numleafs; i++) + brush->leafs[i].efrags = NULL; // Force a vis update r_viewleaf = NULL; @@ -208,8 +212,8 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) // identify sky texture gl_mirrortexturenum = -1; gl_R_ClearTextures (); - for (i = 0; i < r_worldentity.model->numtextures; i++) { - tex = r_worldentity.model->textures[i]; + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; if (!tex) continue; if (!strncmp (tex->name, "sky", 3)) { @@ -219,16 +223,17 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) gl_mirrortexturenum = i; } - gl_R_InitSurfaceChains (r_worldentity.model); + gl_R_InitSurfaceChains (brush); gl_R_AddTexture (r_notexture_mip); - register_textures (r_worldentity.model); + register_textures (brush); for (i = 0; i < num_models; i++) { if (!models[i]) continue; - if (*models[i]->name == '*') + if (*models[i]->path == '*') continue; - if (models[i] != r_worldentity.model && models[i]->type == mod_brush) - register_textures (models[i]); + if (models[i] != r_worldentity.renderer.model + && models[i]->type == mod_brush) + register_textures (&models[i]->brush); } } @@ -246,19 +251,21 @@ gl_R_ViewChanged (float aspect) void gl_R_TimeRefresh_f (void) { +/*FIXME update for simd double start, stop, time; int i; - vid.end_rendering (); + gl_ctx->end_rendering (); start = Sys_DoubleTime (); for (i = 0; i < 128; i++) { r_refdef.viewangles[1] = i * (360.0 / 128.0); gl_R_RenderView (); - vid.end_rendering (); + gl_ctx->end_rendering (); } stop = Sys_DoubleTime (); time = stop - start; Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); +*/ } diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index 3cfb3c49b..96d1ec93f 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -45,6 +45,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" #include "QF/GL/defines.h" @@ -85,7 +86,7 @@ static instsurf_t **sky_chain_tail; (chain) = inst; \ } while (0) -static texture_t **r_texture_chains; +static gltex_t **r_texture_chains; static int r_num_texture_chains; static int max_texture_chains; @@ -129,31 +130,32 @@ release_instsurfs (void) } void -gl_R_AddTexture (texture_t *tex) +gl_R_AddTexture (texture_t *tx) { int i; if (r_num_texture_chains == max_texture_chains) { max_texture_chains += 64; r_texture_chains = realloc (r_texture_chains, - max_texture_chains * sizeof (texture_t *)); + max_texture_chains * sizeof (gltex_t *)); for (i = r_num_texture_chains; i < max_texture_chains; i++) r_texture_chains[i] = 0; } + gltex_t *tex = tx->render; r_texture_chains[r_num_texture_chains++] = tex; tex->tex_chain = NULL; tex->tex_chain_tail = &tex->tex_chain; } void -gl_R_InitSurfaceChains (model_t *model) +gl_R_InitSurfaceChains (mod_brush_t *brush) { int i; if (static_chains) free (static_chains); - static_chains = calloc (model->nummodelsurfaces, sizeof (instsurf_t)); - for (i = 0; i < model->nummodelsurfaces; i++) - model->surfaces[i].instsurf = static_chains + i; + static_chains = calloc (brush->nummodelsurfaces, sizeof (instsurf_t)); + for (i = 0; i < brush->nummodelsurfaces; i++) + brush->surfaces[i].instsurf = static_chains + i; release_instsurfs (); } @@ -174,7 +176,7 @@ R_RenderFullbrights (void) int i, j; glpoly_t *p; instsurf_t *sc; - texture_t *tex; + gltex_t *tex; for (i = 0; i < r_num_texture_chains; i++) { if (!(tex = r_texture_chains[i]) || !tex->gl_fb_texturenum) @@ -266,7 +268,7 @@ R_RenderBrushPoly_1 (msurface_t *fa) } static inline void -R_AddToLightmapChain (msurface_t *fa) +R_AddToLightmapChain (mod_brush_t *brush, msurface_t *fa) { int maps, smax, tmax; glRect_t *theRect; @@ -305,7 +307,7 @@ R_AddToLightmapChain (msurface_t *fa) theRect->w = (fa->light_s - theRect->l) + smax; if ((theRect->h + theRect->t) < (fa->light_t + tmax)) theRect->h = (fa->light_t - theRect->t) + tmax; - gl_R_BuildLightMap (fa); + gl_R_BuildLightMap (brush, fa); } } } @@ -332,13 +334,15 @@ gl_R_DrawWaterSurfaces (void) i = -1; for (s = waterchain; s; s = s->tex_chain) { + gltex_t *tex; fa = s->surface; if (s->transform) qfglLoadMatrixf (s->transform); else qfglLoadMatrixf (gl_r_world_matrix); - if (i != fa->texinfo->texture->gl_texturenum) { - i = fa->texinfo->texture->gl_texturenum; + tex = fa->texinfo->texture->render; + if (i != tex->gl_texturenum) { + i = tex->gl_texturenum; qfglBindTexture (GL_TEXTURE_2D, i); } GL_EmitWaterPolys (fa); @@ -360,7 +364,7 @@ DrawTextureChains (int disable_blend, int do_bind) int i; instsurf_t *s; msurface_t *fa; - texture_t *tex; + gltex_t *tex; if (gl_mtex_active_tmus >= 2) { // Lightmaps @@ -469,7 +473,7 @@ static void clear_texture_chains (void) { int i; - texture_t *tex; + gltex_t *tex; for (i = 0; i < r_num_texture_chains; i++) { tex = r_texture_chains[i]; @@ -478,7 +482,7 @@ clear_texture_chains (void) tex->tex_chain = NULL; tex->tex_chain_tail = &tex->tex_chain; } - tex = r_notexture_mip; + tex = r_notexture_mip->render; tex->tex_chain = NULL; tex->tex_chain_tail = &tex->tex_chain; release_instsurfs (); @@ -487,7 +491,8 @@ clear_texture_chains (void) } static inline void -chain_surface (msurface_t *surf, vec_t *transform, float *color) +chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, + float *color) { instsurf_t *sc; @@ -496,15 +501,17 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) } else if (surf->flags & SURF_DRAWSKY) { CHAIN_SURF_F2B (surf, sky_chain); } else { - texture_t *tex; + texture_t *tx; + gltex_t *tex; if (!surf->texinfo->texture->anim_total) - tex = surf->texinfo->texture; + tx = surf->texinfo->texture; else - tex = R_TextureAnimation (surf); + tx = R_TextureAnimation (surf); + tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); - R_AddToLightmapChain (surf); + R_AddToLightmapChain (brush, surf); } if (!(sc = surf->instsurf)) sc = surf->tinst; @@ -523,22 +530,28 @@ gl_R_DrawBrushModel (entity_t *e) msurface_t *psurf; qboolean rotated; vec3_t mins, maxs; + mod_brush_t *brush; + mat4f_t worldMatrix; - model = e->model; + model = e->renderer.model; + brush = &model->brush; - if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { + Transform_GetWorldMatrix (e->transform, worldMatrix); + if (worldMatrix[0][0] != 1 || worldMatrix[1][1] != 1 + || worldMatrix[2][2] != 1) { rotated = true; radius = model->radius; #if 0 //QSG FIXME if (e->scale != 1.0) radius *= e->scale; #endif - if (R_CullSphere (e->origin, radius)) + if (R_CullSphere (&worldMatrix[3][0], radius)) {//FIXME return; + } } else { rotated = false; - VectorAdd (e->origin, model->mins, mins); - VectorAdd (e->origin, model->maxs, maxs); + VectorAdd (worldMatrix[3], model->mins, mins); + VectorAdd (worldMatrix[3], model->maxs, maxs); #if 0 // QSG FIXME if (e->scale != 1.0) { VectorScale (mins, e->scale, mins); @@ -549,18 +562,17 @@ gl_R_DrawBrushModel (entity_t *e) return; } - VectorSubtract (r_refdef.vieworg, e->origin, modelorg); + VectorSubtract (r_refdef.viewposition, worldMatrix[3], modelorg); if (rotated) { - vec3_t temp; + vec4f_t temp = { modelorg[0], modelorg[1], modelorg[2], 0 }; - VectorCopy (modelorg, temp); - modelorg[0] = DotProduct (temp, e->transform + 0); - modelorg[1] = DotProduct (temp, e->transform + 4); - modelorg[2] = DotProduct (temp, e->transform + 8); + modelorg[0] = dotf (temp, worldMatrix[0])[0]; + modelorg[1] = dotf (temp, worldMatrix[1])[0]; + modelorg[2] = dotf (temp, worldMatrix[2])[0]; } // calculate dynamic lighting for bmodel if it's not an instanced model - if (model->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { + if (brush->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { @@ -568,21 +580,21 @@ gl_R_DrawBrushModel (entity_t *e) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], k, - model->nodes + model->hulls[0].firstclipnode); + VectorSubtract (r_dlights[k].origin, worldMatrix[3], lightorigin); + R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, + brush->nodes + brush->hulls[0].firstclipnode); } } qfglPushMatrix (); gl_R_RotateForEntity (e); - qfglGetFloatv (GL_MODELVIEW_MATRIX, e->full_transform); + qfglGetFloatv (GL_MODELVIEW_MATRIX, e->renderer.full_transform); qfglPopMatrix (); - psurf = &model->surfaces[model->firstmodelsurface]; + psurf = &brush->surfaces[brush->firstmodelsurface]; // draw texture - for (i = 0; i < model->nummodelsurfaces; i++, psurf++) { + for (i = 0; i < brush->nummodelsurfaces; i++, psurf++) { // find which side of the node we are on pplane = psurf->plane; @@ -591,7 +603,8 @@ gl_R_DrawBrushModel (entity_t *e) // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (psurf, e->full_transform, e->colormod); + chain_surface (brush, psurf, e->renderer.full_transform, + e->renderer.colormod); } } } @@ -618,7 +631,7 @@ get_side (mnode_t *node) } static inline void -visit_node (mnode_t *node, int side) +visit_node (mod_brush_t *brush, mnode_t *node, int side) { int c; msurface_t *surf; @@ -627,7 +640,7 @@ visit_node (mnode_t *node, int side) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -636,7 +649,7 @@ visit_node (mnode_t *node, int side) if (side ^ (surf->flags & SURF_PLANEBACK)) continue; // wrong side - chain_surface (surf, 0, 0); + chain_surface (brush, surf, 0, 0); } } } @@ -654,7 +667,7 @@ test_node (mnode_t *node) } static void -R_VisitWorldNodes (model_t *model) +R_VisitWorldNodes (mod_brush_t *brush) { typedef struct { mnode_t *node; @@ -666,9 +679,9 @@ R_VisitWorldNodes (model_t *model) mnode_t *front; int side; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { @@ -684,7 +697,7 @@ R_VisitWorldNodes (model_t *model) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -693,7 +706,7 @@ R_VisitWorldNodes (model_t *model) node_ptr--; node = node_ptr->node; side = node_ptr->side; - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; continue; } @@ -709,9 +722,9 @@ gl_R_DrawWorld (void) entity_t worldent; memset (&worldent, 0, sizeof (worldent)); - worldent.model = r_worldentity.model; + worldent.renderer.model = r_worldentity.renderer.model; - VectorCopy (r_refdef.vieworg, modelorg); + VectorCopy (r_refdef.viewposition, modelorg); currententity = &worldent; @@ -721,12 +734,13 @@ gl_R_DrawWorld (void) gl_R_DrawSky (); } - R_VisitWorldNodes (r_worldentity.model); + R_VisitWorldNodes (&r_worldentity.renderer.model->brush); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_brush) + if (ent->renderer.model->type != mod_brush) { continue; + } currententity = ent; gl_R_DrawBrushModel (currententity); @@ -816,7 +830,7 @@ GL_BuildSurfaceDisplayList (msurface_t *fa) medge_t *pedges, *r_pedge; // reconstruct the polygon - pedges = gl_currentmodel->edges; + pedges = gl_currentmodel->brush.edges; lnumverts = fa->numedges; // draw texture @@ -828,7 +842,7 @@ GL_BuildSurfaceDisplayList (msurface_t *fa) poly->numverts = lnumverts; for (i = 0; i < lnumverts; i++) { - lindex = gl_currentmodel->surfedges[fa->firstedge + i]; + lindex = gl_currentmodel->brush.surfedges[fa->firstedge + i]; if (lindex > 0) { r_pedge = &pedges[lindex]; diff --git a/libs/video/renderer/gl/gl_screen.c b/libs/video/renderer/gl/gl_screen.c index ce6c257a7..85de3c89e 100644 --- a/libs/video/renderer/gl/gl_screen.c +++ b/libs/video/renderer/gl/gl_screen.c @@ -59,6 +59,7 @@ #include "compat.h" #include "r_internal.h" #include "sbar.h" +#include "vid_gl.h" /* SCREEN SHOTS */ @@ -69,7 +70,8 @@ gl_SCR_CaptureBGR (void) tex_t *tex; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; @@ -99,7 +101,8 @@ gl_SCR_ScreenShot (unsigned width, unsigned height) fracw = (float) vid.width / (float) w; frach = (float) vid.height / (float) h; - tex = malloc (field_offset (tex_t, data[w * h])); + tex = malloc (sizeof (tex_t) + w * h); + tex->data = (byte *) (tex + 1); if (!tex) return 0; @@ -149,7 +152,7 @@ gl_SCR_ScreenShot_f (void) // find a file name to save it to if (!QFS_NextFilename (pcxname, - va ("%s/qf", qfs_gamedir->dir.shots), ".tga")) { + va (0, "%s/qf", qfs_gamedir->dir.shots), ".tga")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); } else { tex_t *tex; @@ -187,37 +190,23 @@ SCR_TileClear (void) } } -/* - SCR_UpdateScreen - - This is called every frame, and can also be called explicitly to flush - text to the screen. - - WARNING: be very careful calling this from elsewhere, because the refresh - needs almost the entire 256k of stack space! -*/ void -gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +gl_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { double time1 = 0, time2; static int begun = 0; - if (scr_skipupdate) - return; - - if (begun) - vid.end_rendering (); - - vr_data.realtime = realtime; + if (begun) { + gl_ctx->end_rendering (); + begun = 0; + } vid.numpages = 2 + gl_triplebuffer->int_val; - scr_copytop = 0; + //FIXME forces the status bar to redraw. needed because it does not fully + //update in sw modes but must in gl mode vr_data.scr_copyeverything = 1; - if (!scr_initialized) - return; // not initialized yet - begun = 1; if (r_speeds->int_val) { @@ -226,14 +215,6 @@ gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) gl_c_alias_polys = 0; } - if (oldfov != scr_fov->value) { // determine size of refresh window - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - - if (vid.recalc_refdef) - SCR_CalcRefdef (); - // do 3D refresh drawing, and then update the screen scr_3dfunc (); @@ -263,7 +244,7 @@ gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) qfglFlush (); if (gl_finish->int_val) { - vid.end_rendering (); + gl_ctx->end_rendering (); begun = 0; } } diff --git a/libs/video/renderer/gl/gl_sky.c b/libs/video/renderer/gl/gl_sky.c index a4d325f09..db289326b 100644 --- a/libs/video/renderer/gl/gl_sky.c +++ b/libs/video/renderer/gl/gl_sky.c @@ -131,11 +131,12 @@ gl_R_LoadSkys (const char *skyname) qfglBindTexture (GL_TEXTURE_2D, SKY_TEX + i); - targa = LoadImage (name = va ("env/%s%s", skyname, suf[i])); + targa = LoadImage (name = va (0, "env/%s%s", skyname, suf[i]), 1); if (!targa || targa->format < 3) { // FIXME Can't do PCX right now Sys_MaskPrintf (SYS_DEV, "Couldn't load %s\n", name); // also look in gfx/env, where Darkplaces looks for skies - targa = LoadImage (name = va ("gfx/env/%s%s", skyname, suf[i])); + targa = LoadImage (name = va (0, "gfx/env/%s%s", skyname, + suf[i]), 1); if (!targa) { Sys_MaskPrintf (SYS_DEV, "Couldn't load %s\n", name); gl_skyloaded = false; @@ -188,9 +189,9 @@ R_DrawSkyBox (void) float *v = (float *) gl_skyvec[i][j]; qfglTexCoord2fv (v); - qfglVertex3f (r_refdef.vieworg[0] + v[2], - r_refdef.vieworg[1] + v[3], - r_refdef.vieworg[2] + v[4]); + qfglVertex3f (r_refdef.viewposition[0] + v[2], + r_refdef.viewposition[1] + v[3], + r_refdef.viewposition[2] + v[4]); } qfglEnd (); } @@ -218,7 +219,7 @@ skydome_vertex (const vec3_t v, float speedscale) s = speedscale + dir[0]; t = speedscale + dir[1]; - VectorAdd (r_refdef.vieworg, v, point); + VectorAdd (r_refdef.viewposition, v, point); qfglTexCoord2f (s, t); qfglVertex3fv (point); @@ -241,7 +242,7 @@ skydome_debug (void) h = 1; t = 0; - VectorAdd (zenith, r_refdef.vieworg, v[0]); + VectorAdd (zenith, r_refdef.viewposition, v[0]); for (b = 1; b <= 8; b++) { x = gl_bubble_costable[b + 8]; y = -gl_bubble_sintable[b + 8]; @@ -249,7 +250,7 @@ skydome_debug (void) v[h][0] = a1x * x; v[h][1] = a1y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); @@ -261,7 +262,7 @@ skydome_debug (void) v[h][0] = a2x * x; v[h][1] = a2y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); @@ -273,7 +274,7 @@ skydome_debug (void) h = 1; t = 0; - VectorAdd (nadir, r_refdef.vieworg, v[0]); + VectorAdd (nadir, r_refdef.viewposition, v[0]); for (b = 15; b >= 8; b--) { x = gl_bubble_costable[b + 8]; y = -gl_bubble_sintable[b + 8]; @@ -281,7 +282,7 @@ skydome_debug (void) v[h][0] = a2x * x; v[h][1] = a2y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); @@ -293,7 +294,7 @@ skydome_debug (void) v[h][0] = a1x * x; v[h][1] = a1y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); diff --git a/libs/video/renderer/gl/gl_sky_clip.c b/libs/video/renderer/gl/gl_sky_clip.c index 613e8b177..697403eb9 100644 --- a/libs/video/renderer/gl/gl_sky_clip.c +++ b/libs/video/renderer/gl/gl_sky_clip.c @@ -220,14 +220,14 @@ find_cube_vertex (int face1, int face2, int face3, vec3_t v) set_vertex add the vertex to the polygon describing the face of the cube. Offsets - the vertex relative to r_refdef.vieworg so the cube is always centered + the vertex relative to r_refdef.viewposition so the cube is always centered on the player and also calculates the texture coordinates of the vertex (wish I could find a cleaner way of calculating s and t). */ static void set_vertex (struct box_def *box, int face, int ind, const vec3_t v) { - VectorAdd (v, r_refdef.vieworg, box->face[face].poly.verts[ind]); + VectorAdd (v, r_refdef.viewposition, box->face[face].poly.verts[ind]); switch (face) { case 0: box->face[face].poly.verts[ind][3] = (1024 - v[1] + 4) / BOX_WIDTH; @@ -370,7 +370,6 @@ process_corners (struct box_def *box) for (i = 0; i < 6; i++) { if (max_visit < box->face_visits[i]) { max_visit = box->face_visits[i]; - center = i; } } @@ -602,14 +601,14 @@ R_DrawSkyBoxPoly (const glpoly_t *poly) Sys_Error ("too many verts!"); } - VectorSubtract (poly->verts[poly->numverts - 1], r_refdef.vieworg, last_v); + VectorSubtract (poly->verts[poly->numverts - 1], r_refdef.viewposition, last_v); prev_face = determine_face (last_v); box.visited_faces[0].face = prev_face; box.face_count = 1; for (i = 0; i < poly->numverts; i++) { - VectorSubtract (poly->verts[i], r_refdef.vieworg, v); + VectorSubtract (poly->verts[i], r_refdef.viewposition, v); face = determine_face (v); if (face != prev_face) { if ((face_axis[face]) == (face_axis[prev_face])) { @@ -865,11 +864,11 @@ gl_R_DrawSkyChain (const instsurf_t *sky_chain) vec3_t x, c = { 0, 0, 0 }; for (i = 0; i < p->numverts; i++) { - VectorSubtract (p->verts[i], r_refdef.vieworg, x); + VectorSubtract (p->verts[i], r_refdef.viewposition, x); VectorAdd (x, c, c); } VectorScale (c, 1.0 / p->numverts, c); - VectorAdd (c, r_refdef.vieworg, c); + VectorAdd (c, r_refdef.viewposition, c); qfglVertex3fv (c); p = p->next; } @@ -890,7 +889,7 @@ gl_R_DrawSkyChain (const instsurf_t *sky_chain) qfglBegin (GL_LINE_LOOP); for (j = 0; j < 4; j++) { VectorScale (&gl_skyvec[i][j][2], 1.0 / 128.0, v); - VectorAdd (v, r_refdef.vieworg, v); + VectorAdd (v, r_refdef.viewposition, v); qfglVertex3fv (v); } qfglEnd (); diff --git a/libs/video/renderer/gl/namehack.h b/libs/video/renderer/gl/namehack.h index 075e31836..e33d0aef6 100644 --- a/libs/video/renderer/gl/namehack.h +++ b/libs/video/renderer/gl/namehack.h @@ -69,7 +69,7 @@ #define SCR_CaptureBGR gl_SCR_CaptureBGR #define SCR_ScreenShot gl_SCR_ScreenShot #define SCR_ScreenShot_f gl_SCR_ScreenShot_f -#define SCR_UpdateScreen gl_SCR_UpdateScreen +#define R_RenderFrame gl_R_RenderFrame #define c_alias_polys gl_c_alias_polys #define c_brush_polys gl_c_brush_polys #define r_easter_eggs_f gl_r_easter_eggs_f @@ -125,7 +125,7 @@ #undef SCR_CaptureBGR #undef SCR_ScreenShot #undef SCR_ScreenShot_f -#undef SCR_UpdateScreen +#undef R_RenderFrame #undef c_alias_polys #undef c_brush_polys #undef r_easter_eggs_f diff --git a/libs/video/renderer/gl/qfgl_ext.c b/libs/video/renderer/gl/qfgl_ext.c index fa28797d5..f012726de 100644 --- a/libs/video/renderer/gl/qfgl_ext.c +++ b/libs/video/renderer/gl/qfgl_ext.c @@ -61,6 +61,7 @@ #include "QF/GL/funcs.h" #include "r_internal.h" +#include "vid_gl.h" // First we need to get all the function pointers declared. #define QFGL_WANT(ret, name, args) \ @@ -75,9 +76,9 @@ qboolean GLF_FindFunctions (void) { #define QFGL_WANT(ret, name, args) \ - qf##name = vid.get_proc_address (#name, false); + qf##name = gl_ctx->get_proc_address (#name, false); #define QFGL_NEED(ret, name, args) \ - qf##name = vid.get_proc_address (#name, true); + qf##name = gl_ctx->get_proc_address (#name, true); #include "QF/GL/qf_funcs_list.h" #undef QFGL_NEED #undef QFGL_WANT @@ -91,7 +92,7 @@ GLF_FindFunctions (void) It takes a bit of care to be fool-proof about parsing an OpenGL extensions string. Don't be fooled by sub-strings, etc. */ -static qboolean +static __attribute__((pure)) qboolean QFGL_ParseExtensionList (const GLubyte *list, const char *name) { const char *start; @@ -135,6 +136,6 @@ void * QFGL_ExtensionAddress (const char *name) { if (name) - return vid.get_proc_address (name, false); + return gl_ctx->get_proc_address (name, false); return NULL; } diff --git a/libs/video/renderer/gl/vtxarray.c b/libs/video/renderer/gl/vtxarray.c index 78e245a55..dda46974b 100644 --- a/libs/video/renderer/gl/vtxarray.c +++ b/libs/video/renderer/gl/vtxarray.c @@ -445,7 +445,6 @@ qfgl_InterleavedArrays (GLenum format, GLsizei stride, const GLvoid *pointer) case GL_C4UB_V2F: qfgl_VertexPointer (2, GL_FLOAT, stride - 2 * sizeof (GLfloat), ptr); - ptr += 2 * sizeof (GLfloat); break; case GL_V3F: case GL_C4UB_V3F: @@ -459,13 +458,11 @@ qfgl_InterleavedArrays (GLenum format, GLsizei stride, const GLvoid *pointer) case GL_T2F_C4F_N3F_V3F: qfgl_VertexPointer (3, GL_FLOAT, stride - 3 * sizeof (GLfloat), ptr); - ptr += 3 * sizeof (GLfloat); break; case GL_T4F_V4F: case GL_T4F_C4F_N3F_V4F: qfgl_VertexPointer (4, GL_FLOAT, stride - 4 * sizeof (GLfloat), ptr); - ptr += 4 * sizeof (GLfloat); break; default: break; diff --git a/libs/video/renderer/glsl/Makefile.am b/libs/video/renderer/glsl/Makefile.am deleted file mode 100644 index ca8f4314a..000000000 --- a/libs/video/renderer/glsl/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(GLX_CFLAGS) - -shader_src= quakeforge.glsl -shader_gen= quakeforge.slc - -glsl_src = \ - glsl_alias.c glsl_bsp.c glsl_draw.c glsl_fog.c glsl_iqm.c glsl_lightmap.c \ - glsl_main.c glsl_particles.c glsl_screen.c glsl_shader.c glsl_sprite.c \ - glsl_textures.c qfglsl.c vid_common_glsl.c - -noinst_LTLIBRARIES= libglsl.la -BUILT_SOURCES= $(shader_gen) - -SUFFICES=.frag .vert .fc .vc .slc .glsl -.glsl.slc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ -.frag.fc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ -.vert.vc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ - -libglsl_la_SOURCES= $(glsl_src) - -EXTRA_DIST = $(glsl_src) $(shader_src) namehack.h -CLEANFILES= *.vc *.fc *.slc diff --git a/libs/video/renderer/glsl/glsl_alias.c b/libs/video/renderer/glsl/glsl_alias.c index 3fdd50b66..22983ceef 100644 --- a/libs/video/renderer/glsl/glsl_alias.c +++ b/libs/video/renderer/glsl/glsl_alias.c @@ -43,6 +43,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/skin.h" #include "QF/sys.h" @@ -111,7 +112,7 @@ static struct { {"fog", 1}, }; -static mat4_t alias_vp; +static mat4f_t alias_vp; void glsl_R_InitAlias (void) @@ -156,16 +157,20 @@ calc_lighting (entity_t *ent, float *ambient, float *shadelight, unsigned i; float add; vec3_t dist; + vec4f_t entorigin; int light; + entorigin = Transform_GetWorldPosition (ent->transform); + VectorSet ( -1, 0, 0, lightvec); //FIXME - light = R_LightPoint (ent->origin); - *ambient = max (light, max (ent->model->min_light, ent->min_light) * 128); + light = R_LightPoint (&r_worldentity.renderer.model->brush, &entorigin[0]); + *ambient = max (light, max (ent->renderer.model->min_light, + ent->renderer.min_light) * 128); *shadelight = *ambient; for (i = 0; i < r_maxdlights; i++) { if (r_dlights[i].die >= vr_data.realtime) { - VectorSubtract (ent->origin, r_dlights[i].origin, dist); + VectorSubtract (entorigin, r_dlights[i].origin, dist); add = r_dlights[i].radius - VectorLength (dist); if (add > 0) *ambient += add; @@ -228,50 +233,52 @@ glsl_R_DrawAlias (void) float skin_size[2]; float blend; entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; aliashdr_t *hdr; vec_t norm_mat[9]; - mat4_t mvp_mat; int skin_tex; int colormap; aliasvrt_t *pose1 = 0; // VBO's are null based aliasvrt_t *pose2 = 0; // VBO's are null based + mat4f_t worldMatrix; if (!(hdr = model->aliashdr)) hdr = Cache_Get (&model->cache); calc_lighting (ent, &ambient, &shadelight, lightvec); + Transform_GetWorldMatrix (ent->transform, worldMatrix); // we need only the rotation for normals. - VectorCopy (ent->transform + 0, norm_mat + 0); - VectorCopy (ent->transform + 4, norm_mat + 3); - VectorCopy (ent->transform + 8, norm_mat + 6); + VectorCopy (worldMatrix[0], norm_mat + 0); + VectorCopy (worldMatrix[1], norm_mat + 3); + VectorCopy (worldMatrix[2], norm_mat + 6); // ent model scaling and offset - Mat4Zero (mvp_mat); - mvp_mat[0] = hdr->mdl.scale[0]; - mvp_mat[5] = hdr->mdl.scale[1]; - mvp_mat[10] = hdr->mdl.scale[2]; - mvp_mat[15] = 1; - VectorCopy (hdr->mdl.scale_origin, mvp_mat + 12); - Mat4Mult (ent->transform, mvp_mat, mvp_mat); - Mat4Mult (alias_vp, mvp_mat, mvp_mat); + mat4f_t mvp_mat = { + { hdr->mdl.scale[0], 0, 0, 0 }, + { 0, hdr->mdl.scale[1], 0, 0 }, + { 0, 0, hdr->mdl.scale[2], 0 }, + { hdr->mdl.scale_origin[0], hdr->mdl.scale_origin[1], + hdr->mdl.scale_origin[2], 1 }, + }; + mmulf (mvp_mat, worldMatrix, mvp_mat); + mmulf (mvp_mat, alias_vp, mvp_mat); colormap = glsl_colormap; - if (ent->skin && ent->skin->auxtex) - colormap = ent->skin->auxtex; - if (ent->skin && ent->skin->texnum) { - skin_t *skin = ent->skin; + if (ent->renderer.skin && ent->renderer.skin->auxtex) + colormap = ent->renderer.skin->auxtex; + if (ent->renderer.skin && ent->renderer.skin->texnum) { + skin_t *skin = ent->renderer.skin; skin_tex = skin->texnum; } else { maliasskindesc_t *skindesc; - skindesc = R_AliasGetSkindesc (ent->skinnum, hdr); + skindesc = R_AliasGetSkindesc (ent->renderer.skinnum, hdr); skin_tex = skindesc->texnum; } blend = R_AliasGetLerpedFrames (ent, hdr); - pose1 += ent->pose1 * hdr->poseverts; - pose2 += ent->pose2 * hdr->poseverts; + pose1 += ent->animation.pose1 * hdr->poseverts; + pose2 += ent->animation.pose2 * hdr->poseverts; skin_size[0] = hdr->mdl.skinwidth; skin_size[1] = hdr->mdl.skinheight; @@ -293,7 +300,8 @@ glsl_R_DrawAlias (void) qfeglUniform1f (quake_mdl.shadelight.location, shadelight); qfeglUniform3fv (quake_mdl.lightvec.location, 1, lightvec); qfeglUniform2fv (quake_mdl.skin_size.location, 1, skin_size); - qfeglUniformMatrix4fv (quake_mdl.mvp_matrix.location, 1, false, mvp_mat); + qfeglUniformMatrix4fv (quake_mdl.mvp_matrix.location, 1, false, + &mvp_mat[0][0]); qfeglUniformMatrix3fv (quake_mdl.norm_matrix.location, 1, false, norm_mat); #ifndef TETRAHEDRON @@ -321,7 +329,7 @@ glsl_R_AliasBegin (void) quat_t fog; // pre-multiply the view and projection matricies - Mat4Mult (glsl_projection, glsl_view, alias_vp); + mmulf (alias_vp, glsl_projection, glsl_view); qfeglUseProgram (quake_mdl.program); qfeglEnableVertexAttribArray (quake_mdl.vertexa.location); @@ -333,7 +341,7 @@ glsl_R_AliasBegin (void) qfeglDisableVertexAttribArray (quake_mdl.colora.location); qfeglDisableVertexAttribArray (quake_mdl.colorb.location); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_mdl.fog.location, 1, fog); diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index e52402660..50a4e98af 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -46,6 +46,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/sys.h" @@ -73,7 +74,7 @@ static instsurf_t **waterchain_tail = &waterchain; static instsurf_t *sky_chain; static instsurf_t **sky_chain_tail = &sky_chain; -static texture_t **r_texture_chains; +static glsltex_t **r_texture_chains; static int r_num_texture_chains; static int max_texture_chains; @@ -94,7 +95,7 @@ static instsurf_t **instsurfs_tail = &instsurfs; static instsurf_t *free_instsurfs; static GLuint bsp_vbo; -static mat4_t bsp_vp; +static mat4f_t bsp_vp; static GLuint skybox_tex; static qboolean skybox_loaded; @@ -293,16 +294,17 @@ GET_RELEASE (instsurf_t, static_instsurf) GET_RELEASE (instsurf_t, instsurf) void -glsl_R_AddTexture (texture_t *tex) +glsl_R_AddTexture (texture_t *tx) { int i; if (r_num_texture_chains == max_texture_chains) { max_texture_chains += 64; r_texture_chains = realloc (r_texture_chains, - max_texture_chains * sizeof (texture_t *)); + max_texture_chains * sizeof (glsltex_t *)); for (i = r_num_texture_chains; i < max_texture_chains; i++) r_texture_chains[i] = 0; } + glsltex_t *tex = tx->render; r_texture_chains[r_num_texture_chains++] = tex; tex->tex_chain = 0; tex->tex_chain_tail = &tex->tex_chain; @@ -310,22 +312,22 @@ glsl_R_AddTexture (texture_t *tex) tex->elechain_tail = &tex->elechain; } -void -glsl_R_InitSurfaceChains (model_t *model) +static void +glsl_R_InitSurfaceChains (mod_brush_t *brush) { int i; release_static_instsurfs (); release_instsurfs (); - for (i = 0; i < model->nummodelsurfaces; i++) { - model->surfaces[i].instsurf = get_static_instsurf (); - model->surfaces[i].instsurf->surface = &model->surfaces[i]; + for (i = 0; i < brush->nummodelsurfaces; i++) { + brush->surfaces[i].instsurf = get_static_instsurf (); + brush->surfaces[i].instsurf->surface = &brush->surfaces[i]; } } static inline void -clear_tex_chain (texture_t *tex) +clear_tex_chain (glsltex_t *tex) { tex->tex_chain = 0; tex->tex_chain_tail = &tex->tex_chain; @@ -343,7 +345,7 @@ clear_texture_chains (void) continue; clear_tex_chain (r_texture_chains[i]); } - clear_tex_chain (r_notexture_mip); + clear_tex_chain (r_notexture_mip->render); release_elechains (); release_elementss (); release_instsurfs (); @@ -357,7 +359,7 @@ glsl_R_ClearElements (void) } static void -update_lightmap (msurface_t *surf) +update_lightmap (mod_brush_t *brush, msurface_t *surf) { int maps; @@ -368,12 +370,13 @@ update_lightmap (msurface_t *surf) if ((surf->dlightframe == r_framecount) || surf->cached_dlight) { dynamic: if (r_dynamic->int_val) - glsl_R_BuildLightMap (surf); + glsl_R_BuildLightMap (brush, surf); } } static inline void -chain_surface (msurface_t *surf, vec_t *transform, float *color) +chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, + float *color) { instsurf_t *is; @@ -382,15 +385,17 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) } else if ((surf->flags & SURF_DRAWTURB) || (color && color[3] < 1.0)) { CHAIN_SURF_B2F (surf, waterchain); } else { - texture_t *tex; + texture_t *tx; + glsltex_t *tex; if (!surf->texinfo->texture->anim_total) - tex = surf->texinfo->texture; + tx = surf->texinfo->texture; else - tex = R_TextureAnimation (surf); + tx = R_TextureAnimation (surf); + tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); - update_lightmap (surf); + update_lightmap (brush, surf); } if (!(is = surf->instsurf)) is = surf->tinst; @@ -399,13 +404,13 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) } static void -register_textures (model_t *model) +register_textures (mod_brush_t *brush) { int i; texture_t *tex; - for (i = 0; i < model->numtextures; i++) { - tex = model->textures[i]; + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; if (!tex) continue; glsl_R_AddTexture (tex); @@ -423,28 +428,30 @@ glsl_R_RegisterTextures (model_t **models, int num_models) { int i; model_t *m; + mod_brush_t *brush; glsl_R_ClearTextures (); - glsl_R_InitSurfaceChains (r_worldentity.model); + glsl_R_InitSurfaceChains (&r_worldentity.renderer.model->brush); glsl_R_AddTexture (r_notexture_mip); - register_textures (r_worldentity.model); + register_textures (&r_worldentity.renderer.model->brush); for (i = 0; i < num_models; i++) { m = models[i]; if (!m) continue; // sub-models are done as part of the main model - if (*m->name == '*') + if (*m->path == '*') continue; // world has already been done, not interested in non-brush models - if (m == r_worldentity.model || m->type != mod_brush) + if (m == r_worldentity.renderer.model || m->type != mod_brush) continue; - m->numsubmodels = 1; // no support for submodels in non-world model - register_textures (m); + brush = &m->brush; + brush->numsubmodels = 1; // no support for submodels in non-world model + register_textures (brush); } } static elechain_t * -add_elechain (texture_t *tex, int ec_index) +add_elechain (glsltex_t *tex, int ec_index) { elechain_t *ec; @@ -475,16 +482,17 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, glslpoly_t *poly; GLushort *ind; float s, t; + mod_brush_t *brush; if (fa->ec_index < 0) { - vertices = models[-fa->ec_index - 1]->vertexes; - edges = models[-fa->ec_index - 1]->edges; - surfedges = models[-fa->ec_index - 1]->surfedges; + brush = &models[-fa->ec_index - 1]->brush; } else { - vertices = r_worldentity.model->vertexes; - edges = r_worldentity.model->edges; - surfedges = r_worldentity.model->surfedges; + brush = &r_worldentity.renderer.model->brush; } + vertices = brush->vertexes; + edges = brush->edges; + surfedges = brush->surfedges; + numverts = fa->numedges; numtris = numverts - 2; numindices = numtris * 3; @@ -542,9 +550,10 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) dmodel_t *dm; msurface_t *surf; dstring_t *vertices; + mod_brush_t *brush; - QuatSet (sqrt(0.5), 0, 0, sqrt(0.5), sky_fix); // proper skies - QuatSet (1, 0, 0, 0, sky_rotation[0]); + QuatSet (0, 0, sqrt(0.5), sqrt(0.5), sky_fix); // proper skies + QuatSet (0, 0, 0, 1, sky_rotation[0]); QuatCopy (sky_rotation[0], sky_rotation[1]); QuatSet (0, 0, 0, 0, sky_velocity); QuatExp (sky_velocity, sky_velocity); @@ -558,27 +567,28 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) if (!m) continue; // sub-models are done as part of the main model - if (*m->name == '*') + if (*m->path == '*' || m->type != mod_brush) continue; + brush = &m->brush; // non-bsp models don't have surfaces. - dm = m->submodels; - for (j = 0; j < m->numsurfaces; j++) { - texture_t *tex; + dm = brush->submodels; + for (j = 0; j < brush->numsurfaces; j++) { + glsltex_t *tex; if (j == dm->firstface + dm->numfaces) { dm++; - if (dm - m->submodels == m->numsubmodels) { + if (dm - brush->submodels == brush->numsubmodels) { // limit the surfaces // probably never hit Sys_Printf ("R_BuildDisplayLists: too many surfaces\n"); - m->numsurfaces = j; + brush->numsurfaces = j; break; } } - surf = m->surfaces + j; - surf->ec_index = dm - m->submodels; - if (!surf->ec_index && m != r_worldentity.model) + surf = brush->surfaces + j; + surf->ec_index = dm - brush->submodels; + if (!surf->ec_index && m != r_worldentity.renderer.model) surf->ec_index = -1 - i; // instanced model - tex = surf->texinfo->texture; + tex = surf->texinfo->texture->render; CHAIN_SURF_F2B (surf, tex->tex_chain); } } @@ -590,7 +600,7 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) // For animated textures, if a surface is on one texture of the group, it // will be on all. for (i = 0; i < r_num_texture_chains; i++) { - texture_t *tex; + glsltex_t *tex; instsurf_t *is; elechain_t *ec = 0; elements_t *el = 0; @@ -650,34 +660,40 @@ R_DrawBrushModel (entity_t *e) plane_t *plane; msurface_t *surf; qboolean rotated; - vec3_t mins, maxs, org; + vec3_t mins, maxs; + vec4f_t org; + mod_brush_t *brush; - model = e->model; - if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { + model = e->renderer.model; + brush = &model->brush; + mat4f_t mat; + Transform_GetWorldMatrix (e->transform, mat); + memcpy (e->renderer.full_transform, mat, sizeof (mat));//FIXME + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { rotated = true; radius = model->radius; - if (R_CullSphere (e->origin, radius)) + if (R_CullSphere (&mat[3][0], radius)) { // FIXME return; + } } else { rotated = false; - VectorAdd (e->origin, model->mins, mins); - VectorAdd (e->origin, model->maxs, maxs); + VectorAdd (mat[3], model->mins, mins); + VectorAdd (mat[3], model->maxs, maxs); if (R_CullBox (mins, maxs)) return; } - VectorSubtract (r_refdef.vieworg, e->origin, org); + org = r_refdef.viewposition - mat[3]; if (rotated) { - vec3_t temp; + vec4f_t temp = org; - VectorCopy (org, temp); - org[0] = DotProduct (temp, e->transform + 0); - org[1] = DotProduct (temp, e->transform + 4); - org[2] = DotProduct (temp, e->transform + 8); + org[0] = dotf (temp, mat[0])[0]; + org[1] = dotf (temp, mat[1])[0]; + org[2] = dotf (temp, mat[2])[0]; } // calculate dynamic lighting for bmodel if it's not an instanced model - if (model->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { + if (brush->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { @@ -685,15 +701,15 @@ R_DrawBrushModel (entity_t *e) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], k, - model->nodes + model->hulls[0].firstclipnode); + VectorSubtract (r_dlights[k].origin, mat[3], lightorigin); + R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, + brush->nodes + brush->hulls[0].firstclipnode); } } - surf = &model->surfaces[model->firstmodelsurface]; + surf = &brush->surfaces[brush->firstmodelsurface]; - for (i = 0; i < model->nummodelsurfaces; i++, surf++) { + for (i = 0; i < brush->nummodelsurfaces; i++, surf++) { // find the node side on which we are plane = surf->plane; @@ -702,7 +718,8 @@ R_DrawBrushModel (entity_t *e) // enqueue the polygon if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (surf, e->transform, e->colormod); + chain_surface (brush, surf, e->renderer.full_transform, + e->renderer.colormod); } } } @@ -727,7 +744,7 @@ get_side (mnode_t *node) } static inline void -visit_node (mnode_t *node, int side) +visit_node (mod_brush_t *brush, mnode_t *node, int side) { int c; msurface_t *surf; @@ -736,7 +753,7 @@ visit_node (mnode_t *node, int side) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -745,7 +762,7 @@ visit_node (mnode_t *node, int side) if (side ^ (surf->flags & SURF_PLANEBACK)) continue; // wrong side - chain_surface (surf, 0, 0); + chain_surface (brush, surf, 0, 0); } } } @@ -763,7 +780,7 @@ test_node (mnode_t *node) } static void -R_VisitWorldNodes (model_t *model) +R_VisitWorldNodes (mod_brush_t *brush) { typedef struct { mnode_t *node; @@ -775,9 +792,9 @@ R_VisitWorldNodes (model_t *model) mnode_t *front; int side; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { @@ -793,7 +810,7 @@ R_VisitWorldNodes (model_t *model) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -802,7 +819,7 @@ R_VisitWorldNodes (model_t *model) node_ptr--; node = node_ptr->node; side = node_ptr->side; - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; continue; } @@ -831,10 +848,10 @@ draw_elechain (elechain_t *ec, int matloc, int vertloc, int tlstloc, } } if (ec->transform) { - Mat4Mult (bsp_vp, ec->transform, mat); + Mat4Mult (&bsp_vp[0][0], ec->transform, mat);//FIXME qfeglUniformMatrix4fv (matloc, 1, false, mat); } else { - qfeglUniformMatrix4fv (matloc, 1, false, bsp_vp); + qfeglUniformMatrix4fv (matloc, 1, false, &bsp_vp[0][0]); } for (el = ec->elements; el; el = el->next) { if (!el->list->size) @@ -862,7 +879,7 @@ bsp_begin (void) QuatCopy (default_color, last_color); qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + mmulf (bsp_vp, glsl_projection, glsl_view); qfeglUseProgram (quake_bsp.program); qfeglEnableVertexAttribArray (quake_bsp.vertex.location); @@ -871,7 +888,7 @@ bsp_begin (void) qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_bsp.fog.location, 1, fog); @@ -917,7 +934,7 @@ turb_begin (void) QuatCopy (default_color, last_color); qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + mmulf (bsp_vp, glsl_projection, glsl_view); qfeglUseProgram (quake_turb.program); qfeglEnableVertexAttribArray (quake_turb.vertex.location); @@ -926,7 +943,7 @@ turb_begin (void) qfeglVertexAttrib4fv (quake_turb.color.location, default_color); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_turb.fog.location, 1, fog); @@ -990,7 +1007,7 @@ sky_begin (void) QuatCopy (default_color, last_color); qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + mmulf (bsp_vp, glsl_projection, glsl_view); if (skybox_loaded) { sky_params.mvp_matrix = &quake_skybox.mvp_matrix; @@ -1030,7 +1047,7 @@ sky_begin (void) qfeglEnable (GL_TEXTURE_2D); } - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (sky_params.fog->location, 1, fog); @@ -1057,7 +1074,7 @@ sky_end (void) } static inline void -add_surf_elements (texture_t *tex, instsurf_t *is, +add_surf_elements (glsltex_t *tex, instsurf_t *is, elechain_t **ec, elements_t **el) { msurface_t *surf = is->surface; @@ -1096,7 +1113,7 @@ add_surf_elements (texture_t *tex, instsurf_t *is, } static void -build_tex_elechain (texture_t *tex) +build_tex_elechain (glsltex_t *tex) { instsurf_t *is; elechain_t *ec = 0; @@ -1116,15 +1133,15 @@ glsl_R_DrawWorld (void) clear_texture_chains (); // do this first for water and skys memset (&worldent, 0, sizeof (worldent)); - worldent.model = r_worldentity.model; + worldent.renderer.model = r_worldentity.renderer.model; currententity = &worldent; - R_VisitWorldNodes (worldent.model); + R_VisitWorldNodes (&worldent.renderer.model->brush); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_brush) + if (ent->renderer.model->type != mod_brush) continue; currententity = ent; @@ -1136,7 +1153,7 @@ glsl_R_DrawWorld (void) bsp_begin (); qfeglActiveTexture (GL_TEXTURE0 + 0); for (i = 0; i < r_num_texture_chains; i++) { - texture_t *tex; + glsltex_t *tex; elechain_t *ec = 0; tex = r_texture_chains[i]; @@ -1163,7 +1180,7 @@ glsl_R_DrawWaterSurfaces () { instsurf_t *is; msurface_t *surf; - texture_t *tex = 0; + glsltex_t *tex = 0; elechain_t *ec = 0; elements_t *el = 0; @@ -1173,7 +1190,7 @@ glsl_R_DrawWaterSurfaces () turb_begin (); for (is = waterchain; is; is = is->tex_chain) { surf = is->surface; - if (tex != surf->texinfo->texture) { + if (tex != surf->texinfo->texture->render) { if (tex) { qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); for (ec = tex->elechain; ec; ec = ec->next) @@ -1184,7 +1201,7 @@ glsl_R_DrawWaterSurfaces () tex->elechain = 0; tex->elechain_tail = &tex->elechain; } - tex = surf->texinfo->texture; + tex = surf->texinfo->texture->render; } add_surf_elements (tex, is, &ec, &el); } @@ -1209,7 +1226,7 @@ glsl_R_DrawSky (void) { instsurf_t *is; msurface_t *surf; - texture_t *tex = 0; + glsltex_t *tex = 0; elechain_t *ec = 0; elements_t *el = 0; @@ -1219,7 +1236,7 @@ glsl_R_DrawSky (void) sky_begin (); for (is = sky_chain; is; is = is->tex_chain) { surf = is->surface; - if (tex != surf->texinfo->texture) { + if (tex != surf->texinfo->texture->render) { if (tex) { if (!skybox_loaded) { qfeglActiveTexture (GL_TEXTURE0 + 0); @@ -1233,7 +1250,7 @@ glsl_R_DrawSky (void) tex->elechain = 0; tex->elechain_tail = &tex->elechain; } - tex = surf->texinfo->texture; + tex = surf->texinfo->texture->render; } add_surf_elements (tex, is, &ec, &el); } @@ -1321,7 +1338,7 @@ glsl_R_InitBsp (void) GLSL_FreeShader (frag_shader); } -static inline int +static inline __attribute__((const)) int is_pow2 (unsigned x) { int count; @@ -1399,14 +1416,15 @@ glsl_R_LoadSkys (const char *sky) //blender envmap // bk rt ft // dn up lt - tex = LoadImage (name = va ("env/%s_map", sky)); + tex = LoadImage (name = va (0, "env/%s_map", sky), 1); if (tex && tex->format >= 3 && tex->height * 3 == tex->width * 2 && is_pow2 (tex->height)) { tex_t *sub; int size = tex->height / 2; skybox_loaded = true; - sub = malloc (field_offset (tex_t, data[size * size * tex->format])); + sub = malloc (sizeof (tex_t) + size * size * tex->format); + sub->data = (byte *) (sub + 1); sub->width = size; sub->height = size; sub->format = tex->format; @@ -1426,12 +1444,12 @@ glsl_R_LoadSkys (const char *sky) } else { skybox_loaded = true; for (i = 0; i < 6; i++) { - tex = LoadImage (name = va ("env/%s%s", sky, sky_suffix[i])); + tex = LoadImage (name = va (0, "env/%s%s", sky, sky_suffix[i]), 1); if (!tex || tex->format < 3) { // FIXME pcx support Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); // also look in gfx/env, where Darkplaces looks for skies - tex = LoadImage (name = va ("gfx/env/%s%s", sky, - sky_suffix[i])); + tex = LoadImage (name = va (0, "gfx/env/%s%s", sky, + sky_suffix[i]), 1); if (!tex || tex->format < 3) { // FIXME pcx support Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); skybox_loaded = false; diff --git a/libs/video/renderer/glsl/glsl_draw.c b/libs/video/renderer/glsl/glsl_draw.c index 6a8ef0268..6d1f14f0b 100644 --- a/libs/video/renderer/glsl/glsl_draw.c +++ b/libs/video/renderer/glsl/glsl_draw.c @@ -375,7 +375,7 @@ glsl_Draw_Init (void) qpic_t *pic; //FIXME glpic_t *gl; - pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, 0); + pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, 0, 0); QFS_GamedirCallback (Draw_ClearCache); //FIXME temporary work around for the timing of cvar creation and palette //loading diff --git a/libs/video/renderer/glsl/glsl_fog.c b/libs/video/renderer/glsl/glsl_fog.c index 8e246b6b7..82777061e 100644 --- a/libs/video/renderer/glsl/glsl_fog.c +++ b/libs/video/renderer/glsl/glsl_fog.c @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "QF/cmd.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/sys.h" @@ -189,32 +189,29 @@ glsl_Fog_ParseWorldspawn (plitem_t *worldspawn) calculates fog color for this frame, taking into account fade times */ -float * -glsl_Fog_GetColor (void) +void +glsl_Fog_GetColor (quat_t fogcolor) { - static float c[4]; float f; int i; if (fade_done > vr_data.realtime) { f = (fade_done - vr_data.realtime) / fade_time; - c[0] = f * old_red + (1.0 - f) * fog_red; - c[1] = f * old_green + (1.0 - f) * fog_green; - c[2] = f * old_blue + (1.0 - f) * fog_blue; - c[3] = 1.0; + fogcolor[0] = f * old_red + (1.0 - f) * fog_red; + fogcolor[1] = f * old_green + (1.0 - f) * fog_green; + fogcolor[2] = f * old_blue + (1.0 - f) * fog_blue; + fogcolor[3] = 1.0; } else { - c[0] = fog_red; - c[1] = fog_green; - c[2] = fog_blue; - c[3] = 1.0; + fogcolor[0] = fog_red; + fogcolor[1] = fog_green; + fogcolor[2] = fog_blue; + fogcolor[3] = 1.0; } //find closest 24-bit RGB value, so solid-colored sky can match the fog //perfectly for (i = 0; i < 3; i++) - c[i] = (float) (rint (c[i] * 255)) / 255.0f; - - return c; + fogcolor[i] = (float) (rint (fogcolor[i] * 255)) / 255.0f; } /* diff --git a/libs/video/renderer/glsl/glsl_iqm.c b/libs/video/renderer/glsl/glsl_iqm.c index d189a4cbe..93a25e982 100644 --- a/libs/video/renderer/glsl/glsl_iqm.c +++ b/libs/video/renderer/glsl/glsl_iqm.c @@ -43,6 +43,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/skin.h" #include "QF/sys.h" @@ -137,7 +138,7 @@ static struct va_attr_s { {&iqm_shader.vcolor, 4, GL_UNSIGNED_BYTE, 1}, }; -static mat4_t iqm_vp; +static mat4f_t iqm_vp; void glsl_R_InitIQM (void) @@ -207,28 +208,33 @@ glsl_R_DrawIQM (void) { static quat_t color = { 1, 1, 1, 1}; entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; glsliqm_t *glsl = (glsliqm_t *) iqm->extra_data; dlight_t *lights[MAX_IQM_LIGHTS]; int i; vec_t norm_mat[9]; - mat4_t mvp_mat; + vec4f_t entorigin; + mat4f_t mvp_mat; float blend; iqmframe_t *frame; - R_LightPoint (ent->origin); //FIXME min_light? - VectorScale (ambientcolor, 1/255.0, ambientcolor); - R_FindNearLights (ent->origin, MAX_IQM_LIGHTS, lights); - // we need only the rotation for normals. - VectorCopy (ent->transform + 0, norm_mat + 0); - VectorCopy (ent->transform + 4, norm_mat + 3); - VectorCopy (ent->transform + 8, norm_mat + 6); - Mat4Mult (iqm_vp, ent->transform, mvp_mat); + mat4f_t mat; + Transform_GetWorldMatrix (ent->transform, mat); + VectorCopy (mat[0], norm_mat + 0); + VectorCopy (mat[1], norm_mat + 3); + VectorCopy (mat[2], norm_mat + 6); + entorigin = mat[3]; + mmulf (mvp_mat, iqm_vp, mat); + + R_LightPoint (&r_worldentity.renderer.model->brush, &entorigin[0]);//FIXME min_light? + VectorScale (ambientcolor, 1/255.0, ambientcolor); + R_FindNearLights (&entorigin[0], MAX_IQM_LIGHTS, lights);//FIXME blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendFrames (iqm, ent->pose1, ent->pose2, blend, 0); + frame = R_IQMBlendFrames (iqm, ent->animation.pose1, ent->animation.pose2, + blend, 0); qfeglUniform3fv (iqm_shader.ambient.location, 1, ambientcolor); for (i = 0; i < MAX_IQM_LIGHTS; i++) { @@ -236,7 +242,7 @@ glsl_R_DrawIQM (void) lightpar_t *l = &iqm_shader.lights[i]; if (!lights[i]) break; - VectorSubtract (lights[i]->origin, ent->origin, val); + VectorSubtract (lights[i]->origin, entorigin, val); val[3] = lights[i]->radius; qfeglUniform4fv (l->position.location, 1, val); qfeglUniform4fv (l->color.location, 1, lights[i]->color); @@ -249,7 +255,8 @@ glsl_R_DrawIQM (void) qfeglBindBuffer (GL_ARRAY_BUFFER, glsl->vertex_array); qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, glsl->element_array); - qfeglUniformMatrix4fv (iqm_shader.mvp_matrix.location, 1, false, mvp_mat); + qfeglUniformMatrix4fv (iqm_shader.mvp_matrix.location, 1, false, + &mvp_mat[0][0]); qfeglUniformMatrix3fv (iqm_shader.norm_matrix.location, 1, false, norm_mat); qfeglUniformMatrix4fv (iqm_shader.bonemats.location, iqm->num_joints, @@ -274,11 +281,11 @@ glsl_R_IQMBegin (void) quat_t fog; // pre-multiply the view and projection matricies - Mat4Mult (glsl_projection, glsl_view, iqm_vp); + mmulf (iqm_vp, glsl_projection, glsl_view); qfeglUseProgram (iqm_shader.program); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (iqm_shader.fog.location, 1, fog); diff --git a/libs/video/renderer/glsl/glsl_lightmap.c b/libs/video/renderer/glsl/glsl_lightmap.c index 11ae46ca8..f34de4692 100644 --- a/libs/video/renderer/glsl/glsl_lightmap.c +++ b/libs/video/renderer/glsl/glsl_lightmap.c @@ -44,6 +44,7 @@ #endif #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -58,11 +59,10 @@ #define BLOCK_SIZE (BLOCK_WIDTH * BLOCK_HEIGHT) static scrap_t *light_scrap; -static byte *light_data; static unsigned *blocklights; static int bl_extents[2]; -void (*glsl_R_BuildLightMap) (msurface_t *surf); +void (*glsl_R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); static void R_AddDynamicLights_1 (msurface_t *surf) @@ -71,6 +71,7 @@ R_AddDynamicLights_1 (msurface_t *surf) int sd, td; float dist, rad, minlight; vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1}; int s, t; int smax, tmax; mtexinfo_t *tex; @@ -79,12 +80,16 @@ R_AddDynamicLights_1 (msurface_t *surf) tmax = (surf->extents[1] >> 4) + 1; tex = surf->texinfo; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, - lightorigin); + VectorSubtract (r_dlights[lnum].origin, entorigin, lightorigin); rad = r_dlights[lnum].radius; dist = DotProduct (lightorigin, surf->plane->normal) - surf->plane->dist; @@ -122,7 +127,7 @@ R_AddDynamicLights_1 (msurface_t *surf) } static void -R_BuildLightMap_1 (msurface_t *surf) +R_BuildLightMap_1 (mod_brush_t *brush, msurface_t *surf) { int smax, tmax, size; unsigned scale; @@ -139,7 +144,7 @@ R_BuildLightMap_1 (msurface_t *surf) // clear to no light memset (blocklights, 0, size * sizeof (blocklights[0])); - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { // because we by-pass the inversion, "no light" = "full bright" GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1); return; @@ -197,14 +202,13 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) { int i, j, size; model_t *m; + mod_brush_t *brush; //FIXME RGB support if (!light_scrap) { light_scrap = GLSL_CreateScrap (2048, GL_LUMINANCE, 1); - light_data = malloc (BLOCK_SIZE * MAX_LIGHTMAPS); } else { GLSL_ScrapClear (light_scrap); - memset (light_data, 0, BLOCK_SIZE * MAX_LIGHTMAPS); } glsl_R_BuildLightMap = R_BuildLightMap_1; @@ -213,13 +217,14 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->name[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } + brush = &m->brush; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - msurface_t *surf = m->surfaces + i; + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; surf->lightpic = 0; // paranoia if (surf->flags & SURF_DRAWTURB) continue; @@ -234,15 +239,16 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->name[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } + brush = &m->brush; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - msurface_t *surf = m->surfaces + i; + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; if (surf->lightpic) - glsl_R_BuildLightMap (surf); + glsl_R_BuildLightMap (brush, surf); } } } diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 9fd3a9c0c..fed46ed3a 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -58,16 +58,17 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_gl.h" -mat4_t glsl_projection; -mat4_t glsl_view; +mat4f_t glsl_projection; +mat4f_t glsl_view; void glsl_R_ViewChanged (float aspect) { double xmin, xmax, ymin, ymax; float fovx, fovy, neard, fard; - vec_t *proj = glsl_projection; + vec4f_t *proj = glsl_projection; fovx = r_refdef.fov_x; fovy = r_refdef.fov_y; @@ -79,25 +80,30 @@ glsl_R_ViewChanged (float aspect) xmax = neard * tan (fovx * M_PI / 360); // fov_2 / 2 xmin = -xmax; - proj[0] = (2 * neard) / (xmax - xmin); - proj[4] = 0; - proj[8] = (xmax + xmin) / (xmax - xmin); - proj[12] = 0; - - proj[1] = 0; - proj[5] = (2 * neard) / (ymax - ymin); - proj[9] = (ymax + ymin) / (ymax - ymin); - proj[13] = 0; - - proj[2] = 0; - proj[6] = 0; - proj[10] = (fard + neard) / (neard - fard); - proj[14] = (2 * fard * neard) / (neard - fard); - - proj[3] = 0; - proj[7] = 0; - proj[11] = -1; - proj[15] = 0; + proj[0] = (vec4f_t) { + (2 * neard) / (xmax - xmin), + 0, + 0, + 0 + }; + proj[1] = (vec4f_t) { + 0, + (2 * neard) / (ymax - ymin), + 0, + 0 + }; + proj[2] = (vec4f_t) { + (xmax + xmin) / (xmax - xmin), + (ymax + ymin) / (ymax - ymin), + (fard + neard) / (neard - fard), + -1 + }; + proj[3] = (vec4f_t) { + 0, + 0, + (2 * fard * neard) / (neard - fard), + 0 + }; } void @@ -107,24 +113,28 @@ glsl_R_SetupFrame (void) R_ClearEnts (); r_framecount++; - VectorCopy (r_refdef.vieworg, r_origin); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (r_refdef.viewposition, r_origin); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); + + R_SetFrustum (); - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); } static void R_SetupView (void) { float x, y, w, h; - mat4_t mat; - static mat4_t z_up = { - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1, + static mat4f_t z_up = { + { 0, 0, -1, 0}, + {-1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 0, 1}, }; + vec4f_t offset = { 0, 0, 0, 1 }; x = r_refdef.vrect.x; y = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)); @@ -132,17 +142,11 @@ R_SetupView (void) h = r_refdef.vrect.height; qfeglViewport (x, y, w, h); - Mat4Zero (mat); - VectorCopy (vpn, mat + 0); - VectorNegate (vright, mat + 4); // we want vleft - VectorCopy (vup, mat + 8); - mat[15] = 1; - Mat4Transpose (mat, mat);//AngleVectors gives the transpose of what we want - Mat4Mult (z_up, mat, glsl_view); - - Mat4Identity (mat); - VectorNegate (r_refdef.vieworg, mat + 12); - Mat4Mult (glsl_view, mat, glsl_view); + mat4fquat (glsl_view, qconjf (r_refdef.viewrotation)); + mmulf (glsl_view, z_up, glsl_view); + offset = -r_refdef.viewposition; + offset[3] = 1; + glsl_view[3] = mvmulf (glsl_view, offset); qfeglEnable (GL_CULL_FACE); qfeglEnable (GL_DEPTH_TEST); @@ -160,7 +164,7 @@ R_RenderEntities (void) do { \ begun = 0; \ for (ent = r_ent_queue; ent; ent = ent->next) { \ - if (ent->model->type != mod_##type_name) \ + if (ent->renderer.model->type != mod_##type_name) \ continue; \ if (!begun) { \ glsl_R_##Type##Begin (); \ @@ -185,7 +189,7 @@ R_DrawViewModel (void) if (vr_data.inhibit_viewmodel || !r_drawviewmodel->int_val || !r_drawentities->int_val - || !currententity->model) + || !currententity->renderer.model) return; // hack the depth range to prevent view model from poking into walls @@ -272,7 +276,7 @@ glsl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) d_lightstylevalue[i] = 264; // normal light value memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; // Force a vis update r_viewleaf = NULL; @@ -301,19 +305,21 @@ glsl_R_ClearState (void) void glsl_R_TimeRefresh_f (void) { +/* FIXME update for simd double start, stop, time; int i; - vid.end_rendering (); + glsl_ctx->end_rendering (); start = Sys_DoubleTime (); for (i = 0; i < 128; i++) { r_refdef.viewangles[1] = i * (360.0 / 128.0); glsl_R_RenderView (); - vid.end_rendering (); + glsl_ctx->end_rendering (); } stop = Sys_DoubleTime (); time = stop - start; Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); +*/ } diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index c4e214c50..de8c64602 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -42,6 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/mersenne.h" #include "QF/qargs.h" @@ -313,12 +314,12 @@ glsl_R_ReadPointFile_f (void) vec3_t org; QFile *f; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("%s.pts", mapname); + name = va (0, "%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); @@ -629,12 +630,14 @@ R_RocketTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -663,12 +666,14 @@ R_GrenadeTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -698,12 +703,14 @@ R_BloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 5.0 + qfrandom (10.0); @@ -738,12 +745,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (7.5); @@ -778,12 +787,14 @@ R_WizTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -819,12 +830,14 @@ R_FlameTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -860,12 +873,14 @@ R_VoorTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; int j; vec3_t subtract, old_origin, porg, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -898,7 +913,8 @@ R_GlowTrail_QF (const entity_t *ent, int glow_color) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, (maxlen - dist), subtract); @@ -977,12 +993,14 @@ R_RocketTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -1012,12 +1030,14 @@ R_GrenadeTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -1251,7 +1271,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) // l = r_maxparticles - numparticles; // } - VectorCopy (ent->origin, org); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { dir [1] = i * 8; @@ -1285,6 +1305,7 @@ R_EntityParticles_ID (const entity_t *ent) float angle, sp, sy, cp, cy; // cr, sr float beamlength = 16.0, dist = 64.0; vec3_t forward, porg; + vec3_t org; if (numparticles + j >= r_maxparticles) { return; @@ -1292,6 +1313,8 @@ R_EntityParticles_ID (const entity_t *ent) j = r_maxparticles - numparticles; } + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; for (k = 0; k < 3; k++) { @@ -1315,11 +1338,11 @@ R_EntityParticles_ID (const entity_t *ent) forward[1] = cp * sy; forward[2] = -sp; - porg[0] = ent->origin[0] + vertex_normals[i][0] * dist + + porg[0] = org[0] + vertex_normals[i][0] * dist + forward[0] * beamlength; - porg[1] = ent->origin[1] + vertex_normals[i][1] * dist + + porg[1] = org[1] + vertex_normals[i][1] * dist + forward[1] * beamlength; - porg[2] = ent->origin[2] + vertex_normals[i][2] * dist + + porg[2] = org[2] + vertex_normals[i][2] * dist + forward[2] * beamlength; particle_new (pt_explode, part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.01, 0x6f, 1.0, 0); @@ -1338,7 +1361,8 @@ R_RocketTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, (maxlen - dist), subtract); @@ -1370,7 +1394,8 @@ R_GrenadeTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1397,12 +1422,14 @@ R_BloodTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, subtract, vec, porg; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1428,12 +1455,14 @@ R_SlightBloodTrail_ID (const entity_t *ent) float dist = 6.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1459,12 +1488,14 @@ R_WizTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1496,12 +1527,14 @@ R_FlameTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1533,12 +1566,14 @@ R_VoorTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1568,10 +1603,10 @@ draw_qf_particles (void) particle_t *part; vec3_t up_scale, right_scale, up_right_scale, down_right_scale; partvert_t *VA; - mat4_t vp_mat; + mat4f_t vp_mat; quat_t fog; - Mat4Mult (glsl_projection, glsl_view, vp_mat); + mmulf (vp_mat, glsl_projection, glsl_view); qfeglDepthMask (GL_FALSE); qfeglUseProgram (quake_part.program); @@ -1579,11 +1614,12 @@ draw_qf_particles (void) qfeglEnableVertexAttribArray (quake_part.color.location); qfeglEnableVertexAttribArray (quake_part.st.location); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_part.fog.location, 1, fog); - qfeglUniformMatrix4fv (quake_part.mvp_matrix.location, 1, false, vp_mat); + qfeglUniformMatrix4fv (quake_part.mvp_matrix.location, 1, false, + &vp_mat[0][0]); qfeglUniform1i (quake_part.texture.location, 0); qfeglActiveTexture (GL_TEXTURE0 + 0); @@ -1593,7 +1629,7 @@ draw_qf_particles (void) // LordHavoc: particles should not affect zbuffer qfeglDepthMask (GL_FALSE); - minparticledist = DotProduct (r_refdef.vieworg, vpn) + + minparticledist = DotProduct (r_refdef.viewposition, vpn) + r_particles_nearclip->value; activeparticles = 0; @@ -1712,10 +1748,10 @@ draw_id_particles (void) float minparticledist; particle_t *part; partvert_t *VA; - mat4_t vp_mat; + mat4f_t vp_mat; quat_t fog; - Mat4Mult (glsl_projection, glsl_view, vp_mat); + mmulf (vp_mat, glsl_projection, glsl_view); // LordHavoc: particles should not affect zbuffer qfeglDepthMask (GL_FALSE); @@ -1723,9 +1759,10 @@ draw_id_particles (void) qfeglEnableVertexAttribArray (quake_point.vertex.location); qfeglEnableVertexAttribArray (quake_point.color.location); - qfeglUniformMatrix4fv (quake_point.mvp_matrix.location, 1, false, vp_mat); + qfeglUniformMatrix4fv (quake_point.mvp_matrix.location, 1, false, + &vp_mat[0][0]); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_point.fog.location, 1, fog); @@ -1734,7 +1771,7 @@ draw_id_particles (void) qfeglEnable (GL_TEXTURE_2D); qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); - minparticledist = DotProduct (r_refdef.vieworg, vpn) + + minparticledist = DotProduct (r_refdef.viewposition, vpn) + r_particles_nearclip->value; activeparticles = 0; @@ -1800,6 +1837,27 @@ glsl_R_DrawParticles (void) } } +static void +glsl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, + float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); +} + +static void +glsl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, float die, + int color, float alpha, float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, + color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -1984,24 +2042,3 @@ glsl_R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -glsl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); -} - -void -glsl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, - color, alpha, ramp); -} diff --git a/libs/video/renderer/glsl/glsl_screen.c b/libs/video/renderer/glsl/glsl_screen.c index b356a0108..982f3988c 100644 --- a/libs/video/renderer/glsl/glsl_screen.c +++ b/libs/video/renderer/glsl/glsl_screen.c @@ -60,6 +60,7 @@ #include "QF/GLSL/qf_vid.h" #include "r_internal.h" +#include "vid_gl.h" /* Unknown renamed to GLErr_Unknown to solve conflict with winioctl.h */ static unsigned int GLErr_InvalidEnum; @@ -154,8 +155,7 @@ SCR_TileClear (void) } void -glsl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, - SCR_Func *scr_funcs) +glsl_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { static int begun = 0; @@ -165,26 +165,17 @@ glsl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, if (begun) { begun = 0; - vid.end_rendering (); + glsl_ctx->end_rendering (); } - vr_data.realtime = realtime; - vr_data.scr_copyeverything = 1; //FIXME useless cvar? vid.numpages = 2 + gl_triplebuffer->int_val; - if (!scr_initialized) - return; - qfeglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); begun = 1; - - if (oldfov != scr_fov->value) { - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - if (vid.recalc_refdef) - SCR_CalcRefdef (); + //FIXME forces the status bar to redraw. needed because it does not fully + //update in sw modes but must in glsl mode + vr_data.scr_copyeverything = 1; scr_3dfunc (); @@ -210,7 +201,8 @@ glsl_SCR_CaptureBGR (void) tex_t *tex; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; @@ -227,7 +219,7 @@ glsl_SCR_CaptureBGR (void) return tex; } -tex_t * +__attribute__((const)) tex_t * glsl_SCR_ScreenShot (unsigned width, unsigned height) { return 0; @@ -239,8 +231,8 @@ glsl_SCR_ScreenShot_f (void) dstring_t *name = dstring_new (); // find a file name to save it to - if (!QFS_NextFilename (name, - va ("%s/qf", qfs_gamedir->dir.shots), ".png")) { + if (!QFS_NextFilename (name, va (0, "%s/qf", + qfs_gamedir->dir.shots), ".png")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PNG file\n"); } else { tex_t *tex; diff --git a/libs/video/renderer/glsl/glsl_shader.c b/libs/video/renderer/glsl/glsl_shader.c index d38bb2c29..c45494dc0 100644 --- a/libs/video/renderer/glsl/glsl_shader.c +++ b/libs/video/renderer/glsl/glsl_shader.c @@ -72,7 +72,7 @@ GLSL_RegisterEffect (const char *name, const char *src) segtext_t *text; if (!effect_tab) - effect_tab = Hash_NewTable (61, effect_get_key, 0, 0); + effect_tab = Hash_NewTable (61, effect_get_key, 0, 0, 0); if (Hash_Find (effect_tab, name)) { Sys_Printf ("WARNING: ignoring duplicate '%s' effect\n", name); diff --git a/libs/video/renderer/glsl/glsl_sprite.c b/libs/video/renderer/glsl/glsl_sprite.c index 83f116ee3..7eecea5dd 100644 --- a/libs/video/renderer/glsl/glsl_sprite.c +++ b/libs/video/renderer/glsl/glsl_sprite.c @@ -42,6 +42,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/draw.h" #include "QF/dstring.h" #include "QF/quakefs.h" @@ -131,7 +132,7 @@ static void R_GetSpriteFrames (entity_t *ent, msprite_t *sprite, mspriteframe_t **frame1, mspriteframe_t **frame2, float *blend) { - int framenum = currententity->frame; + int framenum = currententity->animation.frame; int pose; int i, numframes; float *intervals; @@ -143,7 +144,6 @@ R_GetSpriteFrames (entity_t *ent, msprite_t *sprite, mspriteframe_t **frame1, if (framenum >= sprite->numframes || framenum < 0) framenum = 0; - numframes = sprite->numframes; framedesc = &sprite->frames[framenum]; if (framedesc->type == SPR_SINGLE) { frame_interval = 0.1; @@ -154,7 +154,7 @@ R_GetSpriteFrames (entity_t *ent, msprite_t *sprite, mspriteframe_t **frame1, numframes = group->numframes; fullinterval = intervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; targettime = time - ((int) (time / fullinterval)) * fullinterval; for (i = 0; i < numframes - 1; i++) { @@ -171,50 +171,51 @@ R_GetSpriteFrames (entity_t *ent, msprite_t *sprite, mspriteframe_t **frame1, //group frames. *blend = R_EntityBlend (ent, pose, frame_interval); if (group) { - *frame1 = group->frames[ent->pose1]; - *frame2 = group->frames[ent->pose2]; + *frame1 = group->frames[ent->animation.pose1]; + *frame2 = group->frames[ent->animation.pose2]; } else { - *frame1 = sprite->frames[ent->pose1].frameptr; - *frame2 = sprite->frames[ent->pose2].frameptr; + *frame1 = sprite->frames[ent->animation.pose1].frameptr; + *frame2 = sprite->frames[ent->animation.pose2].frameptr; } } static void -make_quad (mspriteframe_t *frame, const vec3_t vpn, const vec3_t vright, - const vec3_t vup, float verts[6][3]) +make_quad (mspriteframe_t *frame, vec4f_t vpn, vec4f_t vright, + vec4f_t vup, float verts[6][3]) { - vec3_t left, up, right, down; - vec3_t ul, ur, ll, lr; + vec4f_t left, up, right, down; + vec4f_t ul, ur, ll, lr; + vec4f_t origin = Transform_GetWorldPosition (currententity->transform); // build the sprite poster in worldspace // first, rotate the sprite axes into world space - VectorScale (vright, frame->right, right); - VectorScale (vup, frame->up, up); - VectorScale (vright, frame->left, left); - VectorScale (vup, frame->down, down); + right = frame->right * vright; + up = frame->up * vup; + left = frame->left * vright; + down = frame->down * vup; // next, build the sprite corners from the axes - VectorAdd (up, left, ul); - VectorAdd (up, right, ur); - VectorAdd (down, left, ll); - VectorAdd (down, right, lr); + ul = up + left; + ur = up + right; + ll = down + left; + lr = down + right; // finally, translate the sprite corners, creating two triangles - VectorAdd (currententity->origin, ul, verts[0]); // first triangle - VectorAdd (currententity->origin, ur, verts[1]); - VectorAdd (currententity->origin, lr, verts[2]); - VectorAdd (currententity->origin, ul, verts[3]); // second triangle - VectorAdd (currententity->origin, lr, verts[4]); - VectorAdd (currententity->origin, ll, verts[5]); + VectorAdd (origin, ul, verts[0]); // first triangle + VectorAdd (origin, ur, verts[1]); + VectorAdd (origin, lr, verts[2]); + VectorAdd (origin, ul, verts[3]); // second triangle + VectorAdd (origin, lr, verts[4]); + VectorAdd (origin, ll, verts[5]); } void R_DrawSprite (void) { entity_t *ent = currententity; - msprite_t *sprite = (msprite_t *) ent->model->cache.data; + msprite_t *sprite = (msprite_t *) ent->renderer.model->cache.data; mspriteframe_t *frame1, *frame2; - float blend, sr, cr, dot, angle; + float blend, sr, cr, dot; vec3_t tvec; - vec3_t svpn, svright, svup; + vec4f_t svpn = {}, svright = {}, svup = {}, rot; static quat_t color = { 1, 1, 1, 1}; float vertsa[6][3], vertsb[6][3]; static float uvab[6][4] = { @@ -243,7 +244,7 @@ R_DrawSprite (void) VectorSet (0, 0, 1, svup); // CrossProduct (svup, -r_origin, svright) VectorSet (tvec[1], -tvec[0], 0, svright); - VectorNormalize (svright); + svright = normalf (svright); // CrossProduct (svright, svup, svpn); VectorSet (-svright[1], svright[0], 0, svpn); break; @@ -268,25 +269,26 @@ R_DrawSprite (void) VectorSet (0, 0, 1, svup); // CrossProduct (svup, -r_origin, svright) VectorSet (vpn[1], -vpn[0], 0, svright); - VectorNormalize (svright); + svright = normalf (svright); // CrossProduct (svright, svup, svpn); VectorSet (-svright[1], svright[0], 0, svpn); break; case SPR_ORIENTED: // generate the prite's axes according to the sprite's world // orientation - VectorCopy (currententity->transform + 0, svpn); - VectorNegate (currententity->transform + 4, svright); - VectorCopy (currententity->transform + 8, svup); + svup = Transform_Up (currententity->transform); + svright = Transform_Right (currententity->transform); + svpn = Transform_Forward (currententity->transform); break; case SPR_VP_PARALLEL_ORIENTED: // generate the sprite's axes parallel to the viewplane, but // rotated in that plane round the center according to the sprite // entity's roll angle. Thus svpn stays the same, but svright and // svup rotate - angle = currententity->angles[ROLL] * (M_PI / 180); - sr = sin (angle); - cr = cos (angle); + rot = Transform_GetLocalRotation (currententity->transform); + //FIXME assumes the entity is only rolled + sr = 2 * rot[0] * rot[3]; + cr = rot[3] * rot[3] - rot[0] * rot[0]; VectorCopy (vpn, svpn); VectorScale (vright, cr, svright); VectorMultAdd (svright, sr, vup, svright); @@ -325,7 +327,7 @@ R_DrawSprite (void) void R_SpriteBegin (void) { - mat4_t mat; + mat4f_t mat; quat_t fog; qfeglUseProgram (quake_sprite.program); @@ -336,7 +338,7 @@ R_SpriteBegin (void) qfeglDisableVertexAttribArray (quake_sprite.colorb.location); qfeglDisableVertexAttribArray (quake_sprite.blend.location); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_sprite.fog.location, 1, fog); @@ -353,8 +355,8 @@ R_SpriteBegin (void) qfeglEnable (GL_TEXTURE_2D); qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); - Mat4Mult (glsl_projection, glsl_view, mat); - qfeglUniformMatrix4fv (quake_sprite.matrix.location, 1, false, mat); + mmulf (mat, glsl_projection, glsl_view); + qfeglUniformMatrix4fv (quake_sprite.matrix.location, 1, false, &mat[0][0]); } void diff --git a/libs/video/renderer/glsl/glsl_textures.c b/libs/video/renderer/glsl/glsl_textures.c index 62b331662..1edd77b71 100644 --- a/libs/video/renderer/glsl/glsl_textures.c +++ b/libs/video/renderer/glsl/glsl_textures.c @@ -44,6 +44,7 @@ #include "QF/cmd.h" #include "QF/mathlib.h" #include "QF/model.h" +#include "QF/render.h" #include "QF/sys.h" #include "QF/vrect.h" @@ -51,15 +52,15 @@ #include "QF/GLSL/funcs.h" #include "QF/GLSL/qf_textures.h" +#include "r_scrap.h" + struct scrap_s { + rscrap_t rscrap; GLuint tnum; - int size; // in pixels, for now, always square, power of 2 int format; int bpp; byte *data; // local copy of the texture so updates can be batched vrect_t *batch; - vrect_t *free_rects; - vrect_t *rects; subpic_t *subpics; struct scrap_s *next; }; @@ -248,23 +249,22 @@ static void glsl_scraps_f (void) { scrap_t *scrap; - vrect_t *rect; int area; + int size; if (!scrap_list) { Sys_Printf ("No scraps\n"); return; } for (scrap = scrap_list; scrap; scrap = scrap->next) { - for (rect = scrap->free_rects, area = 0; rect; rect = rect->next) - area += rect->width * rect->height; + area = R_ScrapArea (&scrap->rscrap); + // always square + size = scrap->rscrap.width; Sys_Printf ("tnum=%u size=%d format=%04x bpp=%d free=%d%%\n", - scrap->tnum, scrap->size, scrap->format, scrap->bpp, - area * 100 / (scrap->size * scrap->size)); + scrap->tnum, size, scrap->format, scrap->bpp, + area * 100 / (size * size)); if (Cmd_Argc () > 1) { - for (rect = scrap->rects, area = 0; rect; rect = rect->next) - Sys_Printf ("%d %d %d %d\n", rect->x, rect->y, - rect->width, rect->height); + R_ScrapDump (&scrap->rscrap); } } } @@ -309,11 +309,9 @@ GLSL_CreateScrap (int size, int format, int linear) } scrap = malloc (sizeof (scrap_t)); qfeglGenTextures (1, &scrap->tnum); - scrap->size = size; + R_ScrapInit (&scrap->rscrap, size, size); scrap->format = format; scrap->bpp = bpp; - scrap->free_rects = VRect_New (0, 0, size, size); - scrap->rects = 0; scrap->subpics = 0; scrap->next = scrap_list; scrap_list = scrap; @@ -341,26 +339,13 @@ GLSL_CreateScrap (int size, int format, int linear) void GLSL_ScrapClear (scrap_t *scrap) { - vrect_t *t; subpic_t *sp; - - while (scrap->free_rects) { - t = scrap->free_rects; - scrap->free_rects = t->next; - VRect_Delete (t); - } - while (scrap->rects) { - t = scrap->rects; - scrap->rects = t->next; - VRect_Delete (t); - } while (scrap->subpics) { sp = scrap->subpics; scrap->subpics = (subpic_t *) sp->next; free (sp); } - - scrap->free_rects = VRect_New (0, 0, scrap->size, scrap->size); + R_ScrapClear (&scrap->rscrap); } void @@ -375,7 +360,7 @@ GLSL_DestroyScrap (scrap_t *scrap) } } GLSL_ScrapClear (scrap); - VRect_Delete (scrap->free_rects); + R_ScrapDelete (&scrap->rscrap); GLSL_ReleaseTexture (scrap->tnum); free (scrap->data); free (scrap); @@ -390,57 +375,22 @@ GLSL_ScrapTexture (scrap_t *scrap) subpic_t * GLSL_ScrapSubpic (scrap_t *scrap, int width, int height) { - int i, w, h; - vrect_t **t, **best; - vrect_t *old, *frags, *rect; + vrect_t *rect; subpic_t *subpic; - for (i = 0; i < 16; i++) - if (width <= (1 << i)) - break; - w = 1 << i; - for (i = 0; i < 16; i++) - if (height <= (1 << i)) - break; - h = 1 << i; - - best = 0; - for (t = &scrap->free_rects; *t; t = &(*t)->next) { - if ((*t)->width < w || (*t)->height < h) - continue; // won't fit - if (!best) { - best = t; - continue; - } - if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height) - best = t; + rect = R_ScrapAlloc (&scrap->rscrap, width, height); + if (!rect) { + return 0; } - if (!best) - return 0; // couldn't find a spot - old = *best; - *best = old->next; - rect = VRect_New (old->x, old->y, w, h); - frags = VRect_Difference (old, rect); - VRect_Delete (old); - if (frags) { - // old was bigger than the requested size - for (old = frags; old->next; old = old->next) - ; - old->next = scrap->free_rects; - scrap->free_rects = frags; - } - rect->next = scrap->rects; - scrap->rects = rect; subpic = malloc (sizeof (subpic_t)); *((subpic_t **) &subpic->next) = scrap->subpics; scrap->subpics = subpic; *((scrap_t **) &subpic->scrap) = scrap; *((vrect_t **) &subpic->rect) = rect; - *((int *) &subpic->tnum) = scrap->tnum; *((int *) &subpic->width) = width; *((int *) &subpic->height) = height; - *((float *) &subpic->size) = 1.0 / scrap->size; + *((float *) &subpic->size) = 1.0 / scrap->rscrap.width; return subpic; } @@ -449,8 +399,6 @@ GLSL_SubpicDelete (subpic_t *subpic) { scrap_t *scrap = (scrap_t *) subpic->scrap; vrect_t *rect = (vrect_t *) subpic->rect; - vrect_t *old, *merge; - vrect_t **t; subpic_t **sp; for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next) @@ -460,29 +408,7 @@ GLSL_SubpicDelete (subpic_t *subpic) Sys_Error ("GLSL_ScrapDelSubpic: broken subpic"); *sp = (subpic_t *) subpic->next; free (subpic); - for (t = &scrap->rects; *t; t = &(*t)->next) - if (*t == rect) - break; - if (*t != rect) - Sys_Error ("GLSL_ScrapDelSubpic: broken subpic"); - *t = rect->next; - - do { - merge = 0; - for (t = &scrap->free_rects; *t; t = &(*t)->next) { - merge = VRect_Merge (*t, rect); - if (merge) { - old = *t; - *t = (*t)->next; - VRect_Delete (old); - VRect_Delete (rect); - rect = merge; - break; - } - } - } while (merge); - rect->next = scrap->free_rects; - scrap->free_rects = rect; + R_ScrapFree (&scrap->rscrap, rect); } void @@ -503,7 +429,7 @@ GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch) scrap->batch = VRect_New (rect->x, rect->y, rect->width, rect->height); } - step = scrap->size * scrap->bpp; + step = scrap->rscrap.width * scrap->bpp; sbytes = subpic->width * scrap->bpp; dest = scrap->data + rect->y * step + rect->x * scrap->bpp; for (i = 0; i < subpic->height; i++, dest += step, data += sbytes) @@ -519,7 +445,8 @@ GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch) void GLSL_ScrapFlush (scrap_t *scrap) { - vrect_t *rect = scrap->batch;; + vrect_t *rect = scrap->batch; + int size = scrap->rscrap.width; if (!rect) return; @@ -527,9 +454,9 @@ GLSL_ScrapFlush (scrap_t *scrap) //should update to not update the entire horizontal block qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum); qfeglTexSubImage2D (GL_TEXTURE_2D, 0, 0, rect->y, - scrap->size, rect->height, scrap->format, + size, rect->height, scrap->format, GL_UNSIGNED_BYTE, - scrap->data + rect->y * scrap->size * scrap->bpp); + scrap->data + rect->y * size * scrap->bpp); VRect_Delete (rect); scrap->batch = 0; } diff --git a/libs/video/renderer/glsl/namehack.h b/libs/video/renderer/glsl/namehack.h index 7edaed944..a6f62e701 100644 --- a/libs/video/renderer/glsl/namehack.h +++ b/libs/video/renderer/glsl/namehack.h @@ -52,7 +52,6 @@ #define R_InitParticles glsl_R_InitParticles #define R_InitSky glsl_R_InitSky #define R_InitSprites glsl_R_InitSprites -#define R_InitSurfaceChains glsl_R_InitSurfaceChains #define R_LineGraph glsl_R_LineGraph #define R_LoadSky_f glsl_R_LoadSky_f #define R_LoadSkys glsl_R_LoadSkys @@ -72,7 +71,7 @@ #define SCR_CaptureBGR glsl_SCR_CaptureBGR #define SCR_ScreenShot glsl_SCR_ScreenShot #define SCR_ScreenShot_f glsl_SCR_ScreenShot_f -#define SCR_UpdateScreen glsl_SCR_UpdateScreen +#define R_RenderFrame glsl_R_RenderFrame #define c_alias_polys glsl_c_alias_polys #define c_brush_polys glsl_c_brush_polys #define r_easter_eggs_f glsl_r_easter_eggs_f @@ -128,7 +127,7 @@ #undef SCR_CaptureBGR #undef SCR_ScreenShot #undef SCR_ScreenShot_f -#undef SCR_UpdateScreen +#undef R_RenderFrame #undef c_alias_polys #undef c_brush_polys #undef r_easter_eggs_f diff --git a/libs/video/renderer/glsl/qfglsl.c b/libs/video/renderer/glsl/qfglsl.c index af3a2f839..0e48e9354 100644 --- a/libs/video/renderer/glsl/qfglsl.c +++ b/libs/video/renderer/glsl/qfglsl.c @@ -60,6 +60,7 @@ #include "QF/GLSL/funcs.h" #include "r_internal.h" +#include "vid_gl.h" // First we need to get all the function pointers declared. #define QFGL_WANT(ret, name, args) \ @@ -74,9 +75,9 @@ qboolean EGLF_FindFunctions (void) { #define QFGL_WANT(ret, name, args) \ - qfe##name = vid.get_proc_address (#name, false); + qfe##name = glsl_ctx->get_proc_address (#name, false); #define QFGL_NEED(ret, name, args) \ - qfe##name = vid.get_proc_address (#name, true); + qfe##name = glsl_ctx->get_proc_address (#name, true); #include "QF/GLSL/qf_funcs_list.h" #undef QFGL_NEED #undef QFGL_WANT diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index e346b31af..2a912fcb0 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -464,8 +464,8 @@ main (void) m += bonemats[int (vbones.z)] * vweights.z; m += bonemats[int (vbones.w)] * vweights.w; #if 0 - q0 = m[0].yzwx; //swizzle for conversion betwen QF and GL - qe = m[1].yzwx; //swizzle for conversion betwen QF and GL + q0 = m[0]; + qe = m[1]; sh = m[2].xyz; sc = m[3].xyz; diff --git a/libs/video/renderer/glsl/vid_common_glsl.c b/libs/video/renderer/glsl/vid_common_glsl.c index d684fd4ff..7fabdd6d2 100644 --- a/libs/video/renderer/glsl/vid_common_glsl.c +++ b/libs/video/renderer/glsl/vid_common_glsl.c @@ -57,7 +57,7 @@ #include "r_internal.h" static const char quakeforge_effect[] = -#include "quakeforge.slc" +#include "libs/video/renderer/glsl/quakeforge.slc" ; int glsl_palette; @@ -268,7 +268,7 @@ type_name (GLenum type) case GL_FIXED: return "fixed"; } - return va("%x", type); + return va (0, "%x", type); } static void diff --git a/libs/video/renderer/r_alias.c b/libs/video/renderer/r_alias.c index aa1541ca2..b956f0500 100644 --- a/libs/video/renderer/r_alias.c +++ b/libs/video/renderer/r_alias.c @@ -63,7 +63,7 @@ R_AliasGetSkindesc (int skinnum, aliashdr_t *ahdr) numskins = paliasskingroup->numskins; fullskininterval = pskinintervals[numskins - 1]; - skintime = vr_data.realtime + currententity->syncbase; + skintime = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -118,7 +118,7 @@ alias_get_frame (int framenum, aliashdr_t *hdr, float *frame_interval) numframes = group->numframes; fullinterval = intervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadAliasGroup, we guaranteed all interval values // are positive, so we don't have to worry about division by 0 @@ -148,6 +148,6 @@ R_AliasGetLerpedFrames (entity_t *ent, aliashdr_t *hdr) maliasframedesc_t *frame; float interval; - frame = alias_get_frame (ent->frame, hdr, &interval); + frame = alias_get_frame (ent->animation.frame, hdr, &interval); return R_EntityBlend (ent, frame->firstpose, interval); } diff --git a/libs/video/renderer/r_bsp.c b/libs/video/renderer/r_bsp.c index a6fdc961d..03af6696b 100644 --- a/libs/video/renderer/r_bsp.c +++ b/libs/video/renderer/r_bsp.c @@ -54,6 +54,7 @@ R_MarkLeaves (void) mleaf_t *leaf; mnode_t *node; msurface_t **mark; + mod_brush_t *brush = &r_worldentity.renderer.model->brush; if (r_oldviewleaf == r_viewleaf && !r_novis->int_val) return; @@ -67,13 +68,13 @@ R_MarkLeaves (void) r_oldviewleaf = 0; // so vis will be recalcualted when novis gets // turned off vis = solid; - memset (solid, 0xff, (r_worldentity.model->numleafs + 7) >> 3); + memset (solid, 0xff, (brush->numleafs + 7) >> 3); } else - vis = Mod_LeafPVS (r_viewleaf, r_worldentity.model); + vis = Mod_LeafPVS (r_viewleaf, r_worldentity.renderer.model); - for (i = 0; (int) i < r_worldentity.model->numleafs; i++) { + for (i = 0; (int) i < brush->numleafs; i++) { if (vis[i >> 3] & (1 << (i & 7))) { - leaf = &r_worldentity.model->leafs[i + 1]; + leaf = &brush->leafs[i + 1]; if ((c = leaf->nummarksurfaces)) { mark = leaf->firstmarksurface; do { @@ -81,13 +82,14 @@ R_MarkLeaves (void) mark++; } while (--c); } - node = (mnode_t *) leaf; - do { + leaf->visframe = r_visframecount; + node = brush->leaf_parents[leaf - brush->leafs]; + while (node) { if (node->visframe == r_visframecount) break; node->visframe = r_visframecount; - node = node->parent; - } while (node); + node = brush->node_parents[node - brush->nodes]; + } } } } @@ -103,7 +105,7 @@ R_TextureAnimation (msurface_t *surf) texture_t *base = surf->texinfo->texture; int count, relative; - if (currententity->frame) { + if (currententity->animation.frame) { if (base->alternate_anims) base = base->alternate_anims; } diff --git a/libs/video/renderer/r_cvar.c b/libs/video/renderer/r_cvar.c index d9f3e14d2..934e5bdbb 100644 --- a/libs/video/renderer/r_cvar.c +++ b/libs/video/renderer/r_cvar.c @@ -138,7 +138,7 @@ r_farclip_f (cvar_t *var) Cvar_SetValue (r_particles_nearclip, bound (r_nearclip->value, r_particles_nearclip->value, r_farclip->value)); - vid.recalc_refdef = true; + r_data->vid->recalc_refdef = true; } static void @@ -149,7 +149,13 @@ r_nearclip_f (cvar_t *var) Cvar_SetValue (r_particles_nearclip, bound (r_nearclip->value, r_particles_nearclip->value, r_farclip->value)); - vid.recalc_refdef = true; + r_data->vid->recalc_refdef = true; +} + +static void +scr_fov_f (cvar_t *var) +{ + SCR_SetFOV (var->value); } static void @@ -176,13 +182,19 @@ viewsize_f (cvar_t *var) if (var->int_val < 30 || var->int_val > 120) { Cvar_SetValue (var, bound (30, var->int_val, 120)); } else { - vid.recalc_refdef = true; + r_data->vid->recalc_refdef = true; r_viewsize = bound (0, var->int_val, 100); - if (vr_data.viewsize_callback) - vr_data.viewsize_callback (var); + if (r_data->viewsize_callback) + r_data->viewsize_callback (var); } } +static void +r_dlight_max_f (cvar_t *var) +{ + r_funcs->R_MaxDlightsCheck (var); +} + void R_Init_Cvars (void) { @@ -218,7 +230,7 @@ R_Init_Cvars (void) NULL, "Set to 1 for high quality dynamic " "lighting."); r_dlight_max = Cvar_Get ("r_dlight_max", "32", CVAR_ARCHIVE, - R_MaxDlightsCheck, "Number of dynamic lights."); + r_dlight_max_f, "Number of dynamic lights."); r_drawentities = Cvar_Get ("r_drawentities", "1", CVAR_NONE, NULL, "Toggles drawing of entities (almost " "everything but the world)"); @@ -291,9 +303,9 @@ R_Init_Cvars (void) r_zgraph = Cvar_Get ("r_zgraph", "0", CVAR_NONE, NULL, "Toggle the graph that reports the changes of " "z-axis position"); - scr_fov = Cvar_Get ("fov", "90", CVAR_NONE, NULL, "Your field of view in " - "degrees. Smaller than 90 zooms in. Don't touch in " - "fisheye mode, use ffov instead."); + scr_fov = Cvar_Get ("fov", "90", CVAR_NONE, scr_fov_f, + "Your field of view in degrees. Smaller than 90 zooms " + "in. Don't touch in fisheye mode, use ffov instead."); scr_fisheye = Cvar_Get ("fisheye", "0", CVAR_NONE, scr_fisheye_f, "Toggles fisheye mode."); scr_fviews = Cvar_Get ("fviews", "6", CVAR_NONE, NULL, "The number of " @@ -309,6 +321,6 @@ R_Init_Cvars (void) scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE, viewsize_f, "Set the screen size 30 minimum, 120 maximum"); - vr_data.graphheight = r_graphheight; - vr_data.scr_viewsize = scr_viewsize; + r_data->graphheight = r_graphheight; + r_data->scr_viewsize = scr_viewsize; } diff --git a/libs/video/renderer/r_dyn_textures.c b/libs/video/renderer/r_dyn_textures.c index 167027fad..67b0862c6 100644 --- a/libs/video/renderer/r_dyn_textures.c +++ b/libs/video/renderer/r_dyn_textures.c @@ -50,7 +50,8 @@ R_DotParticleTexture (void) int x, y, dx2, dy, d; tex_t *tex; - tex = malloc (field_offset (tex_t, data[sizeof (*data)])); + tex = malloc (sizeof (tex_t) + sizeof (*data)); + tex->data = (byte *) (tex + 1); tex->width = 32; tex->height = 32; tex->format = tex_la; @@ -79,7 +80,8 @@ R_SparkParticleTexture (void) int x, y, dx2, dy, d; tex_t *tex; - tex = malloc (field_offset (tex_t, data[sizeof (*data)])); + tex = malloc (sizeof (tex_t) + sizeof (*data)); + tex->data = (byte*) (tex + 1); tex->width = 32; tex->height = 32; tex->format = tex_la; @@ -113,7 +115,8 @@ R_SmokeParticleTexture (void) int x, y, c; tex_t *tex; - tex = malloc (field_offset (tex_t, data[sizeof (*data)])); + tex = malloc (sizeof (tex_t) + sizeof (*data)); + tex->data = (byte *) (tex + 1); tex->width = 32; tex->height = 32; tex->format = tex_la; diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 74592fa30..eb559e9cd 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -30,14 +30,13 @@ #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" +#include "qfalloca.h" #include "r_internal.h" -static mnode_t *r_pefragtopnode; -static vec3_t r_emins, r_emaxs; - typedef struct s_efrag_list { struct s_efrag_list *next; efrag_t efrags[MAX_EFRAGS]; @@ -48,10 +47,6 @@ static t_efrag_list *efrag_list; /* ENTITY FRAGMENT FUNCTIONS */ -static efrag_t **lastlink; -static entity_t *r_addent; - - static inline void init_efrag_list (t_efrag_list *efl) { @@ -89,7 +84,7 @@ R_ClearEfrags (void) if (!efrag_list) efrag_list = calloc (1, sizeof (t_efrag_list)); - r_free_efrags = efrag_list->efrags;; + r_free_efrags = efrag_list->efrags; for (efl = efrag_list; efl; efl = efl->next) { init_efrag_list (efl); if (efl->next) @@ -107,7 +102,7 @@ R_RemoveEfrags (entity_t *ent) { efrag_t *ef, *old, *walk, **prev; - ef = ent->efrag; + ef = ent->visibility.efrag; while (ef) { prev = &ef->leaf->efrags; @@ -130,35 +125,42 @@ R_RemoveEfrags (entity_t *ent) r_free_efrags = old; } - ent->efrag = 0; + ent->visibility.efrag = 0; } -#define NODE_STACK_SIZE 1024 -static mnode_t *node_stack[NODE_STACK_SIZE]; -static mnode_t **node_ptr = node_stack + NODE_STACK_SIZE; - static void -R_SplitEntityOnNode (mnode_t *node) +R_SplitEntityOnNode (mod_brush_t *brush, entity_t *ent, + vec3_t emins, vec3_t emaxs) { efrag_t *ef; plane_t *splitplane; mleaf_t *leaf; int sides; + efrag_t **lastlink; + mnode_t **node_stack; + mnode_t **node_ptr; + mnode_t *node = brush->nodes; - *--node_ptr = 0; + node_stack = alloca ((brush->depth + 2) * sizeof (mnode_t *)); + node_ptr = node_stack; + + lastlink = &ent->visibility.efrag; + + *node_ptr++ = 0; while (node) { // add an efrag if the node is a leaf if (__builtin_expect (node->contents < 0, 0)) { - if (!r_pefragtopnode) - r_pefragtopnode = node; + if (!ent->visibility.topnode) { + ent->visibility.topnode = node; + } leaf = (mleaf_t *) node; ef = new_efrag (); // ensures ef->entnext is 0 // add the link to the chain of links on the entity - ef->entity = r_addent; + ef->entity = ent; *lastlink = ef; lastlink = &ef->entnext; @@ -167,80 +169,77 @@ R_SplitEntityOnNode (mnode_t *node) ef->leafnext = leaf->efrags; leaf->efrags = ef; - node = *node_ptr++; + node = *--node_ptr; } else { // NODE_MIXED splitplane = node->plane; - sides = BOX_ON_PLANE_SIDE (r_emins, r_emaxs, splitplane); + sides = BOX_ON_PLANE_SIDE (emins, emaxs, splitplane); if (sides == 3) { // split on this plane // if this is the first splitter of this bmodel, remember it - if (!r_pefragtopnode) - r_pefragtopnode = node; + if (!ent->visibility.topnode) { + ent->visibility.topnode = node; + } } // recurse down the contacted sides if (sides & 1 && node->children[0]->contents != CONTENTS_SOLID) { if (sides & 2 && node->children[1]->contents != CONTENTS_SOLID) - *--node_ptr = node->children[1]; + *node_ptr++ = node->children[1]; node = node->children[0]; } else { if (sides & 2 && node->children[1]->contents != CONTENTS_SOLID) node = node->children[1]; else - node = *node_ptr++; + node = *--node_ptr; } } } } void -R_AddEfrags (entity_t *ent) +R_AddEfrags (mod_brush_t *brush, entity_t *ent) { model_t *entmodel; + vec3_t emins, emaxs; - if (!ent->model) + if (!ent->renderer.model || !r_worldentity.renderer.model) return; if (ent == &r_worldentity) return; // never add the world - r_addent = ent; + entmodel = ent->renderer.model; - lastlink = &ent->efrag; - r_pefragtopnode = 0; + vec4f_t org = Transform_GetWorldPosition (ent->transform); + VectorAdd (org, entmodel->mins, emins); + VectorAdd (org, entmodel->maxs, emaxs); - entmodel = ent->model; - - VectorAdd (ent->origin, entmodel->mins, r_emins); - VectorAdd (ent->origin, entmodel->maxs, r_emaxs); - - R_SplitEntityOnNode (r_worldentity.model->nodes); - - ent->topnode = r_pefragtopnode; + ent->visibility.topnode = 0; + R_SplitEntityOnNode (brush, ent, emins, emaxs); } void -R_StoreEfrags (const efrag_t *pefrag) +R_StoreEfrags (const efrag_t *efrag) { - entity_t *pent; + entity_t *ent; model_t *model; - while (pefrag) { - pent = pefrag->entity; - model = pent->model; + while (efrag) { + ent = efrag->entity; + model = ent->renderer.model; switch (model->type) { case mod_alias: case mod_brush: case mod_sprite: case mod_iqm: - if (pent->visframe != r_framecount) { - R_EnqueueEntity (pent); + if (ent->visibility.visframe != r_framecount) { + R_EnqueueEntity (ent); // mark that we've recorded this entity for this frame - pent->visframe = r_framecount; + ent->visibility.visframe = r_framecount; } - pefrag = pefrag->leafnext; + efrag = efrag->leafnext; break; default: diff --git a/libs/video/renderer/r_ent.c b/libs/video/renderer/r_ent.c index e72d10399..5a20bcb1f 100644 --- a/libs/video/renderer/r_ent.c +++ b/libs/video/renderer/r_ent.c @@ -38,6 +38,7 @@ #include #include +#include "QF/entity.h" #include "QF/model.h" #include "QF/msg.h" #include "QF/render.h" @@ -70,6 +71,7 @@ R_AllocEntity (void) if ((ent = free_entities)) { free_entities = ent->next; ent->next = 0; + ent->transform = 0; return ent; } @@ -78,9 +80,12 @@ R_AllocEntity (void) *entpool_tail = pool; entpool_tail = &pool->next; - for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) + for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) { ent->next = ent + 1; + ent->transform = 0; + } ent->next = 0; + ent->transform = 0; free_entities = pool->entities; return R_AllocEntity (); @@ -94,9 +99,18 @@ R_FreeAllEntities (void) int i; for (pool = entity_pools; pool; pool = pool->next) { - for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) + for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) { ent->next = ent + 1; + if (ent->transform) { + Transform_Delete (ent->transform); + ent->transform = 0; + } + } ent->next = pool->next ? pool->next->entities : 0; + if (ent->transform) { + Transform_Delete (ent->transform); + ent->transform = 0; + } } free_entities = entity_pools ? entity_pools->entities : 0; } @@ -121,27 +135,27 @@ R_EntityBlend (entity_t *ent, int pose, float interval) { float blend; - if (ent->pose_model != ent->model) { - ent->pose_model = ent->model; - ent->pose1 = pose; - ent->pose2 = pose; + if (ent->animation.nolerp) { + ent->animation.nolerp = 0; + ent->animation.pose1 = pose; + ent->animation.pose2 = pose; return 0.0; } - ent->frame_interval = interval; - if (ent->pose2 != pose) { - ent->frame_start_time = vr_data.realtime; - if (ent->pose2 == -1) { - ent->pose1 = pose; + ent->animation.frame_interval = interval; + if (ent->animation.pose2 != pose) { + ent->animation.frame_start_time = vr_data.realtime; + if (ent->animation.pose2 == -1) { + ent->animation.pose1 = pose; } else { - ent->pose1 = ent->pose2; + ent->animation.pose1 = ent->animation.pose2; } - ent->pose2 = pose; + ent->animation.pose2 = pose; blend = 0.0; } else if (vr_data.paused) { blend = 1.0; } else { - blend = (vr_data.realtime - ent->frame_start_time) - / ent->frame_interval; + blend = (vr_data.realtime - ent->animation.frame_start_time) + / ent->animation.frame_interval; blend = min (blend, 1.0); } return blend; diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index d4a7e91cd..733004a21 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -46,6 +46,8 @@ #include "QF/plugin/general.h" #include "r_internal.h" +#include "r_scrap.h" +#include "vid_internal.h" cvar_t *vidrend_plugin; plugin_t *vidrendmodule = NULL; @@ -60,10 +62,19 @@ vid_render_funcs_t *r_funcs; #define U __attribute__ ((used)) static U void (*const r_progs_init)(struct progs_s *) = R_Progs_Init; +static U void (*const r_scrapdelete)(rscrap_t *) = R_ScrapDelete; #undef U +static void +R_shutdown (void *data) +{ + if (vidrendmodule->functions->general->p_Shutdown) { + vidrendmodule->functions->general->p_Shutdown (); + } +} + VISIBLE void -R_LoadModule (void (*load_gl)(void), void (*set_palette) (const byte *palette)) +R_LoadModule (vid_internal_t *vid_internal) { PI_RegisterPlugins (vidrend_plugin_list); vidrend_plugin = Cvar_Get ("vid_render", VID_RENDER_DEFAULT, CVAR_ROM, 0, @@ -76,10 +87,10 @@ R_LoadModule (void (*load_gl)(void), void (*set_palette) (const byte *palette)) r_funcs = vidrendmodule->functions->vid_render; mod_funcs = r_funcs->model_funcs; r_data = vidrendmodule->data->vid_render; - r_data->vid->load_gl = load_gl; - r_data->vid->set_palette = set_palette; + r_data->vid->vid_internal = vid_internal; vidrendmodule->functions->general->p_Init (); + Sys_RegisterShutdown (R_shutdown, 0); } VISIBLE void diff --git a/libs/video/renderer/r_iqm.c b/libs/video/renderer/r_iqm.c index 4fa961228..71dc47b3a 100644 --- a/libs/video/renderer/r_iqm.c +++ b/libs/video/renderer/r_iqm.c @@ -49,7 +49,7 @@ float R_IQMGetLerpedFrames (entity_t *ent, iqm_t *iqm) { - int frame = ent->frame; + int frame = ent->animation.frame; float time, fullinterval; iqmanim *anim; @@ -62,7 +62,7 @@ R_IQMGetLerpedFrames (entity_t *ent, iqm_t *iqm) } anim = &iqm->anims[frame]; fullinterval = anim->num_frames / anim->framerate; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; time -= ((int) (time / fullinterval)) * fullinterval; frame = (int) (time * anim->framerate) + anim->first_frame; return R_EntityBlend (ent, frame, 1.0 / anim->framerate); @@ -99,7 +99,7 @@ R_IQMBlendFrames (const iqm_t *iqm, int frame1, int frame2, float blend, } else { #if 0 for (i = 0; i < iqm->num_joints; i++) { - QuatSet (1, 0, 0, 0, frame[i].rt.q0.q); + QuatSet (0, 0, 0, 1, frame[i].rt.q0.q); QuatSet (0, 0, 0, 0, frame[i].rt.qe.q); QuatSet (0, 0, 0, 0, frame[i].shear); QuatSet (1, 1, 1, 0, frame[i].scale); diff --git a/libs/video/renderer/r_light.c b/libs/video/renderer/r_light.c index bd242e7bc..96899621e 100644 --- a/libs/video/renderer/r_light.c +++ b/libs/video/renderer/r_light.c @@ -203,8 +203,8 @@ mark_surfaces (msurface_t *surf, const vec3_t lightorigin, dlight_t *light, // LordHavoc: heavily modified, to eliminate unnecessary texture uploads, // and support bmodel lighting better void -R_RecursiveMarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum, - mnode_t *node) +R_RecursiveMarkLights (mod_brush_t *brush, const vec3_t lightorigin, + dlight_t *light, int lightnum, mnode_t *node) { unsigned i; float ndist, maxdist; @@ -240,14 +240,14 @@ loc0: } // mark the polygons - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (i = 0; i < node->numsurfaces; i++, surf++) { mark_surfaces (surf, lightorigin, light, lightnum); } if (node->children[0]->contents >= 0) { if (node->children[1]->contents >= 0) - R_RecursiveMarkLights (lightorigin, light, lightnum, + R_RecursiveMarkLights (brush, lightorigin, light, lightnum, node->children[1]); node = node->children[0]; goto loc0; @@ -262,11 +262,12 @@ void R_MarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum, model_t *model) { + mod_brush_t *brush = &model->brush; mleaf_t *pvsleaf = Mod_PointInLeaf (lightorigin, model); if (!pvsleaf->compressed_vis) { - mnode_t *node = model->nodes + model->hulls[0].firstclipnode; - R_RecursiveMarkLights (lightorigin, light, lightnum, node); + mnode_t *node = brush->nodes + brush->hulls[0].firstclipnode; + R_RecursiveMarkLights (brush, lightorigin, light, lightnum, node); } else { float radius = light->radius; vec3_t mins, maxs; @@ -280,16 +281,16 @@ R_MarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum, maxs[0] = lightorigin[0] + radius; maxs[1] = lightorigin[1] + radius; maxs[2] = lightorigin[2] + radius; - while (leafnum < model->numleafs) { + while (leafnum < brush->numleafs) { int b; if (!(vis_bits = *in++)) { leafnum += (*in++) * 8; continue; } - for (b = 1; b < 256 && leafnum < model->numleafs; + for (b = 1; b < 256 && leafnum < brush->numleafs; b <<= 1, leafnum++) { int m; - mleaf_t *leaf = &model->leafs[leafnum + 1]; + mleaf_t *leaf = &brush->leafs[leafnum + 1]; if (!(vis_bits & b)) continue; if (leaf->visframe != r_visframecount) @@ -327,7 +328,7 @@ R_PushDlights (const vec3_t entorigin) if (l->die < vr_data.realtime || !l->radius) continue; VectorSubtract (l->origin, entorigin, lightorigin); - R_MarkLights (lightorigin, l, i, r_worldentity.model); + R_MarkLights (lightorigin, l, i, r_worldentity.renderer.model); } } @@ -400,7 +401,8 @@ calc_lighting_3 (msurface_t *surf, int ds, int dt) } static int -RecursiveLightPoint (mnode_t *node, const vec3_t start, const vec3_t end) +RecursiveLightPoint (mod_brush_t *brush, mnode_t *node, const vec3_t start, + const vec3_t end) { unsigned i; int r, s, t, ds, dt, side; @@ -430,7 +432,7 @@ loop: mid[2] = start[2] + (end[2] - start[2]) * frac; // go down front side - r = RecursiveLightPoint (node->children[side], start, mid); + r = RecursiveLightPoint (brush, node->children[side], start, mid); if (r >= 0) return r; // hit something @@ -441,7 +443,7 @@ loop: VectorCopy (mid, lightspot); lightplane = plane; - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (i = 0; i < node->numsurfaces; i++, surf++) { if (surf->flags & SURF_DRAWTILED) continue; // no lightmaps @@ -472,16 +474,16 @@ loop: } // go down back side - return RecursiveLightPoint (node->children[!side], mid, end); + return RecursiveLightPoint (brush, node->children[!side], mid, end); } int -R_LightPoint (const vec3_t p) +R_LightPoint (mod_brush_t *brush, const vec3_t p) { vec3_t end; int r; - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { // allow dlights to have some effect, so don't go /quite/ fullbright ambientcolor[2] = ambientcolor[1] = ambientcolor[0] = 200; return 200; @@ -491,7 +493,7 @@ R_LightPoint (const vec3_t p) end[1] = p[1]; end[2] = p[2] - 2048; - r = RecursiveLightPoint (r_worldentity.model->nodes, p, end); + r = RecursiveLightPoint (brush, brush->nodes, p, end); if (r == -1) r = 0; diff --git a/libs/video/renderer/r_main.c b/libs/video/renderer/r_main.c index 0d38123d3..bc1590dd0 100644 --- a/libs/video/renderer/r_main.c +++ b/libs/video/renderer/r_main.c @@ -70,8 +70,6 @@ vec3_t r_entorigin; // the currently rendering entity in world entity_t *currententity; entity_t r_worldentity; -qboolean r_cache_thrash; // set if surface cache is thrashing - // view origin vec3_t vup, base_vup; vec3_t vpn, base_vpn; diff --git a/libs/video/renderer/r_progs.c b/libs/video/renderer/r_progs.c index 66ae9072f..c09569c56 100644 --- a/libs/video/renderer/r_progs.c +++ b/libs/video/renderer/r_progs.c @@ -68,7 +68,7 @@ typedef struct { static qpic_res_t * qpic_new (draw_resources_t *res) { - PR_RESNEW (qpic_res_t, res->qpic_map); + return PR_RESNEW (res->qpic_map); } static void @@ -86,25 +86,25 @@ static void qpic_free (draw_resources_t *res, qpic_res_t *qp) { bi_draw_free_qpic (qp); - PR_RESFREE (qpic_res_t, res->qpic_map, qp); + PR_RESFREE (res->qpic_map, qp); } static void qpic_reset (draw_resources_t *res) { - PR_RESRESET (qpic_res_t, res->qpic_map); + PR_RESRESET (res->qpic_map); } static inline qpic_res_t * qpic_get (draw_resources_t *res, int index) { - PR_RESGET (res->qpic_map, index); + return PR_RESGET (res->qpic_map, index); } -static inline int +static inline int __attribute__((pure)) qpic_index (draw_resources_t *res, qpic_res_t *qp) { - PR_RESINDEX (res->qpic_map, qp); + return PR_RESINDEX (res->qpic_map, qp); } static qpic_res_t * @@ -345,7 +345,8 @@ void R_Progs_Init (progs_t *pr) { draw_resources_t *res = calloc (1, sizeof (draw_resources_t)); - res->pic_hash = Hash_NewTable (61, bi_draw_get_key, 0, 0); + res->pic_hash = Hash_NewTable (61, bi_draw_get_key, 0, 0, + pr->hashlink_freelist); PR_Resources_Register (pr, "Draw", res, bi_draw_clear); PR_RegisterBuiltins (pr, builtins); diff --git a/libs/video/renderer/r_scrap.c b/libs/video/renderer/r_scrap.c new file mode 100644 index 000000000..86a4ca0a6 --- /dev/null +++ b/libs/video/renderer/r_scrap.c @@ -0,0 +1,183 @@ +/* + r_scrap.c + + Renderer agnostic scrap management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/12 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/sys.h" +#include "QF/vrect.h" + +#include "compat.h" +#include "r_scrap.h" + +static unsigned +pow2rup (unsigned x) +{ + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + return x; +} + +VISIBLE void +R_ScrapInit (rscrap_t *scrap, int width, int height) +{ + width = pow2rup (width); + height = pow2rup (height); + scrap->width = width; + scrap->height = height; + scrap->rects = 0; + scrap->free_rects = VRect_New (0, 0, width, height); +} + +VISIBLE void +R_ScrapDelete (rscrap_t *scrap) +{ + R_ScrapClear (scrap); + VRect_Delete (scrap->free_rects); +} + +VISIBLE vrect_t * +R_ScrapAlloc (rscrap_t *scrap, int width, int height) +{ + int w, h; + vrect_t **t, **best; + vrect_t *old, *frags, *rect; + + w = pow2rup (width); + h = pow2rup (height); + + best = 0; + for (t = &scrap->free_rects; *t; t = &(*t)->next) { + if ((*t)->width < w || (*t)->height < h) + continue; // won't fit + if (!best) { + best = t; + continue; + } + if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height) + best = t; + } + if (!best) + return 0; // couldn't find a spot + old = *best; + *best = old->next; + rect = VRect_New (old->x, old->y, w, h); + frags = VRect_Difference (old, rect); + VRect_Delete (old); + if (frags) { + // old was bigger than the requested size + for (old = frags; old->next; old = old->next) + ; + old->next = scrap->free_rects; + scrap->free_rects = frags; + } + rect->next = scrap->rects; + scrap->rects = rect; + + return rect; +} + +VISIBLE void +R_ScrapFree (rscrap_t *scrap, vrect_t *rect) +{ + vrect_t *old, *merge; + vrect_t **t; + + for (t = &scrap->rects; *t; t = &(*t)->next) + if (*t == rect) + break; + if (*t != rect) + Sys_Error ("R_ScrapFree: broken rect"); + *t = rect->next; + + do { + merge = 0; + for (t = &scrap->free_rects; *t; t = &(*t)->next) { + merge = VRect_Merge (*t, rect); + if (merge) { + old = *t; + *t = (*t)->next; + VRect_Delete (old); + VRect_Delete (rect); + rect = merge; + break; + } + } + } while (merge); + rect->next = scrap->free_rects; + scrap->free_rects = rect; +} + +VISIBLE void +R_ScrapClear (rscrap_t *scrap) +{ + vrect_t *t; + + while (scrap->free_rects) { + t = scrap->free_rects; + scrap->free_rects = t->next; + VRect_Delete (t); + } + while (scrap->rects) { + t = scrap->rects; + scrap->rects = t->next; + VRect_Delete (t); + } + + scrap->free_rects = VRect_New (0, 0, scrap->width, scrap->height); +} + +VISIBLE size_t +R_ScrapArea (rscrap_t *scrap) +{ + vrect_t *rect; + size_t area; + + for (rect = scrap->free_rects, area = 0; rect; rect = rect->next) { + area += rect->width * rect->height; + } + return area; +} + +VISIBLE void +R_ScrapDump (rscrap_t *scrap) +{ + vrect_t *rect; + + for (rect = scrap->rects; rect; rect = rect->next) { + Sys_Printf ("%d %d %d %d\n", rect->x, rect->y, + rect->width, rect->height); + } +} diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index a6d129674..d092d2154 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -94,9 +94,10 @@ int scr_copytop; byte *draw_chars; // 8*8 graphic characters FIXME location -float oldfov; int oldsbar; +qboolean r_cache_thrash; // set if surface cache is thrashing + qboolean scr_initialized; // ready to draw qpic_t *scr_ram; @@ -104,22 +105,22 @@ qpic_t *scr_turtle; int clearconsole; -viddef_t vid; // global video state - vrect_t *pconupdate; vrect_t scr_vrect; qboolean scr_skipupdate; +static float oldfov = -1; + void -R_SetVrect (vrect_t *vrectin, vrect_t *vrect, int lineadj) +R_SetVrect (const vrect_t *vrectin, vrect_t *vrect, int lineadj) { float size; int h; // intermission is always full screen size = min (r_viewsize, 100); - if (vr_data.force_fullscreen) { + if (r_data->force_fullscreen) { size = 100.0; lineadj = 0; } @@ -150,29 +151,57 @@ SCR_CalcRefdef (void) refdef_t *refdef = r_data->refdef; // force a background redraw - vr_data.scr_fullupdate = 0; - vid.recalc_refdef = 0; + r_data->scr_fullupdate = 0; + r_data->vid->recalc_refdef = 0; // bound field of view Cvar_SetValue (scr_fov, bound (1, scr_fov->value, 170)); vrect.x = 0; vrect.y = 0; - vrect.width = vid.width; - vrect.height = vid.height; + vrect.width = r_data->vid->width; + vrect.height = r_data->vid->height; - R_SetVrect (&vrect, &scr_vrect, vr_data.lineadj); + R_SetVrect (&vrect, &scr_vrect, r_data->lineadj); refdef->vrect = scr_vrect; - refdef->fov_x = scr_fov->value; - refdef->fov_y = - CalcFov (refdef->fov_x, refdef->vrect.width, refdef->vrect.height); // notify the refresh of the change - vr_funcs->R_ViewChanged (vid.aspect); + r_funcs->R_ViewChanged (r_data->vid->aspect); } -float +/* + SCR_UpdateScreen + + This is called every frame, and can also be called explicitly to flush + text to the screen. + + WARNING: be very careful calling this from elsewhere, because the refresh + needs almost the entire 256k of stack space! +*/ +void +SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +{ + if (scr_skipupdate || !scr_initialized) { + return; + } + + r_data->realtime = realtime; + scr_copytop = r_data->scr_copyeverything = 0; + + if (oldfov != scr_fov->value) { + oldfov = scr_fov->value; + r_data->vid->recalc_refdef = true; + } + + if (r_data->vid->recalc_refdef) { + SCR_CalcRefdef (); + } + + r_funcs->R_RenderFrame (scr_3dfunc, scr_funcs); +} + +static float __attribute__((pure)) CalcFov (float fov_x, float width, float height) { float a, x; @@ -189,10 +218,19 @@ CalcFov (float fov_x, float width, float height) return a; } +void +SCR_SetFOV (float fov) +{ + refdef_t *refdef = r_data->refdef; + refdef->fov_x = fov; + refdef->fov_y = CalcFov (fov, refdef->vrect.width, refdef->vrect.height); + r_data->vid->recalc_refdef = 1; +} + static void ScreenShot_f (void) { - vr_funcs->SCR_ScreenShot_f (); + r_funcs->SCR_ScreenShot_f (); } /* @@ -205,7 +243,7 @@ SCR_SizeUp_f (void) { if (scr_viewsize->int_val < 120) { Cvar_SetValue (scr_viewsize, scr_viewsize->int_val + 10); - vid.recalc_refdef = 1; + r_data->vid->recalc_refdef = 1; } } @@ -218,7 +256,7 @@ static void SCR_SizeDown_f (void) { Cvar_SetValue (scr_viewsize, scr_viewsize->int_val - 10); - vid.recalc_refdef = 1; + r_data->vid->recalc_refdef = 1; } void @@ -230,7 +268,7 @@ SCR_DrawRam (void) if (!r_cache_thrash) return; - vr_funcs->Draw_Pic (scr_vrect.x + 32, scr_vrect.y, scr_ram); + r_funcs->Draw_Pic (scr_vrect.x + 32, scr_vrect.y, scr_ram); } void @@ -241,7 +279,7 @@ SCR_DrawTurtle (void) if (!scr_showturtle->int_val) return; - if (vr_data.frametime < 0.1) { + if (r_data->frametime < 0.1) { count = 0; return; } @@ -250,7 +288,7 @@ SCR_DrawTurtle (void) if (count < 3) return; - vr_funcs->Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); + r_funcs->Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); } void @@ -261,12 +299,12 @@ SCR_DrawPause (void) if (!scr_showpause->int_val) // turn off for screenshots return; - if (!vr_data.paused) + if (!r_data->paused) return; - pic = vr_funcs->Draw_CachePic ("gfx/pause.lmp", true); - vr_funcs->Draw_Pic ((vid.conwidth - pic->width) / 2, - (vid.conheight - 48 - pic->height) / 2, pic); + pic = r_funcs->Draw_CachePic ("gfx/pause.lmp", true); + r_funcs->Draw_Pic ((r_data->vid->conwidth - pic->width) / 2, + (r_data->vid->conheight - 48 - pic->height) / 2, pic); } void @@ -294,9 +332,9 @@ MipColor (int r, int g, int b) for (i = 0; i < 256; i++) { int j; j = i * 3; - r1 = vid.palette[j] - r; - g1 = vid.palette[j + 1] - g; - b1 = vid.palette[j + 2] - b; + r1 = r_data->vid->palette[j] - r; + g1 = r_data->vid->palette[j + 1] - g; + b1 = r_data->vid->palette[j + 2] - b; dist = r1 * r1 + g1 * g1 + b1 * b1; if (dist < bestdist) { bestdist = dist; @@ -362,9 +400,8 @@ SCR_Init (void) Cmd_AddCommand ("sizeup", SCR_SizeUp_f, "Increases the screen size"); Cmd_AddCommand ("sizedown", SCR_SizeDown_f, "Decreases the screen size"); - scr_ram = vr_funcs->Draw_PicFromWad ("ram"); - scr_turtle = vr_funcs->Draw_PicFromWad ("turtle"); + scr_ram = r_funcs->Draw_PicFromWad ("ram"); + scr_turtle = r_funcs->Draw_PicFromWad ("turtle"); - vid = *vr_data.vid; // cache scr_initialized = true; } diff --git a/libs/video/renderer/sw/Makefile.am b/libs/video/renderer/sw/Makefile.am deleted file mode 100644 index 62f64e689..000000000 --- a/libs/video/renderer/sw/Makefile.am +++ /dev/null @@ -1,33 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -CCASFLAGS+= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -asm = @swrend_libs@ - -noinst_LTLIBRARIES= libsw.la $(asm) -EXTRA_LTLIBRARIES=libswrend_asm.la - -asm_src= \ - d_copy.S d_draw.S d_parta.S d_polysa.S d_scana.S d_spr8.S d_varsa.S \ - fpua.S surf8.S sw_raclipa.S sw_raliasa.S sw_rdrawa.S sw_redgea.S \ - sw_rvarsa.S transform.S - -sw_src= \ - d_edge.c d_fill.c d_init.c d_modech.c d_part.c d_polyse.c d_scan.c \ - d_sky.c d_sprite.c d_surf.c d_vars.c d_zpoint.c draw.c fpu.c nonintel.c \ - screen.c sw_graph.c sw_raclip.c sw_ralias.c sw_rbsp.c sw_rdraw.c \ - sw_redge.c sw_riqm.c sw_rmain.c sw_rmisc.c sw_rpart.c sw_rsky.c \ - sw_rsprite.c sw_rsurf.c \ - vid_common_sw.c - -libswrend_asm_la_LDFLAGS= @STATIC@ -libswrend_asm_la_SOURCES= $(asm_src) - -libsw_la_LDFLAGS= @STATIC@ -libsw_la_SOURCES= $(sw_src) -libsw_la_LIBADD= $(asm) -libsw_la_DEPENDENCIES= $(asm) - -EXTRA_DIST= $(sw_src) $(asm_src) diff --git a/libs/video/renderer/sw/d_edge.c b/libs/video/renderer/sw/d_edge.c index f510e2063..d1e8a4e29 100644 --- a/libs/video/renderer/sw/d_edge.c +++ b/libs/video/renderer/sw/d_edge.c @@ -29,6 +29,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "d_local.h" @@ -207,7 +208,8 @@ D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); TransformVector (local_modelorg, transformed_modelorg); @@ -240,7 +242,8 @@ D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); TransformVector (local_modelorg, transformed_modelorg); diff --git a/libs/video/renderer/sw/d_init.c b/libs/video/renderer/sw/d_init.c index 67e48e71b..00fb21a89 100644 --- a/libs/video/renderer/sw/d_init.c +++ b/libs/video/renderer/sw/d_init.c @@ -56,9 +56,9 @@ D_Init (void) r_worldpolysbacktofront = false; r_recursiveaffinetriangles = true; - vr_data.vid->surf_cache_size = D_SurfaceCacheForRes; - vr_data.vid->flush_caches = D_FlushCaches; - vr_data.vid->init_caches = D_InitCaches; + vr_data.vid->vid_internal->surf_cache_size = D_SurfaceCacheForRes; + vr_data.vid->vid_internal->flush_caches = D_FlushCaches; + vr_data.vid->vid_internal->init_caches = D_InitCaches; VID_InitBuffers (); } diff --git a/libs/video/renderer/sw/d_sky.c b/libs/video/renderer/sw/d_sky.c index 6bc7872aa..853a3e0e0 100644 --- a/libs/video/renderer/sw/d_sky.c +++ b/libs/video/renderer/sw/d_sky.c @@ -72,6 +72,8 @@ D_DrawSkyScans (espan_t *pspan) sstep = 0; // keep compiler happy tstep = 0; // ditto + snext = 0; // ditto + tnext = 0; // ditto do { pdest = (unsigned char *) ((byte *) d_viewbuffer + diff --git a/libs/video/renderer/sw/draw.c b/libs/video/renderer/sw/draw.c index 0224aee81..f6198e86c 100644 --- a/libs/video/renderer/sw/draw.c +++ b/libs/video/renderer/sw/draw.c @@ -826,5 +826,5 @@ Draw_BlendScreen (quat_t color) newpal[2] = vid.gammatable[b]; newpal += 3; } - vid.set_palette (pal); + vid.vid_internal->set_palette (pal); } diff --git a/libs/video/renderer/sw/screen.c b/libs/video/renderer/sw/screen.c index ed4c933f1..5aa2ed53e 100644 --- a/libs/video/renderer/sw/screen.c +++ b/libs/video/renderer/sw/screen.c @@ -51,6 +51,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_sw.h" /* SCREEN SHOTS */ @@ -63,7 +64,8 @@ SCR_CaptureBGR (void) byte *dst; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; @@ -101,7 +103,8 @@ SCR_ScreenShot (unsigned width, unsigned height) fracw = (float) vid.width / (float) w; frach = (float) vid.height / (float) h; - tex = malloc (field_offset (tex_t, data[w * h])); + tex = malloc (sizeof (tex_t) + w * h); + tex->data = (byte *) (tex + 1); if (!tex) return 0; @@ -156,7 +159,7 @@ SCR_ScreenShot_f (void) // find a file name to save it to if (!QFS_NextFilename (pcxname, - va ("%s/qf", qfs_gamedir->dir.shots), ".pcx")) { + va (0, "%s/qf", qfs_gamedir->dir.shots), ".pcx")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX"); } else { // enable direct drawing of console to back buffer @@ -177,39 +180,11 @@ SCR_ScreenShot_f (void) dstring_delete (pcxname); } -/* - SCR_UpdateScreen - - This is called every frame, and can also be called explicitly to flush - text to the screen. - - WARNING: be very careful calling this from elsewhere, because the refresh - needs almost the entire 256k of stack space! -*/ void -SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { vrect_t vrect; - if (scr_skipupdate) - return; - - vr_data.realtime = realtime; - - scr_copytop = 0; - vr_data.scr_copyeverything = 0; - - if (!scr_initialized) - return; // not initialized yet - - if (oldfov != scr_fov->value) { // determine size of refresh window - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - - if (vid.recalc_refdef) - SCR_CalcRefdef (); - // do 3D refresh drawing, and then update the screen D_EnableBackBufferAccess (); // of all overlay stuff if drawing // directly @@ -263,5 +238,5 @@ SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) vrect.height = scr_vrect.height; vrect.next = 0; } - VID_Update (&vrect); + sw_ctx->update (&vrect); } diff --git a/libs/video/renderer/sw/sw_ralias.c b/libs/video/renderer/sw/sw_ralias.c index a275873d3..1fcd1ce12 100644 --- a/libs/video/renderer/sw/sw_ralias.c +++ b/libs/video/renderer/sw/sw_ralias.c @@ -30,6 +30,7 @@ #include +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -94,8 +95,8 @@ R_AliasCheckBBox (void) int minz; // expand, rotate, and translate points into worldspace - currententity->trivial_accept = 0; - pmodel = currententity->model; + currententity->visibility.trivial_accept = 0; + pmodel = currententity->renderer.model; if (!(pahdr = pmodel->aliashdr)) pahdr = Cache_Get (&pmodel->cache); pmdl = (mdl_t *) ((byte *) pahdr + pahdr->model); @@ -103,10 +104,10 @@ R_AliasCheckBBox (void) R_AliasSetUpTransform (0); // construct the base bounding box for this frame - frame = currententity->frame; + frame = currententity->animation.frame; // TODO: don't repeat this check when drawing? if ((frame >= pmdl->numframes) || (frame < 0)) { - Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->name); + Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->path); frame = 0; } @@ -218,11 +219,11 @@ R_AliasCheckBBox (void) return false; // trivial reject off one side } - currententity->trivial_accept = !anyclip & !zclipped; + currententity->visibility.trivial_accept = !anyclip & !zclipped; - if (currententity->trivial_accept) { + if (currententity->visibility.trivial_accept) { if (minz > (r_aliastransition + (pmdl->size * r_resfudge))) { - currententity->trivial_accept |= 2; + currententity->visibility.trivial_accept |= 2; } } @@ -355,10 +356,12 @@ R_AliasSetUpTransform (int trivial_accept) float rotationmatrix[3][4], t2matrix[3][4]; static float tmatrix[3][4]; static float viewmatrix[3][4]; + mat4f_t mat; - VectorCopy (currententity->transform + 0, alias_forward); - VectorNegate (currententity->transform + 4, alias_right); - VectorCopy (currententity->transform + 8, alias_up); + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], alias_forward); + VectorNegate (mat[1], alias_right); + VectorCopy (mat[2], alias_up); tmatrix[0][0] = pmdl->scale[0]; tmatrix[1][1] = pmdl->scale[1]; @@ -542,7 +545,7 @@ R_AliasSetupSkin (void) { int skinnum; - skinnum = currententity->skinnum; + skinnum = currententity->renderer.skinnum; if ((skinnum >= pmdl->numskins) || (skinnum < 0)) { Sys_MaskPrintf (SYS_DEV, "R_AliasSetupSkin: no such skin # %d\n", skinnum); @@ -559,16 +562,16 @@ R_AliasSetupSkin (void) r_affinetridesc.skinheight = pmdl->skinheight; acolormap = vid.colormap8; - if (currententity->skin) { + if (currententity->renderer.skin) { tex_t *base; - base = currententity->skin->texels; + base = currententity->renderer.skin->texels; if (base) { r_affinetridesc.pskin = base->data; r_affinetridesc.skinwidth = base->width; r_affinetridesc.skinheight = base->height; } - acolormap = currententity->skin->colormap; + acolormap = currententity->renderer.skin->colormap; } } @@ -611,7 +614,7 @@ R_AliasSetupFrame (void) { maliasframedesc_t *frame; - frame = R_AliasGetFramedesc (currententity->frame, paliashdr); + frame = R_AliasGetFramedesc (currententity->animation.frame, paliashdr); r_apverts = (trivertx_t *) ((byte *) paliashdr + frame->frame); } @@ -624,8 +627,8 @@ R_AliasDrawModel (alight_t *plighting) r_amodels_drawn++; - if (!(paliashdr = currententity->model->aliashdr)) - paliashdr = Cache_Get (¤tentity->model->cache); + if (!(paliashdr = currententity->renderer.model->aliashdr)) + paliashdr = Cache_Get (¤tentity->renderer.model->cache); pmdl = (mdl_t *) ((byte *) paliashdr + paliashdr->model); size = (CACHE_SIZE - 1) @@ -641,12 +644,12 @@ R_AliasDrawModel (alight_t *plighting) pauxverts = (auxvert_t *) &pfinalverts[pmdl->numverts + 1]; R_AliasSetupSkin (); - R_AliasSetUpTransform (currententity->trivial_accept); + R_AliasSetUpTransform (currententity->visibility.trivial_accept); R_AliasSetupLighting (plighting); R_AliasSetupFrame (); - r_affinetridesc.drawtype = (currententity->trivial_accept == 3) && - r_recursiveaffinetriangles; + r_affinetridesc.drawtype = ((currententity->visibility.trivial_accept == 3) + && r_recursiveaffinetriangles); if (!acolormap) acolormap = vid.colormap8; @@ -664,11 +667,14 @@ R_AliasDrawModel (alight_t *plighting) else ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (currententity->trivial_accept && pmdl->ident != HEADER_MDL16) + if (currententity->visibility.trivial_accept + && pmdl->ident != HEADER_MDL16) { R_AliasPrepareUnclippedPoints (); - else + } else { R_AliasPreparePoints (); + } - if (!currententity->model->aliashdr) - Cache_Release (¤tentity->model->cache); + if (!currententity->renderer.model->aliashdr) { + Cache_Release (¤tentity->renderer.model->cache); + } } diff --git a/libs/video/renderer/sw/sw_rbsp.c b/libs/video/renderer/sw/sw_rbsp.c index 17fcbf5bb..e9b3fde8a 100644 --- a/libs/video/renderer/sw/sw_rbsp.c +++ b/libs/video/renderer/sw/sw_rbsp.c @@ -33,6 +33,7 @@ #include "qfalloca.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -77,9 +78,11 @@ R_EntityRotate (vec3_t vec) void R_RotateBmodel (void) { - VectorCopy (currententity->transform + 0, entity_rotation[0]); - VectorCopy (currententity->transform + 4, entity_rotation[1]); - VectorCopy (currententity->transform + 8, entity_rotation[2]); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], entity_rotation[0]); + VectorCopy (mat[1], entity_rotation[1]); + VectorCopy (mat[2], entity_rotation[2]); // rotate modelorg and the transformation matrix R_EntityRotate (modelorg); @@ -237,7 +240,7 @@ R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) void -R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) +R_DrawSolidClippedSubmodelPolygons (model_t *model) { int i, j, lindex; vec_t dot; @@ -247,12 +250,13 @@ R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) mvertex_t bverts[MAX_BMODEL_VERTS]; bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; medge_t *pedge, *pedges; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; - pedges = pmodel->edges; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; + pedges = brush->edges; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -278,7 +282,7 @@ R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) numbedges += psurf->numedges; for (j = 0; j < psurf->numedges; j++) { - lindex = pmodel->surfedges[psurf->firstedge + j]; + lindex = brush->surfedges[psurf->firstedge + j]; if (lindex > 0) { pedge = &pedges[lindex]; @@ -296,7 +300,8 @@ R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) pbedge[j - 1].pnext = NULL; // mark end of edges - R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf); + R_RecursiveClipBPoly (pbedge, + currententity->visibility.topnode, psurf); } else { Sys_Error ("no edges in bmodel"); } @@ -306,18 +311,19 @@ R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) void -R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) +R_DrawSubmodelPolygons (model_t *model, int clipflags) { int i; vec_t dot; msurface_t *psurf; int numsurfaces; plane_t *pplane; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -328,7 +334,7 @@ R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - r_currentkey = ((mleaf_t *) currententity->topnode)->key; + r_currentkey = ((mleaf_t *) currententity->visibility.topnode)->key; // FIXME: use bounding-box-based frustum clipping info? R_RenderFace (psurf, clipflags); @@ -358,7 +364,7 @@ get_side (mnode_t *node) } static void -visit_node (mnode_t *node, int side, int clipflags) +visit_node (mod_brush_t *brush, mnode_t *node, int side, int clipflags) { int c; msurface_t *surf; @@ -367,7 +373,7 @@ visit_node (mnode_t *node, int side, int clipflags) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -444,7 +450,7 @@ test_node (mnode_t *node, int *clipflags) } static void -R_VisitWorldNodes (model_t *model, int clipflags) +R_VisitWorldNodes (mod_brush_t *brush, int clipflags) { typedef struct { mnode_t *node; @@ -456,9 +462,9 @@ R_VisitWorldNodes (model_t *model, int clipflags) mnode_t *front; int side, cf; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; cf = clipflags; @@ -478,7 +484,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -488,7 +494,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) node = node_ptr->node; side = node_ptr->side; clipflags = node_ptr->clipflags; - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; continue; } @@ -502,17 +508,17 @@ void R_RenderWorld (void) { int i; - model_t *clmodel; btofpoly_t btofpolys[MAX_BTOFPOLYS]; + mod_brush_t *brush; pbtofpolys = btofpolys; currententity = &r_worldentity; VectorCopy (r_origin, modelorg); - clmodel = currententity->model; - r_pcurrentvertbase = clmodel->vertexes; + brush = ¤tentity->renderer.model->brush; + r_pcurrentvertbase = brush->vertexes; - R_VisitWorldNodes (clmodel, 15); + R_VisitWorldNodes (brush, 15); // if the driver wants the polygons back to front, play the visible ones // back in that order diff --git a/libs/video/renderer/sw/sw_rdraw.c b/libs/video/renderer/sw/sw_rdraw.c index c5c943fd5..67c298187 100644 --- a/libs/video/renderer/sw/sw_rdraw.c +++ b/libs/video/renderer/sw/sw_rdraw.c @@ -353,6 +353,7 @@ R_RenderFace (msurface_t *fa, int clipflags) vec3_t p_normal; medge_t *pedges, tedge; clipplane_t *pclip; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // skip out if no more surfs if ((surface_p) >= surf_max) { @@ -382,11 +383,11 @@ R_RenderFace (msurface_t *fa, int clipflags) r_nearzi = 0; r_nearzionly = false; makeleftedge = makerightedge = false; - pedges = currententity->model->edges; + pedges = brush->edges; r_lastvertvalid = false; for (i = 0; i < fa->numedges; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { r_pedge = &pedges[lindex]; @@ -623,6 +624,7 @@ R_RenderPoly (msurface_t *fa, int clipflags) polyvert_t pverts[100]; // FIXME: do real number, safely int vertpage, newverts, newpage, lastvert; qboolean visible; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // FIXME: clean this up and make it faster // FIXME: guard against running out of vertices @@ -641,12 +643,12 @@ R_RenderPoly (msurface_t *fa, int clipflags) // reconstruct the polygon // FIXME: these should be precalculated and loaded off disk - pedges = currententity->model->edges; + pedges = brush->edges; lnumverts = fa->numedges; vertpage = 0; for (i = 0; i < lnumverts; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { r_pedge = &pedges[lindex]; @@ -777,15 +779,16 @@ R_RenderPoly (msurface_t *fa, int clipflags) void -R_ZDrawSubmodelPolys (model_t *pmodel) +R_ZDrawSubmodelPolys (model_t *model) { int i, numsurfaces; msurface_t *psurf; float dot; plane_t *pplane; + mod_brush_t *brush = &model->brush; - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on diff --git a/libs/video/renderer/sw/sw_riqm.c b/libs/video/renderer/sw/sw_riqm.c index 285342b3f..8674e3ca6 100644 --- a/libs/video/renderer/sw/sw_riqm.c +++ b/libs/video/renderer/sw/sw_riqm.c @@ -40,6 +40,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -231,9 +232,12 @@ R_IQMSetupLighting (entity_t *ent, alight_t *plighting) r_shadelight *= VID_GRADES; // rotate the lighting vector into the model's frame of reference - r_plightvec[0] = DotProduct (plighting->plightvec, ent->transform + 0); - r_plightvec[1] = DotProduct (plighting->plightvec, ent->transform + 4); - r_plightvec[2] = DotProduct (plighting->plightvec, ent->transform + 8); + mat4f_t mat; + Transform_GetWorldMatrix (ent->transform, mat); + //FIXME vectorize + r_plightvec[0] = DotProduct (plighting->plightvec, mat[0]); + r_plightvec[1] = DotProduct (plighting->plightvec, mat[1]); + r_plightvec[2] = DotProduct (plighting->plightvec, mat[2]); } static void @@ -244,9 +248,11 @@ R_IQMSetUpTransform (int trivial_accept) static float viewmatrix[3][4]; vec3_t forward, left, up; - VectorCopy (currententity->transform + 0, forward); - VectorCopy (currententity->transform + 4, left); - VectorCopy (currententity->transform + 8, up); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], forward); + VectorCopy (mat[1], left); + VectorCopy (mat[2], up); // TODO: can do this with simple matrix rearrangement @@ -293,7 +299,7 @@ void R_IQMDrawModel (alight_t *plighting) { entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; swiqm_t *sw = (swiqm_t *) iqm->extra_data; int size; @@ -304,18 +310,19 @@ R_IQMDrawModel (alight_t *plighting) + sizeof (finalvert_t) * (iqm->num_verts + 1) + sizeof (auxvert_t) * iqm->num_verts; blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendPalette (iqm, ent->pose1, ent->pose2, blend, size, - sw->blend_palette, sw->palette_size); + frame = R_IQMBlendPalette (iqm, ent->animation.pose1, ent->animation.pose2, + blend, size, sw->blend_palette, + sw->palette_size); pfinalverts = (finalvert_t *) &frame[sw->palette_size]; pfinalverts = (finalvert_t *) (((intptr_t) &pfinalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); pauxverts = (auxvert_t *) &pfinalverts[iqm->num_verts + 1]; - R_IQMSetUpTransform (ent->trivial_accept); + R_IQMSetUpTransform (ent->visibility.trivial_accept); R_IQMSetupLighting (ent, plighting); - r_affinetridesc.drawtype = (ent->trivial_accept == 3) && + r_affinetridesc.drawtype = (ent->visibility.trivial_accept == 3) && r_recursiveaffinetriangles; //if (!acolormap) @@ -326,7 +333,7 @@ R_IQMDrawModel (alight_t *plighting) else ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (ent->trivial_accept) + if (ent->visibility.trivial_accept) R_IQMPrepareUnclippedPoints (iqm, sw, frame); else R_IQMPreparePoints (iqm, sw, frame); diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 2a8fb3c67..6d2358e5f 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -42,7 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" -#include "QF/locs.h" +#include "QF/entity.h" #include "QF/mathlib.h" #include "QF/render.h" #include "QF/screen.h" @@ -164,19 +164,20 @@ void R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) { int i; + mod_brush_t *brush = &worldmodel->brush; memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; R_FreeAllEntities (); // clear out efrags in case the level hasn't been reloaded // FIXME: is this one short? - for (i = 0; i < r_worldentity.model->numleafs; i++) - r_worldentity.model->leafs[i].efrags = NULL; + for (i = 0; i < brush->numleafs; i++) + brush->leafs[i].efrags = NULL; - if (worldmodel->skytexture) - R_InitSky (worldmodel->skytexture); + if (brush->skytexture) + R_InitSky (brush->skytexture); // Force a vis update r_viewleaf = NULL; @@ -361,27 +362,29 @@ R_DrawEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); + switch (currententity->renderer.model->type) { case mod_sprite: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); R_DrawSprite (); break; case mod_alias: case mod_iqm: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); - minlight = max (currententity->model->min_light, currententity->min_light); + minlight = max (currententity->renderer.model->min_light, + currententity->renderer.min_light); // see if the bounding box lets us trivially reject, also // sets trivial accept status - currententity->trivial_accept = 0; //FIXME - if (currententity->model->type == mod_iqm//FIXME + currententity->visibility.trivial_accept = 0; //FIXME + if (currententity->renderer.model->type == mod_iqm//FIXME || R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, + r_entorigin), minlight * 128); lighting.ambientlight = j; lighting.shadelight = j; @@ -390,7 +393,7 @@ R_DrawEntitiesOnList (void) for (lnum = 0; lnum < r_maxdlights; lnum++) { if (r_dlights[lnum].die >= vr_data.realtime) { - VectorSubtract (currententity->origin, + VectorSubtract (r_entorigin, r_dlights[lnum].origin, dist); add = r_dlights[lnum].radius - VectorLength (dist); @@ -405,7 +408,7 @@ R_DrawEntitiesOnList (void) if (lighting.ambientlight + lighting.shadelight > 192) lighting.shadelight = 192 - lighting.ambientlight; - if (currententity->model->type == mod_iqm) + if (currententity->renderer.model->type == mod_iqm) R_IQMDrawModel (&lighting); else R_AliasDrawModel (&lighting); @@ -437,18 +440,21 @@ R_DrawViewModel (void) return; currententity = vr_data.view_model; - if (!currententity->model) + if (!currententity->renderer.model) return; - VectorCopy (currententity->origin, r_entorigin); + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); VectorCopy (vup, viewlightvec); VectorNegate (viewlightvec, viewlightvec); - minlight = max (currententity->min_light, currententity->model->min_light); + minlight = max (currententity->renderer.min_light, + currententity->renderer.model->min_light); - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, + r_entorigin), minlight * 128); r_viewlighting.ambientlight = j; r_viewlighting.shadelight = j; @@ -463,7 +469,7 @@ R_DrawViewModel (void) if (dl->die < vr_data.realtime) continue; - VectorSubtract (currententity->origin, dl->origin, dist); + VectorSubtract (r_entorigin, dl->origin, dist); add = dl->radius - VectorLength (dist); if (add > 0) r_viewlighting.ambientlight += add; @@ -486,13 +492,14 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) int i, *pindex, clipflags; vec3_t acceptpt, rejectpt; double d; + mat4f_t mat; clipflags = 0; - if (currententity->transform[0] != 1 || currententity->transform[5] != 1 - || currententity->transform[10] != 1) { + Transform_GetWorldMatrix (currententity->transform, mat); + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { for (i = 0; i < 4; i++) { - d = DotProduct (currententity->origin, view_clipplanes[i].normal); + d = DotProduct (mat[3], view_clipplanes[i].normal); d -= view_clipplanes[i].dist; if (d <= -clmodel->radius) @@ -540,6 +547,7 @@ R_DrawBEntitiesOnList (void) int j, clipflags; unsigned int k; vec3_t oldorigin; + vec3_t origin; model_t *clmodel; float minmaxs[6]; entity_t *ent; @@ -553,46 +561,48 @@ R_DrawBEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + VectorCopy (Transform_GetWorldPosition (currententity->transform), + origin); + switch (currententity->renderer.model->type) { case mod_brush: - clmodel = currententity->model; + clmodel = currententity->renderer.model; // see if the bounding box lets us trivially reject, also // sets trivial accept status for (j = 0; j < 3; j++) { - minmaxs[j] = currententity->origin[j] + clmodel->mins[j]; - minmaxs[3 + j] = currententity->origin[j] + - clmodel->maxs[j]; + minmaxs[j] = origin[j] + clmodel->mins[j]; + minmaxs[3 + j] = origin[j] + clmodel->maxs[j]; } clipflags = R_BmodelCheckBBox (clmodel, minmaxs); if (clipflags != BMODEL_FULLY_CLIPPED) { - VectorCopy (currententity->origin, r_entorigin); + mod_brush_t *brush = &clmodel->brush; + VectorCopy (origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // FIXME: is this needed? VectorCopy (modelorg, r_worldmodelorg); - r_pcurrentvertbase = clmodel->vertexes; + r_pcurrentvertbase = brush->vertexes; // FIXME: stop transforming twice R_RotateBmodel (); // calculate dynamic lighting for bmodel if it's not an // instanced model - if (clmodel->firstmodelsurface != 0) { + if (brush->firstmodelsurface != 0) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { if ((r_dlights[k].die < vr_data.realtime) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, - currententity->origin, + VectorSubtract (r_dlights[k].origin, origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], - k, clmodel->nodes + - clmodel->hulls[0].firstclipnode); + R_RecursiveMarkLights (brush, lightorigin, + &r_dlights[k], k, + brush->nodes + + brush->hulls[0].firstclipnode); } } // if the driver wants polygons, deliver those. @@ -601,8 +611,9 @@ R_DrawBEntitiesOnList (void) if (r_drawpolys | r_drawculledpolys) { R_ZDrawSubmodelPolys (clmodel); } else { - if (currententity->topnode) { - mnode_t *topnode = currententity->topnode; + if (currententity->visibility.topnode) { + mnode_t *topnode + = currententity->visibility.topnode; if (topnode->contents >= 0) { // not a leaf; has to be clipped to the world @@ -751,7 +762,7 @@ R_RenderView_ (void) // done in screen.c R_LowFPPrecision (); - if (!r_worldentity.model) + if (!r_worldentity.renderer.model) Sys_Error ("R_RenderView: NULL worldmodel"); if (!r_dspeeds->int_val) { @@ -820,7 +831,7 @@ R_RenderView_ (void) R_HighFPPrecision (); } -static void R_RenderViewFishEye (void); +//XXX FIXME static void R_RenderViewFishEye (void); void R_RenderView (void) @@ -840,11 +851,12 @@ R_RenderView (void) if ((intptr_t) (&r_warpbuffer) & 3) Sys_Error ("Globals are missaligned"); - + R_RenderView_ (); +/*XXX FIXME if (!scr_fisheye->int_val) R_RenderView_ (); else - R_RenderViewFishEye (); + R_RenderViewFishEye ();*/ } void @@ -858,7 +870,7 @@ R_InitTurb (void) // AMP2 not 20 } } - +/*XXX FIXME #define BOX_FRONT 0 #define BOX_BEHIND 2 #define BOX_LEFT 3 @@ -1143,7 +1155,7 @@ R_RenderViewFishEye (void) r_refdef.viewangles[PITCH] = pitch; r_refdef.viewangles[ROLL] = roll; renderlookup (offs, scrbufs); -} +}*/ void R_ClearState (void) diff --git a/libs/video/renderer/sw/sw_rmisc.c b/libs/video/renderer/sw/sw_rmisc.c index f30200ffa..2ea74ad4e 100644 --- a/libs/video/renderer/sw/sw_rmisc.c +++ b/libs/video/renderer/sw/sw_rmisc.c @@ -37,6 +37,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_sw.h" static void @@ -52,6 +53,7 @@ R_CheckVariables (void) void R_TimeRefresh_f (void) { +/* FIXME update for simd int i; float start, stop, time; int startangle; @@ -74,13 +76,14 @@ R_TimeRefresh_f (void) vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; vr.next = NULL; - VID_Update (&vr); + sw_ctx->update (&vr); } stop = Sys_DoubleTime (); time = stop - start; Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); r_refdef.viewangles[1] = startangle; +*/ } void @@ -236,14 +239,16 @@ R_SetupFrame (void) #endif // build the transformation matrix for the given view angles - VectorCopy (r_refdef.vieworg, modelorg); - VectorCopy (r_refdef.vieworg, r_origin); + VectorCopy (r_refdef.viewposition, modelorg); + VectorCopy (r_refdef.viewposition, r_origin); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); R_SetFrustum (); // current viewleaf - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); r_dowarpold = r_dowarp; r_dowarp = r_waterwarp->int_val && (r_viewleaf->contents <= diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index aeb2fa904..c429279b2 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -37,6 +37,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/mersenne.h" #include "QF/qargs.h" #include "QF/quakefs.h" @@ -83,12 +84,12 @@ R_ReadPointFile_f (void) const char *name; char *mapname; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("maps/%s.pts", mapname); + name = va (0, "maps/%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); @@ -386,9 +387,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) if (!r_particles->int_val) return; - org[0] = ent->origin[0]; - org[1] = ent->origin[1]; - org[2] = ent->origin[2]; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { for (j = -16; j < 16; j += 8) { for (k = 0; k < 32; k += 8) { @@ -431,10 +430,13 @@ R_EntityParticles_ID (const entity_t *ent) float beamlength = 16.0, dist = 64.0; particle_t *p; vec3_t forward; + vec3_t org; if (!r_particles->int_val) return; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; for (k = 0; k < 3; k++) { @@ -470,11 +472,11 @@ R_EntityParticles_ID (const entity_t *ent) p->type = pt_explode; p->phys = R_ParticlePhysics (p->type); - p->org[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + + p->org[0] = org[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; - p->org[1] = ent->origin[1] + r_avertexnormals[i][1] * dist + + p->org[1] = org[1] + r_avertexnormals[i][1] * dist + forward[1] * beamlength; - p->org[2] = ent->origin[2] + r_avertexnormals[i][2] * dist + + p->org[2] = org[2] + r_avertexnormals[i][2] * dist + forward[2] * beamlength; } } @@ -486,12 +488,14 @@ R_RocketTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -525,12 +529,14 @@ R_GrenadeTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -564,12 +570,14 @@ R_BloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -590,7 +598,6 @@ R_BloodTrail_QF (const entity_t *ent) p->color = 67 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); - break; VectorAdd (old_origin, vec, old_origin); } @@ -603,12 +610,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -640,12 +649,14 @@ R_WizTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -687,12 +698,14 @@ R_FlameTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -735,12 +748,14 @@ R_VoorTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -802,6 +817,52 @@ r_particles_style_f (cvar_t *var) { } +static void +R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, float ramp) +{ + particle_t *p; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (org, p->org); + p->color = color; + p->tex = texnum; + p->scale = scale; + p->alpha = alpha; + VectorCopy (vel, p->vel); + p->type = type; + p->phys = R_ParticlePhysics (p->type); + p->die = die; + p->ramp = ramp; +} + +static void +R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, int org_fuzz, + float scale, int vel_fuzz, float die, int color, + float alpha, float ramp) +{ + float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; + int rnd; + vec3_t porg, pvel; + + rnd = mtwist_rand (&mt); + porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; + porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; + porg[2] = o_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0 + org[2]; + rnd = mtwist_rand (&mt); + pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; + pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; + pvel[2] = v_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0; + + R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -875,49 +936,3 @@ R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, float ramp) -{ - particle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - VectorCopy (org, p->org); - p->color = color; - p->tex = texnum; - p->scale = scale; - p->alpha = alpha; - VectorCopy (vel, p->vel); - p->type = type; - p->phys = R_ParticlePhysics (p->type); - p->die = die; - p->ramp = ramp; -} - -void -R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, int org_fuzz, - float scale, int vel_fuzz, float die, int color, - float alpha, float ramp) -{ - float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; - int rnd; - vec3_t porg, pvel; - - rnd = mtwist_rand (&mt); - porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; - porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; - porg[2] = o_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0 + org[2]; - rnd = mtwist_rand (&mt); - pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; - pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; - pvel[2] = v_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0; - - R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); -} diff --git a/libs/video/renderer/sw/sw_rsprite.c b/libs/video/renderer/sw/sw_rsprite.c index 4ee5d74c3..6a70d2f4f 100644 --- a/libs/video/renderer/sw/sw_rsprite.c +++ b/libs/video/renderer/sw/sw_rsprite.c @@ -37,6 +37,7 @@ #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -246,7 +247,7 @@ R_GetSpriteframe (msprite_t *psprite) int i, numframes, frame; float *pintervals, fullinterval, targettime, time; - frame = currententity->frame; + frame = currententity->animation.frame; if ((frame >= psprite->numframes) || (frame < 0)) { Sys_Printf ("R_DrawSprite: no such frame %d\n", frame); @@ -261,7 +262,7 @@ R_GetSpriteframe (msprite_t *psprite) numframes = pspritegroup->numframes; fullinterval = pintervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -285,9 +286,9 @@ R_DrawSprite (void) int i; msprite_t *psprite; vec3_t tvec; - float dot, angle, sr, cr; + float dot, sr, cr; - psprite = currententity->model->cache.data; + psprite = currententity->renderer.model->cache.data; r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); @@ -361,16 +362,19 @@ R_DrawSprite (void) } else if (psprite->type == SPR_ORIENTED) { // generate the sprite's axes, according to the sprite's world // orientation - VectorCopy (currententity->transform + 0, r_spritedesc.vpn); - VectorNegate (currententity->transform + 4, r_spritedesc.vright); - VectorCopy (currententity->transform + 8, r_spritedesc.vup); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], r_spritedesc.vpn); + VectorNegate (mat[1], r_spritedesc.vright); + VectorCopy (mat[2], r_spritedesc.vup); } else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) { // generate the sprite's axes, parallel to the viewplane, but rotated // in that plane around the center according to the sprite entity's // roll angle. So vpn stays the same, but vright and vup rotate - angle = currententity->angles[ROLL] * (M_PI * 2 / 360); - sr = sin (angle); - cr = cos (angle); + vec4f_t rot = Transform_GetLocalRotation (currententity->transform); + //FIXME assumes the entity is only rolled + sr = 2 * rot[0] * rot[3]; + cr = rot[3] * rot[3] - rot[0] * rot[0]; for (i = 0; i < 3; i++) { r_spritedesc.vpn[i] = vpn[i]; diff --git a/libs/video/renderer/sw/sw_rsurf.c b/libs/video/renderer/sw/sw_rsurf.c index e4d3fa853..36ea5fe79 100644 --- a/libs/video/renderer/sw/sw_rsurf.c +++ b/libs/video/renderer/sw/sw_rsurf.c @@ -28,6 +28,7 @@ # include "config.h" #endif +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -78,6 +79,7 @@ R_AddDynamicLights (void) int sd, td; float dist, rad, minlight; vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1 }; int s, t; int i; int smax, tmax; @@ -88,12 +90,16 @@ R_AddDynamicLights (void) tmax = (surf->extents[1] >> 4) + 1; tex = surf->texinfo; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, - lightorigin); + VectorSubtract (r_dlights[lnum].origin, entorigin, lightorigin); rad = r_dlights[lnum].radius; dist = DotProduct (lightorigin, surf->plane->normal) - surf->plane->dist; @@ -154,7 +160,7 @@ R_BuildLightMap (void) size = smax * tmax; lightmap = surf->samples; - if (!r_worldentity.model->lightdata) { + if (!r_worldentity.renderer.model->brush.lightdata) { for (i = 0; i < size; i++) blocklights[i] = 0; return; diff --git a/libs/video/renderer/sw32/Makefile.am b/libs/video/renderer/sw32/Makefile.am deleted file mode 100644 index 5d078e90c..000000000 --- a/libs/video/renderer/sw32/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include - -noinst_LTLIBRARIES= libsw32.la - -sw32_src= \ - d_edge.c d_fill.c d_init.c d_modech.c d_part.c d_polyse.c d_scan.c \ - d_sky.c d_sprite.c d_surf.c d_vars.c d_zpoint.c draw.c screen.c \ - sw32_graph.c sw32_raclip.c sw32_ralias.c sw32_rbsp.c sw32_rdraw.c \ - sw32_redge.c sw32_riqm.c sw32_rmain.c sw32_rmisc.c sw32_rpart.c \ - sw32_rsky.c sw32_rsprite.c sw32_rsurf.c \ - vid_common_sw32.c - -libsw32_la_SOURCES= $(sw32_src) - -EXTRA_DIST= $(sw32_src) namehack.h diff --git a/libs/video/renderer/sw32/d_edge.c b/libs/video/renderer/sw32/d_edge.c index 6fa0b131a..6015eaf23 100644 --- a/libs/video/renderer/sw32/d_edge.c +++ b/libs/video/renderer/sw32/d_edge.c @@ -32,6 +32,7 @@ #include "namehack.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -243,7 +244,8 @@ sw32_D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to sw32_R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); sw32_TransformVector (local_modelorg, transformed_modelorg); @@ -276,7 +278,8 @@ sw32_D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to sw32_R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); sw32_TransformVector (local_modelorg, transformed_modelorg); diff --git a/libs/video/renderer/sw32/d_init.c b/libs/video/renderer/sw32/d_init.c index ccb5f7392..e786cf32b 100644 --- a/libs/video/renderer/sw32/d_init.c +++ b/libs/video/renderer/sw32/d_init.c @@ -66,9 +66,9 @@ sw32_D_Init (void) sw32_d_zitable[i] = (65536.0 * 65536.0 / (double) i); } - vr_data.vid->surf_cache_size = sw32_D_SurfaceCacheForRes; - vr_data.vid->flush_caches = sw32_D_FlushCaches; - vr_data.vid->init_caches = sw32_D_InitCaches; + vr_data.vid->vid_internal->surf_cache_size = sw32_D_SurfaceCacheForRes; + vr_data.vid->vid_internal->flush_caches = sw32_D_FlushCaches; + vr_data.vid->vid_internal->init_caches = sw32_D_InitCaches; VID_InitBuffers (); VID_MakeColormaps(); diff --git a/libs/video/renderer/sw32/d_scan.c b/libs/video/renderer/sw32/d_scan.c index c77f131df..d5c2000ea 100644 --- a/libs/video/renderer/sw32/d_scan.c +++ b/libs/video/renderer/sw32/d_scan.c @@ -515,14 +515,10 @@ sw32_D_DrawSpans (espan_t *pspan) } if (count & 1) pdest[0] = pbase[(t >> 16) * sw32_cachewidth + (s >> 16)]; - s += sstep; - t += tstep; } else { pdest[0] = pbase[(t >> 16) * sw32_cachewidth + (s >> 16)]; - s += sstep; - t += tstep; } } } while ((pspan = pspan->pnext) != NULL); @@ -657,14 +653,10 @@ sw32_D_DrawSpans (espan_t *pspan) } if (count & 1) pdest[0] = pbase[(t >> 16) * sw32_cachewidth + (s >> 16)]; - s += sstep; - t += tstep; } else { pdest[0] = pbase[(t >> 16) * sw32_cachewidth + (s >> 16)]; - s += sstep; - t += tstep; } } } while ((pspan = pspan->pnext) != NULL); @@ -800,14 +792,10 @@ sw32_D_DrawSpans (espan_t *pspan) } if (count & 1) pdest[0] = pbase[(t >> 16) * sw32_cachewidth + (s >> 16)]; - s += sstep; - t += tstep; } else { pdest[0] = pbase[(t >> 16) * sw32_cachewidth + (s >> 16)]; - s += sstep; - t += tstep; } } } while ((pspan = pspan->pnext) != NULL); diff --git a/libs/video/renderer/sw32/d_sky.c b/libs/video/renderer/sw32/d_sky.c index 20e2765b0..6ceb6095a 100644 --- a/libs/video/renderer/sw32/d_sky.c +++ b/libs/video/renderer/sw32/d_sky.c @@ -79,6 +79,8 @@ sw32_D_DrawSkyScans (espan_t *pspan) sstep = 0; // keep compiler happy tstep = 0; // ditto + snext = 0; // ditto + tnext = 0; // ditto do { pdest = (byte *) sw32_d_viewbuffer + sw32_screenwidth * pspan->v + pspan->u; @@ -146,6 +148,8 @@ sw32_D_DrawSkyScans (espan_t *pspan) sstep = 0; // keep compiler happy tstep = 0; // ditto + snext = 0; // ditto + tnext = 0; // ditto do { pdest = (short *) sw32_d_viewbuffer + sw32_screenwidth * pspan->v + pspan->u; @@ -213,6 +217,8 @@ sw32_D_DrawSkyScans (espan_t *pspan) sstep = 0; // keep compiler happy tstep = 0; // ditto + snext = 0; // ditto + tnext = 0; // ditto do { pdest = (int *) sw32_d_viewbuffer + sw32_screenwidth * pspan->v + pspan->u; diff --git a/libs/video/renderer/sw32/draw.c b/libs/video/renderer/sw32/draw.c index 81ed3ab1f..e8a465dfd 100644 --- a/libs/video/renderer/sw32/draw.c +++ b/libs/video/renderer/sw32/draw.c @@ -1300,7 +1300,7 @@ sw32_Draw_BlendScreen (quat_t color) newpal[2] = vid.gammatable[b]; newpal += 3; } - vid.set_palette (pal); + vid.vid_internal->set_palette (pal); } break; case 2: @@ -1364,6 +1364,7 @@ sw32_Draw_BlendScreen (quat_t color) } break; default: - Sys_Error("V_UpdatePalette: unsupported r_pixbytes %i", sw32_r_pixbytes); + Sys_Error("sw32_Draw_BlendScreen: unsupported r_pixbytes %i", + sw32_r_pixbytes); } } diff --git a/libs/video/renderer/sw32/namehack.h b/libs/video/renderer/sw32/namehack.h index cbdb673ce..6642d2d54 100644 --- a/libs/video/renderer/sw32/namehack.h +++ b/libs/video/renderer/sw32/namehack.h @@ -110,7 +110,7 @@ #define SCR_CaptureBGR sw32_SCR_CaptureBGR #define SCR_ScreenShot sw32_SCR_ScreenShot #define SCR_ScreenShot_f sw32_SCR_ScreenShot_f -#define SCR_UpdateScreen sw32_SCR_UpdateScreen +#define R_RenderFrame sw32_R_RenderFrame #define TransformVector sw32_TransformVector #define Turbulent sw32_Turbulent #define acolormap sw32_acolormap @@ -351,7 +351,7 @@ extern struct surf_s *sw32_surfaces; #undef SCR_CaptureBGR #undef SCR_ScreenShot #undef SCR_ScreenShot_f -#undef SCR_UpdateScreen +#undef R_RenderFrame #undef TransformVector #undef Turbulent #undef VID_InitBuffers diff --git a/libs/video/renderer/sw32/screen.c b/libs/video/renderer/sw32/screen.c index 74ae6f54d..7dabffd9a 100644 --- a/libs/video/renderer/sw32/screen.c +++ b/libs/video/renderer/sw32/screen.c @@ -54,6 +54,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_sw.h" /* SCREEN SHOTS */ @@ -66,7 +67,8 @@ sw32_SCR_CaptureBGR (void) byte *dst; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; @@ -87,7 +89,7 @@ sw32_SCR_CaptureBGR (void) return tex; } -tex_t * +__attribute__((const)) tex_t * sw32_SCR_ScreenShot (unsigned width, unsigned height) { return 0; @@ -101,8 +103,8 @@ sw32_SCR_ScreenShot_f (void) int pcx_len; // find a file name to save it to - if (!QFS_NextFilename (pcxname, - va ("%s/qf", qfs_gamedir->dir.shots), ".pcx")) { + if (!QFS_NextFilename (pcxname, va (0, "%s/qf", + qfs_gamedir->dir.shots), ".pcx")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX"); } else { // enable direct drawing of console to back buffer @@ -135,39 +137,11 @@ sw32_SCR_ScreenShot_f (void) dstring_delete (pcxname); } -/* - SCR_UpdateScreen - - This is called every frame, and can also be called explicitly to flush - text to the screen. - - WARNING: be very careful calling this from elsewhere, because the refresh - needs almost the entire 256k of stack space! -*/ void -sw32_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +sw32_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { vrect_t vrect; - if (scr_skipupdate) - return; - - vr_data.realtime = realtime; - - scr_copytop = 0; - vr_data.scr_copyeverything = 0; - - if (!scr_initialized) - return; // not initialized yet - - if (oldfov != scr_fov->value) { // determine size of refresh window - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - - if (vid.recalc_refdef) - SCR_CalcRefdef (); - // do 3D refresh drawing, and then update the screen sw32_D_EnableBackBufferAccess (); // of all overlay stuff if drawing // directly @@ -221,5 +195,5 @@ sw32_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs vrect.height = scr_vrect.height; vrect.next = 0; } - VID_Update (&vrect); + sw32_ctx->update (&vrect); } diff --git a/libs/video/renderer/sw32/sw32_ralias.c b/libs/video/renderer/sw32/sw32_ralias.c index 167730ab1..1dacb5bc7 100644 --- a/libs/video/renderer/sw32/sw32_ralias.c +++ b/libs/video/renderer/sw32/sw32_ralias.c @@ -31,6 +31,7 @@ #define NH_DEFINE #include "namehack.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -97,8 +98,8 @@ sw32_R_AliasCheckBBox (void) int minz; // expand, rotate, and translate points into worldspace - currententity->trivial_accept = 0; - pmodel = currententity->model; + currententity->visibility.trivial_accept = 0; + pmodel = currententity->renderer.model; if (!(pahdr = pmodel->aliashdr)) pahdr = Cache_Get (&pmodel->cache); pmdl = (mdl_t *) ((byte *) pahdr + pahdr->model); @@ -106,10 +107,10 @@ sw32_R_AliasCheckBBox (void) sw32_R_AliasSetUpTransform (0); // construct the base bounding box for this frame - frame = currententity->frame; + frame = currententity->animation.frame; // TODO: don't repeat this check when drawing? if ((frame >= pmdl->numframes) || (frame < 0)) { - Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->name); + Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->path); frame = 0; } @@ -221,11 +222,11 @@ sw32_R_AliasCheckBBox (void) return false; // trivial reject off one side } - currententity->trivial_accept = !anyclip & !zclipped; + currententity->visibility.trivial_accept = !anyclip & !zclipped; - if (currententity->trivial_accept) { + if (currententity->visibility.trivial_accept) { if (minz > (sw32_r_aliastransition + (pmdl->size * sw32_r_resfudge))) { - currententity->trivial_accept |= 2; + currententity->visibility.trivial_accept |= 2; } } @@ -366,9 +367,11 @@ sw32_R_AliasSetUpTransform (int trivial_accept) static float tmatrix[3][4]; static float viewmatrix[3][4]; - VectorCopy (currententity->transform + 0, alias_forward); - VectorNegate (currententity->transform + 4, alias_right); - VectorCopy (currententity->transform + 8, alias_up); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], alias_forward); + VectorNegate (mat[1], alias_right); + VectorCopy (mat[2], alias_up); tmatrix[0][0] = pmdl->scale[0]; tmatrix[1][1] = pmdl->scale[1]; @@ -543,7 +546,7 @@ R_AliasSetupSkin (void) { int skinnum; - skinnum = currententity->skinnum; + skinnum = currententity->renderer.skinnum; if ((skinnum >= pmdl->numskins) || (skinnum < 0)) { Sys_MaskPrintf (SYS_DEV, "R_AliasSetupSkin: no such skin # %d\n", skinnum); @@ -559,16 +562,16 @@ R_AliasSetupSkin (void) sw32_r_affinetridesc.skinheight = pmdl->skinheight; sw32_acolormap = vid.colormap8; - if (currententity->skin) { + if (currententity->renderer.skin) { tex_t *base; - base = currententity->skin->texels; + base = currententity->renderer.skin->texels; if (base) { sw32_r_affinetridesc.pskin = base->data; sw32_r_affinetridesc.skinwidth = base->width; sw32_r_affinetridesc.skinheight = base->height; } - sw32_acolormap = currententity->skin->colormap; + sw32_acolormap = currententity->renderer.skin->colormap; } } @@ -611,7 +614,7 @@ R_AliasSetupFrame (void) { maliasframedesc_t *frame; - frame = R_AliasGetFramedesc (currententity->frame, paliashdr); + frame = R_AliasGetFramedesc (currententity->animation.frame, paliashdr); sw32_r_apverts = (trivertx_t *) ((byte *) paliashdr + frame->frame); } @@ -624,8 +627,8 @@ sw32_R_AliasDrawModel (alight_t *plighting) sw32_r_amodels_drawn++; - if (!(paliashdr = currententity->model->aliashdr)) - paliashdr = Cache_Get (¤tentity->model->cache); + if (!(paliashdr = currententity->renderer.model->aliashdr)) + paliashdr = Cache_Get (¤tentity->renderer.model->cache); pmdl = (mdl_t *) ((byte *) paliashdr + paliashdr->model); size = (CACHE_SIZE - 1) @@ -641,7 +644,7 @@ sw32_R_AliasDrawModel (alight_t *plighting) sw32_pauxverts = (auxvert_t *) &pfinalverts[pmdl->numverts + 1]; R_AliasSetupSkin (); - sw32_R_AliasSetUpTransform (currententity->trivial_accept); + sw32_R_AliasSetUpTransform (currententity->visibility.trivial_accept); R_AliasSetupLighting (plighting); R_AliasSetupFrame (); @@ -663,11 +666,13 @@ sw32_R_AliasDrawModel (alight_t *plighting) else sw32_ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (currententity->trivial_accept) + if (currententity->visibility.trivial_accept) { R_AliasPrepareUnclippedPoints (); - else + } else { R_AliasPreparePoints (); + } - if (!currententity->model->aliashdr) - Cache_Release (¤tentity->model->cache); + if (!currententity->renderer.model->aliashdr) { + Cache_Release (¤tentity->renderer.model->cache); + } } diff --git a/libs/video/renderer/sw32/sw32_rbsp.c b/libs/video/renderer/sw32/sw32_rbsp.c index 017268dbb..1f62b381e 100644 --- a/libs/video/renderer/sw32/sw32_rbsp.c +++ b/libs/video/renderer/sw32/sw32_rbsp.c @@ -36,6 +36,7 @@ #include "qfalloca.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -80,9 +81,11 @@ R_EntityRotate (vec3_t vec) void sw32_R_RotateBmodel (void) { - VectorCopy (currententity->transform + 0, entity_rotation[0]); - VectorCopy (currententity->transform + 4, entity_rotation[1]); - VectorCopy (currententity->transform + 8, entity_rotation[2]); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], entity_rotation[0]); + VectorCopy (mat[1], entity_rotation[1]); + VectorCopy (mat[2], entity_rotation[2]); // rotate modelorg and the transformation matrix R_EntityRotate (modelorg); @@ -240,7 +243,7 @@ R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) void -sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) +sw32_R_DrawSolidClippedSubmodelPolygons (model_t *model) { int i, j, lindex; vec_t dot; @@ -250,12 +253,13 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) mvertex_t bverts[MAX_BMODEL_VERTS]; bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; medge_t *pedge, *pedges; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; - pedges = pmodel->edges; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; + pedges = brush->edges; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -281,7 +285,7 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) numbedges += psurf->numedges; for (j = 0; j < psurf->numedges; j++) { - lindex = pmodel->surfedges[psurf->firstedge + j]; + lindex = brush->surfedges[psurf->firstedge + j]; if (lindex > 0) { pedge = &pedges[lindex]; @@ -299,7 +303,9 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) pbedge[j - 1].pnext = NULL; // mark end of edges - R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf); + R_RecursiveClipBPoly (pbedge, + currententity->visibility.topnode, + psurf); } else { Sys_Error ("no edges in bmodel"); } @@ -309,18 +315,19 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) void -sw32_R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) +sw32_R_DrawSubmodelPolygons (model_t *model, int clipflags) { int i; vec_t dot; msurface_t *psurf; int numsurfaces; plane_t *pplane; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -331,7 +338,8 @@ sw32_R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - sw32_r_currentkey = ((mleaf_t *) currententity->topnode)->key; + sw32_r_currentkey + = ((mleaf_t *) currententity->visibility.topnode)->key; // FIXME: use bounding-box-based frustum clipping info? sw32_R_RenderFace (psurf, clipflags); @@ -361,7 +369,7 @@ get_side (mnode_t *node) } static void -visit_node (mnode_t *node, int side, int clipflags) +visit_node (mod_brush_t *brush, mnode_t *node, int side, int clipflags) { int c; msurface_t *surf; @@ -370,7 +378,7 @@ visit_node (mnode_t *node, int side, int clipflags) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -447,7 +455,7 @@ test_node (mnode_t *node, int *clipflags) } static void -R_VisitWorldNodes (model_t *model, int clipflags) +R_VisitWorldNodes (mod_brush_t *brush, int clipflags) { typedef struct { mnode_t *node; @@ -459,9 +467,9 @@ R_VisitWorldNodes (model_t *model, int clipflags) mnode_t *front; int side, cf; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; cf = clipflags; @@ -481,7 +489,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -491,7 +499,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) node = node_ptr->node; side = node_ptr->side; clipflags = node_ptr->clipflags; - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; continue; } @@ -505,17 +513,17 @@ void sw32_R_RenderWorld (void) { int i; - model_t *clmodel; btofpoly_t btofpolys[MAX_BTOFPOLYS]; + mod_brush_t *brush; pbtofpolys = btofpolys; currententity = &r_worldentity; VectorCopy (r_origin, modelorg); - clmodel = currententity->model; - r_pcurrentvertbase = clmodel->vertexes; + brush = ¤tentity->renderer.model->brush; + r_pcurrentvertbase = brush->vertexes; - R_VisitWorldNodes (clmodel, 15); + R_VisitWorldNodes (brush, 15); // if the driver wants the polygons back to front, play the visible ones // back in that order diff --git a/libs/video/renderer/sw32/sw32_rdraw.c b/libs/video/renderer/sw32/sw32_rdraw.c index 6624917a7..7c1e696be 100644 --- a/libs/video/renderer/sw32/sw32_rdraw.c +++ b/libs/video/renderer/sw32/sw32_rdraw.c @@ -349,6 +349,7 @@ sw32_R_RenderFace (msurface_t *fa, int clipflags) vec3_t p_normal; medge_t *pedges, tedge; clipplane_t *pclip; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // skip out if no more surfs if ((sw32_surface_p) >= sw32_surf_max) { @@ -378,11 +379,11 @@ sw32_R_RenderFace (msurface_t *fa, int clipflags) sw32_r_nearzi = 0; sw32_r_nearzionly = false; makeleftedge = makerightedge = false; - pedges = currententity->model->edges; + pedges = brush->edges; sw32_r_lastvertvalid = false; for (i = 0; i < fa->numedges; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { sw32_r_pedge = &pedges[lindex]; @@ -621,6 +622,7 @@ sw32_R_RenderPoly (msurface_t *fa, int clipflags) polyvert_t pverts[100]; // FIXME: do real number, safely int vertpage, newverts, newpage, lastvert; qboolean visible; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // FIXME: clean this up and make it faster // FIXME: guard against running out of vertices @@ -639,12 +641,12 @@ sw32_R_RenderPoly (msurface_t *fa, int clipflags) // reconstruct the polygon // FIXME: these should be precalculated and loaded off disk - pedges = currententity->model->edges; + pedges = brush->edges; lnumverts = fa->numedges; vertpage = 0; for (i = 0; i < lnumverts; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { sw32_r_pedge = &pedges[lindex]; @@ -775,15 +777,16 @@ sw32_R_RenderPoly (msurface_t *fa, int clipflags) void -sw32_R_ZDrawSubmodelPolys (model_t *pmodel) +sw32_R_ZDrawSubmodelPolys (model_t *model) { int i, numsurfaces; msurface_t *psurf; float dot; plane_t *pplane; + mod_brush_t *brush = &model->brush; - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on diff --git a/libs/video/renderer/sw32/sw32_riqm.c b/libs/video/renderer/sw32/sw32_riqm.c index b53186bd9..1db5fbbdc 100644 --- a/libs/video/renderer/sw32/sw32_riqm.c +++ b/libs/video/renderer/sw32/sw32_riqm.c @@ -43,6 +43,7 @@ #include "namehack.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -222,9 +223,12 @@ R_IQMSetupLighting (entity_t *ent, alight_t *plighting) r_shadelight *= VID_GRADES; // rotate the lighting vector into the model's frame of reference - r_plightvec[0] = DotProduct (plighting->plightvec, ent->transform + 0); - r_plightvec[1] = DotProduct (plighting->plightvec, ent->transform + 4); - r_plightvec[2] = DotProduct (plighting->plightvec, ent->transform + 8); + mat4f_t mat; + Transform_GetWorldMatrix (ent->transform, mat); + //FIXME vectorize + r_plightvec[0] = DotProduct (plighting->plightvec, mat[0]); + r_plightvec[1] = DotProduct (plighting->plightvec, mat[1]); + r_plightvec[2] = DotProduct (plighting->plightvec, mat[2]); } static void @@ -235,9 +239,11 @@ R_IQMSetUpTransform (int trivial_accept) static float viewmatrix[3][4]; vec3_t forward, left, up; - VectorCopy (currententity->transform + 0, forward); - VectorCopy (currententity->transform + 4, left); - VectorCopy (currententity->transform + 8, up); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], forward); + VectorCopy (mat[1], left); + VectorCopy (mat[2], up); // TODO: can do this with simple matrix rearrangement @@ -284,7 +290,7 @@ void sw32_R_IQMDrawModel (alight_t *plighting) { entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; swiqm_t *sw = (swiqm_t *) iqm->extra_data; int size; @@ -295,7 +301,8 @@ sw32_R_IQMDrawModel (alight_t *plighting) + sizeof (finalvert_t) * (iqm->num_verts + 1) + sizeof (auxvert_t) * iqm->num_verts; blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendPalette (iqm, ent->pose1, ent->pose2, blend, size, + frame = R_IQMBlendPalette (iqm, ent->animation.pose1, ent->animation.pose2, + blend, size, sw->blend_palette, sw->palette_size); pfinalverts = (finalvert_t *) &frame[sw->palette_size]; @@ -303,7 +310,7 @@ sw32_R_IQMDrawModel (alight_t *plighting) (((intptr_t) &pfinalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); pauxverts = (auxvert_t *) &pfinalverts[iqm->num_verts + 1]; - R_IQMSetUpTransform (ent->trivial_accept); + R_IQMSetUpTransform (ent->visibility.trivial_accept); R_IQMSetupLighting (ent, plighting); @@ -315,7 +322,7 @@ sw32_R_IQMDrawModel (alight_t *plighting) else sw32_ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (ent->trivial_accept) + if (ent->visibility.trivial_accept) R_IQMPrepareUnclippedPoints (iqm, sw, frame); else R_IQMPreparePoints (iqm, sw, frame); diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index fd204e587..d6dfd7670 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -42,7 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" -#include "QF/locs.h" +#include "QF/entity.h" #include "QF/mathlib.h" #include "QF/render.h" #include "QF/screen.h" @@ -180,19 +180,20 @@ void sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) { int i; + mod_brush_t *brush = &worldmodel->brush; memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; R_FreeAllEntities (); // clear out efrags in case the level hasn't been reloaded // FIXME: is this one short? - for (i = 0; i < r_worldentity.model->numleafs; i++) - r_worldentity.model->leafs[i].efrags = NULL; + for (i = 0; i < brush->numleafs; i++) + brush->leafs[i].efrags = NULL; - if (worldmodel->skytexture) - sw32_R_InitSky (worldmodel->skytexture); + if (brush->skytexture) + sw32_R_InitSky (brush->skytexture); // Force a vis update r_viewleaf = NULL; @@ -368,27 +369,30 @@ R_DrawEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); + switch (currententity->renderer.model->type) { case mod_sprite: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); sw32_R_DrawSprite (); break; case mod_alias: case mod_iqm: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); - minlight = max (currententity->min_light, currententity->model->min_light); + minlight = max (currententity->renderer.min_light, + currententity->renderer.model->min_light); // see if the bounding box lets us trivially reject, also // sets trivial accept status - currententity->trivial_accept = 0; //FIXME - if (currententity->model->type == mod_iqm//FIXME + currententity->visibility.trivial_accept = 0; //FIXME + if (currententity->renderer.model->type == mod_iqm//FIXME || sw32_R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, + r_entorigin), + minlight * 128); lighting.ambientlight = j; lighting.shadelight = j; @@ -397,7 +401,7 @@ R_DrawEntitiesOnList (void) for (lnum = 0; lnum < r_maxdlights; lnum++) { if (r_dlights[lnum].die >= vr_data.realtime) { - VectorSubtract (currententity->origin, + VectorSubtract (r_entorigin, r_dlights[lnum].origin, dist); add = r_dlights[lnum].radius - VectorLength (dist); @@ -412,7 +416,7 @@ R_DrawEntitiesOnList (void) if (lighting.ambientlight + lighting.shadelight > 192) lighting.shadelight = 192 - lighting.ambientlight; - if (currententity->model->type == mod_iqm) + if (currententity->renderer.model->type == mod_iqm) sw32_R_IQMDrawModel (&lighting); else sw32_R_AliasDrawModel (&lighting); @@ -443,18 +447,21 @@ R_DrawViewModel (void) return; currententity = vr_data.view_model; - if (!currententity->model) + if (!currententity->renderer.model) return; - VectorCopy (currententity->origin, r_entorigin); + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); VectorCopy (vup, viewlightvec); VectorNegate (viewlightvec, viewlightvec); - minlight = max (currententity->min_light, currententity->model->min_light); + minlight = max (currententity->renderer.min_light, + currententity->renderer.model->min_light); - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, + r_entorigin), minlight * 128); r_viewlighting.ambientlight = j; r_viewlighting.shadelight = j; @@ -469,7 +476,7 @@ R_DrawViewModel (void) if (dl->die < vr_data.realtime) continue; - VectorSubtract (currententity->origin, dl->origin, dist); + VectorSubtract (r_entorigin, dl->origin, dist); add = dl->radius - VectorLength (dist); if (add > 0) r_viewlighting.ambientlight += add; @@ -492,13 +499,14 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) int i, *pindex, clipflags; vec3_t acceptpt, rejectpt; double d; + mat4f_t mat; clipflags = 0; - if (currententity->transform[0] != 1 || currententity->transform[5] != 1 - || currententity->transform[10] != 1) { + Transform_GetWorldMatrix (currententity->transform, mat); + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { for (i = 0; i < 4; i++) { - d = DotProduct (currententity->origin, sw32_view_clipplanes[i].normal); + d = DotProduct (mat[3], sw32_view_clipplanes[i].normal); d -= sw32_view_clipplanes[i].dist; if (d <= -clmodel->radius) @@ -546,6 +554,7 @@ R_DrawBEntitiesOnList (void) int j, clipflags; unsigned int k; vec3_t oldorigin; + vec3_t origin; model_t *clmodel; float minmaxs[6]; entity_t *ent; @@ -559,46 +568,48 @@ R_DrawBEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + VectorCopy (Transform_GetWorldPosition (currententity->transform), + origin); + switch (currententity->renderer.model->type) { case mod_brush: - clmodel = currententity->model; + clmodel = currententity->renderer.model; // see if the bounding box lets us trivially reject, also // sets trivial accept status for (j = 0; j < 3; j++) { - minmaxs[j] = currententity->origin[j] + clmodel->mins[j]; - minmaxs[3 + j] = currententity->origin[j] + - clmodel->maxs[j]; + minmaxs[j] = origin[j] + clmodel->mins[j]; + minmaxs[3 + j] = origin[j] + clmodel->maxs[j]; } clipflags = R_BmodelCheckBBox (clmodel, minmaxs); if (clipflags != BMODEL_FULLY_CLIPPED) { - VectorCopy (currententity->origin, r_entorigin); + mod_brush_t *brush = &clmodel->brush; + VectorCopy (origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // FIXME: is this needed? VectorCopy (modelorg, sw32_r_worldmodelorg); - r_pcurrentvertbase = clmodel->vertexes; + r_pcurrentvertbase = brush->vertexes; // FIXME: stop transforming twice sw32_R_RotateBmodel (); // calculate dynamic lighting for bmodel if it's not an // instanced model - if (clmodel->firstmodelsurface != 0) { + if (brush->firstmodelsurface != 0) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { if ((r_dlights[k].die < vr_data.realtime) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, - currententity->origin, + VectorSubtract (r_dlights[k].origin, origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], - k, clmodel->nodes + - clmodel->hulls[0].firstclipnode); + R_RecursiveMarkLights (brush, lightorigin, + &r_dlights[k], k, + brush->nodes + + brush->hulls[0].firstclipnode); } } // if the driver wants polygons, deliver those. @@ -607,8 +618,9 @@ R_DrawBEntitiesOnList (void) if (sw32_r_drawpolys | sw32_r_drawculledpolys) { sw32_R_ZDrawSubmodelPolys (clmodel); } else { - if (currententity->topnode) { - mnode_t *topnode = currententity->topnode; + if (currententity->visibility.topnode) { + mnode_t *topnode + = currententity->visibility.topnode; if (topnode->contents >= 0) { // not a leaf; has to be clipped to the world @@ -753,7 +765,7 @@ R_RenderView_ (void) #endif R_PushDlights (vec3_origin); - if (!r_worldentity.model) + if (!r_worldentity.renderer.model) Sys_Error ("R_RenderView: NULL worldmodel"); if (!r_dspeeds->int_val) { diff --git a/libs/video/renderer/sw32/sw32_rmisc.c b/libs/video/renderer/sw32/sw32_rmisc.c index cb12395d3..390b13b86 100644 --- a/libs/video/renderer/sw32/sw32_rmisc.c +++ b/libs/video/renderer/sw32/sw32_rmisc.c @@ -40,7 +40,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" - +#include "vid_sw.h" static void R_CheckVariables (void) @@ -55,6 +55,7 @@ R_CheckVariables (void) void sw32_R_TimeRefresh_f (void) { +/* FIXME update for simd int i; float start, stop, time; int startangle; @@ -77,13 +78,14 @@ sw32_R_TimeRefresh_f (void) vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; vr.next = NULL; - VID_Update (&vr); + sw32_ctx->update (&vr); } stop = Sys_DoubleTime (); time = stop - start; Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); r_refdef.viewangles[1] = startangle; +*/ } void @@ -233,14 +235,16 @@ sw32_R_SetupFrame (void) #endif // build the transformation matrix for the given view angles - VectorCopy (r_refdef.vieworg, modelorg); - VectorCopy (r_refdef.vieworg, r_origin); + VectorCopy (r_refdef.viewposition, modelorg); + VectorCopy (r_refdef.viewposition, r_origin); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); R_SetFrustum (); // current viewleaf - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); sw32_r_dowarpold = sw32_r_dowarp; sw32_r_dowarp = r_waterwarp->int_val && (r_viewleaf->contents <= diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index 5591b9929..851618819 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -40,6 +40,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/mersenne.h" #include "QF/qargs.h" #include "QF/quakefs.h" @@ -88,12 +89,12 @@ sw32_R_ReadPointFile_f (void) const char *name; char *mapname; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("maps/%s.pts", mapname); + name = va (0, "maps/%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); @@ -330,9 +331,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) particle_t *p; vec3_t dir, org; - org[0] = ent->origin[0]; - org[1] = ent->origin[1]; - org[2] = ent->origin[2]; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { for (j = -16; j < 16; j += 8) { for (k = 0; k < 32; k += 8) { @@ -376,6 +375,9 @@ R_EntityParticles_ID (const entity_t *ent) float beamlength = 16.0, dist = 64.0; particle_t *p; vec3_t forward; + vec3_t org; + + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; @@ -412,11 +414,11 @@ R_EntityParticles_ID (const entity_t *ent) p->type = pt_explode; p->phys = R_ParticlePhysics (p->type); - p->org[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + + p->org[0] = org[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; - p->org[1] = ent->origin[1] + r_avertexnormals[i][1] * dist + + p->org[1] = org[1] + r_avertexnormals[i][1] * dist + forward[1] * beamlength; - p->org[2] = ent->origin[2] + r_avertexnormals[i][2] * dist + + p->org[2] = org[2] + r_avertexnormals[i][2] * dist + forward[2] * beamlength; } } @@ -499,12 +501,14 @@ R_RocketTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -538,12 +542,14 @@ R_GrenadeTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -577,12 +583,14 @@ R_BloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -603,7 +611,6 @@ R_BloodTrail_QF (const entity_t *ent) p->color = 67 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); - break; VectorAdd (old_origin, vec, old_origin); } @@ -616,12 +623,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -653,12 +662,14 @@ R_WizTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -700,12 +711,14 @@ R_FlameTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -748,12 +761,14 @@ R_VoorTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -815,6 +830,53 @@ sw32_r_particles_style_f (cvar_t *var) { } +static void +sw32_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, + float ramp) +{ + particle_t *p; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (org, p->org); + p->color = color; + p->tex = texnum; + p->scale = scale; + p->alpha = alpha; + VectorCopy (vel, p->vel); + p->type = type; + p->phys = R_ParticlePhysics (p->type); + p->die = die; + p->ramp = ramp; +} + +static void +sw32_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, float die, + int color, float alpha, float ramp) +{ + float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; + int rnd; + vec3_t porg, pvel; + + rnd = mtwist_rand (&mt); + porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; + porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; + porg[2] = o_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0 + org[2]; + rnd = mtwist_rand (&mt); + pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; + pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; + pvel[2] = v_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0; + + sw32_R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -888,50 +950,3 @@ sw32_R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -sw32_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) -{ - particle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - VectorCopy (org, p->org); - p->color = color; - p->tex = texnum; - p->scale = scale; - p->alpha = alpha; - VectorCopy (vel, p->vel); - p->type = type; - p->phys = R_ParticlePhysics (p->type); - p->die = die; - p->ramp = ramp; -} - -void -sw32_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp) -{ - float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; - int rnd; - vec3_t porg, pvel; - - rnd = mtwist_rand (&mt); - porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; - porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; - porg[2] = o_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0 + org[2]; - rnd = mtwist_rand (&mt); - pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; - pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; - pvel[2] = v_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0; - - sw32_R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); -} diff --git a/libs/video/renderer/sw32/sw32_rsprite.c b/libs/video/renderer/sw32/sw32_rsprite.c index 92be9b51e..bbdc1996f 100644 --- a/libs/video/renderer/sw32/sw32_rsprite.c +++ b/libs/video/renderer/sw32/sw32_rsprite.c @@ -40,6 +40,7 @@ #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -242,7 +243,7 @@ R_GetSpriteframe (msprite_t *psprite) int i, numframes, frame; float *pintervals, fullinterval, targettime, time; - frame = currententity->frame; + frame = currententity->animation.frame; if ((frame >= psprite->numframes) || (frame < 0)) { Sys_Printf ("R_DrawSprite: no such frame %d\n", frame); @@ -257,7 +258,7 @@ R_GetSpriteframe (msprite_t *psprite) numframes = pspritegroup->numframes; fullinterval = pintervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -281,9 +282,9 @@ sw32_R_DrawSprite (void) int i; msprite_t *psprite; vec3_t tvec; - float dot, angle, sr, cr; + float dot, sr, cr; - psprite = currententity->model->cache.data; + psprite = currententity->renderer.model->cache.data; sw32_r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); @@ -357,16 +358,19 @@ sw32_R_DrawSprite (void) } else if (psprite->type == SPR_ORIENTED) { // generate the sprite's axes, according to the sprite's world // orientation - VectorCopy (currententity->transform + 0, sw32_r_spritedesc.vpn); - VectorNegate (currententity->transform + 4, sw32_r_spritedesc.vright); - VectorCopy (currententity->transform + 8, sw32_r_spritedesc.vup); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], r_spritedesc.vpn); + VectorNegate (mat[1], r_spritedesc.vright); + VectorCopy (mat[2], r_spritedesc.vup); } else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) { // generate the sprite's axes, parallel to the viewplane, but rotated // in that plane around the center according to the sprite entity's // roll angle. So vpn stays the same, but vright and vup rotate - angle = currententity->angles[ROLL] * (M_PI * 2 / 360); - sr = sin (angle); - cr = cos (angle); + vec4f_t rot = Transform_GetLocalRotation (currententity->transform); + //FIXME assumes the entity is only rolled + sr = 2 * rot[0] * rot[3]; + cr = rot[3] * rot[3] - rot[0] * rot[0]; for (i = 0; i < 3; i++) { sw32_r_spritedesc.vpn[i] = vpn[i]; diff --git a/libs/video/renderer/sw32/sw32_rsurf.c b/libs/video/renderer/sw32/sw32_rsurf.c index 9badf0c96..9eba575a9 100644 --- a/libs/video/renderer/sw32/sw32_rsurf.c +++ b/libs/video/renderer/sw32/sw32_rsurf.c @@ -31,6 +31,7 @@ #define NH_DEFINE #include "namehack.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -96,6 +97,7 @@ R_AddDynamicLights (void) int sd, td; float dist, rad, minlight; vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1 }; int s, t; int i; int smax, tmax; @@ -106,12 +108,16 @@ R_AddDynamicLights (void) tmax = (surf->extents[1] >> 4) + 1; tex = surf->texinfo; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, - lightorigin); + VectorSubtract (r_dlights[lnum].origin, entorigin, lightorigin); rad = r_dlights[lnum].radius; dist = DotProduct (lightorigin, surf->plane->normal) - surf->plane->dist; @@ -172,7 +178,7 @@ R_BuildLightMap (void) size = smax * tmax; lightmap = surf->samples; - if (!r_worldentity.model->lightdata) { + if (!r_worldentity.renderer.model->brush.lightdata) { for (i = 0; i < size; i++) blocklights[i] = 0; return; diff --git a/libs/video/renderer/sw32/vid_common_sw32.c b/libs/video/renderer/sw32/vid_common_sw32.c index 279ee08d6..943fb2708 100644 --- a/libs/video/renderer/sw32/vid_common_sw32.c +++ b/libs/video/renderer/sw32/vid_common_sw32.c @@ -150,8 +150,8 @@ VID_MakeColormap16 (void *outcolormap, byte *pal) void VID_MakeColormaps (void) { - vid.colormap16 = malloc (256*VID_GRADES * sizeof (short)); - vid.colormap32 = malloc (256*VID_GRADES * sizeof (int)); + vid.colormap16 = malloc (256*VID_GRADES * sizeof (unsigned short)); + vid.colormap32 = malloc (256*VID_GRADES * sizeof (unsigned int)); SYS_CHECKMEM (vid.colormap16 && vid.colormap32); VID_MakeColormap16(vid.colormap16, vid.palette); VID_MakeColormap32(vid.colormap32, vid.palette); diff --git a/libs/video/renderer/vid_common.c b/libs/video/renderer/vid_common.c index 5a2cd9d43..74a1140b0 100644 --- a/libs/video/renderer/vid_common.c +++ b/libs/video/renderer/vid_common.c @@ -34,6 +34,8 @@ #include "mod_internal.h" #include "r_internal.h" +viddef_t vid; // global video state + vid_render_data_t vid_render_data = { &vid, &r_refdef, &scr_vrect, 0, 0, 0, diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index c79bfaa20..29f3eec9e 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -38,11 +38,15 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" +#include "vid_gl.h" #include "gl/namehack.h" +gl_ctx_t *gl_ctx; + static vid_model_funcs_t model_funcs = { - gl_Mod_LoadExternalTextures, + sizeof (gltex_t), gl_Mod_LoadLighting, gl_Mod_SubdivideSurface, gl_Mod_ProcessTexture, @@ -68,7 +72,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t gl_vid_render_funcs = { - gl_Draw_Init, gl_Draw_Character, gl_Draw_String, gl_Draw_nString, @@ -90,7 +93,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_Draw_Picf, gl_Draw_SubPic, - gl_SCR_UpdateScreen, + SCR_SetFOV, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -102,6 +105,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_Fog_ParseWorldspawn, gl_R_Init, + gl_R_RenderFrame, gl_R_ClearState, gl_R_LoadSkys, gl_R_NewMap, @@ -111,6 +115,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, gl_R_RenderView, R_DecayLights, gl_R_ViewChanged, @@ -123,12 +128,29 @@ vid_render_funcs_t gl_vid_render_funcs = { &model_funcs }; +static void +gl_vid_render_choose_visual (void) +{ + gl_ctx->choose_visual (gl_ctx); +} + +static void +gl_vid_render_create_context (void) +{ + gl_ctx->create_context (gl_ctx); +} + static void gl_vid_render_init (void) { - vr_data.vid->set_palette = GL_SetPalette; - vr_data.vid->init_gl = GL_Init_Common; - vr_data.vid->load_gl (); + gl_ctx = vr_data.vid->vid_internal->gl_context (); + gl_ctx->init_gl = GL_Init_Common; + gl_ctx->load_gl (); + + vr_data.vid->vid_internal->set_palette = GL_SetPalette; + vr_data.vid->vid_internal->choose_visual = gl_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = gl_vid_render_create_context; + vr_funcs = &gl_vid_render_funcs; m_funcs = &model_funcs; } @@ -166,7 +188,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index f09820ab3..60ab6068a 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -38,13 +38,17 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" +#include "vid_gl.h" #include "glsl/namehack.h" +gl_ctx_t *glsl_ctx; + static vid_model_funcs_t model_funcs = { - glsl_Mod_LoadExternalTextures, + sizeof (glsltex_t), glsl_Mod_LoadLighting, - glsl_Mod_SubdivideSurface, + 0,//Mod_SubdivideSurface, glsl_Mod_ProcessTexture, Mod_LoadIQM, @@ -68,7 +72,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t glsl_vid_render_funcs = { - glsl_Draw_Init, glsl_Draw_Character, glsl_Draw_String, glsl_Draw_nString, @@ -90,7 +93,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_Draw_Picf, glsl_Draw_SubPic, - glsl_SCR_UpdateScreen, + SCR_SetFOV, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -102,6 +105,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_Fog_ParseWorldspawn, glsl_R_Init, + glsl_R_RenderFrame, glsl_R_ClearState, glsl_R_LoadSkys, glsl_R_NewMap, @@ -111,6 +115,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, glsl_R_RenderView, R_DecayLights, glsl_R_ViewChanged, @@ -123,12 +128,28 @@ vid_render_funcs_t glsl_vid_render_funcs = { &model_funcs }; +static void +glsl_vid_render_choose_visual (void) +{ + glsl_ctx->choose_visual (glsl_ctx); +} + +static void +glsl_vid_render_create_context (void) +{ + glsl_ctx->create_context (glsl_ctx); +} + static void glsl_vid_render_init (void) { - vr_data.vid->set_palette = GLSL_SetPalette; - vr_data.vid->init_gl = GLSL_Init_Common; - vr_data.vid->load_gl (); + glsl_ctx = vr_data.vid->vid_internal->gl_context (); + glsl_ctx->init_gl = GLSL_Init_Common; + glsl_ctx->load_gl (); + + vr_data.vid->vid_internal->set_palette = GLSL_SetPalette; + vr_data.vid->vid_internal->choose_visual = glsl_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = glsl_vid_render_create_context; vr_funcs = &glsl_vid_render_funcs; m_funcs = &model_funcs; } @@ -166,7 +187,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 7ac10a4d4..470cd4733 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -1,5 +1,5 @@ /* - vid_render_gl.c + vid_render_sw.c SW version of the renderer @@ -33,12 +33,16 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" +#include "vid_sw.h" + +sw_ctx_t *sw_ctx; static vid_model_funcs_t model_funcs = { - sw_Mod_LoadExternalTextures, + 0, sw_Mod_LoadLighting, - sw_Mod_SubdivideSurface, - sw_Mod_ProcessTexture, + 0,//Mod_SubdivideSurface, + 0,//Mod_ProcessTexture, Mod_LoadIQM, Mod_LoadAliasModel, @@ -46,8 +50,8 @@ static vid_model_funcs_t model_funcs = { sw_Mod_MakeAliasModelDisplayLists, sw_Mod_LoadSkin, - sw_Mod_FinalizeAliasModel, - sw_Mod_LoadExternalSkins, + 0, + 0, sw_Mod_IQMFinish, 1, sw_Mod_SpriteLoadTexture, @@ -61,7 +65,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t sw_vid_render_funcs = { - Draw_Init, Draw_Character, Draw_String, Draw_nString, @@ -83,7 +86,7 @@ vid_render_funcs_t sw_vid_render_funcs = { Draw_Picf, Draw_SubPic, - SCR_UpdateScreen, + SCR_SetFOV, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -95,6 +98,7 @@ vid_render_funcs_t sw_vid_render_funcs = { 0, sw_R_Init, + R_RenderFrame, R_ClearState, R_LoadSkys, R_NewMap, @@ -104,6 +108,7 @@ vid_render_funcs_t sw_vid_render_funcs = { R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, R_RenderView, R_DecayLights, R_ViewChanged, @@ -116,9 +121,27 @@ vid_render_funcs_t sw_vid_render_funcs = { &model_funcs }; +static void +sw_vid_render_choose_visual (void) +{ + sw_ctx->choose_visual (sw_ctx); +} + +static void +sw_vid_render_create_context (void) +{ + sw_ctx->create_context (sw_ctx); +} + static void sw_vid_render_init (void) { + sw_ctx = vr_data.vid->vid_internal->sw_context (); + + vr_data.vid->vid_internal->set_palette = sw_ctx->set_palette; + vr_data.vid->vid_internal->choose_visual = sw_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = sw_vid_render_create_context; + vr_funcs = &sw_vid_render_funcs; m_funcs = &model_funcs; } @@ -156,7 +179,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 9bc135c78..d70521f79 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -36,14 +36,18 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" +#include "vid_sw.h" #include "sw32/namehack.h" +sw_ctx_t *sw32_ctx; + static vid_model_funcs_t model_funcs = { - sw_Mod_LoadExternalTextures, + 0, sw_Mod_LoadLighting, - sw_Mod_SubdivideSurface, - sw_Mod_ProcessTexture, + 0,//Mod_SubdivideSurface, + 0,//Mod_ProcessTexture, Mod_LoadIQM, Mod_LoadAliasModel, @@ -51,8 +55,8 @@ static vid_model_funcs_t model_funcs = { sw_Mod_MakeAliasModelDisplayLists, sw_Mod_LoadSkin, - sw_Mod_FinalizeAliasModel, - sw_Mod_LoadExternalSkins, + 0, + 0, sw_Mod_IQMFinish, 1, sw_Mod_SpriteLoadTexture, @@ -66,7 +70,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t sw32_vid_render_funcs = { - sw32_Draw_Init, sw32_Draw_Character, sw32_Draw_String, sw32_Draw_nString, @@ -88,7 +91,7 @@ vid_render_funcs_t sw32_vid_render_funcs = { sw32_Draw_Picf, sw32_Draw_SubPic, - sw32_SCR_UpdateScreen, + SCR_SetFOV, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -100,6 +103,7 @@ vid_render_funcs_t sw32_vid_render_funcs = { 0, sw32_R_Init, + sw32_R_RenderFrame, sw32_R_ClearState, sw32_R_LoadSkys, sw32_R_NewMap, @@ -109,6 +113,7 @@ vid_render_funcs_t sw32_vid_render_funcs = { sw32_R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, sw32_R_RenderView, R_DecayLights, sw32_R_ViewChanged, @@ -121,9 +126,27 @@ vid_render_funcs_t sw32_vid_render_funcs = { &model_funcs }; +static void +sw32_vid_render_choose_visual (void) +{ + sw32_ctx->choose_visual (sw32_ctx); +} + +static void +sw32_vid_render_create_context (void) +{ + sw32_ctx->create_context (sw32_ctx); +} + static void sw32_vid_render_init (void) { + sw32_ctx = vr_data.vid->vid_internal->sw_context (); + + vr_data.vid->vid_internal->set_palette = sw32_ctx->set_palette; + vr_data.vid->vid_internal->choose_visual = sw32_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = sw32_vid_render_create_context; + vr_funcs = &sw32_vid_render_funcs; m_funcs = &model_funcs; } @@ -161,7 +184,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c new file mode 100644 index 000000000..050d2affd --- /dev/null +++ b/libs/video/renderer/vid_render_vulkan.c @@ -0,0 +1,716 @@ +/* + vid_render_vulkan.c + + Vulkan version of the renderer + + Copyright (C) 2019 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "QF/darray.h" +#include "QF/dstring.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "QF/plugin/general.h" +#include "QF/plugin/vid_render.h" + +#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_compose.h" +#include "QF/Vulkan/qf_draw.h" +#include "QF/Vulkan/qf_lighting.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_main.h" +#include "QF/Vulkan/qf_particles.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/capture.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/swapchain.h" + +#include "mod_internal.h" +#include "r_internal.h" +#include "vid_internal.h" +#include "vid_vulkan.h" + +static vulkan_ctx_t *vulkan_ctx; + +static tex_t * +vulkan_SCR_CaptureBGR (void) +{ + return 0; +} + +static tex_t * +vulkan_SCR_ScreenShot (unsigned width, unsigned height) +{ + return 0; +} + +static void +vulkan_Fog_Update (float density, float red, float green, float blue, + float time) +{ +} + +static void +vulkan_Fog_ParseWorldspawn (struct plitem_s *worldspawn) +{ +} + +static void +vulkan_R_Init (void) +{ + Vulkan_CreateStagingBuffers (vulkan_ctx); + Vulkan_CreateMatrices (vulkan_ctx); + Vulkan_CreateSwapchain (vulkan_ctx); + Vulkan_CreateFrames (vulkan_ctx); + Vulkan_CreateCapture (vulkan_ctx); + Vulkan_CreateRenderPass (vulkan_ctx); + Vulkan_CreateFramebuffers (vulkan_ctx); + Vulkan_Texture_Init (vulkan_ctx); + Vulkan_Alias_Init (vulkan_ctx); + Vulkan_Bsp_Init (vulkan_ctx); + Vulkan_Draw_Init (vulkan_ctx); + Vulkan_Particles_Init (vulkan_ctx); + Vulkan_Lighting_Init (vulkan_ctx); + Vulkan_Compose_Init (vulkan_ctx); + Skin_Init (); + + SCR_Init (); +} + +static void +vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +{ + const VkSubpassContents subpassContents + = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS; + uint32_t imageIndex = 0; + qfv_device_t *device = vulkan_ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + VkDevice dev = device->dev; + qfv_queue_t *queue = &vulkan_ctx->device->queue; + + __auto_type frame = &vulkan_ctx->frames.a[vulkan_ctx->curFrame]; + + dfunc->vkWaitForFences (dev, 1, &frame->fence, VK_TRUE, 2000000000); + QFV_AcquireNextImage (vulkan_ctx->swapchain, + frame->imageAvailableSemaphore, + 0, &imageIndex); + vulkan_ctx->swapImageIndex = imageIndex; + + frame->framebuffer = vulkan_ctx->framebuffers->a[imageIndex]; + + scr_3dfunc (); + while (*scr_funcs) { + (*scr_funcs) (); + scr_funcs++; + } + + Vulkan_FlushText (vulkan_ctx); + + Vulkan_Lighting_Draw (vulkan_ctx); + Vulkan_Compose_Draw (vulkan_ctx); + + VkCommandBufferBeginInfo beginInfo + = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + VkRenderPassBeginInfo renderPassInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, + vulkan_ctx->renderpass, 0, + { {0, 0}, vulkan_ctx->swapchain->extent }, + vulkan_ctx->clearValues->size, vulkan_ctx->clearValues->a + }; + + dfunc->vkBeginCommandBuffer (frame->cmdBuffer, &beginInfo); + renderPassInfo.framebuffer = frame->framebuffer; + dfunc->vkCmdBeginRenderPass (frame->cmdBuffer, &renderPassInfo, + subpassContents); + + for (int i = 0; i < frame->cmdSetCount; i++) { + if (frame->cmdSets[i].size) { + dfunc->vkCmdExecuteCommands (frame->cmdBuffer, + frame->cmdSets[i].size, + frame->cmdSets[i].a); + } + // reset for next time around + frame->cmdSets[i].size = 0; + + if (i < frame->cmdSetCount - 1) { + dfunc->vkCmdNextSubpass (frame->cmdBuffer, subpassContents); + } + } + + dfunc->vkCmdEndRenderPass (frame->cmdBuffer); + if (vulkan_ctx->capture_callback) { + VkImage srcImage = vulkan_ctx->swapchain->images->a[imageIndex]; + VkCommandBuffer cmd = QFV_CaptureImage (vulkan_ctx->capture, srcImage, + vulkan_ctx->curFrame); + dfunc->vkCmdExecuteCommands (frame->cmdBuffer, 1, &cmd); + } + dfunc->vkEndCommandBuffer (frame->cmdBuffer); + + VkPipelineStageFlags waitStage + = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 1, &frame->imageAvailableSemaphore, &waitStage, + 1, &frame->cmdBuffer, + 1, &frame->renderDoneSemaphore, + }; + dfunc->vkResetFences (dev, 1, &frame->fence); + dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, frame->fence); + + if (vulkan_ctx->capture_callback) { + //FIXME look into "threading" this rather than waiting here + dfunc->vkWaitForFences (device->dev, 1, &frame->fence, VK_TRUE, + 1000000000ull); + vulkan_ctx->capture_callback (QFV_CaptureData (vulkan_ctx->capture, + vulkan_ctx->curFrame), + vulkan_ctx->capture->extent.width, + vulkan_ctx->capture->extent.height); + vulkan_ctx->capture_callback = 0; + } + + VkPresentInfoKHR presentInfo = { + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 0, + 1, &frame->renderDoneSemaphore, + 1, &vulkan_ctx->swapchain->swapchain, &imageIndex, + 0 + }; + dfunc->vkQueuePresentKHR (queue->queue, &presentInfo); + + vulkan_ctx->curFrame++; + vulkan_ctx->curFrame %= vulkan_ctx->frames.size; +} + +static void +vulkan_R_ClearState (void) +{ + R_ClearEfrags (); + R_ClearDlights (); + Vulkan_ClearParticles (vulkan_ctx); +} + +static void +vulkan_R_LoadSkys (const char *skyname) +{ + Vulkan_LoadSkys (skyname, vulkan_ctx); +} + +static void +vulkan_R_NewMap (model_t *worldmodel, model_t **models, int num_models) +{ + Vulkan_NewMap (worldmodel, models, num_models, vulkan_ctx); +} + +static void +vulkan_R_LineGraph (int x, int y, int *h_vals, int count) +{ +} + +static void +vulkan_R_RenderView (void) +{ + Vulkan_RenderView (vulkan_ctx); +} + +static void +vulkan_Draw_Character (int x, int y, unsigned ch) +{ + Vulkan_Draw_Character (x, y, ch, vulkan_ctx); +} + +static void +vulkan_Draw_String (int x, int y, const char *str) +{ + Vulkan_Draw_String (x, y, str, vulkan_ctx); +} + +static void +vulkan_Draw_nString (int x, int y, const char *str, int count) +{ + Vulkan_Draw_nString (x, y, str, count, vulkan_ctx); +} + +static void +vulkan_Draw_AltString (int x, int y, const char *str) +{ + Vulkan_Draw_AltString (x, y, str, vulkan_ctx); +} + +static void +vulkan_Draw_ConsoleBackground (int lines, byte alpha) +{ + Vulkan_Draw_ConsoleBackground (lines, alpha, vulkan_ctx); +} + +static void +vulkan_Draw_Crosshair (void) +{ + Vulkan_Draw_Crosshair (vulkan_ctx); +} + +static void +vulkan_Draw_CrosshairAt (int ch, int x, int y) +{ + Vulkan_Draw_CrosshairAt (ch, x, y, vulkan_ctx); +} + +static void +vulkan_Draw_TileClear (int x, int y, int w, int h) +{ + Vulkan_Draw_TileClear (x, y, w, h, vulkan_ctx); +} + +static void +vulkan_Draw_Fill (int x, int y, int w, int h, int c) +{ + Vulkan_Draw_Fill (x, y, w, h, c, vulkan_ctx); +} + +static void +vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha) +{ + Vulkan_Draw_TextBox (x, y, width, lines, alpha, vulkan_ctx); +} + +static void +vulkan_Draw_FadeScreen (void) +{ + Vulkan_Draw_FadeScreen (vulkan_ctx); +} + +static void +vulkan_Draw_BlendScreen (quat_t color) +{ + Vulkan_Draw_BlendScreen (color, vulkan_ctx); +} + +static qpic_t * +vulkan_Draw_CachePic (const char *path, qboolean alpha) +{ + return Vulkan_Draw_CachePic (path, alpha, vulkan_ctx); +} + +static void +vulkan_Draw_UncachePic (const char *path) +{ + Vulkan_Draw_UncachePic (path, vulkan_ctx); +} + +static qpic_t * +vulkan_Draw_MakePic (int width, int height, const byte *data) +{ + return Vulkan_Draw_MakePic (width, height, data, vulkan_ctx); +} + +static void +vulkan_Draw_DestroyPic (qpic_t *pic) +{ + Vulkan_Draw_DestroyPic (pic, vulkan_ctx); +} + +static qpic_t * +vulkan_Draw_PicFromWad (const char *name) +{ + return Vulkan_Draw_PicFromWad (name, vulkan_ctx); +} + +static void +vulkan_Draw_Pic (int x, int y, qpic_t *pic) +{ + Vulkan_Draw_Pic (x, y, pic, vulkan_ctx); +} + +static void +vulkan_Draw_Picf (float x, float y, qpic_t *pic) +{ + Vulkan_Draw_Picf (x, y, pic, vulkan_ctx); +} + +static void +vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height) +{ + Vulkan_Draw_SubPic (x, y, pic, srcx, srcy, width, height, vulkan_ctx); +} + +static void +vulkan_R_ViewChanged (float aspect) +{ + Vulkan_CalcProjectionMatrices (vulkan_ctx, aspect); +} + +static void +vulkan_R_ClearParticles (void) +{ + Vulkan_ClearParticles (vulkan_ctx); +} + +static void +vulkan_R_InitParticles (void) +{ + Vulkan_InitParticles (vulkan_ctx); +} + +static int +is_bgr (VkFormat format) +{ + return (format >= VK_FORMAT_B8G8R8A8_UNORM + && format <= VK_FORMAT_B8G8R8A8_SRGB); +} + +static void +capture_screenshot (const byte *data, int width, int height) +{ + dstring_t *name = dstring_new (); + // find a file name to save it to + if (!QFS_NextFilename (name, va (vulkan_ctx->va_ctx, "%s/qf", + qfs_gamedir->dir.shots), + ".ppm")) { + Sys_Printf ("SCR_ScreenShot_f: Couldn't create a ppm file\n"); + } else { + QFile *file = QFS_Open (name->str, "wb"); + if (!file) { + Sys_Printf ("Couldn't open %s\n", name->str); + } else { + Qprintf (file, "P6\n%d\n%d\n255\n", width, height); + if (vulkan_ctx->capture->canBlit || + !is_bgr (vulkan_ctx->swapchain->format)) { + for (int count = width * height; count-- > 0; ) { + Qwrite (file, data, 3); + data += 4; + } + } else { + for (int count = width * height; count-- > 0; ) { + byte rgb[] = { data[2], data[1], data[0] }; + Qwrite (file, rgb, 3); + data += 4; + } + } + Qclose (file); + } + } + dstring_delete (name); +} + +static void +vulkan_SCR_ScreenShot_f (void) +{ + if (!vulkan_ctx->capture) { + Sys_Printf ("Screenshot not supported\n"); + return; + } + vulkan_ctx->capture_callback = capture_screenshot; +} + +static void +vulkan_r_easter_eggs_f (struct cvar_s *var) +{ + Vulkan_r_easter_eggs_f (var, vulkan_ctx); +} + +static void +vulkan_r_particles_style_f (struct cvar_s *var) +{ + Vulkan_r_particles_style_f (var, vulkan_ctx); +} + +static void +vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp) +{ + Vulkan_Mod_LoadLighting (mod, bsp, vulkan_ctx); +} + +static void +vulkan_Mod_SubdivideSurface (model_t *mod, msurface_t *fa) +{ +} + +static void +vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx) +{ + Vulkan_Mod_ProcessTexture (mod, tx, vulkan_ctx); +} + +static void +vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, + void *_m, int _s, int extra) +{ + Vulkan_Mod_MakeAliasModelDisplayLists (alias_ctx, _m, _s, extra, + vulkan_ctx); +} + +static void * +vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc) +{ + return Vulkan_Mod_LoadSkin (alias_ctx, skin, skinsize, snum, gnum, group, + skindesc, vulkan_ctx); +} + +static void +vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) +{ + Vulkan_Mod_FinalizeAliasModel (alias_ctx, vulkan_ctx); +} + +static void +vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx) +{ +} + +static void +vulkan_Mod_IQMFinish (model_t *mod) +{ +} + +static void +vulkan_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) +{ +} + +static void +vulkan_Skin_SetupSkin (struct skin_s *skin, int cmap) +{ +} + +static void +vulkan_Skin_ProcessTranslation (int cmap, const byte *translation) +{ +} + +static void +vulkan_Skin_InitTranslations (void) +{ +} + +static vid_model_funcs_t model_funcs = { + sizeof (vulktex_t) + 2 * sizeof (qfv_tex_t), + vulkan_Mod_LoadLighting, + vulkan_Mod_SubdivideSurface, + vulkan_Mod_ProcessTexture, + + Mod_LoadIQM, + Mod_LoadAliasModel, + Mod_LoadSpriteModel, + + vulkan_Mod_MakeAliasModelDisplayLists, + vulkan_Mod_LoadSkin, + vulkan_Mod_FinalizeAliasModel, + vulkan_Mod_LoadExternalSkins, + vulkan_Mod_IQMFinish, + 0, + vulkan_Mod_SpriteLoadTexture, + + Skin_SetColormap, + Skin_SetSkin, + vulkan_Skin_SetupSkin, + Skin_SetTranslation, + vulkan_Skin_ProcessTranslation, + vulkan_Skin_InitTranslations, +}; + +vid_render_funcs_t vulkan_vid_render_funcs = { + vulkan_Draw_Character, + vulkan_Draw_String, + vulkan_Draw_nString, + vulkan_Draw_AltString, + vulkan_Draw_ConsoleBackground, + vulkan_Draw_Crosshair, + vulkan_Draw_CrosshairAt, + vulkan_Draw_TileClear, + vulkan_Draw_Fill, + vulkan_Draw_TextBox, + vulkan_Draw_FadeScreen, + vulkan_Draw_BlendScreen, + vulkan_Draw_CachePic, + vulkan_Draw_UncachePic, + vulkan_Draw_MakePic, + vulkan_Draw_DestroyPic, + vulkan_Draw_PicFromWad, + vulkan_Draw_Pic, + vulkan_Draw_Picf, + vulkan_Draw_SubPic, + + SCR_SetFOV, + SCR_DrawRam, + SCR_DrawTurtle, + SCR_DrawPause, + vulkan_SCR_CaptureBGR, + vulkan_SCR_ScreenShot, + SCR_DrawStringToSnap, + + vulkan_Fog_Update, + vulkan_Fog_ParseWorldspawn, + + vulkan_R_Init, + vulkan_R_RenderFrame, + vulkan_R_ClearState, + vulkan_R_LoadSkys, + vulkan_R_NewMap, + R_AddEfrags, + R_RemoveEfrags, + R_EnqueueEntity, + vulkan_R_LineGraph, + R_AllocDlight, + R_AllocEntity, + R_MaxDlightsCheck, + vulkan_R_RenderView, + R_DecayLights, + vulkan_R_ViewChanged, + vulkan_R_ClearParticles, + vulkan_R_InitParticles, + vulkan_SCR_ScreenShot_f, + vulkan_r_easter_eggs_f, + vulkan_r_particles_style_f, + 0, + &model_funcs +}; + +static void +set_palette (const byte *palette) +{ + //FIXME really don't want this here: need an application domain + //so Quake can be separated from QuakeForge (ie, Quake itself becomes + //an app using the QuakeForge engine) +} + +static void +vulkan_vid_render_choose_visual (void) +{ + Vulkan_CreateDevice (vulkan_ctx); + vulkan_ctx->choose_visual (vulkan_ctx); + vulkan_ctx->cmdpool = QFV_CreateCommandPool (vulkan_ctx->device, + vulkan_ctx->device->queue.queueFamily, + 0, 1); + __auto_type cmdset = QFV_AllocCommandBufferSet (1, alloca); + QFV_AllocateCommandBuffers (vulkan_ctx->device, vulkan_ctx->cmdpool, 0, + cmdset); + vulkan_ctx->cmdbuffer = cmdset->a[0]; + vulkan_ctx->fence = QFV_CreateFence (vulkan_ctx->device, 1); + Sys_MaskPrintf (SYS_VULKAN, "vk choose visual %p %p %d %p\n", + vulkan_ctx->device->dev, vulkan_ctx->device->queue.queue, + vulkan_ctx->device->queue.queueFamily, + vulkan_ctx->cmdpool); +} + +static void +vulkan_vid_render_create_context (void) +{ + vulkan_ctx->create_window (vulkan_ctx); + vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx); + Sys_MaskPrintf (SYS_VULKAN, "vk create context %p\n", vulkan_ctx->surface); +} + +static void +vulkan_vid_render_init (void) +{ + vulkan_ctx = vr_data.vid->vid_internal->vulkan_context (); + vulkan_ctx->load_vulkan (vulkan_ctx); + + Vulkan_Init_Common (vulkan_ctx); + + vr_data.vid->vid_internal->set_palette = set_palette; + vr_data.vid->vid_internal->choose_visual = vulkan_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = vulkan_vid_render_create_context; + + vr_funcs = &vulkan_vid_render_funcs; + m_funcs = &model_funcs; +} + +static void +vulkan_vid_render_shutdown (void) +{ + qfv_device_t *device = vulkan_ctx->device; + qfv_devfuncs_t *df = device->funcs; + VkDevice dev = device->dev; + QFV_DeviceWaitIdle (device); + df->vkDestroyFence (dev, vulkan_ctx->fence, 0); + df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); + Vulkan_Compose_Shutdown (vulkan_ctx); + Vulkan_Lighting_Shutdown (vulkan_ctx); + Vulkan_Draw_Shutdown (vulkan_ctx); + Vulkan_Bsp_Shutdown (vulkan_ctx); + Vulkan_Alias_Shutdown (vulkan_ctx); + Mod_ClearAll (); + Vulkan_Texture_Shutdown (vulkan_ctx); + Vulkan_DestroyFramebuffers (vulkan_ctx); + Vulkan_DestroyRenderPass (vulkan_ctx); + Vulkan_Shutdown_Common (vulkan_ctx); +} + +static general_funcs_t plugin_info_general_funcs = { + vulkan_vid_render_init, + vulkan_vid_render_shutdown, +}; + +static general_data_t plugin_info_general_data; + +static plugin_funcs_t plugin_info_funcs = { + &plugin_info_general_funcs, + 0, + 0, + 0, + 0, + 0, + &vulkan_vid_render_funcs, +}; + +static plugin_data_t plugin_info_data = { + &plugin_info_general_data, + 0, + 0, + 0, + 0, + 0, + &vid_render_data, +}; + +static plugin_t plugin_info = { + qfp_vid_render, + 0, + QFPLUGIN_VERSION, + "0.1", + "Vulkan Renderer", + "Copyright (C) 1996-1997 Id Software, Inc.\n" + "Copyright (C) 1999-2019 contributors of the QuakeForge project\n" + "Please see the file \"AUTHORS\" for a list of contributors", + &plugin_info_funcs, + &plugin_info_data, +}; + +PLUGIN_INFO(vid_render, vulkan) +{ + return &plugin_info; +} diff --git a/libs/video/renderer/vulkan/barrier.c b/libs/video/renderer/vulkan/barrier.c new file mode 100644 index 000000000..935b370e0 --- /dev/null +++ b/libs/video/renderer/vulkan/barrier.c @@ -0,0 +1,101 @@ +/* + barrier.c + + Memory barrier helpers + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" + +const VkImageMemoryBarrier imageLayoutTransitionBarriers[] = { + // undefined -> transfer dst optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + // transfer dst optimal -> shader read only optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + // shader read only optimal -> transfer dst optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_SHADER_READ_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + // undefined -> depth stencil attachment optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 } + }, + // undefined -> color attachment optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + { /* end of transition barriers */ } +}; + +const qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { + // undefined -> transfer dst optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT }, + // transfer dst optimal -> shader read only optimal + { VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, + // shader read only optimal -> transfer dst optimal + { VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT }, + // undefined -> depth stencil attachment optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT }, + // undefined -> color attachment optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }, +}; diff --git a/libs/video/renderer/vulkan/buffer.c b/libs/video/renderer/vulkan/buffer.c new file mode 100644 index 000000000..71b094e68 --- /dev/null +++ b/libs/video/renderer/vulkan/buffer.c @@ -0,0 +1,165 @@ +/* + buffer.c + + Vulkan buffer functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/memory.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +VkBuffer +QFV_CreateBuffer (qfv_device_t *device, VkDeviceSize size, + VkBufferUsageFlags usage) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkBufferCreateInfo createInfo = { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, + 0, + size, usage, VK_SHARING_MODE_EXCLUSIVE, + 0, 0 + }; + VkBuffer buffer; + dfunc->vkCreateBuffer (dev, &createInfo, 0, &buffer); + return buffer; +} + +VkDeviceMemory +QFV_AllocBufferMemory (qfv_device_t *device, + VkBuffer buffer, VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset) +{ + VkDevice dev = device->dev; + qfv_physdev_t *physdev = device->physDev; + VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties; + qfv_devfuncs_t *dfunc = device->funcs; + + VkMemoryRequirements requirements; + dfunc->vkGetBufferMemoryRequirements (dev, buffer, &requirements); + + size = max (size, offset + requirements.size); + VkDeviceMemory object = 0; + + for (uint32_t type = 0; type < memprops->memoryTypeCount; type++) { + if ((requirements.memoryTypeBits & (1 << type)) + && ((memprops->memoryTypes[type].propertyFlags & properties) + == properties)) { + VkMemoryAllocateInfo allocate_info = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, + size, type + }; + + VkResult res = dfunc->vkAllocateMemory (dev, &allocate_info, + 0, &object); + if (res == VK_SUCCESS) { + break; + } + } + } + + return object; +} + +int +QFV_BindBufferMemory (qfv_device_t *device, + VkBuffer buffer, VkDeviceMemory object, + VkDeviceSize offset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkResult res = dfunc->vkBindBufferMemory (dev, buffer, object, offset); + return res == VK_SUCCESS; +} + +qfv_bufferbarrierset_t * +QFV_CreateBufferTransitions (qfv_buffertransition_t *transitions, + int numTransitions) +{ + qfv_bufferbarrierset_t *barrierset; + barrierset = DARRAY_ALLOCFIXED (*barrierset, numTransitions, malloc); + + for (int i = 0; i < numTransitions; i++) { + barrierset->a[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrierset->a[i].pNext = 0; + barrierset->a[i].srcAccessMask = transitions[i].srcAccess; + barrierset->a[i].dstAccessMask = transitions[i].dstAccess; + barrierset->a[i].srcQueueFamilyIndex = transitions[i].srcQueueFamily; + barrierset->a[i].dstQueueFamilyIndex = transitions[i].dstQueueFamily; + barrierset->a[i].buffer = transitions[i].buffer; + barrierset->a[i].offset = transitions[i].offset; + barrierset->a[i].size = transitions[i].size; + } + return barrierset; +} + +VkBufferView +QFV_CreateBufferView (qfv_device_t *device, VkBuffer buffer, VkFormat format, + VkDeviceSize offset, VkDeviceSize size) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkBufferViewCreateInfo createInfo = { + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, 0, + 0, + buffer, format, offset, size, + }; + + VkBufferView view; + dfunc->vkCreateBufferView (dev, &createInfo, 0, &view); + return view; +} diff --git a/libs/video/renderer/vulkan/capture.c b/libs/video/renderer/vulkan/capture.c new file mode 100644 index 000000000..1fa0d8193 --- /dev/null +++ b/libs/video/renderer/vulkan/capture.c @@ -0,0 +1,270 @@ +/* + capture.c + + Vulkan frame capture support + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/capture.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/swapchain.h" + +#include "vid_vulkan.h" + +qfv_capture_t * +QFV_CreateCapture (qfv_device_t *device, int numframes, + qfv_swapchain_t *swapchain, VkCommandPool cmdPool) +{ + qfv_instfuncs_t *ifunc = device->physDev->instance->funcs; + qfv_devfuncs_t *dfunc = device->funcs; + VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; + int canBlit = 1; + + VkFormatProperties format_props; + ifunc->vkGetPhysicalDeviceFormatProperties (device->physDev->dev, + swapchain->format, + &format_props); + if (!(swapchain->usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) { + Sys_Printf ("Swapchain does not support reading. FIXME\n"); + return 0; + } + if (!(format_props.optimalTilingFeatures + & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) { + Sys_MaskPrintf (SYS_VULKAN, + "Device does not support blitting from optimal tiled " + "images.\n"); + canBlit = 0; + } + ifunc->vkGetPhysicalDeviceFormatProperties (device->physDev->dev, format, + &format_props); + if (!(format_props.linearTilingFeatures + & VK_FORMAT_FEATURE_BLIT_DST_BIT)) { + Sys_MaskPrintf (SYS_VULKAN, + "Device does not support blitting from optimal tiled " + "images.\n"); + canBlit = 0; + } + + qfv_capture_t *capture = malloc (sizeof (qfv_capture_t)); + capture->device = device; + capture->canBlit = canBlit; + capture->extent = swapchain->extent; + capture->image_set = QFV_AllocCaptureImageSet (numframes, malloc); + + __auto_type cmdset = QFV_AllocCommandBufferSet (numframes, alloca); + QFV_AllocateCommandBuffers (device, cmdPool, 1, cmdset); + + VkImageCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = format, + .extent = { swapchain->extent.width, swapchain->extent.height, 1 }, + .arrayLayers = 1, + .mipLevels = 1, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT, + }; + + for (int i = 0; i < numframes; i++) { + __auto_type image = &capture->image_set->a[i]; + dfunc->vkCreateImage (device->dev, &createInfo, 0, &image->image); + image->layout = VK_IMAGE_LAYOUT_UNDEFINED; + image->cmd = cmdset->a[i]; + } + size_t image_size = QFV_GetImageSize (device, + capture->image_set->a[0].image); + capture->memsize = numframes * image_size; + capture->memory = QFV_AllocImageMemory (device, + capture->image_set->a[0].image, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + capture->memsize, 0); + byte *data; + dfunc->vkMapMemory (device->dev, capture->memory, 0, capture->memsize, 0, + (void **) &data); + + for (int i = 0; i < numframes; i++) { + __auto_type image = &capture->image_set->a[i]; + image->data = data + i * image_size; + dfunc->vkBindImageMemory (device->dev, image->image, capture->memory, + image->data - data); + } + return capture; +} + +void +QFV_DestroyCapture (qfv_capture_t *capture) +{ + qfv_device_t *device = capture->device; + qfv_devfuncs_t *dfunc = device->funcs; + + for (size_t i = 0; i < capture->image_set->size; i++) { + __auto_type image = &capture->image_set->a[i]; + dfunc->vkDestroyImage (device->dev, image->image, 0); + } + dfunc->vkUnmapMemory (device->dev, capture->memory); + dfunc->vkFreeMemory (device->dev, capture->memory, 0); + free (capture->image_set); + free (capture); +} + +static void +blit_image (qfv_capture_t *capture, qfv_devfuncs_t *dfunc, + VkImage scImage, qfv_capture_image_t *image) +{ + VkImageBlit blit = { + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, + { { }, { capture->extent.width, capture->extent.height, 1 } }, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, + { { }, { capture->extent.width, capture->extent.height, 1 } }, + }; + dfunc->vkCmdBlitImage (image->cmd, + scImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + 1, &blit, VK_FILTER_NEAREST); +} + +static void +copy_image (qfv_capture_t *capture, qfv_devfuncs_t *dfunc, + VkImage scImage, qfv_capture_image_t *image) +{ + VkImageCopy copy = { + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, { }, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, { }, + { capture->extent.width, capture->extent.height, 1 }, + }; + dfunc->vkCmdCopyImage (image->cmd, + scImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©); +} + +VkCommandBuffer +QFV_CaptureImage (qfv_capture_t *capture, VkImage scImage, int frame) +{ + qfv_device_t *device = capture->device; + qfv_devfuncs_t *dfunc = device->funcs; + __auto_type image = &capture->image_set->a[frame]; + + dfunc->vkResetCommandBuffer (image->cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + 0, 0, 0, 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (image->cmd, &beginInfo); + + VkImageMemoryBarrier start_barriers[] = { + { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = image->layout, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .image = image->image, + .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, + }, + { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .image = scImage, + .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, + }, + }; + VkImageMemoryBarrier end_barriers[] = { + { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .image = image->image, + .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, + }, + { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + .image = scImage, + .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, + }, + }; + + dfunc->vkCmdPipelineBarrier (image->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 0, 0, + 2, start_barriers); + + if (capture->canBlit) { + blit_image (capture, dfunc, scImage, image); + } else { + copy_image (capture, dfunc, scImage, image); + } + + dfunc->vkCmdPipelineBarrier (image->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 0, 0, + 2, end_barriers); + image->layout = VK_IMAGE_LAYOUT_GENERAL; + + dfunc->vkEndCommandBuffer (image->cmd); + + return image->cmd; +} + +const byte * +QFV_CaptureData (qfv_capture_t *capture, int frame) +{ + __auto_type image = &capture->image_set->a[frame]; + return image->data; +} diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c new file mode 100644 index 000000000..10f0cc559 --- /dev/null +++ b/libs/video/renderer/vulkan/command.c @@ -0,0 +1,165 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2019 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h"//FIXME should QFV_CmdPipelineBarrier be here? +#include "QF/Vulkan/image.h"//FIXME should QFV_CmdPipelineBarrier be here? +#include "QF/Vulkan/renderpass.h"//FIXME should QFV_CmdPipelineBarrier be here? +#include "QF/Vulkan/pipeline.h"//FIXME should QFV_CmdPipelineBarrier be here? +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +VkCommandPool +QFV_CreateCommandPool (qfv_device_t *device, uint32_t queueFamily, + int transient, int reset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + uint32_t flags = 0; + if (transient) { + flags |= VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + } + if (reset) { + flags |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + } + VkCommandPoolCreateInfo createInfo = { + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, + flags, + queueFamily + }; + VkCommandPool pool; + dfunc->vkCreateCommandPool (dev, &createInfo, 0, &pool); + return pool; +} + +int +QFV_AllocateCommandBuffers (qfv_device_t *device, VkCommandPool pool, + int secondary, qfv_cmdbufferset_t *bufferset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + uint32_t level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + if (secondary) { + level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + } + VkCommandBufferAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, + pool, level, bufferset->size + }; + int ret = dfunc->vkAllocateCommandBuffers (dev, &allocInfo, bufferset->a); + return ret == VK_SUCCESS; +} + +VkSemaphore +QFV_CreateSemaphore (qfv_device_t *device) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkSemaphoreCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 0, + 0 + }; + + VkSemaphore semaphore; + dfunc->vkCreateSemaphore (dev, &createInfo, 0, &semaphore); + return semaphore; +} + +VkFence +QFV_CreateFence (qfv_device_t *device, int signaled) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkFenceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 0, + signaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0, + }; + + VkFence fence; + dfunc->vkCreateFence (dev, &createInfo, 0, &fence); + return fence; +} + +int +QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, + VkPipelineStageFlags *stages, + qfv_cmdbufferset_t *buffers, + qfv_semaphoreset_t *signalSemaphores, VkFence fence) +{ + qfv_device_t *device = queue->device; + qfv_devfuncs_t *dfunc = device->funcs; + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + waitSemaphores->size, waitSemaphores->a, stages, + buffers->size, buffers->a, + signalSemaphores->size, signalSemaphores->a + }; + //FIXME multi-batch + return dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, fence) + == VK_SUCCESS; +} + +int +QFV_QueueWaitIdle (qfv_queue_t *queue) +{ + qfv_device_t *device = queue->device; + qfv_devfuncs_t *dfunc = device->funcs; + return dfunc->vkQueueWaitIdle (queue->queue) == VK_SUCCESS; +} diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist new file mode 100644 index 000000000..d956a5792 --- /dev/null +++ b/libs/video/renderer/vulkan/deferred.plist @@ -0,0 +1,473 @@ +{ + images = { + depth = { + imageType = VK_IMAGE_TYPE_2D; //FIXME short form is 2d... + format = x8_d24_unorm_pack32; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = depth_stencil_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + color = { + imageType = VK_IMAGE_TYPE_2D; + format = r8g8b8a8_unorm; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + emission = { + imageType = VK_IMAGE_TYPE_2D; + format = r16g16b16a16_sfloat; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + normal = { + imageType = VK_IMAGE_TYPE_2D; + format = r16g16b16a16_sfloat; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + position = { + imageType = VK_IMAGE_TYPE_2D; + format = r32g32b32a32_sfloat; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + opaque = { + imageType = VK_IMAGE_TYPE_2D; + format = r8g8b8a8_unorm; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + translucent = { + imageType = VK_IMAGE_TYPE_2D; + format = r8g8b8a8_unorm; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + }; + imageViews = { + depth = { + image = depth; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.depth.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = depth; + levelCount = 1; + layerCount = 1; + }; + }; + color = { + image = color; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.color.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + emission = { + image = emission; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.emission.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + normal = { + image = normal; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.normal.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + position = { + image = position; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.position.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + opaque = { + image = opaque; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.opaque.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + translucent = { + image = translucent; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.translucent.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + }; + framebuffer = { + renderPass = $properties.renderpass; + attachments = (depth, color, emission, normal, position, opaque, + translucent, "$swapchain.views[$swapImageIndex]"); + width = $swapchain.extent.width; + height = $swapchain.extent.height; + layers = 1; + }; + clearValues = ( + { depthStencil = { depth = 1; stencil = 0; }; }, + { color = "[0, 0, 0, 1]"; }, // color + { color = "[0, 0, 0, 1]"; }, // emission + { color = "[0, 0, 0, 1]"; }, // normal + { color = "[0, 0, 0, 1]"; }, // position + { color = "[0, 0, 0, 1]"; }, // opaque + { color = "[0, 0, 0, 0]"; }, // translucent + { color = "[0, 0, 0, 1]"; }, // swapchain + ); + renderpass = { + attachments = ( + { + format = $properties.images.depth.format; + samples = 1; + loadOp = clear; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = depth_stencil_attachment_optimal; + }, + { + format = $properties.images.color.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.emission.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.normal.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.position.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.opaque.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.translucent.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $swapchain.format; + samples = 1; + loadOp = clear; + storeOp = store; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = present_src_khr; + }, + ); + subpasses = ( + { // 0 depth + pipelineBindPoint = graphics; + depthStencilAttachment = { + attachment = 0; + layout = depth_stencil_attachment_optimal; + }; + }, + { // 1 translucent + pipelineBindPoint = graphics; + colorAttachments = ( + { // translucent + attachment = 6; + layout = color_attachment_optimal; + }, + ); + depthStencilAttachment = { + attachment = 0; + layout = depth_stencil_read_only_optimal; + }; + preserveAttachments = (1, 2, 3, 4, 5); + }, + { // 2 g-buffer generation + pipelineBindPoint = graphics; + colorAttachments = ( + { // color + attachment = 1; + layout = color_attachment_optimal; + }, + { // emission + attachment = 2; + layout = color_attachment_optimal; + }, + { // normal + attachment = 3; + layout = color_attachment_optimal; + }, + { // position + attachment = 4; + layout = color_attachment_optimal; + }, + ); + depthStencilAttachment = { + attachment = 0; + layout = depth_stencil_read_only_optimal; + }; + preserveAttachments = (6); + }, + { // 3 lighting + pipelineBindPoint = graphics; + inputAttachments = ( + { // depth + attachment = 0; + layout = shader_read_only_optimal; + }, + { // color + attachment = 1; + layout = shader_read_only_optimal; + }, + { // emission + attachment = 2; + layout = shader_read_only_optimal; + }, + { // normal + attachment = 3; + layout = shader_read_only_optimal; + }, + { // position + attachment = 4; + layout = shader_read_only_optimal; + }, + ); + colorAttachments = ( + { // opaque + attachment = 5; + layout = color_attachment_optimal; + }, + ); + preserveAttachments = (6); + }, + { // 4 compose + pipelineBindPoint = graphics; + inputAttachments = ( + { // opaque + attachment = 5; + layout = shader_read_only_optimal; + }, + { // translucent + attachment = 6; + layout = shader_read_only_optimal; + }, + ); + colorAttachments = ( + { // swapchain + attachment = 7; + layout = color_attachment_optimal; + }, + ); + preserveAttachments = (0, 1, 2, 3, 4); + }, + ); + dependencies = ( + { + srcSubpass = 0; // depth + dstSubpass = 1; // translucent + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 0; // depth + dstSubpass = 2; // g-buffer + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 2; // g-buffer + dstSubpass = 3; // lighting + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 3; // lighting + dstSubpass = 4; // compose + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 1; // translucent + dstSubpass = 4; // compose + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + ); + }; +} diff --git a/libs/video/renderer/vulkan/descriptor.c b/libs/video/renderer/vulkan/descriptor.c new file mode 100644 index 000000000..dc7cc6fa4 --- /dev/null +++ b/libs/video/renderer/vulkan/descriptor.c @@ -0,0 +1,197 @@ +/* + descriptor.c + + Vulkan descriptor functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +VkSampler +QFV_CreateSampler (qfv_device_t *device, + VkFilter magFilter, VkFilter minFilter, + VkSamplerMipmapMode mipmapMode, + VkSamplerAddressMode addressModeU, + VkSamplerAddressMode addressModeV, + VkSamplerAddressMode addressModeW, + float mipLodBias, + VkBool32 anisotryEnable, float maxAnisotropy, + VkBool32 compareEnable, VkCompareOp compareOp, + float minLod, float maxLod, + VkBorderColor borderColor, + VkBool32 unnormalizedCoordinates) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkSamplerCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 0, + 0, + magFilter, minFilter, mipmapMode, + addressModeU, addressModeV, addressModeW, + mipLodBias, + anisotryEnable, maxAnisotropy, + compareEnable, compareOp, + minLod, maxLod, + borderColor, unnormalizedCoordinates, + }; + + VkSampler sampler; + dfunc->vkCreateSampler (dev, &createInfo, 0, &sampler); + return sampler; +} + +VkDescriptorSetLayout +QFV_CreateDescriptorSetLayout (qfv_device_t *device, + qfv_bindingset_t *bindingset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkDescriptorSetLayoutCreateInfo createInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 0, + 0, + bindingset->size, bindingset->a, + }; + + VkDescriptorSetLayout layout; + dfunc->vkCreateDescriptorSetLayout (dev, &createInfo, 0, &layout); + return layout; +} + +// There are currently only 13 descriptor types, so 16 should be plenty +static VkDescriptorPoolSize poolsize_pool[16]; +static VkDescriptorPoolSize *poolsize_next; + +static uintptr_t +poolsize_gethash (const void *ele, void *unused) +{ + const VkDescriptorPoolSize *poolsize = ele; + return poolsize->type; +} + +static int +poolsize_compmare (const void *ele1, const void *ele2, void *unused) +{ + const VkDescriptorPoolSize *poolsize1 = ele1; + const VkDescriptorPoolSize *poolsize2 = ele2; + return poolsize1->type == poolsize2->type; +} + +//FIXME not thread-safe +VkDescriptorPool +QFV_CreateDescriptorPool (qfv_device_t *device, + VkDescriptorPoolCreateFlags flags, uint32_t maxSets, + qfv_bindingset_t *bindings) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + static hashtab_t *poolsizes; + + if (!poolsizes) { + poolsizes = Hash_NewTable (16, 0, 0, 0, 0);//FIXME threads + Hash_SetHashCompare (poolsizes, poolsize_gethash, poolsize_compmare); + } else { + Hash_FlushTable (poolsizes); + } + poolsize_next = poolsize_pool; + + VkDescriptorPoolSize *ps; + for (size_t i = 0; i < bindings->size; i++) { + VkDescriptorPoolSize test = { bindings->a[i].descriptorType, 0 }; + ps = Hash_FindElement (poolsizes, &test); + if (!ps) { + ps = poolsize_next++; + if ((size_t) (poolsize_next - poolsize_pool) + > sizeof (poolsize_pool) / sizeof (poolsize_pool[0])) { + Sys_Error ("Too many descriptor types"); + } + Hash_AddElement (poolsizes, ps); + } + //XXX is descriptorCount correct? + //FIXME assumes only one layout is used with this pool + ps->descriptorCount += bindings->a[i].descriptorCount * maxSets; + } + + VkDescriptorPoolCreateInfo createInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 0, + flags, maxSets, poolsize_next - poolsize_pool, poolsize_pool, + }; + + VkDescriptorPool pool; + dfunc->vkCreateDescriptorPool (dev, &createInfo, 0, &pool); + return pool; +} + +qfv_descriptorsets_t * +QFV_AllocateDescriptorSet (qfv_device_t *device, + VkDescriptorPool pool, + qfv_descriptorsetlayoutset_t *layouts) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkDescriptorSetAllocateInfo allocateInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 0, + pool, layouts->size, layouts->a, + }; + + __auto_type descriptorsets + = QFV_AllocDescriptorSets (layouts->size, malloc); + dfunc->vkAllocateDescriptorSets (dev, &allocateInfo, descriptorsets->a); + return descriptorsets; +} diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c new file mode 100644 index 000000000..778c98273 --- /dev/null +++ b/libs/video/renderer/vulkan/device.c @@ -0,0 +1,239 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2019 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +static int __attribute__((const)) +count_bits (uint32_t val) +{ + int bits = 0; + while (val) { + bits += val & 1; + val >>= 1; + } + return bits; +} + +static int +find_queue_family (qfv_instance_t *instance, VkPhysicalDevice dev, + uint32_t flags) +{ + qfv_instfuncs_t *funcs = instance->funcs; + uint32_t numFamilies; + VkQueueFamilyProperties *queueFamilies; + int best_diff = 32; + uint32_t family = -1; + + funcs->vkGetPhysicalDeviceQueueFamilyProperties (dev, &numFamilies, 0); + queueFamilies = alloca (numFamilies * sizeof (*queueFamilies)); + funcs->vkGetPhysicalDeviceQueueFamilyProperties (dev, &numFamilies, + queueFamilies); + + for (uint32_t i = 0; i < numFamilies; i++) { + VkQueueFamilyProperties *queue = &queueFamilies[i]; + + if ((queue->queueFlags & flags) == flags) { + int diff = count_bits (queue->queueFlags & ~flags); + if (diff < best_diff) { + best_diff = diff; + family = i; + } + } + } + return family; +} + +static void +load_device_funcs (qfv_instance_t *inst, qfv_device_t *dev) +{ + qfv_instfuncs_t *ifunc = inst->funcs; + qfv_devfuncs_t *dfunc = dev->funcs; + VkDevice device = dev->dev; +#define DEVICE_LEVEL_VULKAN_FUNCTION(name) \ + dfunc->name = (PFN_##name) ifunc->vkGetDeviceProcAddr (device, #name); \ + if (!dfunc->name) { \ + Sys_Error ("Couldn't find device level function %s", #name); \ + } + +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (!ext || dev->extension_enabled (dev, ext)) { \ + dfunc->name = (PFN_##name) ifunc->vkGetDeviceProcAddr (device, #name); \ + if (!dfunc->name) { \ + Sys_MaskPrintf (SYS_VULKAN_PARSE, \ + "Couldn't find device level function %s", #name); \ + } else { \ + Sys_MaskPrintf (SYS_VULKAN_PARSE, \ + "Found device level function %s\n", #name); \ + } \ + } + +#include "QF/Vulkan/funclist.h" +} + +static int +device_extension_enabled (qfv_device_t *device, const char *ext) +{ + return strset_contains (device->enabled_extensions, ext); +} + +qfv_device_t * +QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) +{ + uint32_t nlay = 1; // ensure alloca doesn't see 0 and terminated + uint32_t next = count_strings (extensions) + 1; // ensure terminated + const char **lay = alloca (nlay * sizeof (const char *)); + const char **ext = alloca (next * sizeof (const char *)); + // ensure there are null pointers so merge_strings can act as append + // since it does not add a null, but also make sure the counts reflect + // actual numbers + memset (lay, 0, nlay-- * sizeof (const char *)); + memset (ext, 0, next-- * sizeof (const char *)); + merge_strings (ext, extensions, 0); + + qfv_instance_t *inst = ctx->instance; + qfv_instfuncs_t *ifunc = inst->funcs; + + for (uint32_t i = 0; i < inst->numDevices; i++) { + VkPhysicalDevice physdev = inst->devices[i].dev; + /* + if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, + ext)) { + continue; + } + */ + int family = find_queue_family (inst, physdev, VK_QUEUE_GRAPHICS_BIT); + if (family < 0) { + continue; + } + if (!ctx->get_presentation_support (ctx, physdev, family)) { + continue; + } + float priority = 1; + VkDeviceQueueCreateInfo qCreateInfo = { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0, + family, 1, &priority + }; + VkPhysicalDeviceFeatures features = { + .geometryShader = 1, + }; + VkDeviceCreateInfo dCreateInfo = { + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, + 1, &qCreateInfo, + nlay, lay, + next, ext, + &features + }; + qfv_device_t *device = calloc (1, sizeof (qfv_device_t) + + sizeof (qfv_devfuncs_t)); + device->funcs = (qfv_devfuncs_t *) (device + 1); + if (ifunc->vkCreateDevice (physdev, &dCreateInfo, 0, + &device->dev) == VK_SUCCESS) { + qfv_devfuncs_t *dfunc = device->funcs; + device->enabled_extensions = new_strset (ext); + device->extension_enabled = device_extension_enabled; + + device->physDev = &inst->devices[i]; + load_device_funcs (inst, device); + device->queue.device = device; + device->queue.queueFamily = family; + dfunc->vkGetDeviceQueue (device->dev, family, 0, + &device->queue.queue); + ctx->device = device; + return device; + } + free (device); + } + return 0; +} + +void +QFV_DestroyDevice (qfv_device_t *device) +{ + device->funcs->vkDestroyDevice (device->dev, 0); + del_strset (device->enabled_extensions); + free (device); +} + +int +QFV_DeviceWaitIdle (qfv_device_t *device) +{ + qfv_devfuncs_t *dfunc = device->funcs; + return dfunc->vkDeviceWaitIdle (device->dev) == VK_SUCCESS; +} + +VkFormat +QFV_FindSupportedFormat (qfv_device_t *device, + VkImageTiling tiling, VkFormatFeatureFlags features, + int numCandidates, const VkFormat *candidates) +{ + VkPhysicalDevice pdev = device->physDev->dev; + qfv_instfuncs_t *ifuncs = device->physDev->instance->funcs; + for (int i = 0; i < numCandidates; i++) { + VkFormat format = candidates[i]; + VkFormatProperties props; + ifuncs->vkGetPhysicalDeviceFormatProperties (pdev, format, &props); + if ((tiling == VK_IMAGE_TILING_LINEAR + && (props.linearTilingFeatures & features) == features) + || (tiling == VK_IMAGE_TILING_OPTIMAL + && (props.optimalTilingFeatures & features) == features)) { + return format; + } + } + Sys_Error ("no supported format"); +} diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c new file mode 100644 index 000000000..c05ececf9 --- /dev/null +++ b/libs/video/renderer/vulkan/image.c @@ -0,0 +1,322 @@ +/* + image.c + + Vulkan image functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/memory.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +VkImage +QFV_CreateImage (qfv_device_t *device, int cubemap, + VkImageType type, + VkFormat format, + VkExtent3D size, + uint32_t num_mipmaps, + uint32_t num_layers, + VkSampleCountFlags samples, + VkImageUsageFlags usage_scenarios) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkImageCreateInfo createInfo = { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, + cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0, + type, format, size, num_mipmaps, + cubemap ? 6 * num_layers : num_layers, + samples, + VK_IMAGE_TILING_OPTIMAL, + usage_scenarios, + VK_SHARING_MODE_EXCLUSIVE, + 0, 0, + VK_IMAGE_LAYOUT_UNDEFINED, + }; + VkImage image; + dfunc->vkCreateImage (dev, &createInfo, 0, &image); + return image; +} + +VkDeviceMemory +QFV_AllocImageMemory (qfv_device_t *device, + VkImage image, VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset) +{ + VkDevice dev = device->dev; + qfv_physdev_t *physdev = device->physDev; + VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties; + qfv_devfuncs_t *dfunc = device->funcs; + + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (dev, image, &requirements); + + size = max (size, offset + requirements.size); + VkDeviceMemory object = 0; + + for (uint32_t type = 0; type < memprops->memoryTypeCount; type++) { + if ((requirements.memoryTypeBits & (1 << type)) + && ((memprops->memoryTypes[type].propertyFlags & properties) + == properties)) { + VkMemoryAllocateInfo allocate_info = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, + size, type + }; + + VkResult res = dfunc->vkAllocateMemory (dev, &allocate_info, + 0, &object); + if (res == VK_SUCCESS) { + break; + } + } + } + + return object; +} + +int +QFV_BindImageMemory (qfv_device_t *device, + VkImage image, VkDeviceMemory object, VkDeviceSize offset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkResult res = dfunc->vkBindImageMemory (dev, image, object, offset); + return res == VK_SUCCESS; +} + +qfv_imagebarrierset_t * +QFV_CreateImageTransitionSet (qfv_imagetransition_t *transitions, + int numTransitions) +{ + qfv_imagebarrierset_t *barrierset; + barrierset = DARRAY_ALLOCFIXED (*barrierset, numTransitions, malloc); + + for (int i = 0; i < numTransitions; i++) { + barrierset->a[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrierset->a[i].pNext = 0; + barrierset->a[i].srcAccessMask = transitions[i].srcAccess; + barrierset->a[i].dstAccessMask = transitions[i].dstAccess; + barrierset->a[i].oldLayout = transitions[i].oldLayout; + barrierset->a[i].newLayout = transitions[i].newLayout; + barrierset->a[i].srcQueueFamilyIndex = transitions[i].srcQueueFamily; + barrierset->a[i].dstQueueFamilyIndex = transitions[i].dstQueueFamily; + barrierset->a[i].image = transitions[i].image; + barrierset->a[i].subresourceRange.aspectMask = transitions[i].aspect; + barrierset->a[i].subresourceRange.baseMipLevel = 0; + barrierset->a[i].subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrierset->a[i].subresourceRange.baseArrayLayer = 0; + barrierset->a[i].subresourceRange.layerCount + = VK_REMAINING_ARRAY_LAYERS; + } + return barrierset; +} + +VkImageView +QFV_CreateImageView (qfv_device_t *device, VkImage image, + VkImageViewType type, VkFormat format, + VkImageAspectFlags aspect) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkImageViewCreateInfo createInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 0, + 0, + image, type, format, + { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + }, + { + aspect, + 0, VK_REMAINING_MIP_LEVELS, + 0, VK_REMAINING_ARRAY_LAYERS, + } + }; + + VkImageView view; + dfunc->vkCreateImageView (dev, &createInfo, 0, &view); + return view; +} + +size_t +QFV_GetImageSize (qfv_device_t *device, VkImage image) +{ + qfv_devfuncs_t *dfunc = device->funcs; + size_t size; + size_t align; + + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (device->dev, image, &requirements); + size = requirements.size; + align = requirements.alignment - 1; + size = (size + align) & ~(align); + return size; +} + +void +QFV_GenerateMipMaps (qfv_device_t *device, VkCommandBuffer cmd, + VkImage image, unsigned mips, + unsigned width, unsigned height, unsigned layers) +{ + qfv_devfuncs_t *dfunc = device->funcs; + + qfv_pipelinestagepair_t pre_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + }; + qfv_pipelinestagepair_t post_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + }; + qfv_pipelinestagepair_t final_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + }; + VkImageMemoryBarrier pre_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers } + }; + VkImageMemoryBarrier post_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers } + }; + VkImageMemoryBarrier final_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers } + }; + + VkImageBlit blit = { + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers}, + {{0, 0, 0}, {width, height, 1}}, + {VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, layers}, + {{0, 0, 0}, {max (width >> 1, 1), max (height >> 1, 1), 1}}, + }; + + while (--mips > 0) { + dfunc->vkCmdPipelineBarrier (cmd, pre_stages.src, pre_stages.dst, 0, + 0, 0, 0, 0, + 1, &pre_barrier); + dfunc->vkCmdBlitImage (cmd, + image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, VK_FILTER_LINEAR); + + dfunc->vkCmdPipelineBarrier (cmd, post_stages.src, post_stages.dst, 0, + 0, 0, 0, 0, + 1, &post_barrier); + + blit.srcSubresource.mipLevel++; + blit.srcOffsets[1].x = blit.dstOffsets[1].x; + blit.srcOffsets[1].y = blit.dstOffsets[1].y; + blit.dstSubresource.mipLevel++; + blit.dstOffsets[1].x = max (blit.dstOffsets[1].x >> 1, 1); + blit.dstOffsets[1].y = max (blit.dstOffsets[1].y >> 1, 1); + pre_barrier.subresourceRange.baseMipLevel++; + post_barrier.subresourceRange.baseMipLevel++; + final_barrier.subresourceRange.baseMipLevel++; + } + dfunc->vkCmdPipelineBarrier (cmd, final_stages.src, final_stages.dst, 0, + 0, 0, 0, 0, + 1, &final_barrier); +} + +static int +ilog2 (unsigned x) +{ + unsigned o = x; + if (x > 0x7fffffff) { + // avoid overflow + return 31; + } + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + int y = 0; + y |= ((x & 0xffff0000) != 0) << 4; + y |= ((x & 0xff00ff00) != 0) << 3; + y |= ((x & 0xf0f0f0f0) != 0) << 2; + y |= ((x & 0xcccccccc) != 0) << 1; + y |= ((x & 0xaaaaaaaa) != 0) << 0; + return y - ((o & (x - 1)) != 0); +} + +int +QFV_MipLevels (int width, int height) +{ + return ilog2 (max (width, height)) + 1; +} diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c new file mode 100644 index 000000000..f50ec526b --- /dev/null +++ b/libs/video/renderer/vulkan/instance.c @@ -0,0 +1,311 @@ +/* + init.c + + Copyright (C) 2019 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/instance.h" + +#include "vid_vulkan.h" + +#include "util.h" + +cvar_t *vulkan_use_validation; + +static uint32_t numLayers; +static VkLayerProperties *instanceLayerProperties; +static strset_t *instanceLayers; + +static uint32_t numExtensions; +static VkExtensionProperties *instanceExtensionProperties; +static strset_t *instanceExtensions; + +const char * const vulkanValidationLayers[] = { + "VK_LAYER_KHRONOS_validation", + 0, +}; + +static const char * const debugExtensions[] = { + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + 0, +}; + +static void +get_instance_layers_and_extensions (vulkan_ctx_t *ctx) +{ + uint32_t i; + VkLayerProperties *layers; + VkExtensionProperties *extensions; + + ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0); + layers = malloc (numLayers * sizeof (VkLayerProperties)); + ctx->vkEnumerateInstanceLayerProperties (&numLayers, layers); + instanceLayers = new_strset (0); + for (i = 0; i < numLayers; i++) { + strset_add (instanceLayers, layers[i].layerName); + } + + ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); + extensions = malloc (numExtensions * sizeof (VkLayerProperties)); + ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, + extensions); + instanceExtensions = new_strset (0); + for (i = 0; i < numExtensions; i++) { + strset_add (instanceExtensions, extensions[i].extensionName); + } + + if (developer->int_val & SYS_VULKAN) { + for (i = 0; i < numLayers; i++) { + Sys_Printf ("%s %x %u %s\n", + layers[i].layerName, + layers[i].specVersion, + layers[i].implementationVersion, + layers[i].description); + } + for (i = 0; i < numExtensions; i++) { + Sys_Printf ("%d %s\n", + extensions[i].specVersion, + extensions[i].extensionName); + } + } + instanceLayerProperties = layers; + instanceExtensionProperties = extensions; +} + +static int +instance_extension_enabled (qfv_instance_t *inst, const char *ext) +{ + return strset_contains (inst->enabled_extensions, ext); +} + +static int message_severities = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; +static int message_types = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + +static void +debug_breakpoint (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity) +{ +} + +static VKAPI_ATTR VkBool32 VKAPI_CALL +debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* callbackData, + void *data) +{ + const char *msgSev = ""; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + msgSev = "verbose: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + msgSev = "info: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + msgSev = "warning: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + msgSev = "error: "; + } + fprintf (stderr, "validation layer: %s%s\n", msgSev, + callbackData->pMessage); + debug_breakpoint (messageSeverity); + return VK_FALSE; +} + +static void +setup_debug_callback (qfv_instance_t *instance) +{ + VkDebugUtilsMessengerEXT debug_handle; + VkDebugUtilsMessengerCreateInfoEXT createInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = message_severities, + .messageType = message_types, + .pfnUserCallback = debug_callback, + .pUserData = instance, + }; + instance->funcs->vkCreateDebugUtilsMessengerEXT(instance->instance, + &createInfo, 0, + &debug_handle); + instance->debug_handle = debug_handle; +} + +static void +load_instance_funcs (vulkan_ctx_t *ctx) +{ + qfv_instance_t *instance = ctx->instance; + qfv_instfuncs_t *funcs = instance->funcs; + VkInstance inst = instance->instance; +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ + funcs->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \ + if (!funcs->name) { \ + Sys_Error ("Couldn't find instance level function %s", #name); \ + } + +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (instance->extension_enabled (instance, ext)) { \ + funcs->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \ + if (!funcs->name) { \ + Sys_Error ("Couldn't find instance level function %s", #name); \ + } \ + } + +#include "QF/Vulkan/funclist.h" +} + +qfv_instance_t * +QFV_CreateInstance (vulkan_ctx_t *ctx, + const char *appName, uint32_t appVersion, + const char **layers, const char **extensions) +{ + VkApplicationInfo appInfo = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, 0, + appName, appVersion, + PACKAGE_STRING, 0x000702ff, //FIXME version + VK_API_VERSION_1_0, + }; + VkInstanceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, + &appInfo, + 0, 0, + 0, 0, + }; + VkResult res; + VkInstance instance; + + if (!instanceLayerProperties) { + get_instance_layers_and_extensions (ctx); + } + + uint32_t nlay = count_strings (layers) + 1; + uint32_t next = count_strings (extensions) + + count_strings (ctx->required_extensions) + 1; + if (vulkan_use_validation->int_val) { + nlay += count_strings (vulkanValidationLayers); + next += count_strings (debugExtensions); + } + const char **lay = alloca (nlay * sizeof (const char *)); + const char **ext = alloca (next * sizeof (const char *)); + // ensure there are null pointers so merge_strings can act as append + // since it does not add a null + memset (lay, 0, nlay-- * sizeof (const char *)); + memset (ext, 0, next-- * sizeof (const char *)); + merge_strings (lay, layers, 0); + merge_strings (ext, extensions, ctx->required_extensions); + if (vulkan_use_validation->int_val) { + merge_strings (lay, lay, vulkanValidationLayers); + merge_strings (ext, ext, debugExtensions); + } + prune_strings (instanceLayers, lay, &nlay); + prune_strings (instanceExtensions, ext, &next); + lay[nlay] = 0; + ext[next] = 0; + createInfo.enabledLayerCount = nlay; + createInfo.ppEnabledLayerNames = lay; + createInfo.enabledExtensionCount = next; + createInfo.ppEnabledExtensionNames = ext; + + res = ctx->vkCreateInstance (&createInfo, 0, &instance); + if (res != VK_SUCCESS) { + Sys_Error ("unable to create vulkan instance\n"); + } + qfv_instance_t *inst = calloc (1, sizeof(qfv_instance_t) + + sizeof (qfv_instfuncs_t)); + inst->instance = instance; + inst->funcs = (qfv_instfuncs_t *)(inst + 1); + inst->enabled_extensions = new_strset (ext); + inst->extension_enabled = instance_extension_enabled; + ctx->instance = inst; + load_instance_funcs (ctx); + + if (vulkan_use_validation->int_val) { + setup_debug_callback (inst); + } + + qfv_instfuncs_t *ifunc = inst->funcs; + ifunc->vkEnumeratePhysicalDevices (instance, &inst->numDevices, 0); + inst->devices = malloc (inst->numDevices * sizeof (*inst->devices)); + VkPhysicalDevice *devices = alloca (inst->numDevices * sizeof (*devices)); + ifunc->vkEnumeratePhysicalDevices (instance, &inst->numDevices, devices); + for (uint32_t i = 0; i < inst->numDevices; i++) { + VkPhysicalDevice physDev = devices[i]; + qfv_physdev_t *dev = &inst->devices[i]; + dev->instance = inst; + dev->dev = physDev; + ifunc->vkGetPhysicalDeviceProperties (physDev, &dev->properties); + ifunc->vkGetPhysicalDeviceMemoryProperties (physDev, + &dev->memory_properties); + } + return inst; +} + +void +QFV_DestroyInstance (qfv_instance_t *instance) +{ + qfv_instfuncs_t *ifunc = instance->funcs; + + if (instance->debug_handle) { + ifunc->vkDestroyDebugUtilsMessengerEXT (instance->instance, + instance->debug_handle, 0); + } + instance->funcs->vkDestroyInstance (instance->instance, 0); + del_strset (instance->enabled_extensions); + free (instance->devices); + free (instance); +} + +VkSampleCountFlagBits +QFV_GetMaxSampleCount (qfv_physdev_t *physdev) +{ + VkSampleCountFlagBits maxSamples = VK_SAMPLE_COUNT_64_BIT; + VkSampleCountFlagBits counts; + counts = min (physdev->properties.limits.framebufferColorSampleCounts, + physdev->properties.limits.framebufferDepthSampleCounts); + while (maxSamples && maxSamples > counts) { + maxSamples >>= 1; + } + Sys_MaskPrintf (SYS_VULKAN, "Max samples: %x (%d)\n", maxSamples, counts); + return maxSamples; +} diff --git a/libs/video/renderer/vulkan/memory.c b/libs/video/renderer/vulkan/memory.c new file mode 100644 index 000000000..9397f4366 --- /dev/null +++ b/libs/video/renderer/vulkan/memory.c @@ -0,0 +1,91 @@ +/* + memory.c + + Vulkan memory functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/memory.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +void * +QFV_MapMemory (qfv_device_t *device, VkDeviceMemory object, + VkDeviceSize offset, VkDeviceSize size) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + void *map = 0; + + dfunc->vkMapMemory (dev, object, offset, size, 0, &map); + return map; +} + +void +QFV_FlushMemory (qfv_device_t *device, qfv_mappedmemrangeset_t *flushRanges) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkMappedMemoryRange *ranges = alloca(sizeof (*ranges) * flushRanges->size); + + for (uint32_t i = 0; i < flushRanges->size; i++) { + ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + ranges[i].pNext = 0; + ranges[i].memory = flushRanges->a[i].object; + ranges[i].offset = flushRanges->a[i].offset; + ranges[i].size = flushRanges->a[i].size; + } + dfunc->vkFlushMappedMemoryRanges (dev, flushRanges->size, ranges); +} diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c new file mode 100644 index 000000000..2db39812c --- /dev/null +++ b/libs/video/renderer/vulkan/pipeline.c @@ -0,0 +1,164 @@ +/* + pipeline.c + + Vulkan pipeline functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/pipeline.h" +#include "QF/Vulkan/renderpass.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +VkPipelineCache +QFV_CreatePipelineCache (qfv_device_t *device, dstring_t *cacheData) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkPipelineCacheCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, 0, 0, + cacheData->size, cacheData->str, + }; + + VkPipelineCache cache; + dfunc->vkCreatePipelineCache (dev, &createInfo, 0, &cache); + return cache; +} + +dstring_t * +QFV_GetPipelineCacheData (qfv_device_t *device, VkPipelineCache cache) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + dstring_t *cacheData = dstring_new (); + + dfunc->vkGetPipelineCacheData (dev, cache, &cacheData->size, 0); + dstring_adjust (cacheData); + dfunc->vkGetPipelineCacheData (dev, cache, + &cacheData->size, cacheData->str); + return cacheData; +} + +void +QFV_MergePipelineCaches (qfv_device_t *device, + VkPipelineCache targetCache, + qfv_pipelinecacheset_t *sourceCaches) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkMergePipelineCaches (dev, targetCache, + sourceCaches->size, sourceCaches->a); +} + +VkPipelineLayout +QFV_CreatePipelineLayout (qfv_device_t *device, + qfv_descriptorsetlayoutset_t *layouts, + qfv_pushconstantrangeset_t *pushConstants) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkPipelineLayoutCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, + layouts->size, layouts->a, + pushConstants->size, pushConstants->a, + }; + + VkPipelineLayout layout; + dfunc->vkCreatePipelineLayout (dev, &createInfo, 0, &layout); + return layout; +} + +qfv_pipelineset_t * +QFV_CreateGraphicsPipelines (qfv_device_t *device, + VkPipelineCache cache, + qfv_graphicspipelinecreateinfoset_t *gpciSet) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type pipelines = QFV_AllocPipelineSet (gpciSet->size, malloc); + dfunc->vkCreateGraphicsPipelines (dev, cache, gpciSet->size, gpciSet->a, 0, + pipelines->a); + + return pipelines; +} + +qfv_pipelineset_t * +QFV_CreateComputePipelines (qfv_device_t *device, + VkPipelineCache cache, + qfv_computepipelinecreateinfoset_t *cpciSet) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type pipelines = QFV_AllocPipelineSet (cpciSet->size, malloc); + dfunc->vkCreateComputePipelines (dev, cache, cpciSet->size, cpciSet->a, 0, + pipelines->a); + return pipelines; +} + +void +QFV_DestroyPipeline (qfv_device_t *device, VkPipeline pipeline) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyPipeline (dev, pipeline, 0); +} diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist new file mode 100644 index 000000000..d19294a80 --- /dev/null +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -0,0 +1,857 @@ +{ + samplers = { + quakepic = { + magFilter = nearest; + minFilter = nearest; + mipmapMode = nearest; + addressModeU = clamp_to_edge; + addressModeV = clamp_to_edge; + addressModeW = clamp_to_edge; + mipLodBias = 0; + anisotropyEnable = false; + maxAnisotropy = 0; + compareEnable = false; + compareOp = always; + minLod = 0; + maxLod = 0; + borderColor = float_transparent_black; + unnormalizedCoordinates = false; + }; + quakebsp_sampler = { + magFilter = linear; + minFilter = linear; + mipmapMode = linear; + addressModeU = repeat; + addressModeV = repeat; + addressModeW = repeat; + mipLodBias = 0; + anisotropyEnable = false; + maxAnisotropy = 0; + compareEnable = false; + compareOp = always; + minLod = 0; + maxLod = 4; + borderColor = float_transparent_black; + unnormalizedCoordinates = false; + }; + alias_sampler = { + magFilter = linear; + minFilter = linear; + mipmapMode = linear; + addressModeU = clamp_to_edge; + addressModeV = clamp_to_edge; + addressModeW = clamp_to_edge; + mipLodBias = 0; + anisotropyEnable = false; + maxAnisotropy = 0; + compareEnable = false; + compareOp = always; + minLod = 0; + maxLod = 1000; + borderColor = float_transparent_black; + unnormalizedCoordinates = false; + }; + }; + descriptorPools = { + twod_pool = { + flags = 0; + maxSets = $frames.size; + bindings = ( + { + type = uniform_buffer; + descriptorCount = $frames.size; + }, + { + type = combined_image_sampler; + descriptorCount = $frames.size; + }, + ); + }; + alias_pool = { + flags = 0; + maxSets = "2z * $frames.size"; + bindings = ( + { + type = uniform_buffer; + descriptorCount = "2z * $frames.size"; + }, + ); + }; + lighting_attach_pool = { + flags = 0; + maxSets = $frames.size; + bindings = ( + { + type = input_attachment; + descriptorCount = "5z * $frames.size"; + }, + ); + }; + lighting_lights_pool = { + flags = 0; + maxSets = $frames.size; + bindings = ( + { + type = uniform_buffer; + descriptorCount = $frames.size; + }, + ); + }; + compose_attach_pool = { + flags = 0; + maxSets = $frames.size; + bindings = ( + { + type = input_attachment; + descriptorCount = "2z * $frames.size"; + }, + ); + }; + }; + setLayouts = { + twod_set = { + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + { + binding = 1; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + quakebsp_set = { + flags = push_descriptor; + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex|geometry; + }, + { + binding = 1; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 2; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 3; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 4; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 5; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + alias_set = { + flags = push_descriptor; + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + { + binding = 1; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + alias_matrices = { + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + ); + }; + alias_textures = { + flags = push_descriptor; + bindings = ( + { + binding = 0; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 1; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 2; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 3; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + alias_lights = { + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + lighting_attach = { + bindings = ( + { + binding = 0; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 1; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 2; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 3; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 4; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + lighting_lights = { + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + compose_attach = { + bindings = ( + { + binding = 0; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 1; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + }; + pipelineLayouts = { + twod_layout = { + setLayouts = (twod_set); + }; + quakebsp_layout = { + setLayouts = (quakebsp_set); + pushConstantRanges = ( + { + stageFlags = vertex; + offset = 0; + size = "16 * 4"; + }, + { + stageFlags = fragment; + offset = 64; + size = 32; + }, + ); + }; + alias_layout = { + //setLayouts = (alias_matrices, alias_lights, alias_textures); + setLayouts = (alias_set); + pushConstantRanges = ( + { + stageFlags = vertex; + offset = 0; + size = "16 * 4 + 4"; + }, + { + stageFlags = fragment; + offset = 68; + size = "3 * 4 + 2 * 4 * 4"; + }, + ); + }; + lighting_layout = { + setLayouts = (lighting_attach, lighting_lights); + }; + compose_layout = { + setLayouts = (compose_attach); + }; + }; + + depthStencil = { + test_and_write = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + test_only = { + depthTestEnable = true; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + disable = { + depthTestEnable = false; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + }; + + inputAssembly = { + alias = { + topology = triangle_list; + primitiveRestartEnable = false; + }; + brush = { + topology = triangle_fan; + primitiveRestartEnable = true; + }; + twod = { + topology = triangle_strip; + primitiveRestartEnable = true; + }; + }; + + vertexInput = { + alias = { + bindings = ( + { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, + { binding = 1; stride = "2 * 4 * 4"; inputRate = vertex; }, + { binding = 2; stride = "2 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, + { location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, + { location = 2; binding = 1; format = r32g32b32a32_sfloat; offset = 0; }, + { location = 3; binding = 1; format = r32g32b32a32_sfloat; offset = 16; }, + { location = 4; binding = 2; format = r32g32_sfloat; offset = 0; }, + ); + }; + brush = { + bindings = ( + { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, + { location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, + ); + }; + twod = { + bindings = ( + { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32_sfloat; offset = 0; }, + { location = 1; binding = 0; format = r32g32_sfloat; offset = 8; }, + { location = 2; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, + ); + }; + }; + + rasterization = { + cw_cull_back = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + counter_cw_cull_back = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + }; + + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + + attachmentBlendOp = { + disabled = { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }; + alpha_blend = { + blendEnable = true; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }; + }; + + fsquad = { + vertexInput = { + bindings = ( + { binding = 0; stride = "4 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, + ); + }; + inputAssembly = { + topology = triangle_strip; + primitiveRestartEnable = false; + }; + colorBlend = { + logicOpEnable = false; + attachments = ($properties.attachmentBlendOp.disabled); + }; + }; + + pipelines = { + alias_depth = { + subpass = 0; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/alias_depth.vert; + }, + ); + vertexInput = { + // depth pass doesn't use UVs + bindings = ( + "$properties.vertexInput.alias.bindings[0]", + "$properties.vertexInput.alias.bindings[1]", + ); + attributes = ( + "$properties.vertexInput.alias.attributes[0]", + "$properties.vertexInput.alias.attributes[1]", + "$properties.vertexInput.alias.attributes[2]", + "$properties.vertexInput.alias.attributes[3]", + ); + }; + inputAssembly = $properties.inputAssembly.alias; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_and_write; + colorBlend = $properties.pipelines.alias_gbuf.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = alias_layout; + //renderPass = renderpass; + }; + alias_gbuf = { + subpass = 2; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/alias.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/alias_gbuf.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + ); + data = <00000008>; + }; + }, + ); + vertexInput = $properties.vertexInput.alias; + inputAssembly = $properties.inputAssembly.alias; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ( + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + ); + }; + dynamic = { + dynamicState = ( viewport, scissor, blend_constants ); + }; + layout = alias_layout; + //renderPass = renderpass; + }; + bsp_depth = { + subpass = 0; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/bsp_depth.vert; + }, + ); + vertexInput = { + bindings = ( + "$properties.vertexInput.brush.bindings[0]", + ); + attributes = ( + "$properties.vertexInput.brush.attributes[0]", + ); + }; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_and_write; + colorBlend = $properties.pipelines.bsp_gbuf.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = quakebsp_layout; + //renderPass = renderpass; + }; + bsp_gbuf = { + subpass = 2; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/bsp_gbuf.vert; + }, + { + stage = geometry; + name = main; + module = $builtin/bsp_gbuf.geom; + }, + { + stage = fragment; + name = main; + module = $builtin/bsp_gbuf.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + { size = 4; offset = 0; constantID = 1; }, + { size = 4; offset = 0; constantID = 2; }, + { size = 4; offset = 0; constantID = 3; }, + ); + data = <00000000ffffffff>; + }; + }, + ); + vertexInput = $properties.vertexInput.brush; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ( + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + ); + }; + dynamic = { + dynamicState = ( viewport, scissor, blend_constants ); + }; + layout = quakebsp_layout; + //renderPass = renderpass; + }; + bsp_skybox = { + subpass = 1; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/quakebsp.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/bsp_sky.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 1; }, + { size = 4; offset = 4; constantID = 0; }, + ); + data = <00000000ffffffff>; + }; + }, + ); + vertexInput = $properties.vertexInput.brush; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ($properties.attachmentBlendOp.disabled); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = quakebsp_layout; + //renderPass = renderpass; + }; + bsp_skysheet = { + subpass = 1; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/quakebsp.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/bsp_sky.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + { size = 4; offset = 4; constantID = 1; }, + ); + data = <00000000ffffffff>; + }; + }, + ); + vertexInput = $properties.vertexInput.brush; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ($properties.attachmentBlendOp.disabled); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = quakebsp_layout; + //renderPass = renderpass; + }; + bsp_turb = { + subpass = 1; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/quakebsp.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/bsp_turb.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + { size = 4; offset = 4; constantID = 1; }, + ); + data = <00000000ffffffff>; + }; + }, + ); + vertexInput = $properties.vertexInput.brush; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ($properties.attachmentBlendOp.disabled); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = quakebsp_layout; + //renderPass = renderpass; + }; + twod = { + subpass = 1; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/twod.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/twod.frag; + }, + ); + vertexInput = $properties.vertexInput.twod; + inputAssembly = $properties.inputAssembly.twod; + viewport = $properties.viewport; + rasterization = $properties.rasterization.counter_cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ($properties.attachmentBlendOp.alpha_blend); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = twod_layout; + //renderPass = renderpass; + }; + lighting = { + subpass = 3; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/passthrough.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/lighting.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + ); + data = <00000100>; + }; + }, + ); + vertexInput = $properties.fsquad.vertexInput; + inputAssembly = $properties.fsquad.inputAssembly; + viewport = $properties.viewport; + rasterization = $properties.rasterization.counter_cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.disable; + colorBlend = $properties.fsquad.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = lighting_layout; + //renderPass = renderpass; + }; + compose = { + subpass = 4; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/passthrough.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/compose.frag; + }, + ); + vertexInput = $properties.fsquad.vertexInput; + inputAssembly = $properties.fsquad.inputAssembly; + viewport = $properties.viewport; + rasterization = $properties.rasterization.counter_cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.disable; + colorBlend = $properties.fsquad.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = compose_layout; + //renderPass = renderpass; + }; + }; +} diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c new file mode 100644 index 000000000..4970b050b --- /dev/null +++ b/libs/video/renderer/vulkan/renderpass.c @@ -0,0 +1,169 @@ +/* + renderpass.c + + Vulkan render pass and frame buffer functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/renderpass.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +VkRenderPass +QFV_CreateRenderPass (qfv_device_t *device, + qfv_attachmentdescription_t *attachments, + qfv_subpassparametersset_t *subpassparams, + qfv_subpassdependency_t *dependencies) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + if (developer->int_val & SYS_VULKAN) { + Sys_Printf ("attachments: %ld\n", attachments->size); + for (size_t i = 0; i < attachments->size; i++) { + Sys_Printf (" attachment: %zd\n", i); + Sys_Printf (" flags: %x\n", attachments->a[i].flags); + Sys_Printf (" format: %d\n", attachments->a[i].format); + Sys_Printf (" samples: %x\n", attachments->a[i].samples); + Sys_Printf (" loadOp: %d\n", attachments->a[i].loadOp); + Sys_Printf (" storeOp: %d\n", attachments->a[i].storeOp); + Sys_Printf (" stencilLoadOp: %d\n", + attachments->a[i].stencilLoadOp); + Sys_Printf (" stencilStoreOp: %d\n", + attachments->a[i].stencilStoreOp); + Sys_Printf (" initialLayout: %d\n", + attachments->a[i].initialLayout); + Sys_Printf (" finalLayout: %d\n", + attachments->a[i].finalLayout); + } + Sys_Printf ("subpassparams: %ld\n", subpassparams->size); + for (size_t i = 0; i < subpassparams->size; i++) { + VkSubpassDescription *sp = &subpassparams->a[i]; + Sys_Printf (" flags: %x\n", sp->flags); + Sys_Printf (" piplineBindPoint: %d\n", sp->pipelineBindPoint); + Sys_Printf (" inputAttachmentCount: %d\n", + sp->inputAttachmentCount); + for (size_t j = 0; j < sp->inputAttachmentCount; j++) { + const VkAttachmentReference *ref = &sp->pInputAttachments[j]; + Sys_Printf (" c %d %d\n", ref->attachment, ref->layout); + } + Sys_Printf (" colorAttachmentCount: %d\n", + sp->colorAttachmentCount); + for (size_t j = 0; j < sp->colorAttachmentCount; j++) { + const VkAttachmentReference *ref = &sp->pColorAttachments[j]; + Sys_Printf (" c %d %d\n", ref->attachment, ref->layout); + } + if (sp->pResolveAttachments) { + for (size_t j = 0; j < sp->colorAttachmentCount; j++) { + const VkAttachmentReference *ref + = &sp->pResolveAttachments[j]; + Sys_Printf (" r %d %d\n", ref->attachment, + ref->layout); + } + } + Sys_Printf (" pDepthStencilAttachment: %p\n", + sp->pDepthStencilAttachment); + if (sp->pDepthStencilAttachment) { + const VkAttachmentReference *ref = sp->pDepthStencilAttachment; + Sys_Printf (" %d %d\n", ref->attachment, ref->layout); + } + Sys_Printf (" preserveAttachmentCount: %d\n", + sp->preserveAttachmentCount); + for (size_t j = 0; j < sp->preserveAttachmentCount; j++) { + Sys_Printf (" %d\n", sp->pPreserveAttachments[j]); + } + } + Sys_Printf ("dependencies: %ld\n", dependencies->size); + for (size_t i = 0; i < dependencies->size; i++) { + Sys_Printf (" srcSubpass: %d\n", dependencies->a[i].srcSubpass); + Sys_Printf (" dstSubpass: %d\n", dependencies->a[i].dstSubpass); + Sys_Printf (" srcStageMask: %x\n", dependencies->a[i].srcStageMask); + Sys_Printf (" dstStageMask: %x\n", dependencies->a[i].dstStageMask); + Sys_Printf (" srcAccessMask: %x\n", dependencies->a[i].srcAccessMask); + Sys_Printf (" dstAccessMask: %x\n", dependencies->a[i].dstAccessMask); + Sys_Printf (" dependencyFlags: %x\n", dependencies->a[i].dependencyFlags); + } + } + VkRenderPassCreateInfo createInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0, + attachments->size, attachments->a, + subpassparams->size, subpassparams->a, + dependencies->size, dependencies->a, + }; + + VkRenderPass renderpass; + dfunc->vkCreateRenderPass (dev, &createInfo, 0, &renderpass); + return renderpass; +} + +VkFramebuffer +QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass, + qfv_imageviewset_t *attachments, + VkExtent2D extent, uint32_t layers) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkFramebufferCreateInfo createInfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0, + renderPass, attachments->size, attachments->a, + extent.width, extent.height, layers, + }; + + VkFramebuffer framebuffer; + dfunc->vkCreateFramebuffer (dev, &createInfo, 0, &framebuffer); + return framebuffer; +} diff --git a/libs/video/renderer/vulkan/scrap.c b/libs/video/renderer/vulkan/scrap.c new file mode 100644 index 000000000..ab053bf10 --- /dev/null +++ b/libs/video/renderer/vulkan/scrap.c @@ -0,0 +1,370 @@ +/* + scrap.c + + Vulkan scrap manager + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/image.h" +#include "QF/quakefs.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/scrap.h" +#include "QF/Vulkan/staging.h" + +#include "r_scrap.h" +#include "vid_vulkan.h" + +struct scrap_s { + rscrap_t rscrap; + VkImage image; + VkDeviceMemory memory; + VkImageView view; + size_t bpp; + qfv_packet_t *packet; + vrect_t *batch; + vrect_t **batch_tail; + vrect_t *batch_free; + size_t batch_count; + subpic_t *subpics; + qfv_device_t *device; +}; + +scrap_t * +QFV_CreateScrap (qfv_device_t *device, const char *name, int size, + QFFormat format, qfv_stagebuf_t *stage) +{ + qfv_devfuncs_t *dfunc = device->funcs; + int bpp = 0; + VkFormat fmt = VK_FORMAT_UNDEFINED; + dstring_t *str = dstring_new (); + + switch (format) { + case tex_l: + case tex_a: + case tex_palette: + bpp = 1; + fmt = VK_FORMAT_R8_UNORM; + break; + case tex_la: + bpp = 2; + fmt = VK_FORMAT_R8G8_UNORM; + break; + case tex_rgb: + bpp = 3; + fmt = VK_FORMAT_R8G8B8_UNORM; + break; + case tex_rgba: + bpp = 4; + fmt = VK_FORMAT_R8G8B8A8_UNORM; + break; + case tex_frgba: + bpp = 16; + fmt = VK_FORMAT_R32G32B32A32_SFLOAT; + break; + } + + scrap_t *scrap = malloc (sizeof (scrap_t)); + + R_ScrapInit (&scrap->rscrap, size, size); + + // R_ScrapInit rounds sizes up to next power of 2 + size = scrap->rscrap.width; + VkExtent3D extent = { size, size, 1 }; + scrap->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, fmt, + extent, 1, 1, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, scrap->image, + dsprintf (str, "image:scrap:%s", name)); + scrap->memory = QFV_AllocImageMemory (device, scrap->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, scrap->memory, + dsprintf (str, "memory:scrap:%s", name)); + QFV_BindImageMemory (device, scrap->image, scrap->memory, 0); + scrap->view = QFV_CreateImageView (device, scrap->image, + VK_IMAGE_VIEW_TYPE_2D, fmt, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, scrap->view, + dsprintf (str, "iview:scrap:%s", name)); + dstring_delete (str); + scrap->bpp = bpp; + scrap->subpics = 0; + scrap->device = device; + scrap->packet = 0; + scrap->batch = 0; + scrap->batch_tail = &scrap->batch; + scrap->batch_free = 0; + scrap->batch_count = 0; + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + qfv_packet_t *packet = QFV_PacketAcquire (stage); + // no data for the packet + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + VkClearColorValue color = { + float32:{0xde/255.0, 0xad/255.0, 0xbe/255.0, 0xef/255.0}, + }; + VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + dfunc->vkCmdClearColorImage (packet->cmd, scrap->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &color, 1, &range); + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + QFV_PacketSubmit (packet); + return scrap; +} + +size_t +QFV_ScrapSize (scrap_t *scrap) +{ + return scrap->rscrap.width * scrap->rscrap.height * scrap->bpp; +} + +void +QFV_ScrapClear (scrap_t *scrap) +{ + subpic_t *sp; + while (scrap->subpics) { + sp = scrap->subpics; + scrap->subpics = (subpic_t *) sp->next; + free (sp); + } + R_ScrapClear (&scrap->rscrap); +} + +void +QFV_DestroyScrap (scrap_t *scrap) +{ + qfv_device_t *device = scrap->device; + qfv_devfuncs_t *dfunc = device->funcs; + + QFV_ScrapClear (scrap); + R_ScrapDelete (&scrap->rscrap); + dfunc->vkDestroyImageView (device->dev, scrap->view, 0); + dfunc->vkDestroyImage (device->dev, scrap->image, 0); + dfunc->vkFreeMemory (device->dev, scrap->memory, 0); + + while (scrap->batch_free) { + vrect_t *b = scrap->batch_free; + scrap->batch_free = b->next; + VRect_Delete (b); + } + free (scrap); +} + +VkImageView +QFV_ScrapImageView (scrap_t *scrap) +{ + return scrap->view; +} + +subpic_t * +QFV_ScrapSubpic (scrap_t *scrap, int width, int height) +{ + vrect_t *rect; + subpic_t *subpic; + + rect = R_ScrapAlloc (&scrap->rscrap, width, height); + if (!rect) { + return 0; + } + + subpic = malloc (sizeof (subpic_t)); + *((subpic_t **) &subpic->next) = scrap->subpics; + scrap->subpics = subpic; + *((scrap_t **) &subpic->scrap) = scrap; + *((vrect_t **) &subpic->rect) = rect; + *((int *) &subpic->width) = width; + *((int *) &subpic->height) = height; + *((float *) &subpic->size) = 1.0 / scrap->rscrap.width; + return subpic; +} + +void +QFV_SubpicDelete (subpic_t *subpic) +{ + scrap_t *scrap = (scrap_t *) subpic->scrap; + vrect_t *rect = (vrect_t *) subpic->rect; + subpic_t **sp; + + for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next) { + if (*sp == subpic) { + break; + } + } + if (*sp != subpic) { + Sys_Error ("QFV_SubpicDelete: broken subpic"); + } + *sp = (subpic_t *) subpic->next; + free (subpic); + R_ScrapFree (&scrap->rscrap, rect); +} + +void * +QFV_SubpicBatch (subpic_t *subpic, qfv_stagebuf_t *stage) +{ + scrap_t *scrap = (scrap_t *) subpic->scrap; + vrect_t *rect = (vrect_t *) subpic->rect; + vrect_t *batch; + byte *dest; + size_t size; + + if (!scrap->packet) { + scrap->packet = QFV_PacketAcquire (stage); + } + size = (subpic->width * subpic->height * scrap->bpp + 3) & ~3; + if (!(dest = QFV_PacketExtend (scrap->packet, size))) { + if (scrap->packet->length) { + QFV_ScrapFlush (scrap); + + scrap->packet = QFV_PacketAcquire (stage); + dest = QFV_PacketExtend (scrap->packet, size); + } + if (!dest) { + printf ("scrap: could not get space for update\n"); + return 0; + } + } + + if (scrap->batch_free) { + batch = scrap->batch_free; + scrap->batch_free = batch->next; + batch->x = rect->x; + batch->y = rect->y; + batch->width = subpic->width; + batch->height = subpic->height; + } else { + batch = VRect_New (rect->x, rect->y, subpic->width, subpic->height); + } + *scrap->batch_tail = batch; + scrap->batch_tail = &batch->next; + batch->next = 0; + scrap->batch_count++; + return dest; +} + +void +QFV_ScrapFlush (scrap_t *scrap) +{ + qfv_device_t *device = scrap->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (!scrap->batch_count) { + return; + } + + qfv_packet_t *packet = scrap->packet; + qfv_stagebuf_t *stage = packet->stage; + size_t i; + __auto_type copy = QFV_AllocBufferImageCopy (128, alloca); + memset (copy->a, 0, 128 * sizeof (copy->a[0])); + + for (i = 0; i < scrap->batch_count && i < 128; i++) { + copy->a[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy->a[i].imageSubresource.layerCount = 1; + copy->a[i].imageExtent.depth = 1; + } + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_ShaderReadOnly_to_TransferDst]; + barrier=imageLayoutTransitionBarriers[qfv_LT_ShaderReadOnly_to_TransferDst]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + + size_t offset = packet->offset, size; + vrect_t *batch = scrap->batch; + while (scrap->batch_count) { + for (i = 0; i < scrap->batch_count && i < 128; i++) { + size = batch->width * batch->height * scrap->bpp; + + copy->a[i].bufferOffset = offset; + copy->a[i].imageOffset.x = batch->x; + copy->a[i].imageOffset.y = batch->y; + copy->a[i].imageExtent.width = batch->width; + copy->a[i].imageExtent.height = batch->height; + + offset += (size + 3) & ~3; + batch = batch->next; + } + dfunc->vkCmdCopyBufferToImage (packet->cmd, stage->buffer, scrap->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + i, copy->a); + scrap->batch_count -= i; + } + + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + + *scrap->batch_tail = scrap->batch_free; + scrap->batch_free = scrap->batch; + scrap->batch = 0; + scrap->batch_tail = &scrap->batch; + + QFV_PacketSubmit (scrap->packet); + scrap->packet = 0; +} diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c new file mode 100644 index 000000000..c10d9a286 --- /dev/null +++ b/libs/video/renderer/vulkan/shader.c @@ -0,0 +1,195 @@ +/* + shader.c + + Vulkan shader manager + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" + +#include "vid_vulkan.h" + +static +#include "libs/video/renderer/vulkan/shader/twod.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/twod.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/quakebsp.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/quakebsp.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_depth.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_gbuf.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_gbuf.geom.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_gbuf.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_sky.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_turb.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/lighting.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/compose.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/alias.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/alias_depth.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/alias.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/alias_gbuf.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/passthrough.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/pushcolor.frag.spvc" + +typedef struct shaderdata_s { + const char *name; + const uint32_t *data; + size_t size; +} shaderdata_t; + +static shaderdata_t builtin_shaders[] = { + { "twod.vert", twod_vert, sizeof (twod_vert) }, + { "twod.frag", twod_frag, sizeof (twod_frag) }, + { "quakebsp.vert", quakebsp_vert, sizeof (quakebsp_vert) }, + { "quakebsp.frag", quakebsp_frag, sizeof (quakebsp_frag) }, + { "bsp_depth.vert", bsp_depth_vert, sizeof (bsp_depth_vert) }, + { "bsp_gbuf.vert", bsp_gbuf_vert, sizeof (bsp_gbuf_vert) }, + { "bsp_gbuf.geom", bsp_gbuf_geom, sizeof (bsp_gbuf_geom) }, + { "bsp_gbuf.frag", bsp_gbuf_frag, sizeof (bsp_gbuf_frag) }, + { "bsp_sky.frag", bsp_sky_frag, sizeof (bsp_sky_frag) }, + { "bsp_turb.frag", bsp_turb_frag, sizeof (bsp_turb_frag) }, + { "lighting.frag", lighting_frag, sizeof (lighting_frag) }, + { "compose.frag", compose_frag, sizeof (compose_frag) }, + { "alias.vert", alias_vert, sizeof (alias_vert) }, + { "alias_depth.vert", alias_depth_vert, sizeof (alias_depth_vert) }, + { "alias.frag", alias_frag, sizeof (alias_frag) }, + { "alias_gbuf.frag", alias_gbuf_frag, sizeof (alias_gbuf_frag) }, + { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, + { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, + {} +}; + +#define BUILTIN "$builtin/" +#define BUILTIN_SIZE (sizeof (BUILTIN) - 1) +#define SHADER "$shader/" +#define SHADER_SIZE (sizeof (SHADER) - 1) + +VkShaderModule +QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + shaderdata_t _data = {}; + shaderdata_t *data = 0; + dstring_t *path = 0; + QFile *file = 0; + VkShaderModule shader = 0; + + if (strncmp (shader_path, BUILTIN, BUILTIN_SIZE) == 0) { + const char *name = shader_path + BUILTIN_SIZE; + + for (int i = 0; builtin_shaders[i].name; i++) { + if (strcmp (builtin_shaders[i].name, name) == 0) { + data = &builtin_shaders[i]; + break; + } + } + } else if (strncmp (shader_path, SHADER, SHADER_SIZE)) { + path = dstring_new (); + dsprintf (path, "%s/%s", FS_SHADERPATH, shader_path + SHADER_SIZE); + file = Qopen (path->str, "rbz"); + } else { + file = QFS_FOpenFile (shader_path); + } + + if (file) { + _data.size = Qfilesize (file); + _data.data = malloc (_data.size); + Qread (file, (void *) _data.data, _data.size); + Qclose (file); + data = &_data; + } + + if (data) { + Sys_MaskPrintf (SYS_VULKAN, + "QFV_CreateShaderModule: creating shader module %s\n", + shader_path); + VkShaderModuleCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, + 0, data->size, data->data + }; + + dfunc->vkCreateShaderModule (dev, &createInfo, 0, &shader); + } else { + Sys_MaskPrintf (SYS_VULKAN, + "QFV_CreateShaderModule: could not find shader %s\n", + shader_path); + } + + if (path) { + dstring_delete (path); + } + if (_data.data) { + free ((void *) _data.data); + } + return shader; +} + +void +QFV_DestroyShaderModule (qfv_device_t *device, VkShaderModule module) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyShaderModule (dev, module, 0); +} diff --git a/libs/video/renderer/vulkan/shader/alias.frag b/libs/video/renderer/vulkan/shader/alias.frag new file mode 100644 index 000000000..3b5c9fddd --- /dev/null +++ b/libs/video/renderer/vulkan/shader/alias.frag @@ -0,0 +1,76 @@ +#version 450 +layout (set = 0, binding = 2) uniform sampler2DArray Skin; +/* +layout (set = 2, binding = 0) uniform sampler2D Texture; +layout (set = 2, binding = 1) uniform sampler2D GlowMap; +layout (set = 2, binding = 2) uniform sampler2D ColorA; +layout (set = 2, binding = 3) uniform sampler2D ColorB; +*/ +struct LightData { + vec3 color; + float dist; + vec3 position; + int type; + vec3 direction; + float cone; +}; + +layout (constant_id = 0) const int MaxLights = 8; +//layout (set = 1, binding = 0) uniform Lights { +layout (set = 0, binding = 1) uniform Lights { + int light_count; + LightData lights[MaxLights]; +}; + +layout (push_constant) uniform PushConstants { + layout (offset = 68) + uint base_color; + uint colorA; + uint colorB; + vec4 fog; + vec4 color; +}; + +layout (location = 0) in vec2 st; +layout (location = 1) in vec3 position; +layout (location = 2) in vec3 normal; + +layout (location = 0) out vec4 frag_color; + +vec3 +calc_light (LightData light) +{ + if (light.type == 0) { + vec3 dist = light.position - position; + float dd = dot (dist, dist); + float mag = max (0.0, dot (dist, normal)); + return light.color * mag * light.dist / dd; + } else if (light.type == 1) { + } else if (light.type == 2) { + float mag = max (0.0, -dot (light.direction, normal)); + // position is ambient light + return light.color * dot (light.direction, normal) + light.position; + } +} + +void +main (void) +{ + vec4 c; + int i; + vec3 light = vec3 (0); + c = texture (Skin, vec3 (st, 0)) * unpackUnorm4x8(base_color); + c += texture (Skin, vec3 (st, 1)) * unpackUnorm4x8(colorA); + c += texture (Skin, vec3 (st, 2)) * unpackUnorm4x8(colorB); + + if (MaxLights > 0) { + for (i = 0; i < light_count; i++) { + light += calc_light (lights[i]); + } + } + c *= vec4 (light, 1); + + c += texture (Skin, vec3 (st, 3)); + //frag_color = vec4((normal + 1)/2, 1); + frag_color = c;//fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/shader/alias.vert b/libs/video/renderer/vulkan/shader/alias.vert new file mode 100644 index 000000000..a54b43674 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/alias.vert @@ -0,0 +1,38 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; + float blend; +}; + +layout (location = 0) in vec4 vertexa; +layout (location = 1) in vec3 normala; +layout (location = 2) in vec4 vertexb; +layout (location = 3) in vec3 normalb; +layout (location = 4) in vec2 uv; + +layout (location = 0) out vec2 st; +layout (location = 1) out vec4 position; +layout (location = 2) out vec3 normal; + +void +main (void) +{ + vec4 vertex; + vec3 norm; + vec4 pos; + + vertex = mix (vertexa, vertexb, blend); + norm = mix (normala, normalb, blend); + pos = (Model * vertex); + gl_Position = Projection * (View * pos); + position = pos; + normal = mat3 (Model) * norm; + st = uv; +} diff --git a/libs/video/renderer/vulkan/shader/alias_depth.vert b/libs/video/renderer/vulkan/shader/alias_depth.vert new file mode 100644 index 000000000..44437788e --- /dev/null +++ b/libs/video/renderer/vulkan/shader/alias_depth.vert @@ -0,0 +1,28 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; + float blend; +}; + +layout (location = 0) in vec4 vertexa; +layout (location = 1) in vec3 normala; +layout (location = 2) in vec4 vertexb; +layout (location = 3) in vec3 normalb; + +void +main (void) +{ + vec4 vertex; + vec4 pos; + + vertex = mix (vertexa, vertexb, blend); + pos = (Model * vertex); + gl_Position = Projection * (View * pos); +} diff --git a/libs/video/renderer/vulkan/shader/alias_gbuf.frag b/libs/video/renderer/vulkan/shader/alias_gbuf.frag new file mode 100644 index 000000000..c9cc81db0 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/alias_gbuf.frag @@ -0,0 +1,38 @@ +#version 450 +layout (set = 0, binding = 1) uniform sampler2DArray Skin; + +layout (push_constant) uniform PushConstants { + layout (offset = 68) + uint base_color; + uint colorA; + uint colorB; + vec4 fog; + vec4 color; +}; + +layout (location = 0) in vec2 st; +layout (location = 1) in vec4 position; +layout (location = 2) in vec3 normal; + +layout (location = 0) out vec4 frag_color; +layout (location = 1) out vec4 frag_emission; +layout (location = 2) out vec4 frag_normal; +layout (location = 3) out vec4 frag_position; + +void +main (void) +{ + vec4 c; + vec4 e; + int i; + vec3 light = vec3 (0); + c = texture (Skin, vec3 (st, 0)) * unpackUnorm4x8(base_color); + c += texture (Skin, vec3 (st, 1)) * unpackUnorm4x8(colorA); + c += texture (Skin, vec3 (st, 2)) * unpackUnorm4x8(colorB); + e = texture (Skin, vec3 (st, 3)); + + frag_color = c; + frag_emission = e; + frag_normal = vec4(normal, 1); + frag_position = position; +} diff --git a/libs/video/renderer/vulkan/shader/bsp_depth.vert b/libs/video/renderer/vulkan/shader/bsp_depth.vert new file mode 100644 index 000000000..02a4fed80 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_depth.vert @@ -0,0 +1,19 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; +}; + +layout (location = 0) in vec4 vertex; + +void +main (void) +{ + gl_Position = Projection * (View * (Model * vertex)); +} diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag new file mode 100644 index 000000000..c00c0d72d --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag @@ -0,0 +1,132 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; +layout (set = 0, binding = 2) uniform sampler2D GlowMap; +layout (set = 0, binding = 3) uniform sampler2D LightMap; +layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 5) uniform samplerCube SkyCube; + +layout (push_constant) uniform PushConstants { + layout (offset = 64) + vec4 fog; + float time; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec3 direction; +layout (location = 2) in vec3 normal; +layout (location = 3) in vec4 position; + +layout (location = 0) out vec4 frag_color; +layout (location = 1) out vec4 frag_emission; +layout (location = 2) out vec4 frag_normal; +layout (location = 3) out vec4 frag_position; + +layout (constant_id = 0) const bool doWarp = false; +layout (constant_id = 1) const bool doLight = true; +layout (constant_id = 2) const bool doSkyCube = false; +layout (constant_id = 3) const bool doSkySheet = false; + +const float PI = 3.14159265; +const float SPEED = 20.0; +const float CYCLE = 128.0; +const float FACTOR = PI * 2.0 / CYCLE; +const vec2 BIAS = vec2 (1.0, 1.0); +const float SCALE = 8.0; + +vec2 +warp_st (vec2 st, float time) +{ + vec2 angle = st.ts * CYCLE / 2.0; + vec2 phase = vec2 (time, time) * SPEED; + return st + (sin ((angle + phase) * FACTOR) + BIAS) / SCALE; +} + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +vec4 +sky_sheet (vec3 dir, float time) +{ + float len; + vec2 flow = vec2 (1.0, 1.0); + vec2 base; + vec3 st1, st2; + vec4 c1, c2, c; + + dir.z *= 3.0; + len = dot (dir, dir); + len = SCALE * inversesqrt (len); + base = dir.yx * vec2(1.0, -1.0) * len; + + st1 = vec3 (base + flow * time / 8.0, 0); + st2 = vec3 (base + flow * time / 16.0, 1); + + c1 = texture (SkySheet, st1); + c2 = texture (SkySheet, st2); + + c = vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + + return c; +} + +vec4 +sky_cube (vec3 dir, float time) +{ + // NOTE: quake's world is right-handed with Z up and X forward, but + // Vulkan's cube maps are left-handed with Y up and Z forward. The + // rotation to X foward is done by the Sky matrix so all that's left + // to do here is swizzle the Y and Z coordinates + return texture (SkyCube, dir.xzy); +} + +vec4 +sky_color (vec3 dir, float time) +{ + if (!doSkySheet) { + return vec4 (1, 0, 1, 1); + //return sky_cube (dir, time); + } if (!doSkyCube) { + return sky_sheet (dir, time); + } else { + // can see through the sheet (may look funny when looking down) + // maybe have 4 sheet layers instead of 2? + vec4 c1 = sky_sheet (dir, time); + vec4 c2 = sky_cube (dir, time); + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + return vec4 (1, 0, 1, 1); + } +} + +void +main (void) +{ + vec4 c = vec4 (0); + vec4 e; + vec2 t_st = tl_st.xy; + vec2 l_st = tl_st.zw; + + if (doWarp) { + t_st = warp_st (t_st, time); + } + if (doSkyCube || doSkySheet) { + e = sky_color (direction, time); + } else { + c = texture (Texture, t_st); + if (doLight) { + c *= vec4 (texture (LightMap, l_st).xyz, 1); + } + e = texture (GlowMap, t_st); + } + frag_color = c;//fogBlend (c); + frag_emission = e; + frag_normal = vec4 (normal, 0); + frag_position = position; +} diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.geom b/libs/video/renderer/vulkan/shader/bsp_gbuf.geom new file mode 100644 index 000000000..bb46ae43a --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.geom @@ -0,0 +1,38 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (triangles) in; +layout (triangle_strip, max_vertices = 3) out; +layout (location = 0) in vec4 v_tl_st[]; +layout (location = 1) in vec3 v_direction[]; + +layout (location = 0) out vec4 tl_st; +layout (location = 1) out vec3 direction; +layout (location = 2) out vec3 normal; +layout (location = 3) out vec4 position; + +void +main() +{ + vec3 a = gl_in[0].gl_Position.xyz; + vec3 b = gl_in[1].gl_Position.xyz; + vec3 c = gl_in[2].gl_Position.xyz; + + vec3 n = normalize (cross (c - a, b - a)); + + for (int vert = 0; vert < 3; vert++) { + vec4 p = gl_in[vert].gl_Position; + gl_Position = Projection * (View * (p)); + tl_st = v_tl_st[vert]; + direction = v_direction[vert]; + normal = n; + position = p; + EmitVertex (); + } + EndPrimitive (); +} diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.vert b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert new file mode 100644 index 000000000..abfb6c4e6 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert @@ -0,0 +1,26 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; +}; + +layout (location = 0) in vec4 vertex; +layout (location = 1) in vec4 tl_uv; + +layout (location = 0) out vec4 tl_st; +layout (location = 1) out vec3 direction; + +void +main (void) +{ + // geometry shader will take care of Projection and View + gl_Position = Model * vertex; + direction = (Sky * vertex).xyz; + tl_st = tl_uv; +} diff --git a/libs/video/renderer/vulkan/shader/bsp_sky.frag b/libs/video/renderer/vulkan/shader/bsp_sky.frag new file mode 100644 index 000000000..ed6828a10 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_sky.frag @@ -0,0 +1,97 @@ +#version 450 + +layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 5) uniform samplerCube SkyCube; + +layout (push_constant) uniform PushConstants { + layout (offset = 64) + vec4 fog; + float time; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec3 direction; + +layout (location = 0) out vec4 frag_color; + +layout (constant_id = 0) const bool doSkyBox = false; +layout (constant_id = 1) const bool doSkySheet = false; + +const float SCALE = 8.0; + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +vec4 +sky_sheet (vec3 dir, float time) +{ + float len; + vec2 flow = vec2 (1.0, 1.0); + vec2 base; + vec3 st1, st2; + vec4 c1, c2, c; + + dir.z *= 3.0; + len = dot (dir, dir); + len = SCALE * inversesqrt (len); + base = dir.yx * vec2(1.0, -1.0) * len; + + st1 = vec3 (base + flow * time / 8.0, 0); + st2 = vec3 (base + flow * time / 16.0, 1); + + c1 = texture (SkySheet, st1); + c2 = texture (SkySheet, st2); + + c = vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + + return c; +} + +vec4 +sky_box (vec3 dir, float time) +{ + // NOTE: quake's world is right-handed with Z up and X forward, but + // Vulkan's cube maps are left-handed with Y up and Z forward. The + // rotation to X foward is done by the Sky matrix so all that's left + // to do here is swizzle the Y and Z coordinates + dir = normalize(dir); + //return vec4(dir.xyz, 1) * 0.5 + vec4(0.5); + return texture (SkyCube, dir.xzy); +} + +vec4 +sky_color (vec3 dir, float time) +{ + if (!doSkySheet) { + return sky_box (dir, time); + } if (!doSkyBox) { + return sky_sheet (dir, time); + } else { + // can see through the sheet (may look funny when looking down) + // maybe have 4 sheet layers instead of 2? + vec4 c1 = sky_sheet (dir, time); + vec4 c2 = sky_box (dir, time); + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + return vec4 (1, 0, 1, 1); + } +} + +void +main (void) +{ + vec4 c; + + if (doSkyBox || doSkySheet) { + c = sky_color (direction, time); + } else { + c = vec4 (0, 0, 0, 1); + } + frag_color = c;//fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/shader/bsp_turb.frag b/libs/video/renderer/vulkan/shader/bsp_turb.frag new file mode 100644 index 000000000..ab4b04c7d --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_turb.frag @@ -0,0 +1,52 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; + +layout (push_constant) uniform PushConstants { + layout (offset = 64) + vec4 fog; + float time; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec3 direction; + +layout (location = 0) out vec4 frag_color; + +const float PI = 3.14159265; +const float SPEED = 20.0; +const float CYCLE = 128.0; +const float FACTOR = PI * 2.0 / CYCLE; +const vec2 BIAS = vec2 (1.0, 1.0); +const float SCALE = 8.0; + +vec2 +warp_st (vec2 st, float time) +{ + vec2 angle = st.ts * CYCLE / 2.0; + vec2 phase = vec2 (time, time) * SPEED; + return st + (sin ((angle + phase) * FACTOR) + BIAS) / SCALE; +} + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +void +main (void) +{ + vec4 c = vec4 (0); + vec4 e; + vec2 t_st = tl_st.xy; + vec2 l_st = tl_st.zw; + + t_st = warp_st (t_st, time); + c = texture (Texture, t_st); + frag_color = c;//fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/shader/compose.frag b/libs/video/renderer/vulkan/shader/compose.frag new file mode 100644 index 000000000..542ba4c1b --- /dev/null +++ b/libs/video/renderer/vulkan/shader/compose.frag @@ -0,0 +1,20 @@ +#version 450 + +layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput opaque; +layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput translucent; + +layout (location = 0) out vec4 frag_color; + +void +main (void) +{ + vec3 o; + vec4 t; + vec3 c; + + o = subpassLoad (opaque).rgb; + t = subpassLoad (translucent); + c = mix (o, t.rgb, t.a); + c = pow (c, vec3(0.83));//FIXME make gamma correction configurable + frag_color = vec4 (c, 1); +} diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag new file mode 100644 index 000000000..3be1485ee --- /dev/null +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -0,0 +1,67 @@ +#version 450 + +layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput depth; +layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput color; +layout (input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput emission; +layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput normal; +layout (input_attachment_index = 4, set = 0, binding = 4) uniform subpassInput position; + +struct LightData { + vec3 color; + int data;// bits 0-6: intensity key (however, values 0-66) + vec3 position; + float radius; + vec3 direction; + float cone; +}; + +layout (constant_id = 0) const int MaxLights = 128; +layout (set = 1, binding = 0) uniform Lights { + vec4 intensity[16]; // 64 floats + vec3 intensity2; + int lightCount; + LightData lights[MaxLights]; +}; + +layout (location = 0) out vec4 frag_color; + +vec3 +calc_light (LightData light, vec3 position, vec3 normal) +{ + float r = light.radius; + vec3 dist = light.position - position; + float d = sqrt (dot (dist, dist)); + if (d > r) { + // the light is too far away + return vec3 (0); + } + + vec3 incoming = dist / d; + float spotdot = dot (incoming, light.direction); + float lightdot = dot (incoming, normal); + + int style = light.data & 0x7f; + // deliberate array index error: access intensity2 as well + float i = intensity[style / 4][style % 4]; + i *= step (d, r) * clamp (lightdot, 0, 1); + i *= smoothstep (spotdot, 1 - (1 - spotdot) * 0.995, light.cone); + return light.color * i * (r - d); +} + +void +main (void) +{ + //float d = subpassLoad (depth).r; + vec3 c = subpassLoad (color).rgb; + vec3 e = subpassLoad (emission).rgb; + vec3 n = subpassLoad (normal).rgb; + vec3 p = subpassLoad (position).rgb; + vec3 light = vec3 (0); + + if (MaxLights > 0) { + for (int i = 0; i < lightCount; i++) { + light += calc_light (lights[i], p, n); + } + } + frag_color = vec4 (c * light + e, 1); +} diff --git a/libs/video/renderer/vulkan/shader/passthrough.vert b/libs/video/renderer/vulkan/shader/passthrough.vert new file mode 100644 index 000000000..0283a53b3 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/passthrough.vert @@ -0,0 +1,8 @@ +#version 450 + +layout (location = 0) in vec4 app_position; + +void main() +{ + gl_Position = app_position; +} diff --git a/libs/video/renderer/vulkan/shader/pushcolor.frag b/libs/video/renderer/vulkan/shader/pushcolor.frag new file mode 100644 index 000000000..d19413fe1 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/pushcolor.frag @@ -0,0 +1,12 @@ +#version 450 + +layout (location = 0) out vec4 frag_color; + +layout (push_constant) uniform ColorBlock { + vec4 Color; +} PushConstant; + +void main() +{ + frag_color = PushConstant.Color; +} diff --git a/libs/video/renderer/vulkan/shader/quakebsp.frag b/libs/video/renderer/vulkan/shader/quakebsp.frag new file mode 100644 index 000000000..fe596246e --- /dev/null +++ b/libs/video/renderer/vulkan/shader/quakebsp.frag @@ -0,0 +1,123 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; +layout (set = 0, binding = 2) uniform sampler2D GlowMap; +layout (set = 0, binding = 3) uniform sampler2D LightMap; +layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 5) uniform samplerCube SkyCube; + +layout (push_constant) uniform PushConstants { + layout (offset = 64) + vec4 fog; + float time; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec3 direction; + +layout (location = 0) out vec4 frag_color; + +layout (constant_id = 0) const bool doWarp = false; +layout (constant_id = 1) const bool doLight = true; +layout (constant_id = 2) const bool doSkyCube = false; +layout (constant_id = 3) const bool doSkySheet = false; + +const float PI = 3.14159265; +const float SPEED = 20.0; +const float CYCLE = 128.0; +const float FACTOR = PI * 2.0 / CYCLE; +const vec2 BIAS = vec2 (1.0, 1.0); +const float SCALE = 8.0; + +vec2 +warp_st (vec2 st, float time) +{ + vec2 angle = st.ts * CYCLE / 2.0; + vec2 phase = vec2 (time, time) * SPEED; + return st + (sin ((angle + phase) * FACTOR) + BIAS) / SCALE; +} + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +vec4 +sky_sheet (vec3 dir, float time) +{ + float len; + vec2 flow = vec2 (1.0, 1.0); + vec2 base; + vec3 st1, st2; + vec4 c1, c2, c; + + dir.z *= 3.0; + len = dot (dir, dir); + len = SCALE * inversesqrt (len); + base = dir.yx * vec2(1.0, -1.0) * len; + + st1 = vec3 (base + flow * time / 8.0, 0); + st2 = vec3 (base + flow * time / 16.0, 1); + + c1 = texture (SkySheet, st1); + c2 = texture (SkySheet, st2); + + c = vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + + return c; +} + +vec4 +sky_cube (vec3 dir, float time) +{ + // NOTE: quake's world is right-handed with Z up and X forward, but + // Vulkan's cube maps are left-handed with Y up and Z forward. The + // rotation to X foward is done by the Sky matrix so all that's left + // to do here is swizzle the Y and Z coordinates + return texture (SkyCube, dir.xzy); +} + +vec4 +sky_color (vec3 dir, float time) +{ + if (!doSkySheet) { + return vec4 (1, 0, 1, 1); + //return sky_cube (dir, time); + } if (!doSkyCube) { + return sky_sheet (dir, time); + } else { + // can see through the sheet (may look funny when looking down) + // maybe have 4 sheet layers instead of 2? + vec4 c1 = sky_sheet (dir, time); + vec4 c2 = sky_cube (dir, time); + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + return vec4 (1, 0, 1, 1); + } +} + +void +main (void) +{ + vec4 c; + vec2 t_st = tl_st.xy; + vec2 l_st = tl_st.zw; + + if (doWarp) { + t_st = warp_st (t_st, time); + } + if (doSkyCube || doSkySheet) { + c = sky_color (direction, time); + } else { + c = texture (Texture, t_st); + if (doLight) { + c *= vec4 (texture (LightMap, l_st).xyz, 1); + } + c += texture (GlowMap, t_st); + } + frag_color = c;//fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/shader/quakebsp.vert b/libs/video/renderer/vulkan/shader/quakebsp.vert new file mode 100644 index 000000000..bb9e87e4a --- /dev/null +++ b/libs/video/renderer/vulkan/shader/quakebsp.vert @@ -0,0 +1,25 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; +}; + +layout (location = 0) in vec4 vertex; +layout (location = 1) in vec4 tl_uv; + +layout (location = 0) out vec4 tl_st; +layout (location = 1) out vec3 direction; + +void +main (void) +{ + gl_Position = Projection * (View * (Model * vertex)); + direction = (Sky * vertex).xyz; + tl_st = tl_uv; +} diff --git a/libs/video/renderer/vulkan/shader/twod.frag b/libs/video/renderer/vulkan/shader/twod.frag new file mode 100644 index 000000000..a6a40212d --- /dev/null +++ b/libs/video/renderer/vulkan/shader/twod.frag @@ -0,0 +1,17 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; + +layout (location = 0) in vec2 st; +layout (location = 1) in vec4 color; + +layout (location = 0) out vec4 frag_color; + +void +main (void) +{ + vec4 pix; + + pix = texture (Texture, st); + frag_color = pix * color; +} diff --git a/libs/video/renderer/vulkan/shader/twod.vert b/libs/video/renderer/vulkan/shader/twod.vert new file mode 100644 index 000000000..c5dc5063a --- /dev/null +++ b/libs/video/renderer/vulkan/shader/twod.vert @@ -0,0 +1,26 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; +}; +/** Vertex position. + + x, y, s, t + + \a vertex provides the onscreen location at which to draw the icon + (\a x, \a y) and texture coordinate for the icon (\a s=z, \a t=w). +*/ +layout (location = 0) in vec2 vertex; +layout (location = 1) in vec2 uv; +layout (location = 2) in vec4 vcolor; + +layout (location = 0) out vec2 st; +layout (location = 1) out vec4 color; + +void +main (void) +{ + gl_Position = Projection * vec4 (vertex.xy, 0.0, 1.0); + st = uv; + color = vcolor; +} diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c new file mode 100644 index 000000000..28ea169a7 --- /dev/null +++ b/libs/video/renderer/vulkan/staging.c @@ -0,0 +1,308 @@ +/* + staging.c + + Vulkan staging buffer manager + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" + +#include "vid_vulkan.h" + +qfv_stagebuf_t * +QFV_CreateStagingBuffer (qfv_device_t *device, const char *name, size_t size, + VkCommandPool cmdPool) +{ + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + qfv_devfuncs_t *dfunc = device->funcs; + dstring_t *str = dstring_new (); + + qfv_stagebuf_t *stage = calloc (1, sizeof (qfv_stagebuf_t)); + stage->atom_mask = atom - 1; + size = (size + stage->atom_mask) & ~stage->atom_mask; + stage->device = device; + stage->buffer = QFV_CreateBuffer (device, size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, stage->buffer, + dsprintf (str, "staging:buffer:%s", name)); + stage->memory = QFV_AllocBufferMemory (device, stage->buffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, stage->memory, + dsprintf (str, "staging:memory:%s", name)); + stage->size = size; + stage->end = size; + + dfunc->vkMapMemory (device->dev, stage->memory, 0, size, 0, &stage->data); + QFV_BindBufferMemory (device, stage->buffer, stage->memory, 0); + + int count = RB_buffer_size (&stage->packets); + + __auto_type bufferset = QFV_AllocCommandBufferSet (count, alloca); + QFV_AllocateCommandBuffers (device, cmdPool, 0, bufferset); + for (int i = 0; i < count; i++) { + qfv_packet_t *packet = &stage->packets.buffer[i]; + packet->stage = stage; + packet->cmd = bufferset->a[i]; + packet->fence = QFV_CreateFence (device, 1); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + packet->cmd, + dsprintf (str, "staging:packet:cmd:%s:%d", + name, i)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_FENCE, + packet->fence, + dsprintf (str, "staging:packet:fence:%s:%d", + name, i)); + packet->offset = 0; + packet->length = 0; + } + dstring_delete (str); + return stage; +} + +void +QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage) +{ + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + int count = RB_buffer_size (&stage->packets); + __auto_type fences = QFV_AllocFenceSet (count, alloca); + for (int i = 0; i < count; i++) { + fences->a[i] = stage->packets.buffer[i].fence; + } + dfunc->vkWaitForFences (device->dev, fences->size, fences->a, VK_TRUE, + 500000000ull); + for (int i = 0; i < count; i++) { + dfunc->vkDestroyFence (device->dev, fences->a[i], 0); + } + + dfunc->vkUnmapMemory (device->dev, stage->memory); + dfunc->vkFreeMemory (device->dev, stage->memory, 0); + dfunc->vkDestroyBuffer (device->dev, stage->buffer, 0); + free (stage); +} + +void +QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size) +{ + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + offset &= ~stage->atom_mask; + size = (size + stage->atom_mask) & ~stage->atom_mask; + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + stage->memory, offset, size + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); +} + +static void +release_space (qfv_stagebuf_t *stage, size_t offset, size_t length) +{ + if (stage->space_end != offset + && offset != 0 + && stage->space_end != stage->end) { + Sys_Error ("staging: out of sequence packet release"); + } + if (stage->space_end == stage->end) { + stage->space_end = 0; + stage->end = stage->size; + } + stage->space_end += length; +} + +static void * +acquire_space (qfv_packet_t *packet, size_t size) +{ + qfv_stagebuf_t *stage = packet->stage; + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + // clean up after any completed packets + while (RB_DATA_AVAILABLE (stage->packets) > 1) { + qfv_packet_t *p = RB_PEEK_DATA (stage->packets, 0); + if (dfunc->vkGetFenceStatus (device->dev, p->fence) != VK_SUCCESS) { + break; + } + release_space (stage, p->offset, p->length); + RB_RELEASE (stage->packets, 1); + } + + if (size > stage->size) { + // utterly impossible allocation + return 0; + } + + // if the staging buffer has been freed up and no data is assigned to the + // single existing packet, then ensure the packet starts at the beginning + // of the staging buffer in order to maximize the space available to it + // (some of the tests are redundant since if any space is assigned to a + // packet, the buffer cannot be fully freed up) + if (stage->space_end == stage->space_start + && RB_DATA_AVAILABLE (stage->packets) == 1 + && packet->length == 0) { + stage->space_end = 0; + stage->space_start = 0; + packet->offset = 0; + } + if (stage->space_start >= stage->space_end) { + // all the space to the actual end of the buffer is free + if (stage->space_start + size <= stage->size) { + void *data = (byte *) stage->data + stage->space_start; + stage->space_start += size; + return data; + } + // doesn't fit at the end of the buffer, try the beginning but only + // if the packet can be moved (no spaced has been allocated to it yet) + if (packet->length > 0) { + // can't move it + return 0; + } + // mark the unused end of the buffer such that it gets reclaimed + // properly when the preceeding packet is freed + stage->end = stage->space_start; + stage->space_start = 0; + packet->offset = 0; + } + while (stage->space_start + size > stage->space_end + && RB_DATA_AVAILABLE (stage->packets) > 1) { + packet = RB_PEEK_DATA (stage->packets, 0); + dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE, + ~0ull); + release_space (stage, packet->offset, packet->length); + RB_RELEASE (stage->packets, 1); + } + if (stage->space_start + size > stage->space_end) { + return 0; + } + void *data = (byte *) stage->data + stage->space_start; + stage->space_start += size; + return data; +} + +qfv_packet_t * +QFV_PacketAcquire (qfv_stagebuf_t *stage) +{ + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + qfv_packet_t *packet = 0; + if (!RB_SPACE_AVAILABLE (stage->packets)) { + // need to wait for a packet to become available + packet = RB_PEEK_DATA (stage->packets, 0); + dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE, + ~0ull); + release_space (stage, packet->offset, packet->length); + RB_RELEASE (stage->packets, 1); + } + packet = RB_ACQUIRE (stage->packets, 1); + + packet->offset = stage->space_start; + packet->length = 0; + + dfunc->vkResetFences (device->dev, 1, &packet->fence); + dfunc->vkResetCommandBuffer (packet->cmd, 0); + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, + }; + dfunc->vkBeginCommandBuffer (packet->cmd, &beginInfo); + + return packet; +} + +void * +QFV_PacketExtend (qfv_packet_t *packet, size_t size) +{ + void *data = acquire_space (packet, size); + if (data) { + packet->length += size; + } + return data; +} + +void +QFV_PacketSubmit (qfv_packet_t *packet) +{ + qfv_stagebuf_t *stage = packet->stage; + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (!packet->length) { + // XXX at this stage, this looks the same as below, I think a queue + // completing is the only way to set a fence (other than creation), + // so submit the (hopefully) empty command buffer so the fence becomes + // set, but without waiting on or triggering any semaphores. + dfunc->vkEndCommandBuffer (packet->cmd); + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 0, 0, 0, + 1, &packet->cmd, + 0, 0, + }; + dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, + packet->fence); + return; + } + + QFV_FlushStagingBuffer (stage, packet->offset, packet->length); + + dfunc->vkEndCommandBuffer (packet->cmd); + //XXX it may become necessary to pass in semaphores etc (maybe add to + //packet?) + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 0, 0, 0, + 1, &packet->cmd, + 0, 0, + }; + // The fence was reset when the packet was acquired + dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, packet->fence); +} diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c new file mode 100644 index 000000000..762e2c799 --- /dev/null +++ b/libs/video/renderer/vulkan/swapchain.c @@ -0,0 +1,203 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/cvars.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/swapchain.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_swapchain_t * +QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) +{ + qfv_instfuncs_t *ifuncs = ctx->instance->funcs; + qfv_devfuncs_t *dfuncs = ctx->device->funcs; + qfv_queue_t *queue = &ctx->device->queue; + VkPhysicalDevice physDev = ctx->device->physDev->dev; + + VkBool32 supported; + ifuncs->vkGetPhysicalDeviceSurfaceSupportKHR (physDev, + queue->queueFamily, + ctx->surface, + &supported); + if (!supported) { + Sys_Error ("unsupported surface for swapchain"); + } + + uint32_t numModes; + VkPresentModeKHR *modes; + VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR; + ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (physDev, + ctx->surface, + &numModes, 0); + modes = alloca (numModes * sizeof (VkPresentModeKHR)); + ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (physDev, + ctx->surface, + &numModes, modes); + for (uint32_t i = 0; i < numModes; i++) { + if ((int) modes[i] == vulkan_presentation_mode->int_val) { + useMode = modes[i]; + } + } + Sys_MaskPrintf (SYS_VULKAN, "presentation mode: %d (%d)\n", useMode, + vulkan_presentation_mode->int_val); + + VkSurfaceCapabilitiesKHR surfCaps; + ifuncs->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (physDev, + ctx->surface, + &surfCaps); + uint32_t numImages = surfCaps.minImageCount + 1; + if (surfCaps.maxImageCount > 0 && numImages > surfCaps.maxImageCount) { + numImages = surfCaps.maxImageCount; + } + + VkExtent2D imageSize = {viddef.width, viddef.height}; + if (surfCaps.currentExtent.width == ~0u) { + imageSize.width = bound (surfCaps.minImageExtent.width, + imageSize.width, + surfCaps.maxImageExtent.width); + imageSize.height = bound (surfCaps.minImageExtent.height, + imageSize.height, + surfCaps.maxImageExtent.height); + } else { + imageSize = surfCaps.currentExtent; + } + Sys_MaskPrintf (SYS_VULKAN, "%d [%d, %d]\n", numImages, + imageSize.width, imageSize.height); + + VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imageUsage &= surfCaps.supportedUsageFlags; + Sys_MaskPrintf (SYS_VULKAN, "%x %x\n", imageUsage, + surfCaps.supportedUsageFlags); + + VkSurfaceTransformFlagBitsKHR surfTransform + = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + + uint32_t numFormats; + ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (physDev, + ctx->surface, + &numFormats, 0); + VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats)); + ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (physDev, + ctx->surface, + &numFormats, formats); + VkSurfaceFormatKHR useFormat = {VK_FORMAT_R8G8B8A8_UNORM, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; + if (numFormats > 1) { + uint32_t i; + for (i = 0; i < numFormats; i++) { + if (formats[i].format == useFormat.format + && formats[i].colorSpace == useFormat.colorSpace) { + break; + } + } + if (i == numFormats) { + useFormat = formats[0]; + } + } else if (numFormats == 1 && formats[0].format != VK_FORMAT_UNDEFINED) { + useFormat = formats[0]; + } + + VkSwapchainCreateInfoKHR createInfo = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 0, 0, + ctx->surface, + numImages, + useFormat.format, useFormat.colorSpace, + imageSize, + 1, // array layers + imageUsage, + VK_SHARING_MODE_EXCLUSIVE, + 0, 0, + surfTransform, + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + useMode, + VK_TRUE, + old_swapchain + }; + + VkDevice dev = ctx->device->dev; + VkSwapchainKHR swapchain; + dfuncs->vkCreateSwapchainKHR (dev, &createInfo, 0, &swapchain); + + if (old_swapchain != swapchain) { + dfuncs->vkDestroySwapchainKHR (dev, old_swapchain, 0); + } + + dfuncs->vkGetSwapchainImagesKHR (dev, swapchain, &numImages, 0); + qfv_swapchain_t *sc = malloc (sizeof (qfv_swapchain_t)); + sc->device = ctx->device; + sc->surface = ctx->surface; + sc->swapchain = swapchain; + sc->format = useFormat.format; + sc->extent = imageSize; + sc->numImages = numImages; + sc->usage = imageUsage; + sc->images = DARRAY_ALLOCFIXED (qfv_imageset_t, numImages, malloc); + sc->imageViews = DARRAY_ALLOCFIXED (qfv_imageviewset_t, numImages, malloc); + dfuncs->vkGetSwapchainImagesKHR (dev, swapchain, &numImages, sc->images->a); + for (uint32_t i = 0; i < numImages; i++) { + sc->imageViews->a[i] + = QFV_CreateImageView (ctx->device, sc->images->a[i], + VK_IMAGE_VIEW_TYPE_2D, sc->format, + VK_IMAGE_ASPECT_COLOR_BIT); + } + return sc; +} + +void +QFV_DestroySwapchain (qfv_swapchain_t *swapchain) +{ + qfv_device_t *device = swapchain->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + for (size_t i = 0; i < swapchain->imageViews->size; i++) { + dfunc->vkDestroyImageView (dev, swapchain->imageViews->a[i], 0); + } + free (swapchain->images); + free (swapchain->imageViews); + dfunc->vkDestroySwapchainKHR (dev, swapchain->swapchain, 0); + free (swapchain); +} + +int +QFV_AcquireNextImage (qfv_swapchain_t *swapchain, VkSemaphore semaphore, + VkFence fence, uint32_t *imageIndex) +{ + qfv_device_t *device = swapchain->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + uint64_t timeout = 2000000000; + *imageIndex = ~0u; + VkResult res = dfunc->vkAcquireNextImageKHR (dev, swapchain->swapchain, + timeout, semaphore, fence, + imageIndex); + switch (res) { + case VK_SUCCESS: + case VK_TIMEOUT: + case VK_NOT_READY: + return 1; + case VK_SUBOPTIMAL_KHR: + case VK_ERROR_OUT_OF_DATE_KHR: + return 0; + default: + Sys_Error ("vkAcquireNextImageKHR failed: %d", res); + } +} diff --git a/libs/video/renderer/vulkan/test/Makemodule.am b/libs/video/renderer/vulkan/test/Makemodule.am new file mode 100644 index 000000000..84c5ff136 --- /dev/null +++ b/libs/video/renderer/vulkan/test/Makemodule.am @@ -0,0 +1,19 @@ +libs_video_renderer_vulkan_tests = \ + libs/video/renderer/vulkan/test/test-staging \ + $e + +TESTS += $(libs_video_renderer_vulkan_tests) + +check_PROGRAMS += $(libs_video_renderer_vulkan_tests) + +libs_video_renderer_vulkan_test_libs= \ + libs/video/renderer/librender_vulkan.la \ + libs/util/libQFutil.la + +libs_video_renderer_vulkan_test_test_staging_SOURCES= \ + libs/video/renderer/vulkan/test/test-staging.c \ + $e +libs_video_renderer_vulkan_test_test_staging_LDADD= \ + $(libs_video_renderer_vulkan_test_libs) +libs_video_renderer_vulkan_test_test_staging_DEPENDENCIES= \ + $(libs_video_renderer_vulkan_test_libs) diff --git a/libs/video/renderer/vulkan/test/test-staging.c b/libs/video/renderer/vulkan/test/test-staging.c new file mode 100644 index 000000000..fcfa4b8a9 --- /dev/null +++ b/libs/video/renderer/vulkan/test/test-staging.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" + +void *stage_memory; + +static VkResult +vkMapMemory (VkDevice device, VkDeviceMemory memory, + VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, + void **data) +{ + char *buf = calloc (1, size); + stage_memory = buf; + *data = buf; + return VK_SUCCESS; +} + +static VkResult +vkBindBufferMemory (VkDevice device, VkBuffer buffer, VkDeviceMemory memory, + VkDeviceSize offset) +{ + return VK_SUCCESS; +} + +static VkResult +vkCreateBuffer (VkDevice device, const VkBufferCreateInfo *cinfo, + const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + *buffer = 0; + return VK_SUCCESS; +} + +static void +vkGetBufferMemoryRequirements (VkDevice device, VkBuffer buffer, + VkMemoryRequirements *requirements) +{ + memset (requirements, 0, sizeof (*requirements)); +} + +static VkResult +vkAllocateCommandBuffers (VkDevice device, + const VkCommandBufferAllocateInfo *info, + VkCommandBuffer *buffers) +{ + static size_t cmdBuffer = 0; + + for (uint32_t i = 0; i < info->commandBufferCount; i++) { + buffers[i] = (VkCommandBuffer) ++cmdBuffer; + } + return VK_SUCCESS; +} + +static VkResult +vkCreateFence (VkDevice device, const VkFenceCreateInfo *info, + const VkAllocationCallbacks *allocator, VkFence *fence) +{ + int *f = malloc (sizeof (int)); + *f = info->flags & VK_FENCE_CREATE_SIGNALED_BIT ? 1 : 0; + *(int **)fence = f; + return VK_SUCCESS; +} + +int wait_count = 0; + +static VkResult +vkWaitForFences (VkDevice device, uint32_t fenceCount, const VkFence *fences, + VkBool32 waitAll, uint64_t timeout) +{ + for (uint32_t i = 0; i < fenceCount; i++) { + int *f = (int *)fences[i]; + if (*f) { + wait_count++; + } + *f = 0; + } + return VK_SUCCESS; +} + +static VkResult +vkResetFences (VkDevice device, uint32_t fenceCount, const VkFence *fences) +{ + for (uint32_t i = 0; i < fenceCount; i++) { + int *f = (int *)fences[i]; + *f = 0; + } + return VK_SUCCESS; +} + +static VkResult +vkGetFenceStatus (VkDevice device, VkFence fence) +{ + int *f = (int *)fence; + return *f ? VK_SUCCESS : VK_NOT_READY; +} + +static VkResult +vkResetCommandBuffer (VkCommandBuffer buffer, VkCommandBufferResetFlags flags) +{ + return VK_SUCCESS; +} + +static VkResult +vkBeginCommandBuffer (VkCommandBuffer buffer, + const VkCommandBufferBeginInfo *info) +{ + return VK_SUCCESS; +} + +static VkResult +vkEndCommandBuffer (VkCommandBuffer buffer) +{ + return VK_SUCCESS; +} + +static VkResult +vkFlushMappedMemoryRanges (VkDevice device, uint32_t count, + const VkMappedMemoryRange *ranges) +{ + return VK_SUCCESS; +} + +static VkResult +vkQueueSubmit (VkQueue queue, uint32_t count, const VkSubmitInfo *submits, + VkFence fence) +{ + int *f = (int *)fence; + *f = 1; + return VK_SUCCESS; +} + +qfv_devfuncs_t dfuncs = { + vkCreateBuffer:vkCreateBuffer, + vkGetBufferMemoryRequirements:vkGetBufferMemoryRequirements, + vkMapMemory:vkMapMemory, + vkBindBufferMemory:vkBindBufferMemory, + vkAllocateCommandBuffers:vkAllocateCommandBuffers, + vkCreateFence:vkCreateFence, + vkWaitForFences:vkWaitForFences, + vkResetFences:vkResetFences, + vkGetFenceStatus:vkGetFenceStatus, + vkResetCommandBuffer:vkResetCommandBuffer, + vkBeginCommandBuffer:vkBeginCommandBuffer, + vkEndCommandBuffer:vkEndCommandBuffer, + vkFlushMappedMemoryRanges:vkFlushMappedMemoryRanges, + vkQueueSubmit:vkQueueSubmit, +}; +qfv_physdev_t physDev = { + properties:{ + limits:{ + nonCoherentAtomSize:256, + }, + }, +}; +qfv_device_t device = { + physDev:&physDev, + funcs:&dfuncs, +}; + +static void __attribute__ ((format (printf, 2, 3), noreturn)) +_error (int line, const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + fprintf (stderr, "%d: ", line); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + va_end (args); + exit(1); +} +#define error(fmt...) _error(__LINE__, fmt) + +int +main (void) +{ + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, "", 1024, 0); + + if (stage->size != 1024) { + error ("stage has incorrect size: %zd", stage->size); + } + if (stage->end != stage->size) { + error ("stage has incorrect end: %zd", stage->end); + } + if (!stage->data || stage->data != stage_memory) { + error ("stage memory not mapped: d:%p, m:%p", + stage->data, stage_memory); + } + + for (size_t i = 0; i < RB_buffer_size (&stage->packets); i++) { + qfv_packet_t *p = &stage->packets.buffer[i]; + if (p->stage != stage) { + error ("packet[%zd] stage not set: ps:%p s:%p", i, + p->stage, stage); + } + if (!p->cmd) { + error ("packet[%zd] has no command buffer", i); + } + if (!p->fence) { + error ("packet[%zd] has no fence", i); + } + if (vkGetFenceStatus (device.dev, p->fence) != VK_SUCCESS) { + error ("packet[%zd].fence is not signaled", i); + } + if (p->offset || p->length) { + error ("packet[%zd] size/length not initialized: o:%zd l:%zd", + i, p->offset, p->length); + } + } + + qfv_packet_t *packet = QFV_PacketAcquire (stage); + if (!packet) { + error ("could not get a packet"); + } + if (RB_DATA_AVAILABLE (stage->packets) != 1) { + error ("in flight packet count incorrect"); + } + if (vkGetFenceStatus (device.dev, packet->fence) != VK_NOT_READY) { + error ("packet.fence is signaled"); + } + if (QFV_PacketExtend (packet, 2048)) { + error ("2048 byte request did not return null"); + } + if (!QFV_PacketExtend (packet, 1024)) { + error ("1024 byte request returned null"); + } + if (QFV_PacketExtend (packet, 1)) { + error ("1 byte request did not return null"); + } + + return 0; +} diff --git a/libs/video/renderer/vulkan/util.c b/libs/video/renderer/vulkan/util.c new file mode 100644 index 000000000..c62fdbcb6 --- /dev/null +++ b/libs/video/renderer/vulkan/util.c @@ -0,0 +1,115 @@ +/* + util.c + + Copyright (C) 2019 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/hash.h" + +#include "util.h" + +static const char * +strset_get_key (const void *_str, void *unused) +{ + return (const char *)_str; +} + +strset_t * +new_strset (const char * const *strings) +{ + hashtab_t *tab = Hash_NewTable (61, strset_get_key, 0, 0, 0);//FIXME threads + for ( ; strings && *strings; strings++) { + Hash_Add (tab, (void *) *strings); + } + return (strset_t *) tab; +} + +void +del_strset (strset_t *strset) +{ + Hash_DelTable ((hashtab_t *) strset); +} + +void +strset_add (strset_t *strset, const char *str) +{ + hashtab_t *tab = (hashtab_t *) strset; + Hash_Add (tab, (void *) str); +} + +int +strset_contains (strset_t *strset, const char *str) +{ + return Hash_Find ((hashtab_t *) strset, str) != 0; +} + +int +count_strings (const char * const *str) +{ + int count = 0; + + if (str) { + while (*str++) { + count++; + } + } + return count; +} + +void +merge_strings (const char **out, const char * const *in1, + const char * const *in2) +{ + if (in1) { + while (*in1) { + *out++ = *in1++; + } + } + if (in2) { + while (*in2) { + *out++ = *in2++; + } + } +} + +void +prune_strings (strset_t *strset, const char **strings, uint32_t *count) +{ + hashtab_t *tab = (hashtab_t *) strset; + + for (uint32_t i = *count; i-- > 0; ) { + if (!Hash_Find (tab, strings[i])) { + memmove (strings + i, strings + i + 1, + (--(*count) - i) * sizeof (const char **)); + } + } +} diff --git a/libs/video/renderer/vulkan/util.h b/libs/video/renderer/vulkan/util.h new file mode 100644 index 000000000..41181ff9e --- /dev/null +++ b/libs/video/renderer/vulkan/util.h @@ -0,0 +1,18 @@ +#ifndef __util_h +#define __util_h + +#include + +typedef struct strset_s strset_t; + +int count_strings (const char * const *str) __attribute__((const)); +void merge_strings (const char **out, const char * const *in1, + const char * const *in2); +void prune_strings (strset_t *strset, const char **strings, uint32_t *count); + +strset_t *new_strset (const char * const *strings); +void del_strset (strset_t *strset); +void strset_add (strset_t *strset, const char *str); +int strset_contains (strset_t *strset, const char *str); + +#endif//__util_h diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am new file mode 100644 index 000000000..ecb5853ee --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -0,0 +1,53 @@ +vkgen = libs/video/renderer/vulkan/vkgen.dat$(EXEEXT) +noinst_PROGRAMS += $(vkgen) + +vkgen_dat_src= \ + libs/video/renderer/vulkan/vkgen/vkalias.r \ + libs/video/renderer/vulkan/vkgen/vkenum.r \ + libs/video/renderer/vulkan/vkgen/vkfieldarray.r \ + libs/video/renderer/vulkan/vkgen/vkfieldauto.r \ + libs/video/renderer/vulkan/vkgen/vkfieldcustom.r \ + libs/video/renderer/vulkan/vkgen/vkfielddata.r \ + libs/video/renderer/vulkan/vkgen/vkfielddef.r \ + libs/video/renderer/vulkan/vkgen/vkfieldsingle.r \ + libs/video/renderer/vulkan/vkgen/vkfieldstring.r \ + libs/video/renderer/vulkan/vkgen/vkfieldtype.r \ + libs/video/renderer/vulkan/vkgen/vkgen.r \ + libs/video/renderer/vulkan/vkgen/vkstruct.r \ + libs/video/renderer/vulkan/vkgen/vktype.r \ + libs/video/renderer/vulkan/vkgen/vulkan.r + +VKGENFLAGS = -I$(top_srcdir)/libs/video/renderer/vulkan/vkgen + +libs_video_renderer_vulkan_vkgen_dat_SOURCES=$(vkgen_dat_src) +libs_video_renderer_vkgen_obj=$(libs_video_renderer_vulkan_vkgen_dat_SOURCES:.r=.o) +libs_video_renderer_vkgen_dep=$(call qcautodep,$(libs_video_renderer_vulkan_vkgen_dat_SOURCES:.o=.Qo)) +libs/video/renderer/vulkan/vkgen.dat$(EXEEXT): $(libs_video_renderer_vkgen_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(libs_video_renderer_vkgen_obj) -lcsqc -lr +include $(libs_video_renderer_vkgen_dep) # am--include-marker +r_depfiles_remade += $(libs_video_renderer_vkgen_dep) + +libs/video/renderer/vulkan/vkgen/vkgen.o: $(top_srcdir)/libs/video/renderer/vulkan/vkgen/vkgen.r + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(QCOMPILE) ${VKGENFLAGS} -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ + sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ + $(am__mv) $$depbase.Tqo $$depbase.Qo + +libs/video/renderer/vulkan/vkgen/vulkan.o: $(top_srcdir)/libs/video/renderer/vulkan/vkgen/vulkan.r + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(QCOMPILE) ${VKGENFLAGS} -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ + sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ + $(am__mv) $$depbase.Tqo $$depbase.Qo + +EXTRA_DIST += \ + libs/video/renderer/vulkan/vkgen/stddef.h \ + libs/video/renderer/vulkan/vkgen/stdint.h \ + libs/video/renderer/vulkan/vkgen/vkalias.h \ + libs/video/renderer/vulkan/vkgen/vkenum.h \ + libs/video/renderer/vulkan/vkgen/vkgen.h \ + libs/video/renderer/vulkan/vkgen/vkstruct.h \ + libs/video/renderer/vulkan/vkgen/vktype.h \ + $e + +CLEANFILES += \ + libs/video/renderer/vkgen/*.sym diff --git a/libs/video/renderer/vulkan/vkgen/stddef.h b/libs/video/renderer/vulkan/vkgen/stddef.h new file mode 100644 index 000000000..5252efc1d --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/stddef.h @@ -0,0 +1,2 @@ +#define const +#define __attribute__(x) diff --git a/libs/video/renderer/vulkan/vkgen/stdint.h b/libs/video/renderer/vulkan/vkgen/stdint.h new file mode 100644 index 000000000..04fc06933 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/stdint.h @@ -0,0 +1,11 @@ +typedef int uint8_t; +typedef int uint16_t; +typedef int uint32_t; +typedef int uint64_t; +typedef int int8_t; +typedef int int16_t; +typedef int int32_t; +typedef int int64_t; +typedef int size_t; +typedef int long; +typedef int char; diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.h b/libs/video/renderer/vulkan/vkgen/vkalias.h new file mode 100644 index 000000000..fadf6619f --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkalias.h @@ -0,0 +1,11 @@ +#ifndef __renderer_vulkan_vkgen_vkalias_h +#define __renderer_vulkan_vkgen_vkalias_h + +#include "vktype.h" + +@interface Alias: Type +{ +} +@end + +#endif//__renderer_vulkan_vkgen_vkalias_h diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.r b/libs/video/renderer/vulkan/vkgen/vkalias.r new file mode 100644 index 000000000..e0aad2943 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkalias.r @@ -0,0 +1,148 @@ +#include + +#include "vkalias.h" +#include "vkenum.h" +#include "vkgen.h" +#include "vkstruct.h" + +@implementation Alias +-(string) name +{ + return type.alias.name; +} + +-(Type *) resolveType +{ + return [Type findType: type.alias.aux_type]; +} + +-(void)addToQueue +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + [enumObj addToQueue]; + } + } else if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + [enumObj addToQueue]; + } else if ([alias class] == [Enum class] + || [alias class] == [Struct class]) { + [alias addToQueue]; + } else if (alias.type.meta == ty_basic && alias.type.type == ev_pointer) { + Type *type = [Type findType:alias.type.fldptr.aux_type]; + if (!type) { + // pointer to opaque struct. Probably + // VK_DEFINE_NON_DISPATCHABLE_HANDLE or VK_DEFINE_HANDLE + string createInfo = name + "CreateInfo"; + id structObj = (id) Hash_Find (available_types, createInfo); + if (structObj) { + [structObj addToQueue]; + } + } else if ([type class] == [Alias class]) { + type = [type resolveType]; + if ([type class] == [Struct class]) { + [type addToQueue]; + } + } + } +} + +-(string) cexprType +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj cexprType]; + } + } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj cexprType]; + } + if (name == "uint32_t") { + return "cexpr_uint"; + } + if (name == "size_t") { + return "cexpr_size_t"; + } + return [alias cexprType]; +} + +-(string) parseType +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj parseType]; + } + } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj parseType]; + } + if (name == "uint32_t" || name == "size_t") { + return "QFString"; + } + return [alias parseType]; +} + +-(string) parseFunc +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj parseFunc]; + } + } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj parseFunc]; + } + if (name == "uint32_t") { + return "parse_uint32_t"; + } + return [alias parseFunc]; +} + +-(string) parseData +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj parseData]; + } + } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj parseData]; + } + if (name == "uint32_t") { + return "0"; + } + if (name == "size_t") { + return "&cexpr_size_t"; + } + return [alias parseData]; +} +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.h b/libs/video/renderer/vulkan/vkgen/vkenum.h new file mode 100644 index 000000000..5577b8a23 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkenum.h @@ -0,0 +1,17 @@ +#ifndef __renderer_vulkan_vkgen_vkenum_h +#define __renderer_vulkan_vkgen_vkenum_h + +#include "vktype.h" + +@class PLItem; + +@interface Enum: Type +{ + int prefix_length; +} +-(void) writeTable; +-(void) writeSymtabInit; +-(void) writeSymtabEntry; +@end + +#endif//__renderer_vulkan_vkgen_vkenum_h diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r new file mode 100644 index 000000000..b4dc8b79f --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -0,0 +1,180 @@ +#include + +#include "vkenum.h" +#include "vkgen.h" + +typedef enum VkBool32 { + VK_FALSE, + VK_TRUE, + VK_MAX_ENUM = VK_TRUE +} VkBool32; + +@implementation Enum +-(void)process +{ + string end = "_MAX_ENUM"; + int len; + string prefix = nil; + + if (str_mid([self name], -8) == "FlagBits") { + end = "_FLAG_BITS_MAX_ENUM"; + } + len = -strlen (end); + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (str_mid (var.name, len) == end) { + // len is negative so +1 consumes 1 more char (_) + prefix = str_hold (str_mid (var.name, 0, len + 1)); + } + } + if (prefix) { + prefix_length = strlen (prefix); + } +} + +-initWithType: (qfot_type_t *) type +{ + if (!(self = [super initWithType: type])) { + return nil; + } + [self process]; + return self; +} + +-(string) name +{ + return str_mid(type.strct.tag, 4); +} + +-(void) addToQueue +{ + string name = [self name]; + if (!Hash_Find (processed_types, name)) { + printf (" +%s\n", name); + Hash_Add (processed_types, (void *) name); + [queue addObject: self]; + } +} + +static int +skip_value(string name) +{ + return (str_str (name, "_MAX_ENUM") >= 0 + || str_str (name, "_BEGIN_RANGE") >= 0 + || str_str (name, "_END_RANGE") >= 0 + || str_str (name, "_RANGE_SIZE") >= 0); +} + +-(void) writeTable +{ + int strip_bit = 0; + if (str_mid([self name], -8) == "FlagBits") { + strip_bit = 1; + } + + fprintf (output_file, "static exprtype_t %s_type = {\n", [self name]); + fprintf (output_file, "\t\"%s\",\n", [self name]); + fprintf (output_file, "\tsizeof (int),\n"); + if (strip_bit) { + fprintf (output_file, "\tflag_binops,\n"); + fprintf (output_file, "\tflag_unops,\n"); + } else { + fprintf (output_file, "\tenum_binops,\n"); + fprintf (output_file, "\t0,\n"); + } + fprintf (output_file, "};\n"); + + fprintf (output_file, "static %s %s_values[] = {\n", [self name], [self name]); + for (int i = 0, index = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (skip_value (var.name)) { + continue; + } + fprintf (output_file, "\t%s, // %d 0x%x\n", + var.name, var.offset, var.offset); + index++; + } + fprintf (output_file, "};\n"); + fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", [self name]); + for (int i = 0, index = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (skip_value (var.name)) { + continue; + } + fprintf (output_file, "\t{\"%s\", &%s_type, %s_values + %d},\n", + var.name, [self name], [self name], index); + if (prefix_length) { + string shortname = str_mid (var.name, prefix_length); + if (strip_bit) { + int bit_pos = str_str (shortname, "_BIT"); + if (bit_pos >= 0) { + shortname = str_mid (shortname, 0, bit_pos); + } + } + fprintf (output_file, "\t{\"%s\", &%s_type, %s_values + %d},\n", + str_lower(shortname), [self name], [self name], index); + } + index++; + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); + fprintf (output_file, "static exprtab_t %s_symtab = {\n", [self name]); + fprintf (output_file, "\t%s_symbols,\n", [self name]); + fprintf (output_file, "};\n"); + fprintf (output_file, "static exprenum_t %s_enum = {\n", [self name]); + fprintf (output_file, "\t&%s_type,\n", [self name]); + fprintf (output_file, "\t&%s_symtab,\n", [self name]); + fprintf (output_file, "};\n"); + + fprintf (output_file, "static plfield_t %s_field = { 0, 0, QFString," + " parse_enum, &%s_enum};\n", + [self name], [self name]); + fprintf (output_file, "int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages," + " void *context)\n", + [self name]); + fprintf (output_file, "{\n"); + fprintf (output_file, + "\treturn parse_enum (&%s_field, item, data, messages," + " context);\n", + [self name]); + fprintf (output_file, "}\n"); + + fprintf (header_file, "int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages," + " void *context);\n", + [self name]); +} + +-(void) writeSymtabInit +{ + fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n", + [self name]); +} + +-(void) writeSymtabEntry +{ + fprintf (output_file, "\tHash_Add (enum_symtab, &%s_enum);\n", + [self name]); +} + +-(string) cexprType +{ + return [self name] + "_type"; +} + +-(string) parseType +{ + return "QFString"; +} + +-(string) parseFunc +{ + return "parse_enum"; +} + +-(string) parseData +{ + return "&" + [self name] + "_enum"; +} +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldarray.h b/libs/video/renderer/vulkan/vkgen/vkfieldarray.h new file mode 100644 index 000000000..6f97f0aa7 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldarray.h @@ -0,0 +1,14 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldarray_h +#define __renderer_vulkan_vkgen_vkfieldarray_h + +#include "vkfielddef.h" + +@class FieldType; + +@interface ArrayField: FieldDef +{ + FieldType *type; +} +@end + +#endif//__renderer_vulkan_vkgen_vkfieldarray_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldarray.r b/libs/video/renderer/vulkan/vkgen/vkfieldarray.r new file mode 100644 index 000000000..159a41ba3 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldarray.r @@ -0,0 +1,49 @@ +#include + +#include "vkfieldarray.h" +#include "vkfieldtype.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation ArrayField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + PLItem *desc = [item getObjectForKey:"type"]; + type = [[FieldType fieldType:[desc getObjectAtIndex:1]] retain]; + + value_field = [[item getObjectForKey:"values"] string]; + size_field = [[item getObjectForKey:"size"] string]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static parse_array_t parse_%s_%s_data = {\n", + struct_name, field_name); + [type writeParseData]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + if (size_field) { + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, size_field); + } else { + fprintf (output_file, "\t-1,\n"); + } + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, "QFArray", "array", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldauto.h b/libs/video/renderer/vulkan/vkgen/vkfieldauto.h new file mode 100644 index 000000000..a2e05deb8 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldauto.h @@ -0,0 +1,9 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldauto_h +#define __renderer_vulkan_vkgen_vkfieldauto_h + +#include "vkfielddef.h" + +@interface AutoField: FieldDef +@end + +#endif//__renderer_vulkan_vkgen_vkfieldauto_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldauto.r b/libs/video/renderer/vulkan/vkgen/vkfieldauto.r new file mode 100644 index 000000000..dab844c92 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldauto.r @@ -0,0 +1,43 @@ +#include "vkfieldauto.h" +#include "vkgen.h" +#include "vkstruct.h" + +@implementation AutoField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + field = [strct findField:field_name]; + + return self; +} + +-writeParseData +{ + printf("FieldDef: '%s' '%s'\n", struct_name, field_name); + return self; +} + +-writeField +{ + Type *field_type = [Type findType: field.type]; + fprintf (output_file, "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", + field_name, struct_name, field_name, + [field_type parseType], [field_type parseFunc], + [field_type parseData]); + return self; +} + +-writeSymbol +{ + Type *field_type = [Type findType: field.type]; + fprintf (output_file, + "\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n", + field_name, [field_type cexprType], struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h new file mode 100644 index 000000000..4b7672a9e --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h @@ -0,0 +1,14 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldcustom_h +#define __renderer_vulkan_vkgen_vkfieldcustom_h + +#include "vkfielddef.h" + +@interface CustomField: FieldDef +{ + string pltype; + string parser; + PLItem *fields; +} +@end + +#endif//__renderer_vulkan_vkgen_vkfieldcustom_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r new file mode 100644 index 000000000..611cd7a9b --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r @@ -0,0 +1,68 @@ +#include +#include + +#include "vkfieldcustom.h" +#include "vkfieldtype.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation CustomField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + PLItem *desc = [item getObjectForKey:"type"]; + pltype = str_hold (parseItemType ([desc getObjectAtIndex:1])); + parser = str_hold ([[desc getObjectAtIndex:2] string]); + + fields = [item getObjectForKey:"fields"]; + return self; +} + +-(void)dealloc +{ + str_free (pltype); + str_free (parser); +} + +-writeParseData +{ + fprintf (output_file, "static size_t parse_%s_%s_offsets[] = {\n", + struct_name, field_name); + for (int i = 0, count = [fields count]; i < count; i++) { + string field = [[fields getObjectAtIndex:i] string]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, field); + } + fprintf (output_file, "};\n"); + + fprintf (output_file, "static parse_custom_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\t%s,\n", parser); + fprintf (output_file, "\tparse_%s_%s_offsets,\n", + struct_name, field_name); + fprintf (output_file, "\t%d,\n", [fields count]); + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, pltype, "custom", struct_name, field_name); + return self; +} + +-writeSymbol +{ + fprintf (output_file, + "\t{\"%s\", 0/*FIXME*/, 0/*(void *) field_offset (%s, %s)*/},\n", + field_name, struct_name, "FIXME"); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddata.h b/libs/video/renderer/vulkan/vkgen/vkfielddata.h new file mode 100644 index 000000000..cf8356262 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddata.h @@ -0,0 +1,9 @@ +#ifndef __renderer_vulkan_vkgen_vkfielddata_h +#define __renderer_vulkan_vkgen_vkfielddata_h + +#include "vkfielddef.h" + +@interface DataField: FieldDef +@end + +#endif//__renderer_vulkan_vkgen_vkfielddata_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddata.r b/libs/video/renderer/vulkan/vkgen/vkfielddata.r new file mode 100644 index 000000000..d13ff8965 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddata.r @@ -0,0 +1,45 @@ +#include + +#include "vkfielddata.h" +#include "vkgen.h" +#include "vkstruct.h" +#include "vktype.h" + +@implementation DataField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + value_field = [[item getObjectForKey:"data"] string]; + size_field = [[item getObjectForKey:"size"] string]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static parse_data_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + if (size_field) { + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, size_field); + } else { + fprintf (output_file, "\tt-1,\n"); + } + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, "QFBinary", "data", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddef.h b/libs/video/renderer/vulkan/vkgen/vkfielddef.h new file mode 100644 index 000000000..0363a9e7f --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddef.h @@ -0,0 +1,28 @@ +#ifndef __renderer_vulkan_vkgen_vkfielddef_h +#define __renderer_vulkan_vkgen_vkfielddef_h + +#include +#include + +@class PLItem; +@class Struct; +@class Type; + +@interface FieldDef: Object +{ + int line; + qfot_var_t *field; + string struct_name; + string field_name; + string value_field; + string size_field; +} ++fielddef:(PLItem *)item struct:(Struct *)strct field:(string)fname; +-init:(PLItem *)item struct:(Struct *)strct field:(string)fname; +-writeParseData; +-writeField; +-writeSymbol; +-(string) name; +@end + +#endif//__renderer_vulkan_vkgen_vkfielddef_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddef.r b/libs/video/renderer/vulkan/vkgen/vkfielddef.r new file mode 100644 index 000000000..6aba1df05 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddef.r @@ -0,0 +1,98 @@ +#include +#include + +#include "vkfieldarray.h" +#include "vkfieldauto.h" +#include "vkfieldcustom.h" +#include "vkfielddata.h" +#include "vkfielddef.h" +#include "vkfieldsingle.h" +#include "vkfieldstring.h" +#include "vkstruct.h" + +@implementation FieldDef + ++fielddef:(PLItem *)item struct:(Struct *)strct field:(string)fname +{ + string record = [item string]; + PLItem *type_desc = [item getObjectForKey:"type"]; + + if (!item) { + record = "auto"; + } + if (!record) { + if (item && !type_desc) { + return nil; + } + record = [type_desc string]; + if (!record) { + record = [[type_desc getObjectAtIndex:0] string]; + } + } + switch (record) { + case "auto": + return [[[AutoField alloc] init:item struct:strct field:fname] autorelease]; + case "custom": + return [[[CustomField alloc] init:item struct:strct field:fname] autorelease]; + case "string": + return [[[StringField alloc] init:item struct:strct field:fname] autorelease]; + case "data": + return [[[DataField alloc] init:item struct:strct field:fname] autorelease]; + case "single": + return [[[SingleField alloc] init:item struct:strct field:fname] autorelease]; + case "array": + return [[[ArrayField alloc] init:item struct:strct field:fname] autorelease]; + } + return nil; +} + +-init:(PLItem *)item struct:(Struct *)strct field:(string)fname +{ + self = [super init]; + if (!self) { + return self; + } + + line = [item line]; + struct_name = str_hold ([strct outname]); + field_name = str_hold (fname); + return self; +} + +-fromField:(qfot_var_t *)field struct:(Struct *)strct +{ + return self; +} + +-(void)dealloc +{ + str_free (struct_name); + str_free (field_name); +} + +-writeParseData +{ + fprintf (output_file, "undefined record type parse: %d\n", line); + return self; +} + +-writeField +{ + fprintf (output_file, "undefined record type field: %d\n", line); + return self; +} + +-writeSymbol +{ + fprintf (output_file, + "\t{\"%s\", 0/*FIXME*/, (void *) field_offset (%s, %s)},\n", + field_name, struct_name, value_field); + return self; +} + +-(string) name +{ + return field_name; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h new file mode 100644 index 000000000..83a3dad77 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h @@ -0,0 +1,14 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldsingle_h +#define __renderer_vulkan_vkgen_vkfieldsingle_h + +#include "vkfielddef.h" + +@class FieldType; + +@interface SingleField: FieldDef +{ + FieldType *type; +} +@end + +#endif//__renderer_vulkan_vkgen_vkfieldsingle_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r new file mode 100644 index 000000000..f1c4b4977 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r @@ -0,0 +1,43 @@ +#include + +#include "vkfieldsingle.h" +#include "vkfieldtype.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation SingleField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + PLItem *desc = [item getObjectForKey:"type"]; + type = [[FieldType fieldType:[desc getObjectAtIndex:1]] retain]; + + value_field = [[item getObjectForKey:"value"] string]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static parse_single_t parse_%s_%s_data = {\n", + struct_name, field_name); + [type writeParseData]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + string parse_type = [type parseType]; + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, parse_type, "single", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldstring.h b/libs/video/renderer/vulkan/vkgen/vkfieldstring.h new file mode 100644 index 000000000..fead71504 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldstring.h @@ -0,0 +1,9 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldstring_h +#define __renderer_vulkan_vkgen_vkfieldstring_h + +#include "vkfielddef.h" + +@interface StringField: FieldDef +@end + +#endif//__renderer_vulkan_vkgen_vkfieldstring_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldstring.r b/libs/video/renderer/vulkan/vkgen/vkfieldstring.r new file mode 100644 index 000000000..ff0ba525d --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldstring.r @@ -0,0 +1,36 @@ +#include + +#include "vkfieldstring.h" +#include "vkgen.h" + +@implementation StringField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + value_field = [[item getObjectForKey:"string"] string]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static parse_string_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, "QFString", "string", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldtype.h b/libs/video/renderer/vulkan/vkgen/vkfieldtype.h new file mode 100644 index 000000000..8e5d26bf8 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldtype.h @@ -0,0 +1,22 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldtype_h +#define __renderer_vulkan_vkgen_vkfieldtype_h + +#include + +@class PLItem; + +@interface FieldType: Object +{ + string parse_type; + string type; + string parser; +} ++fieldType:(PLItem *)item; +-initWithItem:(PLItem *)item; +-writeParseData; +-(string)parseType; +@end + +string parseItemType (PLItem *item); + +#endif//__renderer_vulkan_vkgen_vkfieldtype_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldtype.r b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r new file mode 100644 index 000000000..5f9429a20 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r @@ -0,0 +1,72 @@ +#include +#include + +#include "vkfieldtype.h" +#include "vkgen.h" +#include "vktype.h" + +string +parseItemType (PLItem *item) +{ + string str = [item string]; + if (str) { + return str; + } + string mask = "QFMultiType"; + for (int i = [item count]; i-- > 0; ) { + str = [[item getObjectAtIndex:i] string]; + mask = mask + " | (1 << " + str + ")"; + } + return mask; +} + +@implementation FieldType + ++fieldType:(PLItem *)item +{ + return [[[self alloc] initWithItem:item] autorelease]; +} + +-(void)dealloc +{ + str_free (type); + str_free (parser); + str_free (parse_type); +} + +-initWithItem:(PLItem *)item +{ + if (!(self = [super init])) { + return nil; + } + + type = [item string]; + if (type) { + Type *field_type = [[Type lookup:type] dereference]; + type = str_hold (type); + parse_type = [field_type parseType]; + parser = str_hold ("parse_" + type); + } else { + PLItem *typeItem = [item getObjectForKey:"parse_type"]; + parse_type = str_hold (parseItemType(typeItem)); + type = str_hold ([[item getObjectForKey:"type"] string]); + parser = str_hold ([[item getObjectForKey:"parser"] string]); + } + + return self; +} + +-writeParseData +{ + fprintf (output_file, "\t%s,\n", parse_type); + fprintf (output_file, "\tsizeof (%s),\n", type); + fprintf (output_file, "\t%s,\n", parser); + return self; +} + +-(string) parseType +{ + return parse_type; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.h b/libs/video/renderer/vulkan/vkgen/vkgen.h new file mode 100644 index 000000000..8f9cd5c93 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkgen.h @@ -0,0 +1,21 @@ +#ifndef __renderer_vulkan_vkgen_vkgen_h +#define __renderer_vulkan_vkgen_vkgen_h + +#include +#include +#include +#include + +typedef void varfunc (qfot_var_t *var); + +void printf (string fmt, ...); +void fprintf (QFile file, string format, ...); +extern Array *queue; +extern Array *output_types; +extern PLItem *parse; +extern QFile output_file; +extern QFile header_file; +extern hashtab_t *processed_types; +extern hashtab_t *available_types; + +#endif//__renderer_vulkan_vkgen_vkgen_h diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r new file mode 100644 index 000000000..25bcbaf69 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vkgen.h" +#include "vkstruct.h" +#include "vkenum.h" + +static AutoreleasePool *autorelease_pool; +static void +arp_start (void) +{ + autorelease_pool = [[AutoreleasePool alloc] init]; +} + +static void +arp_end (void) +{ + [autorelease_pool release]; + autorelease_pool = nil; +} + +void printf (string fmt, ...) = #0; + +void fprintf (QFile file, string format, ...) +{ + Qputs (file, vsprintf (format, va_copy (@args))); +} + +hashtab_t *available_types; +hashtab_t *processed_types; +Array *queue; +Array *output_types; + +PLItem *parse; +QFile output_file; +QFile header_file; + +qfot_type_encodings_t *encodings; + +qfot_type_t * +next_type (qfot_type_t *type) +{ + int size = type.size; + if (!size) + size = 4; + return (qfot_type_t *) ((int *) type + size); +} + +int +type_is_null (qfot_type_t *type) +{ + return type.size == 0; +} + +void print_type (qfot_type_t *type) +{ + printf ("type: %p %d %d %s", type, type.meta, type.size, type.encoding); + switch (type.meta) { + case ty_basic: + printf (" %d", type.type); + switch (type.type) { + case ev_pointer: + case ev_field: + printf (" "); + print_type (type.fldptr.aux_type); + break; + case ev_func: + printf (" %p %d\n", type.func.return_type, + type.func.num_params); + default: + printf ("\n"); + break; + } + break; + case ty_struct: + case ty_union: + case ty_enum: + printf (" %s %d\n", type.strct.tag, type.strct.num_fields); + break; + case ty_array: + printf (" %p %d %d\n", type.array.type, type.array.base, + type.array.size); + break; + case ty_class: + printf (" %s\n", type.class); + break; + case ty_alias: + printf (" %d %s ", type.alias.type, type.alias.name); + print_type (type.alias.aux_type); + break; + } +} + +void struct_func (qfot_var_t *var) +{ + Type *type = [Type findType:var.type]; + [type addToQueue]; +} + +void +scan_types (void) +{ + qfot_type_t *type; + + for (type = encodings.types; + ((int *)type - (int *) encodings.types) < encodings.size; + type = next_type (type)) { + if (type.size) { + string tag = str_mid(type.strct.tag, 4); + Type *avail_type = [Type fromType: type]; + if (avail_type) { + if (!Hash_Find (available_types, [avail_type name])) { + printf ("scan: %s %s\n", tag, [avail_type name]); + Hash_Add (available_types, avail_type); + } + } + } + } +} + +static string +get_string_key (void *str, void *unused) +{ + return (string) str; +} + +static string +get_object_key (void *obj, void *unused) +{ + return [(id)obj name]; +} + +void +usage (string name) +{ + printf ("%s [plist file] [output file] [header file]\n", name); +} + +int +main(int argc, string *argv) +{ + int do_struct = 0; + int do_enum = 0; + string plist_filename; + QFile plist_file; + PLItem *plist; + PLItem *search; + PLItem *handles; + + arp_start (); + + if (argc != 4) { + usage (argv[0]); + return 1; + } + plist_filename = argv[1]; + plist_file = Qopen (plist_filename, "rt"); + if (!plist_file) { + printf ("could not open property list file: %s\n", plist_filename); + return 1; + } + plist = [[PLItem fromFile: plist_file] retain]; + if (!plist) { + printf ("error parsing: %s\n", plist_filename); + return 1; + } + Qclose (plist_file); + if ([plist class] != [PLDictionary class]) { + printf ("%s not a dictionary\n", plist_filename); + } + search = [[plist getObjectForKey: "search"] retain]; + handles = [[plist getObjectForKey: "handles"] retain]; + parse = [[plist getObjectForKey: "parse"] retain]; + + encodings = PR_FindGlobal (".type_encodings"); + if (!encodings) { + printf ("Can't find encodings\n"); + return 1; + } + queue = [[Array array] retain]; + output_types = [[Array array] retain]; + available_types = Hash_NewTable (127, get_object_key, nil, nil); + processed_types = Hash_NewTable (127, get_string_key, nil, nil); + scan_types (); + + for (int i = [search numObjects]; i-- > 0; ) { + PLString *str = (PLString *) [search getObjectAtIndex:i]; + string search_name = [str string]; + id obj = (id) Hash_Find (available_types, search_name); + obj = [obj resolveType]; + printf("obj: %d %s\n", obj, class_get_class_name([obj class])); + if (obj && [obj class] == [Struct class]) { + [obj addToQueue]; + } + } + + while ([queue count]) { + id obj = [queue objectAtIndex:0]; + [queue removeObjectAtIndex:0]; + if ([obj class] == [Struct class]) { + if ([[parse getObjectForKey:[obj name]] string] == "skip") { + continue; + } + [obj forEachFieldCall:struct_func]; + } + [output_types addObject:obj]; + } + + for (int i = 0; i < argc; i++) { + printf ("vkgen %d %s\n", i, argv[i]); + } + + arp_end (); + + output_file = Qopen (argv[2], "wt"); + header_file = Qopen (argv[3], "wt"); + for (int i = [output_types count]; i-- > 0; ) { + id obj = [output_types objectAtIndex:i]; + if ([obj name] == "VkStructureType") { + continue; + } + if ([obj class] != [Enum class]) { + continue; + } + + arp_start (); + [obj writeTable]; + arp_end (); + } + for (int i = [output_types count]; i-- > 0; ) { + id obj = [output_types objectAtIndex:i]; + if ([obj name] == "VkStructureType") { + continue; + } + if ([obj class] != [Struct class]) { + continue; + } + + arp_start (); + [obj writeTable]; + arp_end (); + } + fprintf (output_file, "static void\n"); + fprintf (output_file, "vkgen_init_symtabs (exprctx_t *context)\n"); + fprintf (output_file, "{\n"); + for (int i = [output_types count]; i-- > 0; ) { + id obj = [output_types objectAtIndex:i]; + if ([obj name] == "VkStructureType") { + continue; + } + arp_start (); + [obj writeSymtabInit]; + [obj writeSymtabEntry]; + arp_end (); + } + fprintf (output_file, "}\n"); + Qclose (output_file); + Qclose (header_file); + return 0; +} diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.h b/libs/video/renderer/vulkan/vkgen/vkstruct.h new file mode 100644 index 000000000..08b489592 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.h @@ -0,0 +1,23 @@ +#ifndef __renderer_vulkan_vkgen_vkstruct_h +#define __renderer_vulkan_vkgen_vkstruct_h + +#include + +#include "vkgen.h" +#include "vktype.h" + +@class PLItem; + +@interface Struct: Type +{ + string outname; +} +-(void) forEachFieldCall: (varfunc) func; +-(qfot_var_t *)findField:(string) fieldName; +-(void) writeTable; +-(void) writeSymtabInit; +-(void) writeSymtabEntry; +-(string) outname; +@end + +#endif//__renderer_vulkan_vkgen_vkstruct_h diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r new file mode 100644 index 000000000..77b11fad5 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "vkfielddef.h" +#include "vkgen.h" +#include "vkstruct.h" + +@implementation Struct + +-(string) name +{ + return str_mid(type.strct.tag, 4); +} + +-(void) addToQueue +{ + string name = [self name]; + if (!Hash_Find (processed_types, name)) { + printf (" +%s\n", name); + Hash_Add (processed_types, (void *) name); + [queue addObject: self]; + } +} + +-(void) forEachFieldCall: (varfunc) func +{ + qfot_struct_t *strct =&type.strct; + + for (int i = 0; i < strct.num_fields; i++) { + func (&strct.fields[i]); + } +} + +-(qfot_var_t *)findField:(string) fieldName +{ + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (var.name == fieldName) { + return var; + } + } + return nil; +} + +-(string)sTypeName +{ + string s = "VK_STRUCTURE_TYPE"; + string name = str_hold ([self outname]); + int length = strlen (name); + int start, end, c; + for (start = 2; start < length; start = end) { + for (end = start + 1; end < length; end++) { + c = str_char (name, end); + if (c >= 'A' && c <= 'Z') { + break; + } + } + s += "_" + str_mid (name, start, end); + } + str_free (name); + return str_upper (s); +} + +-(void) writeTable +{ + PLItem *field_dict = [parse getObjectForKey:[self name]]; + PLItem *new_name = [field_dict getObjectForKey:".name"]; + Array *field_defs = [Array array]; + int have_sType = 0; + + if ([parse string] == "skip") { + return; + } + if (new_name) { + outname = str_hold ([new_name string]); + } + + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *field = &type.strct.fields[i]; + if (field.name == "sType") { + have_sType = 1; + } + } + if (field_dict) { + PLItem *field_keys = [field_dict allKeys]; + + for (int i = [field_keys count]; i-- > 0; ) { + string field_name = [[field_keys getObjectAtIndex:i] string]; + + if (str_mid(field_name, 0, 1) == ".") { + continue; + } + PLItem *field_item = [field_dict getObjectForKey:field_name]; + FieldDef *field_def = [FieldDef fielddef:field_item + struct:self + field:field_name]; + [field_defs addObject: field_def]; + } + } else { + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *field = &type.strct.fields[i]; + if (field.name == "sType" || field.name == "pNext") { + continue; + } + FieldDef *field_def = [FieldDef fielddef:nil + struct:self + field:field.name]; + [field_defs addObject: field_def]; + } + } + for (int i = [field_defs count]; i-- > 0; ) { + FieldDef *field_def = [field_defs objectAtIndex:i]; + [field_def writeParseData]; + } + fprintf (output_file, "static plfield_t %s_fields[] = {\n", [self outname]); + for (int i = [field_defs count]; i-- > 0; ) { + FieldDef *field_def = [field_defs objectAtIndex:i]; + [field_def writeField]; + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); + + fprintf (header_file, "int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages," + " void *context);\n", + [self outname]); + fprintf (output_file, "int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages," + " void *context)\n", + [self outname]); + fprintf (output_file, "{\n"); + if (have_sType) { + fprintf (output_file, "\t((%s *) data)->sType", [self outname]); + fprintf (output_file, " = %s;\n", [self sTypeName]); + } + fprintf (output_file, + "\tif (PL_Type (item) == QFString\n" + "\t\t&& !(item = parse_reference (item, \"%s\", messages, context))) {\n" + "\t\treturn 0;\n" + "\t}\n" + "\treturn PL_ParseStruct (%s_fields, item, data, messages," + " context);\n", + [self outname], [self outname]); + fprintf (output_file, "}\n"); + + fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", [self outname]); + if (field_defs) { + PLItem *field_def; + qfot_var_t *field; + + for (int i = [field_defs count]; i-- > 0; ) { + FieldDef *field_def = [field_defs objectAtIndex:i]; + [field_def writeSymbol]; + } + } else { + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *field = &type.strct.fields[i]; + if (field.name == "sType" || field.name == "pNext") { + continue; + } + Type *field_type = [Type findType: field.type]; + fprintf (output_file, + "\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n", + field.name, [field_type cexprType], [self outname], field.name); + } + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); + + fprintf (output_file, "static exprtab_t %s_symtab = {\n", [self outname]); + fprintf (output_file, "\t%s_symbols,\n", [self outname]); + fprintf (output_file, "};\n"); + + fprintf (output_file, "exprtype_t %s_type = {\n", [self outname]); + fprintf (output_file, "\t\"%s\",\n", [self outname]); + fprintf (output_file, "\tsizeof (%s),\n", [self outname]); + fprintf (output_file, "\tcexpr_struct_binops,\n"); + fprintf (output_file, "\t0,\n"); + fprintf (output_file, "\t&%s_symtab,\n", [self outname]); + fprintf (output_file, "};\n"); + fprintf (output_file, "\n"); + fprintf (header_file, "extern exprtype_t %s_type;\n", [self outname]); +} + +-(void) writeSymtabInit +{ + PLItem *field_dict = [parse getObjectForKey:[self outname]]; + + if ([parse string] == "skip") { + return; + } + + fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n", + [self outname]); +} + +-(void) writeSymtabEntry +{ +} + +-(string) outname +{ + if (outname) { + return outname; + } + return [self name]; +} + +-(string) cexprType +{ + return [self outname] + "_type"; +} + +-(string) parseType +{ + return "QFMultiType | (1 << QFString) | (1 << QFDictionary)"; +} + +-(string) parseFunc +{ + return "parse_" + [self outname]; +} + +-(string) parseData +{ + return "0"; +} +@end diff --git a/libs/video/renderer/vulkan/vkgen/vktype.h b/libs/video/renderer/vulkan/vkgen/vktype.h new file mode 100644 index 000000000..0008c83ab --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vktype.h @@ -0,0 +1,31 @@ +#ifndef __renderer_vulkan_vkgen_vktype_h +#define __renderer_vulkan_vkgen_vktype_h + +#include +#include + +@interface Type: Object +{ + qfot_type_t *type; +} ++fromType: (qfot_type_t *) type; +/** \warning returned string is ephemeral +*/ +-(string) key; +/** \warning returned string is ephemeral +*/ +-(string) name; +-(void) addToQueue; +-(Type *) resolveType; ++(Type *) findType: (qfot_type_t *) type; ++(Type *) lookup: (string) name; +-(string) cexprType; +-(string) parseType; +-(string) parseFunc; +-(string) parseData; + +-(int) isPointer; +-(Type *) dereference; +@end + +#endif//__renderer_vulkan_vkgen_vktype_h diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r new file mode 100644 index 000000000..735e88339 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -0,0 +1,153 @@ +#include + +#include "vkalias.h" +#include "vkenum.h" +#include "vkgen.h" +#include "vkstruct.h" +#include "vktype.h" + +@implementation Type + +static hashtab_t *registered_types; + +static string get_type_key (void *type, void *unused) +{ + return ((Type *) type).type.encoding; +} + ++(void)initialize +{ + registered_types = Hash_NewTable (127, get_type_key, nil, nil); +} + +-initWithType: (qfot_type_t *) type +{ + if (!(self = [super init])) { + return nil; + } + self.type = type; + Hash_Add (registered_types, self); + return self; +} + ++(Type *) findType: (qfot_type_t *) type +{ + if (type.meta == ty_alias && !type.alias.name) { + type = type.alias.full_type; + } + return (Type *) Hash_Find (registered_types, type.encoding); +} + ++(Type *) lookup: (string) name +{ + return (Type *) Hash_Find (available_types, name); +} + ++fromType: (qfot_type_t *) type +{ + if (type.size == 0) { + return nil; + } + switch (type.meta) { + case ty_basic: + case ty_array: + case ty_class: + return [[Type alloc] initWithType: type]; + case ty_enum: + return [[Enum alloc] initWithType: type]; + case ty_struct: + case ty_union: + return [[Struct alloc] initWithType: type]; + case ty_alias: + if (type.alias.name) { + return [[Alias alloc] initWithType: type]; + } + break; + } + return nil; +} + +-(string) key +{ + return type.encoding; +} + +-(string) name +{ + if (type.meta == ty_basic) { + if (type.type == ev_integer) { + return "int"; + } + return pr_type_name[type.type]; + } + //FIXME extract alias name and return proper type name + return type.encoding; +} + +-(void) addToQueue +{ + string name = [self name]; + if (type.meta == ty_basic && type.type == ev_pointer) { + [[Type findType: type.fldptr.aux_type] addToQueue]; + } +} + +-(Type *) resolveType +{ + return self; +} + +-(string) cexprType +{ + return "cexpr_" + [self name]; +} + +-(string) parseType +{ + if (type.meta == ty_basic) { + return "QFString"; + } + return "no parse"; +} + +-(string) parseFunc +{ + if (type.meta == ty_basic) { + return "parse_basic"; + } + return "0"; +} + +-(string) parseData +{ + if (type.meta == ty_basic) { + if (type.type == ev_integer) { + return "&cexpr_int"; + } + return "&cexpr_" + pr_type_name[type.type]; + } + return "0"; +} + +-(int) isPointer +{ + if ((type.meta == ty_basic || type.meta == ty_alias) + && type.type == ev_pointer) { + return 1; + } + return 0; +} + +-(Type *) dereference +{ + qfot_type_t *t = type; + if (t.meta == ty_alias && t.type == ev_pointer) { + t = type.alias.full_type; + } + if (t.meta == ty_basic && t.type == ev_pointer) { + t = type.fldptr.aux_type; + } + return [Type findType:t]; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vulkan.r b/libs/video/renderer/vulkan/vkgen/vulkan.r new file mode 100644 index 000000000..a2a53be7c --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vulkan.r @@ -0,0 +1,3 @@ +#define __x86_64__ +#include +#include "QF/Vulkan/swapchain.h" diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c new file mode 100644 index 000000000..798cd98f9 --- /dev/null +++ b/libs/video/renderer/vulkan/vkparse.c @@ -0,0 +1,1393 @@ +/* + vkparse.c + + Parser for scripted vulkan structs + + Copyright (C) 2020 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cexpr.h" +#include "QF/cmem.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/plist.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/simd/vec4f.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/pipeline.h" +#include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" +#include "QF/Vulkan/swapchain.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +#define vkparse_internal +#include "vkparse.h" +#undef vkparse_internal + +static void flag_or (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + *(int *) (result->value) = *(int *) (val1->value) | *(int *) (val2->value); +} + +static void flag_and (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + *(int *) (result->value) = *(int *) (val1->value) & *(int *) (val2->value); +} + +static void flag_cast_int (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + // FIXME should check value is valid + *(int *) (result->value) = *(int *) (val2->value); +} + +static void flag_not (const exprval_t *val, exprval_t *result, exprctx_t *ctx) +{ + *(int *) (result->value) = ~(*(int *) (val->value)); +} + +binop_t flag_binops[] = { + { '|', 0, 0, flag_or }, + { '&', 0, 0, flag_and }, + { '=', &cexpr_int, 0, flag_cast_int }, + { '=', &cexpr_plitem, 0, cexpr_cast_plitem }, + {} +}; + +binop_t enum_binops[] = { + { '=', &cexpr_plitem, 0, cexpr_cast_plitem }, + {} +}; + +unop_t flag_unops[] = { + { '~', 0, flag_not }, + {} +}; + +typedef struct parse_single_s { + pltype_t type; + size_t stride; + plparser_t parser; + size_t value_offset; +} parse_single_t; + +typedef struct parse_array_s { + pltype_t type; + size_t stride; + plparser_t parser; + size_t value_offset; + size_t size_offset; +} parse_array_t; + +typedef struct parse_data_s { + size_t value_offset; + size_t size_offset; +} parse_data_t; + +typedef struct parse_string_s { + size_t value_offset; +} parse_string_t; + +typedef struct parse_custom_s { + int (*parse) (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context); + size_t *offsets; + size_t num_offsets; +} parse_custom_t; + +static int +parse_basic (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + int ret = 1; + __auto_type etype = (exprtype_t *) field->data; + exprctx_t ectx = *((parsectx_t *) context)->ectx; + exprval_t result = { etype, data }; + ectx.symtab = 0; + ectx.result = &result; + const char *valstr = PL_String (item); + //Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_basic: %s %zd %d %p %p: %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + if (strcmp (valstr, "VK_SUBPASS_EXTERNAL") == 0) { + //FIXME handle subpass in a separate parser? + *(uint32_t *) data = VK_SUBPASS_EXTERNAL; + } else { + ret = !cexpr_eval_string (valstr, &ectx); + if (!ret) { + PL_Message (messages, item, "error parsing %s: %s", + field->name, valstr); + } + } + //Sys_MaskPrintf (SYS_VULKAN_PARSE, " %x\n", *(uint32_t *)data); + + return ret; +} + +static int +parse_uint32_t (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + int ret = 1; + // use size_t (and cexpr_size_t) for val so references to array sizes + // can be used + size_t val = 0; + exprval_t result = { &cexpr_size_t, &val }; + exprctx_t ectx = *((parsectx_t *) context)->ectx; + ectx.symtab = 0; + ectx.result = &result; + const char *valstr = PL_String (item); + //Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_uint32_t: %s %zd %d %p %p: %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + if (strcmp (valstr, "VK_SUBPASS_EXTERNAL") == 0) { + //FIXME handle subpass in a separate parser? + *(uint32_t *) data = VK_SUBPASS_EXTERNAL; + } else { + //Sys_MaskPrintf (SYS_VULKAN_PARSE, + // "parse_uint32_t: %s %zd %d %p %p %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + ret = !cexpr_eval_string (valstr, &ectx); + if (!ret) { + PL_Message (messages, item, "error parsing %s: %s", + field->name, valstr); + } + *(uint32_t *) data = val; + //Sys_MaskPrintf (SYS_VULKAN_PARSE, " %d\n", *(uint32_t *)data); + } + + return ret; +} + +static int +parse_enum (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + int ret = 1; + __auto_type enm = (exprenum_t *) field->data; + exprctx_t ectx = *((parsectx_t *)context)->ectx; + exprval_t result = { enm->type, data }; + ectx.symtab = enm->symtab; + ectx.result = &result; + const char *valstr = PL_String (item); + //Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_enum: %s %zd %d %p %p %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + ret = !cexpr_parse_enum (enm, valstr, &ectx, data); + if (!ret) { + PL_Message (messages, item, "error parsing enum: %s", valstr); + } + //Sys_MaskPrintf (SYS_VULKAN_PARSE, " %d\n", *(int *)data); + return ret; +} + +static const plitem_t * +parse_reference (const plitem_t *item, const char *type, plitem_t *messages, + parsectx_t *pctx) +{ + exprctx_t ectx = *pctx->ectx; + vulkan_ctx_t *ctx = pctx->vctx; + plitem_t *refItem = 0; + exprval_t result = { &cexpr_plitem, &refItem }; + ectx.symtab = 0; + ectx.result = &result; + const char *name = PL_String (item); + if (cexpr_eval_string (name, &ectx)) { + PL_Message (messages, item, va (ctx->va_ctx, "not a %s reference", type)); + return 0; + } + return refItem; +} + +static void * +vkparse_alloc (void *context, size_t size) +{ + parsectx_t *pctx = context; + return cmemalloc (pctx->ectx->memsuper, size); +} + +static int +parse_single (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type single = (parse_single_t *) field->data; + void *flddata = (byte *)data + single->value_offset; + + //Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_single: %s %zd %d %p %p\n", + // field->name, field->offset, + // field->type, field->parser, field->data); + + if (!PL_CheckType (single->type, PL_Type (item))) { + PL_TypeMismatch (messages, item, field->name, single->type, + PL_Type (item)); + return 0; + } + + plfield_t f = { 0, 0, single->type, single->parser, 0 }; + void *value = vkparse_alloc (context, single->stride); + memset (value, 0, single->stride); + if (!single->parser (&f, item, value, messages, context)) { + return 0; + } + + *(void **) flddata = value; + return 1; +} + +static int +parse_array (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type array = (parse_array_t *) field->data; + __auto_type value = (void **) ((byte *)data + array->value_offset); + __auto_type size = (uint32_t *) ((byte *)data + array->size_offset); + + plelement_t element = { + array->type, + array->stride, + vkparse_alloc, + array->parser, + 0, + }; + plfield_t f = { 0, 0, 0, 0, &element }; + + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr; + + //Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_array: %s %zd %d %p %p %p\n", + // field->name, field->offset, field->type, field->parser, + // field->data, data); + //Sys_MaskPrintf (SYS_VULKAN_PARSE, " %d %zd %p %zd %zd\n", array->type, + // array->stride, array->parser, array->value_offset, + // array->size_offset); + if (!PL_ParseArray (&f, item, &arr, messages, context)) { + return 0; + } + *value = vkparse_alloc (context, array->stride * arr->size); + memcpy (*value, arr->a, array->stride * arr->size); + if ((void *) size >= data) { + *size = arr->size; + } + return 1; +} + +static int +parse_data (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type datad = (parse_data_t *) field->data; + __auto_type value = (void **) ((byte *)data + datad->value_offset); + __auto_type size = (size_t *) ((byte *)data + datad->size_offset); + + const void *bindata = PL_BinaryData (item); + size_t binsize = PL_BinarySize (item); + + Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_data: %s %zd %d %p %p %p\n", + field->name, field->offset, field->type, field->parser, + field->data, data); + Sys_MaskPrintf (SYS_VULKAN_PARSE, " %zd %zd\n", datad->value_offset, + datad->size_offset); + Sys_MaskPrintf (SYS_VULKAN_PARSE, " %zd %p\n", binsize, bindata); + + *value = vkparse_alloc (context, binsize); + memcpy (*value, bindata, binsize); + if ((void *) size > data) { + *size = binsize; + } + return 1; +} + +static int +parse_string (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type string = (parse_string_t *) field->data; + __auto_type value = (char **) ((byte *)data + string->value_offset); + + const char *str = PL_String (item); + + //Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_string: %s %zd %d %p %p %p\n", + // field->name, field->offset, field->type, field->parser, + // field->data, data); + //Sys_MaskPrintf (SYS_VULKAN_PARSE, " %zd\n", string->value_offset); + //Sys_MaskPrintf (SYS_VULKAN_PARSE, " %s\n", str); + + size_t len = strlen (str) + 1; + *value = vkparse_alloc (context, len); + memcpy (*value, str, len); + return 1; +} + +static int +parse_custom (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type custom = (parse_custom_t *) field->data; + void **offsets = alloca (custom->num_offsets * sizeof (void *)); + for (size_t i = 0; i < custom->num_offsets; i++) { + offsets[i] = data + custom->offsets[i]; + } + return custom->parse (item, offsets, messages, context); +} + +static int +parse_RGBA (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + int ret = 1; + exprctx_t ectx = *context->ectx; + exprval_t result = { &cexpr_vector, data[0] }; + ectx.symtab = 0; + ectx.result = &result; + const char *valstr = PL_String (item); + Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_RGBA: %s\n", valstr); + ret = !cexpr_eval_string (valstr, &ectx); + Sys_MaskPrintf (SYS_VULKAN_PARSE, " "VEC4F_FMT"\n", + VEC4_EXP (*(vec4f_t *)data[0])); + return ret; +} + +uint64_t +QFV_GetHandle (hashtab_t *tab, const char *name) +{ + handleref_t *hr = Hash_Find (tab, name); + if (hr) { + return hr->handle; + } + return 0; +} + +void +QFV_AddHandle (hashtab_t *tab, const char *name, uint64_t handle) +{ + handleref_t *hr = malloc (sizeof (handleref_t)); + hr->name = strdup (name); + hr->handle = handle; + Hash_Add (tab, hr); +} + +static int +parse_VkRenderPass (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + __auto_type handle = (VkRenderPass *) data[0]; + int ret = 1; + parsectx_t *pctx = context; + exprctx_t ectx = *pctx->ectx; + vulkan_ctx_t *ctx = pctx->vctx; + + const char *name = PL_String (item); + Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_VkRenderPass: %s\n", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".%s", name); + } + + *handle = (VkRenderPass) QFV_GetHandle (ctx->renderpasses, name); + if (*handle) { + return 1; + } + + plitem_t *setItem = 0; + exprval_t result = { &cexpr_plitem, &setItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkRenderPass setLayout; + setLayout = QFV_ParseRenderPass (ctx, setItem, pctx->properties); + *handle = (VkRenderPass) setLayout; + + QFV_AddHandle (ctx->setLayouts, name, (uint64_t) setLayout); + } + return ret; +} + +static int +parse_VkShaderModule (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + __auto_type handle = (VkShaderModule *) data[0]; + vulkan_ctx_t *ctx = context->vctx; + qfv_device_t *device = ctx->device; + + const char *name = PL_String (item); + *handle = (VkShaderModule) QFV_GetHandle (ctx->shaderModules, name); + if (*handle) { + return 1; + } + if (!(*handle = QFV_CreateShaderModule (device, name))) { + PL_Message (messages, item, "could not find shader %s", name); + return 0; + } + QFV_AddHandle (ctx->shaderModules, name, (uint64_t) *handle); + return 1; +} + +static int +parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type handle = (VkDescriptorSetLayout *) data; + int ret = 1; + parsectx_t *pctx = context; + exprctx_t ectx = *pctx->ectx; + vulkan_ctx_t *ctx = pctx->vctx; + + const char *name = PL_String (item); + Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_VkDescriptorSetLayout: %s\n", + name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".setLayouts.%s", name); + } + + *handle = (VkDescriptorSetLayout) QFV_GetHandle (ctx->setLayouts, name); + if (*handle) { + return 1; + } + + plitem_t *setItem = 0; + exprval_t result = { &cexpr_plitem, &setItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkDescriptorSetLayout setLayout; + setLayout = QFV_ParseDescriptorSetLayout (ctx, setItem, + pctx->properties); + *handle = (VkDescriptorSetLayout) setLayout; + + QFV_AddHandle (ctx->setLayouts, name, (uint64_t) setLayout); + } + return ret; +} + +static int +parse_VkPipelineLayout (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + __auto_type handle = (VkPipelineLayout *) data[0]; + int ret = 1; + exprctx_t ectx = *context->ectx; + vulkan_ctx_t *ctx = context->vctx; + + const char *name = PL_String (item); + Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_VkPipelineLayout: %s\n", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".pipelineLayouts.%s", name); + } + + *handle = (VkPipelineLayout) QFV_GetHandle (ctx->pipelineLayouts, name); + if (*handle) { + return 1; + } + + plitem_t *setItem = 0; + exprval_t result = { &cexpr_plitem, &setItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkPipelineLayout layout; + layout = QFV_ParsePipelineLayout (ctx, setItem, context->properties); + *handle = (VkPipelineLayout) layout; + + QFV_AddHandle (ctx->pipelineLayouts, name, (uint64_t) layout); + } + return ret; +} + +static int +parse_VkImage (const plitem_t *item, void **data, plitem_t *messages, + parsectx_t *context) +{ + __auto_type handle = (VkImage *) data[0]; + int ret = 1; + exprctx_t ectx = *context->ectx; + vulkan_ctx_t *ctx = context->vctx; + + const char *name = PL_String (item); + Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_VkImage: %s\n", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".images.%s", name); + } + + *handle = (VkImage) QFV_GetHandle (ctx->images, name); + if (*handle) { + return 1; + } + + plitem_t *imageItem = 0; + exprval_t result = { &cexpr_plitem, &imageItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkImage image; + image = QFV_ParseImage (ctx, imageItem, context->properties); + *handle = (VkImage) image; + + QFV_AddHandle (ctx->images, name, (uint64_t) image); + } + return ret; +} + +static exprtype_t imageview_type = { + "VkImageView", + sizeof (VkImageView), + 0, 0, 0 +}; + +static int +parse_VkImageView (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *_context) +{ + parsectx_t *context = _context; + __auto_type handle = (VkImageView *) data; + int ret = 1; + exprctx_t ectx = *context->ectx; + vulkan_ctx_t *ctx = context->vctx; + + const char *name = PL_String (item); + Sys_MaskPrintf (SYS_VULKAN_PARSE, "parse_VkImageView: %s\n", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".imageViews.%s", name); + } + + *handle = (VkImageView) QFV_GetHandle (ctx->imageViews, name); + if (*handle) { + return 1; + } + + exprval_t *value = 0; + exprval_t result = { &cexpr_exprval, &value }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + + plitem_t *imageViewItem = 0; + if (ret) { + VkImageView imageView; + if (value->type == &imageview_type) { + imageView = *(VkImageView *) value->value; + } else if (value->type == &cexpr_plitem) { + imageView = QFV_ParseImageView (ctx, imageViewItem, + context->properties); + QFV_AddHandle (ctx->imageViews, name, (uint64_t) imageView); + } else { + PL_Message (messages, item, "not a VkImageView"); + return 0; + } + *handle = (VkImageView) imageView; + } + return ret; +} + +static const char * +handleref_getkey (const void *hr, void *unused) +{ + return ((handleref_t *)hr)->name; +} + +static void +handleref_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + free (handleref->name); + free (handleref); +} + +static void +setLayout_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type layout = (VkDescriptorSetLayout) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (layout) { + dfunc->vkDestroyDescriptorSetLayout (device->dev, layout, 0); + } + handleref_free (handleref, ctx); +} + +static void +shaderModule_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type module = (VkShaderModule) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (module) { + dfunc->vkDestroyShaderModule (device->dev, module, 0); + } + handleref_free (handleref, ctx); +} + +static void +pipelineLayout_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type layout = (VkPipelineLayout) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (layout) { + dfunc->vkDestroyPipelineLayout (device->dev, layout, 0); + }; + handleref_free (handleref, ctx); +} + +static void +descriptorPool_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type pool = (VkDescriptorPool) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (pool) { + dfunc->vkDestroyDescriptorPool (device->dev, pool, 0); + }; + handleref_free (handleref, ctx); +} + +static void +sampler_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type sampler = (VkSampler) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (sampler) { + dfunc->vkDestroySampler (device->dev, sampler, 0); + }; + handleref_free (handleref, ctx); +} + +static void +image_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type image = (VkImage) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (image) { + dfunc->vkDestroyImage (device->dev, image, 0); + }; + handleref_free (handleref, ctx); +} + +static void +imageView_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type imageView = (VkImageView) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (imageView) { + dfunc->vkDestroyImageView (device->dev, imageView, 0); + }; + handleref_free (handleref, ctx); +} + +static void +renderpass_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type renderpass = (VkRenderPass) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (renderpass) { + dfunc->vkDestroyRenderPass (device->dev, renderpass, 0); + }; + handleref_free (handleref, ctx); +} + +static hashtab_t *enum_symtab; + +static int +parse_BasePipeline (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + *(VkPipeline *) data = 0; + PL_Message (messages, item, "not implemented"); + return 0; +} + +#include "libs/video/renderer/vulkan/vkparse.cinc" + +static void +imageviewset_index (const exprval_t *a, size_t index, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type set = *(qfv_imageviewset_t **) a->value; + exprval_t *val = 0; + if (index >= set->size) { + cexpr_error (ctx, "invalid index: %zd", index); + } else { + val = cexpr_value (&imageview_type, ctx); + *(VkImageView *) val->value = set->a[index]; + } + *(exprval_t **) c->value = val; +} + +static void +imageviewset_int (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + size_t index = *(int *) b->value; + imageviewset_index (a, index, c, ctx); +} + +static void +imageviewset_uint (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + size_t index = *(unsigned *) b->value; + imageviewset_index (a, index, c, ctx); +} + +static void +imageviewset_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + size_t index = *(size_t *) b->value; + imageviewset_index (a, index, c, ctx); +} + +binop_t imageviewset_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cexpr_struct_pointer_getfield }, + { '[', &cexpr_int, &imageview_type, imageviewset_int }, + { '[', &cexpr_uint, &imageview_type, imageviewset_uint }, + { '[', &cexpr_size_t, &imageview_type, imageviewset_size_t }, + {} +}; + +static exprsym_t imageviewset_symbols[] = { + {"size", &cexpr_size_t, (void *)field_offset (qfv_imageviewset_t, size)}, + { } +}; +static exprtab_t imageviewset_symtab = { + imageviewset_symbols, +}; +exprtype_t imageviewset_type = { + "imageviewset", + sizeof (qfv_imageviewset_t *), + imageviewset_binops, + 0, + &imageviewset_symtab, +}; +static exprsym_t qfv_swapchain_t_symbols[] = { + {"format", &VkFormat_type, (void *)field_offset (qfv_swapchain_t, format)}, + {"extent", &VkExtent2D_type, (void *)field_offset (qfv_swapchain_t, extent)}, + {"views", &imageviewset_type, (void *)field_offset (qfv_swapchain_t, imageViews)}, + { } +}; +static exprtab_t qfv_swapchain_t_symtab = { + qfv_swapchain_t_symbols, +}; +exprtype_t qfv_swapchain_t_type = { + "qfv_swapchain_t", + sizeof (qfv_swapchain_t), + cexpr_struct_binops, + 0, + &qfv_swapchain_t_symtab, +}; + +static exprsym_t vulkan_frameset_t_symbols[] = { + {"size", &cexpr_size_t, (void *)field_offset (vulkan_frameset_t, size)}, + { } +}; +static exprtab_t vulkan_frameset_t_symtab = { + vulkan_frameset_t_symbols, +}; +exprtype_t vulkan_frameset_t_type = { + "frameset", + sizeof (vulkan_frameset_t *), + cexpr_struct_binops, + 0, + &vulkan_frameset_t_symtab, +}; + +typedef struct qfv_renderpass_s { + qfv_attachmentdescription_t *attachments; + qfv_subpassparametersset_t *subpasses; + qfv_subpassdependency_t *dependencies; +} qfv_renderpass_t; + +static plelement_t parse_qfv_renderpass_attachments_data = { + QFDictionary, + sizeof (VkAttachmentDescription), + vkparse_alloc, + parse_VkAttachmentDescription, + 0, +}; + +static plelement_t parse_qfv_renderpass_subpasses_data = { + QFDictionary, + sizeof (VkSubpassDescription), + vkparse_alloc, + parse_VkSubpassDescription, + 0, +}; + +static plelement_t parse_qfv_renderpass_dependencies_data = { + QFDictionary, + sizeof (VkSubpassDependency), + vkparse_alloc, + parse_VkSubpassDependency, + 0, +}; + +static plfield_t renderpass_fields[] = { + { "attachments", field_offset (qfv_renderpass_t, attachments), QFArray, + PL_ParseArray, &parse_qfv_renderpass_attachments_data }, + { "subpasses", field_offset (qfv_renderpass_t, subpasses), QFArray, + PL_ParseArray, &parse_qfv_renderpass_subpasses_data }, + { "dependencies", field_offset (qfv_renderpass_t, dependencies), QFArray, + PL_ParseArray, &parse_qfv_renderpass_dependencies_data }, + {} +}; + +static hashtab_t * +handlref_symtab (void (*free_func)(void*,void*), vulkan_ctx_t *ctx) +{ + return Hash_NewTable (23, handleref_getkey, free_func, + ctx, &ctx->hashlinks); +} + +static const char * +enum_symtab_getkey (const void *e, void *unused) +{ + __auto_type enm = (const exprenum_t *) e; + return enm->type->name; +} + +void +QFV_InitParse (vulkan_ctx_t *ctx) +{ + exprctx_t context = {}; + enum_symtab = Hash_NewTable (61, enum_symtab_getkey, 0, 0, + &ctx->hashlinks); + context.hashlinks = &ctx->hashlinks; + vkgen_init_symtabs (&context); + cexpr_init_symtab (&qfv_swapchain_t_symtab, &context); + cexpr_init_symtab (&vulkan_frameset_t_symtab, &context); + cexpr_init_symtab (&imageviewset_symtab, &context); + + if (!ctx->setLayouts) { + ctx->shaderModules = handlref_symtab (shaderModule_free, ctx); + ctx->setLayouts = handlref_symtab (setLayout_free, ctx); + ctx->pipelineLayouts = handlref_symtab (pipelineLayout_free, ctx); + ctx->descriptorPools = handlref_symtab (descriptorPool_free, ctx); + ctx->samplers = handlref_symtab (sampler_free, ctx); + ctx->images = handlref_symtab (image_free, ctx); + ctx->imageViews = handlref_symtab (imageView_free, ctx); + ctx->renderpasses = handlref_symtab (renderpass_free, ctx); + } +} + +exprenum_t * +QFV_GetEnum (const char *name) +{ + return Hash_Find (enum_symtab, name); +} + +static int +parse_object (vulkan_ctx_t *ctx, memsuper_t *memsuper, plitem_t *plist, + plparser_t parser, void *object, plitem_t *properties) +{ + plitem_t *messages = PL_NewArray (); + exprctx_t exprctx = {}; + parsectx_t parsectx = { &exprctx, ctx, properties }; + exprsym_t var_syms[] = { + {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"frames", &vulkan_frameset_t_type, &ctx->frames}, + {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, + {"swapImageIndex", &cexpr_uint, &ctx->swapImageIndex}, + {QFV_PROPERTIES, &cexpr_plitem, &parsectx.properties}, + {} + }; + exprtab_t vars_tab = { var_syms, 0 }; + + exprctx.external_variables = &vars_tab; + exprctx.messages = messages; + exprctx.hashlinks = &ctx->hashlinks; + exprctx.memsuper = memsuper; + + cexpr_init_symtab (&vars_tab, &exprctx); + + + if (!parser (0, plist, object, messages, &parsectx)) { + for (int i = 0; i < PL_A_NumObjects (messages); i++) { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "%s\n", + PL_String (PL_ObjectAtIndex (messages, i))); + } + return 0; + } + Hash_DelTable (vars_tab.tab); + PL_Free (messages); + + return 1; +} + +static int +parse_qfv_renderpass (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + return PL_ParseStruct (renderpass_fields, item, data, messages, context); +} + +VkRenderPass +QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + memsuper_t *memsuper = new_memsuper (); + qfv_device_t *device = ctx->device; + + qfv_renderpass_t renderpass_data = {}; + + if (!parse_object (ctx, memsuper, plist, parse_qfv_renderpass, + &renderpass_data, properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkRenderPass renderpass; + renderpass = QFV_CreateRenderPass (device, + renderpass_data.attachments, + renderpass_data.subpasses, + renderpass_data.dependencies); + + delete_memsuper (memsuper); + return renderpass; +} + +VkPipeline +QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + memsuper_t *memsuper = new_memsuper (); + qfv_device_t *device = ctx->device; + + __auto_type cInfo = QFV_AllocGraphicsPipelineCreateInfoSet (1, alloca); + memset (&cInfo->a[0], 0, sizeof (cInfo->a[0])); + + if (!parse_object (ctx, memsuper, plist, parse_VkGraphicsPipelineCreateInfo, + &cInfo->a[0], properties)) { + delete_memsuper (memsuper); + return 0; + } + + cInfo->a[0].renderPass = ctx->renderpass; + __auto_type plSet = QFV_CreateGraphicsPipelines (device, 0, cInfo); + VkPipeline pipeline = plSet->a[0]; + free (plSet); + delete_memsuper (memsuper); + return pipeline; +} + +VkDescriptorPool +QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + VkDescriptorPoolCreateInfo cInfo = {}; + + if (!parse_object (ctx, memsuper, plist, parse_VkDescriptorPoolCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkDescriptorPool pool; + dfunc->vkCreateDescriptorPool (device->dev, &cInfo, 0, &pool); + + delete_memsuper (memsuper); + return pool; +} + +VkDescriptorSetLayout +QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + VkDescriptorSetLayoutCreateInfo cInfo = {}; + + if (!parse_object (ctx, memsuper, plist, + parse_VkDescriptorSetLayoutCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkDescriptorSetLayout setLayout; + dfunc->vkCreateDescriptorSetLayout (device->dev, &cInfo, 0, &setLayout); + + delete_memsuper (memsuper); + return setLayout; +} + +VkPipelineLayout +QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + VkPipelineLayoutCreateInfo cInfo = {}; + + if (!parse_object (ctx, memsuper, plist, parse_VkPipelineLayoutCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkPipelineLayout layout; + dfunc->vkCreatePipelineLayout (device->dev, &cInfo, 0, &layout); + + delete_memsuper (memsuper); + return layout; +} + +VkSampler +QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + VkSamplerCreateInfo cInfo = {}; + + if (!parse_object (ctx, memsuper, plist, parse_VkSamplerCreateInfo, &cInfo, + properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkSampler sampler; + dfunc->vkCreateSampler (device->dev, &cInfo, 0, &sampler); + + delete_memsuper (memsuper); + return sampler; +} + +VkImage +QFV_ParseImage (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + VkImageCreateInfo cInfo = {}; + + if (!parse_object (ctx, memsuper, plist, parse_VkImageCreateInfo, &cInfo, + properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkImage image; + dfunc->vkCreateImage (device->dev, &cInfo, 0, &image); + + delete_memsuper (memsuper); + return image; +} + +VkImageView +QFV_ParseImageView (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + VkImageViewCreateInfo cInfo = {}; + + if (!parse_object (ctx, memsuper, plist, parse_VkImageViewCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkImageView imageView; + dfunc->vkCreateImageView (device->dev, &cInfo, 0, &imageView); + + delete_memsuper (memsuper); + return imageView; +} + +typedef struct { + uint32_t count; + VkImageCreateInfo *info; +} imagecreate_t; + +typedef struct { + uint32_t count; + VkImageViewCreateInfo *info; +} imageviewcreate_t; + +static plelement_t qfv_imagecreate_dict = { + QFDictionary, + sizeof (VkImageCreateInfo), + vkparse_alloc, + parse_VkImageCreateInfo, +}; + +static plelement_t qfv_imageviewcreate_dict = { + QFDictionary, + sizeof (VkImageViewCreateInfo), + vkparse_alloc, + parse_VkImageViewCreateInfo, +}; + +static int +parse_imagecreate_dict (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + plfield_t f = { "images", 0, QFArray, parse_array, + &qfv_imagecreate_dict }; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr = 0; + int ret; + + if ((ret = PL_ParseLabeledArray (&f, item, &arr, messages, context))) { + imagecreate_t *imagecreate = data; + imagecreate->count = arr->size; + imagecreate->info = (VkImageCreateInfo *) arr->a; + } + return ret; +} + +static int +parse_imageviewcreate_dict (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + plfield_t f = { "images", 0, QFArray, parse_array, + &qfv_imageviewcreate_dict }; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr = 0; + int ret; + + if ((ret = PL_ParseLabeledArray (&f, item, &arr, messages, context))) { + imageviewcreate_t *imageviewcreate = data; + imageviewcreate->count = arr->size; + imageviewcreate->info = (VkImageViewCreateInfo *) arr->a; + } else { + //FIXME leaky boat when succeeds + if (arr) { + free (arr); + } + } + return ret; +} + +qfv_imageset_t * +QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *item, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + imagecreate_t create = {}; + + pltype_t type = PL_Type (item); + + if (type == QFDictionary) { + if (!parse_object (ctx, memsuper, item, parse_imagecreate_dict, + &create, properties)) { + delete_memsuper (memsuper); + return 0; + } + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Neither array nor dictionary: %d\n", + PL_Line (item)); + delete_memsuper (memsuper); + return 0; + } + + __auto_type set = QFV_AllocImages (create.count, malloc); + for (uint32_t i = 0; i < create.count; i++) { + dfunc->vkCreateImage (device->dev, &create.info[i], 0, &set->a[i]); + + const char *name = PL_KeyAtIndex (item, i); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, set->a[i], + va (ctx->va_ctx, "image:%s", name)); + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".images.%s", name); + QFV_AddHandle (ctx->images, name, (uint64_t) set->a[i]); + } + + delete_memsuper (memsuper); + return set; +} + +qfv_imageviewset_t * +QFV_ParseImageViewSet (vulkan_ctx_t *ctx, plitem_t *item, + plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + imageviewcreate_t create = {}; + + pltype_t type = PL_Type (item); + + if (type == QFDictionary) { + if (!parse_object (ctx, memsuper, item, parse_imageviewcreate_dict, + &create, properties)) { + delete_memsuper (memsuper); + return 0; + } + } else { + Sys_Printf ("Neither array nor dictionary: %d\n", PL_Line (item)); + delete_memsuper (memsuper); + return 0; + } + + __auto_type set = QFV_AllocImageViews (create.count, malloc); + for (uint32_t i = 0; i < create.count; i++) { + dfunc->vkCreateImageView (device->dev, &create.info[i], 0, &set->a[i]); + + const char *name = PL_KeyAtIndex (item, i); + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".imageViews.%s", name); + QFV_AddHandle (ctx->imageViews, name, (uint64_t) set->a[i]); + } + + delete_memsuper (memsuper); + return set; +} + +VkFramebuffer +QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); + + VkFramebufferCreateInfo cInfo = {}; + + if (!parse_object (ctx, memsuper, plist, parse_VkFramebufferCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); + return 0; + } + + VkFramebuffer framebuffer; + dfunc->vkCreateFramebuffer (device->dev, &cInfo, 0, &framebuffer); + Sys_MaskPrintf (SYS_VULKAN_PARSE, "framebuffer, renderPass: %p, %p\n", + framebuffer, cInfo.renderPass); + + delete_memsuper (memsuper); + return framebuffer; +} + +static int +parse_clearvalueset (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + plelement_t element = { + QFDictionary, + sizeof (VkClearValue), + vkparse_alloc, + parse_VkClearValue, + 0, + }; + plfield_t f = { 0, 0, 0, 0, &element }; + + if (!PL_ParseArray (&f, item, data, messages, context)) { + return 0; + } + return 1; +} + +int +QFV_ParseClearValues (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + int ret = 0; + memsuper_t *memsuper = new_memsuper (); + clearvalueset_t *clearValues = 0; + + ctx->clearValues = 0; + if (parse_object (ctx, memsuper, plist, parse_clearvalueset, &clearValues, + properties)) { + ret = 1; + ctx->clearValues = DARRAY_ALLOCFIXED (clearvalueset_t, + clearValues->size, malloc); + memcpy (ctx->clearValues->a, clearValues->a, + clearValues->size * sizeof (clearValues->a[0])); + } + delete_memsuper (memsuper); + return ret; +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h new file mode 100644 index 000000000..4f258a96f --- /dev/null +++ b/libs/video/renderer/vulkan/vkparse.h @@ -0,0 +1,65 @@ +#ifndef __vkparse_h +#define __vkparse_h + +typedef struct parsectx_s { + struct exprctx_s *ectx; + struct vulkan_ctx_s *vctx; + struct plitem_s *properties; + void *data; +} parsectx_t; + +#include "QF/cexpr.h" +#include "QF/plist.h" +#include "QF/Vulkan/renderpass.h" +#ifdef vkparse_internal +#include "libs/video/renderer/vulkan/vkparse.hinc" +#endif + +#define QFV_PROPERTIES "properties" + +typedef struct parseres_s { + const char *name; + plfield_t *field; + size_t offset; +} parseres_t; + +typedef struct handleref_s { + char *name; + uint64_t handle; +} handleref_t; + +void QFV_InitParse (vulkan_ctx_t *ctx); +exprenum_t *QFV_GetEnum (const char *name); + +uint64_t QFV_GetHandle (struct hashtab_s *tab, const char *name); +void QFV_AddHandle (struct hashtab_s *tab, const char *name, uint64_t handle); + +VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkDescriptorPool QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkDescriptorSetLayout QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, + plitem_t *plist, + plitem_t *properties); +VkPipelineLayout QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkSampler QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkImage QFV_ParseImage (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkImageView QFV_ParseImageView (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +struct qfv_imageset_s *QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +struct qfv_imageviewset_s *QFV_ParseImageViewSet (vulkan_ctx_t *ctx, + plitem_t *plist, + plitem_t *properties); +VkFramebuffer QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +int QFV_ParseClearValues (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); + + +#endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist new file mode 100644 index 000000000..22d9173dc --- /dev/null +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -0,0 +1,342 @@ +{ + search = ( + VkAttachmentDescription, + VkSubpassDescription, + VkSubpassDependency, + VkSpecializationInfo, + VkPipelineShaderStageCreateInfo, + VkPipelineVertexInputStateCreateInfo, + VkPipelineInputAssemblyStateCreateInfo, + VkPipelineViewportStateCreateInfo, + VkPipelineRasterizationStateCreateInfo, + VkPipelineMultisampleStateCreateInfo, + VkPipelineDepthStencilStateCreateInfo, + VkPipelineColorBlendStateCreateInfo, + VkPipelineDynamicStateCreateInfo, + VkDescriptorSetLayoutBinding, + VkDescriptorSetLayoutCreateInfo, + VkPushConstantRange, + VkPipelineLayoutCreateInfo, + VkGraphicsPipelineCreateInfo, + VkDescriptorPoolCreateInfo, + VkSamplerCreateInfo, + VkImageCreateInfo, + VkImageViewCreateInfo, + VkFramebufferCreateInfo, + VkClearValue, + ); + parse = { + VkSubpassDescription = { + flags = auto; + pipelineBindPoint = auto; + inputAttachments = { + type = (array, VkAttachmentReference); + size = inputAttachmentCount; + values = pInputAttachments; + }; + colorAttachments = { + type = (array, VkAttachmentReference); + size = colorAttachmentCount; + values = pColorAttachments; + }; + resolveAttachments = { + type = (array, VkAttachmentReference); + values = pResolveAttachments; + matchSize = colorAttachments; + }; + depthStencilAttachment = { + type = (single, VkAttachmentReference); + value = pDepthStencilAttachment; + }; + preserveAttachments = { + type = (array, uint32_t); + size = preserveAttachmentCount; + values = pPreserveAttachments; + }; + }; + VkRenderPassCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + attachments = { + type = (array, VkAttachmentDescription); + size = attachmentCount; + values = pAttachments; + }; + subpasses = { + type = (array, VkSubpassDescription); + size = subpassCount; + values = pSubpasses; + }; + dependencies = { + type = (array, VkSubpassDependency); + size = dependencyCount; + values = pDependencies; + }; + }; + VkSpecializationInfo = { + mapEntries = { + type = (array, VkSpecializationMapEntry); + size = mapEntryCount; + values = pMapEntries; + }; + data = { + type = data; + size = dataSize; + data = pData; + }; + }; + VkPipelineShaderStageCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + stage = auto; + name = { + type = string; + string = pName; + }; + module = { + type = (custom, QFString, parse_VkShaderModule); + fields = (module); + }; + specializationInfo = { + type = (single, VkSpecializationInfo); + value = pSpecializationInfo; + }; + }; + VkShaderModuleCreateInfo = skip; + VkDescriptorSetLayoutBinding = { + binding = auto; + descriptorType = auto; + descriptorCount = auto; + stageFlags = auto; + // skip pImmutableSamplers (default to 0) until I know how it works + }; + VkDescriptorSetLayoutCreateInfo = { + flags = auto; + bindings = { + type = (array, VkDescriptorSetLayoutBinding); + size = bindingCount; + values = pBindings; + }; + }; + VkDescriptorPoolCreateInfo = { + flags = auto; + maxSets = auto; + bindings = { + type = (array, VkDescriptorPoolSize); + size = poolSizeCount; + values = pPoolSizes; + }; + }; + VkPipelineVertexInputStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + bindings = { + type = (array, VkVertexInputBindingDescription); + size = vertexBindingDescriptionCount; + values = pVertexBindingDescriptions; + }; + attributes = { + type = (array, VkVertexInputAttributeDescription); + size = vertexAttributeDescriptionCount; + values = pVertexAttributeDescriptions; + }; + }; + VkPipelineInputAssemblyStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + topology = auto; + primitiveRestartEnable = auto; + }; + VkPipelineViewportStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + //FIXME redo as one array + viewports = { + type = (array, VkViewport); + size = viewportCount; + values = pViewports; + }; + scissors = { + type = (array, VkRect2D); + size = scissorCount; + values = pScissors; + }; + }; + VkPipelineRasterizationStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + depthClampEnable = auto; + rasterizerDiscardEnable = auto; + polygonMode = auto; + cullMode = auto; + frontFace = auto; + depthBiasEnable = auto; + depthBiasConstantFactor = auto; + depthBiasClamp = auto; + depthBiasSlopeFactor = auto; + lineWidth = auto; + }; + VkPipelineMultisampleStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + rasterizationSamples = auto; + sampleShadingEnable = auto; + minSampleShading = auto; + //pSampleMask = auto; FIXME disabled until correct size is known + alphaToCoverageEnable = auto; + alphaToOneEnable = auto; + }; + VkPipelineDepthStencilStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + depthTestEnable = auto; + depthWriteEnable = auto; + depthCompareOp = auto; + depthBoundsTestEnable = auto; + stencilTestEnable = auto; + front = auto; + back = auto; + minDepthBounds = auto; + maxDepthBounds = auto; + }; + VkPipelineColorBlendStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + logicOpEnable = auto; + logicOp = auto; + attachments = { + type = (array, VkPipelineColorBlendAttachmentState); + size = attachmentCount; + values = pAttachments; + }; + blendConstants = { + type = (custom, QFString, parse_RGBA); + fields = (blendConstants); + }; + }; + VkPipelineDynamicStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + dynamicState = { + type = (array, VkDynamicState); + size = dynamicStateCount; + values = pDynamicStates; + }; + }; + VkPipelineLayoutCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + setLayouts = { + type = (array, { + parse_type = (QFDictionary, QFString); + type = VkDescriptorSetLayout; + parser = parse_VkDescriptorSetLayout; + }); + size = setLayoutCount; + values = pSetLayouts; + }; + pushConstantRanges = { + type = (array, VkPushConstantRange); + size = pushConstantRangeCount; + values = pPushConstantRanges; + }; + }; + VkPipelineTessellationStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + patchControlPoints = auto; + }; + VkGraphicsPipelineCreateInfo = { + flags = auto; + stages = { + type = (array, VkPipelineShaderStageCreateInfo); + size = stageCount; + values = pStages; + }; + vertexInput = { + type = (single, VkPipelineVertexInputStateCreateInfo); + value = pVertexInputState; + }; + inputAssembly = { + type = (single, VkPipelineInputAssemblyStateCreateInfo); + value = pInputAssemblyState; + }; + tessellation = { + type = (single, VkPipelineTessellationStateCreateInfo); + value = pTessellationState; + }; + viewport = { + type = (single, VkPipelineViewportStateCreateInfo); + value = pViewportState; + }; + rasterization = { + type = (single, VkPipelineRasterizationStateCreateInfo); + value = pRasterizationState; + }; + multisample = { + type = (single, VkPipelineMultisampleStateCreateInfo); + value = pMultisampleState; + }; + depthStencil = { + type = (single, VkPipelineDepthStencilStateCreateInfo); + value = pDepthStencilState; + }; + colorBlend = { + type = (single, VkPipelineColorBlendStateCreateInfo); + value = pColorBlendState; + }; + dynamic = { + type = (single, VkPipelineDynamicStateCreateInfo); + value = pDynamicState; + }; + layout = { + type = (custom, QFString, parse_VkPipelineLayout); + fields = (layout); + }; + subpass = auto; + basePipelineHandle = { + type = (custom, QFString, parse_BasePipeline); + fields = (basePipelineHandle); + }; + basePipelineIndex = auto; + }; + VkImageCreateInfo = { + flags = auto; + imageType = auto; + format = auto; + extent = auto; + mipLevels = auto; + arrayLayers = auto; + samples = auto; + tiling = auto; + usage = auto; + sharingMode = skip; // FIXME for now + queueFamilyIndexCount = skip; // FIXME for now + pQueueFamilyIndices = skip; // FIXME for now + initialLayout = auto; + }; + VkImageViewCreateInfo = { + flags = auto; + image = { + type = (custom, (QFDictionary, QFString), + parse_VkImage); + fields = (image); + }; + viewType = auto; + format = auto; + components = auto; + subresourceRange = auto; + }; + VkFramebufferCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + renderPass = { + type = (custom, QFString, parse_VkRenderPass); + fields = (renderPass); + }; + attachments = { + type = (array, VkImageView); + size = attachmentCount; + values = pAttachments; + }; + width = auto; + height = auto; + layers = auto; + }; + VkClearColorValue = skip; + VkClearValue = { + color = { + type = (custom, QFString, parse_RGBA); + fields = (color); + }; + depthStencil = auto; + }; + } +} diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c new file mode 100644 index 000000000..c2581e773 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -0,0 +1,357 @@ +/* + vulkan_alias.c + + Vulkan alias model pipeline + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/26 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/cvar.h" +#include "QF/darray.h" +#include "QF/entity.h" +#include "QF/image.h" +#include "QF/render.h" +#include "QF/skin.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vrect.h" + +#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +static const char *alias_pass_names[] = { + "depth", + "g-buffer", + "translucent", +}; + +static QFV_Subpass subpass_map[] = { + QFV_passDepth, // QFV_aliasDepth + QFV_passGBuffer, // QFV_aliasGBuffer + QFV_passTranslucent, // QFV_aliasTranslucent +}; + +static void +emit_commands (VkCommandBuffer cmd, int pose1, int pose2, + qfv_alias_skin_t *skin, + void *vert_constants, int vert_size, + void *frag_constants, int frag_size, + aliashdr_t *hdr, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasctx_t *actx = ctx->alias_context; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + + __auto_type mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); + + VkDeviceSize offsets[] = { + pose1 * hdr->poseverts * sizeof (aliasvrt_t), + pose2 * hdr->poseverts * sizeof (aliasvrt_t), + 0, + }; + VkBuffer buffers[] = { + mesh->vertex_buffer, + mesh->vertex_buffer, + mesh->uv_buffer, + }; + int bindingCount = skin ? 3 : 2; + + dfunc->vkCmdBindVertexBuffers (cmd, 0, bindingCount, buffers, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0, + VK_INDEX_TYPE_UINT32); + dfunc->vkCmdPushConstants (cmd, actx->layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, vert_size, vert_constants); + if (skin) { + dfunc->vkCmdPushConstants (cmd, actx->layout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 68, frag_size, frag_constants); + aframe->imageInfo[0].imageView = skin->view; + dfunc->vkCmdPushDescriptorSetKHR (cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, + actx->layout, + 0, ALIAS_IMAGE_INFOS, + aframe->descriptors + + ALIAS_BUFFER_INFOS); + } + dfunc->vkCmdDrawIndexed (cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); +} + +void +Vulkan_DrawAlias (entity_t *ent, vulkan_ctx_t *ctx) +{ + aliasctx_t *actx = ctx->alias_context; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + model_t *model = ent->renderer.model; + aliashdr_t *hdr; + qfv_alias_skin_t *skin; + struct { + mat4f_t mat; + float blend; + } vertex_constants; + byte fragment_constants[3][4]; + + if (!(hdr = model->aliashdr)) { + hdr = Cache_Get (&model->cache); + } + + Transform_GetWorldMatrix (ent->transform, vertex_constants.mat); + vertex_constants.blend = R_AliasGetLerpedFrames (ent, hdr); + + if (0/*XXX ent->skin && ent->skin->tex*/) { + //skin = ent->skin->tex; + } else { + maliasskindesc_t *skindesc; + skindesc = R_AliasGetSkindesc (ent->renderer.skinnum, hdr); + skin = (qfv_alias_skin_t *) ((byte *) hdr + skindesc->skin); + } + QuatScale (ent->renderer.colormod, 255, fragment_constants[0]); + QuatCopy (skin->colora, fragment_constants[1]); + QuatCopy (skin->colorb, fragment_constants[2]); + + emit_commands (aframe->cmdSet.a[QFV_aliasDepth], + ent->animation.pose1, ent->animation.pose2, + 0, &vertex_constants, 17 * sizeof (float), + fragment_constants, sizeof (fragment_constants), + hdr, ctx); + emit_commands (aframe->cmdSet.a[QFV_aliasGBuffer], + ent->animation.pose1, ent->animation.pose2, + skin, &vertex_constants, 17 * sizeof (float), + fragment_constants, sizeof (fragment_constants), + hdr, ctx); +} + +static void +alias_begin_subpass (QFV_AliasSubpass subpass, VkPipeline pipeline, + vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasctx_t *actx = ctx->alias_context; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = aframe->cmdSet.a[subpass]; + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass, subpass_map[subpass], + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + //VkDescriptorSet sets[] = { + // aframe->descriptors[0].dstSet, + // aframe->descriptors[1].dstSet, + //}; + //dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + // actx->layout, 0, 2, sets, 0, 0); + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + actx->layout, + 0, 1, aframe->descriptors + 0); + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + //dfunc->vkUpdateDescriptorSets (device->dev, 2, aframe->descriptors, 0, 0); + + //XXX glsl_Fog_GetColor (fog); + //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; +} + +static void +alias_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkEndCommandBuffer (cmd); +} + +void +Vulkan_AliasBegin (vulkan_ctx_t *ctx) +{ + aliasctx_t *actx = ctx->alias_context; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + + //XXX quat_t fog; + DARRAY_APPEND (&cframe->cmdSets[QFV_passDepth], + aframe->cmdSet.a[QFV_aliasDepth]); + DARRAY_APPEND (&cframe->cmdSets[QFV_passGBuffer], + aframe->cmdSet.a[QFV_aliasGBuffer]); + + //FIXME need per frame matrices + aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + + alias_begin_subpass (QFV_aliasDepth, actx->depth, ctx); + alias_begin_subpass (QFV_aliasGBuffer, actx->gbuf, ctx); +} + +void +Vulkan_AliasEnd (vulkan_ctx_t *ctx) +{ + aliasctx_t *actx = ctx->alias_context; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + + alias_end_subpass (aframe->cmdSet.a[QFV_aliasDepth], ctx); + alias_end_subpass (aframe->cmdSet.a[QFV_aliasGBuffer], ctx); +} + +static VkDescriptorBufferInfo base_buffer_info = { + 0, 0, VK_WHOLE_SIZE +}; +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_buffer_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, 0, 0 +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0, 0, 0 +}; + +void +Vulkan_Alias_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + aliasctx_t *actx = calloc (1, sizeof (aliasctx_t)); + ctx->alias_context = actx; + + size_t frames = ctx->frames.size; + DARRAY_INIT (&actx->frames, frames); + DARRAY_RESIZE (&actx->frames, frames); + actx->frames.grow = 0; + + actx->depth = Vulkan_CreatePipeline (ctx, "alias_depth"); + actx->gbuf = Vulkan_CreatePipeline (ctx, "alias_gbuf"); + actx->layout = Vulkan_CreatePipelineLayout (ctx, "alias_layout"); + actx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler"); + + /*__auto_type layouts = QFV_AllocDescriptorSetLayoutSet (2 * frames, alloca); + for (size_t i = 0; i < layouts->size / 2; i++) { + __auto_type mats = QFV_GetDescriptorSetLayout (ctx, "alias.matrices"); + __auto_type lights = QFV_GetDescriptorSetLayout (ctx, "alias.lights"); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, + mats, va (ctx->va_ctx, "set_layout:%s:%d", + "alias.matrices", i)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, + lights, va (ctx->va_ctx, "set_layout:%s:%d", + "alias.lights", i)); + layouts->a[2 * i + 0] = mats; + layouts->a[2 * i + 1] = lights; + }*/ + //__auto_type pool = QFV_GetDescriptorPool (ctx, "alias.pool"); + + //__auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); + for (size_t i = 0; i < frames; i++) { + __auto_type aframe = &actx->frames.a[i]; + + DARRAY_INIT (&aframe->cmdSet, QFV_aliasNumPasses); + DARRAY_RESIZE (&aframe->cmdSet, QFV_aliasNumPasses); + aframe->cmdSet.grow = 0; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &aframe->cmdSet); + + for (int j = 0; j < QFV_aliasNumPasses; j++) { + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + aframe->cmdSet.a[j], + va (ctx->va_ctx, "cmd:alias:%zd:%s", i, + alias_pass_names[j])); + } + for (int j = 0; j < ALIAS_BUFFER_INFOS; j++) { + aframe->bufferInfo[j] = base_buffer_info; + aframe->descriptors[j] = base_buffer_write; + //aframe->descriptors[j].dstSet = sets->a[ALIAS_BUFFER_INFOS*i + j]; + aframe->descriptors[j].dstBinding = j; + aframe->descriptors[j].pBufferInfo = &aframe->bufferInfo[j]; + } + for (int j = 0; j < ALIAS_IMAGE_INFOS; j++) { + aframe->imageInfo[j] = base_image_info; + aframe->imageInfo[j].sampler = actx->sampler; + int k = j + ALIAS_BUFFER_INFOS; + aframe->descriptors[k] = base_image_write; + aframe->descriptors[k].dstBinding = k; + aframe->descriptors[k].pImageInfo = &aframe->imageInfo[j]; + } + } + //free (sets); +} + +void +Vulkan_Alias_Shutdown (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasctx_t *actx = ctx->alias_context; + + for (size_t i = 0; i < actx->frames.size; i++) { + __auto_type aframe = &actx->frames.a[i]; + free (aframe->cmdSet.a); + } + + dfunc->vkDestroyPipeline (device->dev, actx->depth, 0); + dfunc->vkDestroyPipeline (device->dev, actx->gbuf, 0); + free (actx->frames.a); + free (actx); +} diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c new file mode 100644 index 000000000..bceea6666 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -0,0 +1,1660 @@ +/* + vulkan_bsp.c + + Vulkan bsp + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/18 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/cvar.h" +#include "QF/darray.h" +#include "QF/entity.h" +#include "QF/image.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vrect.h" + +#include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/scrap.h" +#include "QF/Vulkan/staging.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +static const char *bsp_pass_names[] = { + "depth", + "g-buffer", + "sky", + "turb", +}; + +static QFV_Subpass subpass_map[] = { + QFV_passDepth, // QFV_bspDepth + QFV_passGBuffer, // QFV_bspGBuffer + QFV_passTranslucent, // QFV_bspSky + QFV_passTranslucent, // QFV_bspTurb +}; + +static float identity[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, +}; + +#define ALLOC_CHUNK 64 + +typedef struct bsppoly_s { + uint32_t count; + uint32_t indices[1]; +} bsppoly_t; + +#define CHAIN_SURF_F2B(surf,chain) \ + do { \ + instsurf_t *inst = (surf)->instsurf; \ + if (__builtin_expect(!inst, 1)) \ + (surf)->tinst = inst = get_instsurf (bctx); \ + inst->surface = (surf); \ + *(chain##_tail) = inst; \ + (chain##_tail) = &inst->tex_chain; \ + *(chain##_tail) = 0; \ + } while (0) + +#define CHAIN_SURF_B2F(surf,chain) \ + do { \ + instsurf_t *inst = (surf)->instsurf; \ + if (__builtin_expect(!inst, 1)) \ + (surf)->tinst = inst = get_instsurf (bctx); \ + inst->surface = (surf); \ + inst->tex_chain = (chain); \ + (chain) = inst; \ + } while (0) + +#define GET_RELEASE(type,name) \ +static inline type * \ +get_##name (bspctx_t *bctx) \ +{ \ + type *ele; \ + if (!bctx->free_##name##s) { \ + int i; \ + bctx->free_##name##s = calloc (ALLOC_CHUNK, sizeof (type)); \ + for (i = 0; i < ALLOC_CHUNK - 1; i++) \ + bctx->free_##name##s[i]._next = &bctx->free_##name##s[i + 1]; \ + } \ + ele = bctx->free_##name##s; \ + bctx->free_##name##s = ele->_next; \ + ele->_next = 0; \ + *bctx->name##s_tail = ele; \ + bctx->name##s_tail = &ele->_next; \ + return ele; \ +} \ +static inline void \ +release_##name##s (bspctx_t *bctx) \ +{ \ + if (bctx->name##s) { \ + *bctx->name##s_tail = bctx->free_##name##s; \ + bctx->free_##name##s = bctx->name##s; \ + bctx->name##s = 0; \ + bctx->name##s_tail = &bctx->name##s; \ + } \ +} + +GET_RELEASE (elechain_t, elechain) +GET_RELEASE (elements_t, elements) +GET_RELEASE (instsurf_t, static_instsurf) +GET_RELEASE (instsurf_t, instsurf) + +static void +add_texture (texture_t *tx, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + + vulktex_t *tex = tx->render; + DARRAY_APPEND (&bctx->texture_chains, tex); + tex->tex_chain = 0; + tex->tex_chain_tail = &tex->tex_chain; + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; +} + +static void +init_surface_chains (mod_brush_t *brush, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int i; + + release_static_instsurfs (bctx); + release_instsurfs (bctx); + + for (i = 0; i < brush->nummodelsurfaces; i++) { + brush->surfaces[i].instsurf = get_static_instsurf (bctx); + brush->surfaces[i].instsurf->surface = &brush->surfaces[i]; + } +} + +static inline void +clear_tex_chain (vulktex_t *tex) +{ + tex->tex_chain = 0; + tex->tex_chain_tail = &tex->tex_chain; + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; +} + +static void +clear_texture_chains (bspctx_t *bctx) +{ + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + if (!bctx->texture_chains.a[i]) + continue; + clear_tex_chain (bctx->texture_chains.a[i]); + } + clear_tex_chain (r_notexture_mip->render); + release_elechains (bctx); + release_elementss (bctx); + release_instsurfs (bctx); +} + +void +Vulkan_ClearElements (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + release_elechains (bctx); + release_elementss (bctx); +} +/* +static void +update_lightmap (mod_brush_t *brush, msurface_t *surf, vulkan_ctx_t *ctx) +{ + int maps; + + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) + if (d_lightstylevalue[surf->styles[maps]] != surf->cached_light[maps]) + goto dynamic; + + if ((surf->dlightframe == r_framecount) || surf->cached_dlight) { +dynamic: + if (r_dynamic->int_val) + Vulkan_BuildLightMap (brush, surf, ctx); + } +} +*/ +static inline void +chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, + float *color, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + instsurf_t *is; + + if (surf->flags & SURF_DRAWSKY) { + CHAIN_SURF_F2B (surf, bctx->sky_chain); + } else if ((surf->flags & SURF_DRAWTURB) || (color && color[3] < 1.0)) { + CHAIN_SURF_B2F (surf, bctx->waterchain); + } else { + texture_t *tx; + vulktex_t *tex; + + if (!surf->texinfo->texture->anim_total) + tx = surf->texinfo->texture; + else + tx = R_TextureAnimation (surf); + tex = tx->render; + CHAIN_SURF_F2B (surf, tex->tex_chain); + + //update_lightmap (brush, surf, ctx); + } + if (!(is = surf->instsurf)) + is = surf->tinst; + is->transform = transform; + is->color = color; +} + +static void +register_textures (mod_brush_t *brush, vulkan_ctx_t *ctx) +{ + int i; + texture_t *tex; + + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; + if (!tex) + continue; + add_texture (tex, ctx); + } +} + +static void +clear_textures (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + bctx->texture_chains.size = 0; +} + +void +Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx) +{ + int i; + model_t *m; + mod_brush_t *brush = &r_worldentity.renderer.model->brush; + + clear_textures (ctx); + init_surface_chains (brush, ctx); + add_texture (r_notexture_mip, ctx); + register_textures (brush, ctx); + for (i = 0; i < num_models; i++) { + m = models[i]; + if (!m) + continue; + // sub-models are done as part of the main model + if (*m->path == '*') + continue; + // world has already been done, not interested in non-brush models + if (m == r_worldentity.renderer.model || m->type != mod_brush) + continue; + brush = &m->brush; + brush->numsubmodels = 1; // no support for submodels in non-world model + register_textures (brush, ctx); + } +} + +static elechain_t * +add_elechain (vulktex_t *tex, int ec_index, bspctx_t *bctx) +{ + elechain_t *ec; + + ec = get_elechain (bctx); + ec->elements = get_elements (bctx); + ec->index = ec_index; + ec->transform = 0; + ec->color = 0; + *tex->elechain_tail = ec; + tex->elechain_tail = &ec->next; + return ec; +} + +static void +count_verts_inds (model_t **models, msurface_t *fa, + uint32_t *verts, uint32_t *inds) +{ + *verts = fa->numedges; + *inds = fa->numedges + 1; +} + +static bsppoly_t * +build_surf_displist (model_t **models, msurface_t *fa, int base, + bspvert_t **vert_list) +{ + int numverts; + int numindices; + int i; + vec_t *vec; + mvertex_t *vertices; + medge_t *edges; + int *surfedges; + int index; + bspvert_t *verts; + bsppoly_t *poly; + uint32_t *ind; + float s, t; + mod_brush_t *brush; + + if (fa->ec_index < 0) { + // instance model + brush = &models[~fa->ec_index]->brush; + } else { + // main or sub model + brush = &r_worldentity.renderer.model->brush; + } + vertices = brush->vertexes; + edges = brush->edges; + surfedges = brush->surfedges; + // create a triangle fan + numverts = fa->numedges; + numindices = numverts + 1; + verts = *vert_list; + // surf->polys is set to the next slot before the call + poly = (bsppoly_t *) fa->polys; + poly->count = numindices; + for (i = 0, ind = poly->indices; i < numverts; i++) { + *ind++ = base + i; + } + *ind++ = -1; // end of primitive + fa->polys = (glpoly_t *) poly; + + for (i = 0; i < numverts; i++) { + index = surfedges[fa->firstedge + i]; + if (index > 0) { + vec = vertices[edges[index].v[0]].position; + } else { + vec = vertices[edges[-index].v[1]].position; + } + + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + VectorCopy (vec, verts[i].vertex); + verts[i].vertex[3] = 1; + verts[i].tlst[0] = s / fa->texinfo->texture->width; + verts[i].tlst[1] = t / fa->texinfo->texture->height; + + //lightmap texture coordinates + if (!fa->lightpic) { + // sky and water textures don't have lightmaps + verts[i].tlst[2] = 0; + verts[i].tlst[3] = 0; + continue; + } + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + s -= fa->texturemins[0]; + t -= fa->texturemins[1]; + s += fa->lightpic->rect->x * 16 + 8; + t += fa->lightpic->rect->y * 16 + 8; + s /= 16; + t /= 16; + verts[i].tlst[2] = s * fa->lightpic->size; + verts[i].tlst[3] = t * fa->lightpic->size; + } + *vert_list += numverts; + return (bsppoly_t *) &poly->indices[numindices]; +} + +void +Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + int i, j; + int vertex_index_base; + model_t *m; + dmodel_t *dm; + msurface_t *surf; + qfv_stagebuf_t *stage; + bspvert_t *vertices; + bsppoly_t *poly; + mod_brush_t *brush; + + QuatSet (0, 0, sqrt(0.5), sqrt(0.5), bctx->sky_fix); // proper skies + QuatSet (0, 0, 0, 1, bctx->sky_rotation[0]); + QuatCopy (bctx->sky_rotation[0], bctx->sky_rotation[1]); + QuatSet (0, 0, 0, 0, bctx->sky_velocity); + QuatExp (bctx->sky_velocity, bctx->sky_velocity); + bctx->sky_time = vr_data.realtime; + + // now run through all surfaces, chaining them to their textures, thus + // effectively sorting the surfaces by texture (without worrying about + // surface order on the same texture chain). + for (i = 0; i < num_models; i++) { + m = models[i]; + if (!m) + continue; + // sub-models are done as part of the main model + if (*m->path == '*' || m->type != mod_brush) + continue; + brush = &m->brush; + // non-bsp models don't have surfaces. + dm = brush->submodels; + for (j = 0; j < brush->numsurfaces; j++) { + vulktex_t *tex; + if (j == dm->firstface + dm->numfaces) { + dm++; + if (dm - brush->submodels == brush->numsubmodels) { + // limit the surfaces + // probably never hit + Sys_Printf ("R_BuildDisplayLists: too many surfaces\n"); + brush->numsurfaces = j; + break; + } + } + surf = brush->surfaces + j; + surf->ec_index = dm - brush->submodels; + if (!surf->ec_index && m != r_worldentity.renderer.model) + surf->ec_index = -1 - i; // instanced model + tex = surf->texinfo->texture->render; + // append surf to the texture chain + CHAIN_SURF_F2B (surf, tex->tex_chain); + } + } + // All vertices from all brush models go into one giant vbo. + uint32_t vertex_count = 0; + uint32_t index_count = 0; + uint32_t poly_count = 0; + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + vulktex_t *tex = bctx->texture_chains.a[i]; + for (instsurf_t *is = tex->tex_chain; is; is = is->tex_chain) { + uint32_t verts, inds; + count_verts_inds (models, is->surface, &verts, &inds); + vertex_count += verts; + index_count += inds; + poly_count++; + } + } + + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + size_t atom_mask = atom - 1; + size_t frames = bctx->frames.size; + size_t index_buffer_size = index_count * frames * sizeof (uint32_t); + size_t vertex_buffer_size = vertex_count * sizeof (bspvert_t); + + index_buffer_size = (index_buffer_size + atom_mask) & ~atom_mask; + stage = QFV_CreateStagingBuffer (device, "bsp", vertex_buffer_size, + ctx->cmdpool); + qfv_packet_t *packet = QFV_PacketAcquire (stage); + vertices = QFV_PacketExtend (packet, vertex_buffer_size); + vertex_index_base = 0; + // holds all the polygon definitions (count + indices) + bctx->polys = malloc ((index_count + poly_count) * sizeof (uint32_t)); + + // All usable surfaces have been chained to the (base) texture they use. + // Run through the textures, using their chains to build display maps. + // For animated textures, if a surface is on one texture of the group, it + // will be on all. + poly = bctx->polys; + int count = 0; + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + vulktex_t *tex; + instsurf_t *is; + elechain_t *ec = 0; + + tex = bctx->texture_chains.a[i]; + + for (is = tex->tex_chain; is; is = is->tex_chain) { + msurface_t *surf = is->surface; + if (!tex->elechain) { + ec = add_elechain (tex, surf->ec_index, bctx); + } + if (surf->ec_index != ec->index) { // next sub-model + ec = add_elechain (tex, surf->ec_index, bctx); + } + + surf->polys = (glpoly_t *) poly; + poly = build_surf_displist (models, surf, vertex_index_base, + &vertices); + vertex_index_base += surf->numedges; + count++; + } + } + clear_texture_chains (bctx); + Sys_MaskPrintf (SYS_VULKAN, + "R_BuildDisplayLists: verts:%u, inds:%u, polys:%u (%d) %zd\n", + vertex_count, index_count, poly_count, count, + ((size_t) poly - (size_t) bctx->polys)/sizeof(uint32_t)); + if (index_buffer_size > bctx->index_buffer_size) { + if (bctx->index_buffer) { + dfunc->vkUnmapMemory (device->dev, bctx->index_memory); + dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0); + } + bctx->index_buffer + = QFV_CreateBuffer (device, index_buffer_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, bctx->index_buffer, + "buffer:bsp:index"); + bctx->index_memory + = QFV_AllocBufferMemory (device, bctx->index_buffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + index_buffer_size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + bctx->index_memory, "memory:bsp:index"); + QFV_BindBufferMemory (device, + bctx->index_buffer, bctx->index_memory, 0); + bctx->index_buffer_size = index_buffer_size; + void *data; + dfunc->vkMapMemory (device->dev, bctx->index_memory, 0, + index_buffer_size, 0, &data); + uint32_t *index_data = data; + for (size_t i = 0; i < frames; i++) { + uint32_t offset = index_count * i; + bctx->frames.a[i].index_data = index_data + offset; + bctx->frames.a[i].index_offset = offset * sizeof (uint32_t); + bctx->frames.a[i].index_count = 0; + } + } + if (vertex_buffer_size > bctx->vertex_buffer_size) { + if (bctx->vertex_buffer) { + dfunc->vkDestroyBuffer (device->dev, bctx->vertex_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->vertex_memory, 0); + } + bctx->vertex_buffer + = QFV_CreateBuffer (device, vertex_buffer_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, + bctx->vertex_buffer, "buffer:bsp:vertex"); + bctx->vertex_memory + = QFV_AllocBufferMemory (device, bctx->vertex_buffer, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + vertex_buffer_size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + bctx->vertex_memory, "memory:bsp:vertex"); + QFV_BindBufferMemory (device, + bctx->vertex_buffer, bctx->vertex_memory, 0); + bctx->vertex_buffer_size = vertex_buffer_size; + } + + VkBufferMemoryBarrier wr_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + bctx->vertex_buffer, 0, vertex_buffer_size, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, &wr_barrier, 0, 0); + VkBufferCopy copy_region = { packet->offset, 0, vertex_buffer_size }; + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, + bctx->vertex_buffer, 1, ©_region); + VkBufferMemoryBarrier rd_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + bctx->vertex_buffer, 0, vertex_buffer_size, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, &rd_barrier, 0, 0); + QFV_PacketSubmit (packet); + QFV_DestroyStagingBuffer (stage); +} + +static void +R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) +{ + float dot, radius; + int i; + unsigned k; + model_t *model; + plane_t *plane; + msurface_t *surf; + qboolean rotated; + vec3_t mins, maxs; + vec4f_t org; + mod_brush_t *brush; + + model = e->renderer.model; + brush = &model->brush; + mat4f_t mat; + Transform_GetWorldMatrix (e->transform, mat); + memcpy (e->renderer.full_transform, mat, sizeof (mat));//FIXME + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { + rotated = true; + radius = model->radius; + if (R_CullSphere (&mat[3][0], radius)) { //FIXME + return; + } + } else { + rotated = false; + VectorAdd (mat[3], model->mins, mins); + VectorAdd (mat[3], model->maxs, maxs); + if (R_CullBox (mins, maxs)) + return; + } + + org = r_refdef.viewposition - mat[3]; + if (rotated) { + vec4f_t temp = org; + + org[0] = DotProduct (temp, mat[0]); + org[1] = DotProduct (temp, mat[1]); + org[2] = DotProduct (temp, mat[2]); + } + + // calculate dynamic lighting for bmodel if it's not an instanced model + if (brush->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { + vec3_t lightorigin; + + for (k = 0; k < r_maxdlights; k++) { + if ((r_dlights[k].die < vr_data.realtime) + || (!r_dlights[k].radius)) + continue; + + VectorSubtract (r_dlights[k].origin, mat[3], lightorigin); + R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, + brush->nodes + brush->hulls[0].firstclipnode); + } + } + + surf = &brush->surfaces[brush->firstmodelsurface]; + + for (i = 0; i < brush->nummodelsurfaces; i++, surf++) { + // find the node side on which we are + plane = surf->plane; + + dot = PlaneDiff (org, plane); + + // enqueue the polygon + if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) + || (!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { + chain_surface (brush, surf, e->renderer.full_transform, + e->renderer.colormod, ctx); + } + } +} + +static inline void +visit_leaf (mleaf_t *leaf) +{ + // deal with model fragments in this leaf + if (leaf->efrags) + R_StoreEfrags (leaf->efrags); +} + +static inline int +get_side (mnode_t *node) +{ + // find the node side on which we are + plane_t *plane = node->plane; + + if (plane->type < 3) + return (r_origin[plane->type] - plane->dist) < 0; + return (DotProduct (r_origin, plane->normal) - plane->dist) < 0; +} + +static inline void +visit_node (mod_brush_t *brush, mnode_t *node, int side, vulkan_ctx_t *ctx) +{ + int c; + msurface_t *surf; + + // sneaky hack for side = side ? SURF_PLANEBACK : 0; + side = (~side + 1) & SURF_PLANEBACK; + // draw stuff + if ((c = node->numsurfaces)) { + surf = brush->surfaces + node->firstsurface; + for (; c; c--, surf++) { + if (surf->visframe != r_visframecount) + continue; + + // side is either 0 or SURF_PLANEBACK + if (side ^ (surf->flags & SURF_PLANEBACK)) + continue; // wrong side + + chain_surface (brush, surf, 0, 0, ctx); + } + } +} + +static inline int +test_node (mnode_t *node) +{ + if (node->contents < 0) + return 0; + if (node->visframe != r_visframecount) + return 0; + if (R_CullBox (node->minmaxs, node->minmaxs + 3)) + return 0; + return 1; +} + +static void +R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx) +{ + typedef struct { + mnode_t *node; + int side; + } rstack_t; + rstack_t *node_ptr; + rstack_t *node_stack; + mnode_t *node; + mnode_t *front; + int side; + + node = brush->nodes; + // +2 for paranoia + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); + node_ptr = node_stack; + + while (1) { + while (test_node (node)) { + side = get_side (node); + front = node->children[side]; + if (test_node (front)) { + node_ptr->node = node; + node_ptr->side = side; + node_ptr++; + node = front; + continue; + } + if (front->contents < 0 && front->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) front); + visit_node (brush, node, side, ctx); + node = node->children[!side]; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); + if (node_ptr != node_stack) { + node_ptr--; + node = node_ptr->node; + side = node_ptr->side; + visit_node (brush, node, side, ctx); + node = node->children[!side]; + continue; + } + break; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); +} + +static void +bind_view (qfv_bsp_tex tex, VkImageView view, bspframe_t *bframe, + VkCommandBuffer cmd, VkPipelineLayout layout, qfv_devfuncs_t *dfunc) +{ + bframe->imageInfo[tex].imageView = view; + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, 0, 1, + bframe->descriptors + tex + + BSP_BUFFER_INFOS); +} + +static void +push_transform (vec_t *transform, VkPipelineLayout layout, + qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) +{ + dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, 16 * sizeof (float), transform); +} + +static void +push_fragconst (fragconst_t *fragconst, VkPipelineLayout layout, + qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) +{ + dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT, + 64, sizeof (fragconst_t), fragconst);//FIXME 64 +} + +static void +push_descriptors (int count, VkWriteDescriptorSet *descriptors, + VkPipelineLayout layout, qfv_devfuncs_t *dfunc, + VkCommandBuffer cmd) +{ + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, 0, count, descriptors); +} + +static void +draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, + VkCommandBuffer cmd) +{ + elements_t *el; + + if (ec->transform) { + push_transform (ec->transform, layout, dfunc, cmd); + } else { + //FIXME should cache current transform + push_transform (identity, layout, dfunc, cmd); + } + for (el = ec->elements; el; el = el->next) { + if (!el->index_count) + continue; + dfunc->vkCmdDrawIndexed (cmd, el->index_count, 1, el->first_index, + 0, 0); + } +} + +static void +reset_elechain (elechain_t *ec) +{ + elements_t *el; + + for (el = ec->elements; el; el = el->next) { + el->first_index = 0; + el->index_count = 0; + } +} + +static VkImageView +get_view (qfv_tex_t *tex, qfv_tex_t *default_tex) +{ + if (tex) { + return tex->view; + } + if (default_tex) { + return default_tex->view; + } + return 0; +} + +static void +bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline, + vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = bframe->cmdSet.a[subpass]; + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass, subpass_map[subpass], + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + QFV_duCmdBeginLabel (device, cmd, bsp_pass_names[subpass], + {0, 0.5, 0.6, 1}); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipeline); + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + VkDeviceSize offsets[] = { 0 }; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &bctx->vertex_buffer, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset, + VK_INDEX_TYPE_UINT32); + + // push VP matrices + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->layout, + 0, 1, bframe->descriptors + 0); + // push static images + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->layout, + 0, 3, bframe->descriptors + 3); + + //XXX glsl_Fog_GetColor (fog); + //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; +} + +static void +bsp_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + QFV_duCmdEndLabel (device, cmd); + dfunc->vkEndCommandBuffer (cmd); +} + +static void +bsp_begin (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + //XXX quat_t fog; + + bctx->default_color[3] = 1; + QuatCopy (bctx->default_color, bctx->last_color); + + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + + DARRAY_APPEND (&cframe->cmdSets[QFV_passDepth], + bframe->cmdSet.a[QFV_bspDepth]); + DARRAY_APPEND (&cframe->cmdSets[QFV_passGBuffer], + bframe->cmdSet.a[QFV_bspGBuffer]); + + //FIXME need per frame matrices + bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + bframe->imageInfo[0].imageView = 0; // set by tex chain loop + bframe->imageInfo[1].imageView = 0; // set by tex chain loop + bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); + bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, + bctx->default_skysheet); + bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, + bctx->default_skybox); + + bsp_begin_subpass (QFV_bspDepth, bctx->depth, ctx); + bsp_begin_subpass (QFV_bspGBuffer, bctx->gbuf, ctx); +} + +static void +bsp_end (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + + bsp_end_subpass (bframe->cmdSet.a[QFV_bspDepth], ctx); + bsp_end_subpass (bframe->cmdSet.a[QFV_bspGBuffer], ctx); +} + +static void +turb_begin (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + + bctx->default_color[3] = bound (0, r_wateralpha->value, 1); + + QuatCopy (bctx->default_color, bctx->last_color); + + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + + DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], + bframe->cmdSet.a[QFV_bspTurb]); + + //FIXME need per frame matrices + bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + bframe->imageInfo[0].imageView = ctx->default_magenta->view; + bframe->imageInfo[1].imageView = ctx->default_magenta->view; + bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); + bframe->imageInfo[3].imageView = bctx->default_skysheet->view; + bframe->imageInfo[4].imageView = bctx->default_skybox->view; + + bsp_begin_subpass (QFV_bspTurb, bctx->turb, ctx); +} + +static void +turb_end (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + + bsp_end_subpass (bframe->cmdSet.a[QFV_bspTurb], ctx); +} + +static void +spin (mat4_t mat, bspctx_t *bctx) +{ + quat_t q; + mat4_t m; + float blend; + + while (vr_data.realtime - bctx->sky_time > 1) { + QuatCopy (bctx->sky_rotation[1], bctx->sky_rotation[0]); + QuatMult (bctx->sky_velocity, bctx->sky_rotation[0], + bctx->sky_rotation[1]); + bctx->sky_time += 1; + } + blend = bound (0, (vr_data.realtime - bctx->sky_time), 1); + + QuatBlend (bctx->sky_rotation[0], bctx->sky_rotation[1], blend, q); + QuatMult (bctx->sky_fix, q, q); + Mat4Identity (mat); + VectorNegate (r_origin, mat + 12); + QuatToMatrix (q, m, 1, 1); + Mat4Mult (m, mat, mat); +} + +static void +sky_begin (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + + bctx->default_color[3] = 1; + QuatCopy (bctx->default_color, bctx->last_color); + + spin (ctx->matrices.sky_3d, bctx); + + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + + DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], + bframe->cmdSet.a[QFV_bspSky]); + + //FIXME need per frame matrices + bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + bframe->imageInfo[0].imageView = ctx->default_magenta->view; + bframe->imageInfo[1].imageView = ctx->default_magenta->view; + bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); + bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, + bctx->default_skysheet); + bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, + bctx->default_skybox); + + if (bctx->skybox_tex) { + bsp_begin_subpass (QFV_bspSky, bctx->skybox, ctx); + } else { + bsp_begin_subpass (QFV_bspSky, bctx->skysheet, ctx); + } +} + +static void +sky_end (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + + bsp_end_subpass (bframe->cmdSet.a[QFV_bspSky], ctx); +} + +static inline void +add_surf_elements (vulktex_t *tex, instsurf_t *is, + elechain_t **ec, elements_t **el, + bspctx_t *bctx, bspframe_t *bframe) +{ + msurface_t *surf = is->surface; + bsppoly_t *poly = (bsppoly_t *) surf->polys; + + if (!tex->elechain) { + (*ec) = add_elechain (tex, surf->ec_index, bctx); + (*ec)->transform = is->transform; + (*ec)->color = is->color; + (*el) = (*ec)->elements; + (*el)->first_index = bframe->index_count; + } + if (is->transform != (*ec)->transform || is->color != (*ec)->color) { + (*ec) = add_elechain (tex, surf->ec_index, bctx); + (*ec)->transform = is->transform; + (*ec)->color = is->color; + (*el) = (*ec)->elements; + (*el)->first_index = bframe->index_count; + } + memcpy (bframe->index_data + bframe->index_count, + poly->indices, poly->count * sizeof (poly->indices[0])); + (*el)->index_count += poly->count; + bframe->index_count += poly->count; +} + +static void +build_tex_elechain (vulktex_t *tex, bspctx_t *bctx, bspframe_t *bframe) +{ + instsurf_t *is; + elechain_t *ec = 0; + elements_t *el = 0; + + for (is = tex->tex_chain; is; is = is->tex_chain) { + add_surf_elements (tex, is, &ec, &el, bctx, bframe); + } +} + +void +Vulkan_DrawWorld (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + entity_t worldent; + mod_brush_t *brush; + + clear_texture_chains (bctx); // do this first for water and skys + bframe->index_count = 0; + + memset (&worldent, 0, sizeof (worldent)); + worldent.renderer.model = r_worldentity.renderer.model; + brush = &r_worldentity.renderer.model->brush; + + //vulktex_t *tex = r_worldentity.renderer.model->skytexture->render; + //bctx->skysheet_tex = tex->tex; + + currententity = &worldent; + + R_VisitWorldNodes (brush, ctx); + if (r_drawentities->int_val) { + entity_t *ent; + for (ent = r_ent_queue; ent; ent = ent->next) { + if (ent->renderer.model->type != mod_brush) + continue; + currententity = ent; + + R_DrawBrushModel (ent, ctx); + } + } + + //Vulkan_FlushLightmaps (ctx); + bsp_begin (ctx); + + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspDepth]); + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); + fragconst_t frag_constants = { time: vr_data.realtime }; + push_fragconst (&frag_constants, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); + //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + vulktex_t *tex; + elechain_t *ec = 0; + + tex = bctx->texture_chains.a[i]; + + build_tex_elechain (tex, bctx, bframe); + + bframe->imageInfo[0].imageView = get_view (tex->tex, + ctx->default_white); + bframe->imageInfo[1].imageView = get_view (tex->glow, + ctx->default_black); + + push_descriptors (2, bframe->descriptors + 1, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); + + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspDepth]); + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); + reset_elechain (ec); + } + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + bsp_end (ctx); + + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + size_t atom_mask = atom - 1; + size_t offset = bframe->index_offset; + size_t size = bframe->index_count * sizeof (uint32_t); + + offset &= ~atom_mask; + size = (size + atom_mask) & ~atom_mask; + + //FIXME this needs to come at the end of the frame after all passes + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + bctx->index_memory, offset, size + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); +} + +void +Vulkan_DrawWaterSurfaces (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + instsurf_t *is; + msurface_t *surf; + vulktex_t *tex = 0; + elechain_t *ec = 0; + elements_t *el = 0; + + if (!bctx->waterchain) + return; + + turb_begin (ctx); + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); + fragconst_t frag_constants = { time: vr_data.realtime }; + push_fragconst (&frag_constants, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); + for (is = bctx->waterchain; is; is = is->tex_chain) { + surf = is->surface; + if (tex != surf->texinfo->texture->render) { + if (tex) { + bind_view (qfv_bsp_texture, + get_view (tex->tex, ctx->default_black), + bframe, + bframe->cmdSet.a[QFV_bspTurb], + bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); + reset_elechain (ec); + } + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + tex = surf->texinfo->texture->render; + } + add_surf_elements (tex, is, &ec, &el, bctx, bframe); + } + if (tex) { + bind_view (qfv_bsp_texture, get_view (tex->tex, ctx->default_black), + bframe, bframe->cmdSet.a[QFV_bspTurb], + bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); + reset_elechain (ec); + } + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + turb_end (ctx); + + bctx->waterchain = 0; + bctx->waterchain_tail = &bctx->waterchain; +} + +void +Vulkan_DrawSky (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + instsurf_t *is; + msurface_t *surf; + vulktex_t *tex = 0; + elechain_t *ec = 0; + elements_t *el = 0; + + if (!bctx->sky_chain) + return; + + sky_begin (ctx); + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspSky]); + fragconst_t frag_constants = { time: vr_data.realtime }; + push_fragconst (&frag_constants, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspSky]); + for (is = bctx->sky_chain; is; is = is->tex_chain) { + surf = is->surface; + if (tex != surf->texinfo->texture->render) { + if (tex) { + bind_view (qfv_bsp_skysheet, + get_view (tex->tex, ctx->default_black), + bframe, + bframe->cmdSet.a[QFV_bspSky], + bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspSky]); + reset_elechain (ec); + } + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + tex = surf->texinfo->texture->render; + } + add_surf_elements (tex, is, &ec, &el, bctx, bframe); + } + if (tex) { + bind_view (qfv_bsp_skysheet, get_view (tex->tex, ctx->default_black), + bframe, bframe->cmdSet.a[QFV_bspSky], + bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspSky]); + reset_elechain (ec); + } + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + sky_end (ctx); + + bctx->sky_chain = 0; + bctx->sky_chain_tail = &bctx->sky_chain; +} + +static void +create_default_skys (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + VkImage skybox; + VkImage skysheet; + VkDeviceMemory memory; + VkImageView boxview; + VkImageView sheetview; + + bctx->default_skybox = calloc (2, sizeof (qfv_tex_t)); + bctx->default_skysheet = bctx->default_skybox + 1; + + VkExtent3D extents = { 1, 1, 1 }; + skybox = QFV_CreateImage (device, 1, VK_IMAGE_TYPE_2D, + VK_FORMAT_B8G8R8A8_UNORM, extents, 1, 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skybox, + "bsp:image:default_skybox"); + + skysheet = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_B8G8R8A8_UNORM, extents, 1, 2, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skysheet, + "bsp:image:default_skysheet"); + + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (device->dev, skybox, &requirements); + size_t boxsize = requirements.size; + dfunc->vkGetImageMemoryRequirements (device->dev, skysheet, &requirements); + size_t sheetsize = requirements.size; + + memory = QFV_AllocImageMemory (device, skybox, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + boxsize + sheetsize, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, memory, + "bsp:memory:default_skys"); + + QFV_BindImageMemory (device, skybox, memory, 0); + QFV_BindImageMemory (device, skysheet, memory, boxsize); + + boxview = QFV_CreateImageView (device, skybox, VK_IMAGE_VIEW_TYPE_CUBE, + VK_FORMAT_B8G8R8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, boxview, + "bsp:iview:default_skybox"); + + sheetview = QFV_CreateImageView (device, skysheet, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_FORMAT_B8G8R8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, sheetview, + "bsp:iview:default_skysheet"); + + bctx->default_skybox->image = skybox; + bctx->default_skybox->view = boxview; + bctx->default_skybox->memory = memory; + bctx->default_skysheet->image = skysheet; + bctx->default_skysheet->view = sheetview; + + // temporarily commandeer the light map's staging buffer + qfv_packet_t *packet = QFV_PacketAcquire (bctx->light_stage); + VkImageMemoryBarrier barrier; + VkImageMemoryBarrier barriers[2]; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + barriers[0] = barrier; + barriers[1] = barrier; + barriers[0].image = skybox; + barriers[1].image = skysheet; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 2, barriers); + + VkClearColorValue color = {}; + VkImageSubresourceRange range = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, VK_REMAINING_MIP_LEVELS, + 0, VK_REMAINING_ARRAY_LAYERS + }; + dfunc->vkCmdClearColorImage (packet->cmd, skybox, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &color, 1, &range); + dfunc->vkCmdClearColorImage (packet->cmd, skysheet, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &color, 1, &range); + + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + barriers[0] = barrier; + barriers[1] = barrier; + barriers[0].image = skybox; + barriers[1].image = skysheet; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 2, barriers); + QFV_PacketSubmit (packet); +} + +static VkDescriptorBufferInfo base_buffer_info = { + 0, 0, VK_WHOLE_SIZE +}; +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_buffer_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, 0, 0 +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0, 0, 0 +}; + +void +Vulkan_Bsp_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + bspctx_t *bctx = calloc (1, sizeof (bspctx_t)); + ctx->bsp_context = bctx; + + bctx->waterchain_tail = &bctx->waterchain; + bctx->sky_chain_tail = &bctx->sky_chain; + bctx->static_instsurfs_tail = &bctx->static_instsurfs; + bctx->elechains_tail = &bctx->elechains; + bctx->elementss_tail = &bctx->elementss; + bctx->instsurfs_tail = &bctx->instsurfs; + + bctx->light_scrap = QFV_CreateScrap (device, "lightmap_atlas", 2048, + tex_frgba, ctx->staging); + size_t size = QFV_ScrapSize (bctx->light_scrap); + bctx->light_stage = QFV_CreateStagingBuffer (device, "lightmap", size, + ctx->cmdpool); + + create_default_skys (ctx); + + DARRAY_INIT (&bctx->texture_chains, 64); + + size_t frames = ctx->frames.size; + DARRAY_INIT (&bctx->frames, frames); + DARRAY_RESIZE (&bctx->frames, frames); + bctx->frames.grow = 0; + + bctx->depth = Vulkan_CreatePipeline (ctx, "bsp_depth"); + bctx->gbuf = Vulkan_CreatePipeline (ctx, "bsp_gbuf"); + bctx->skybox = Vulkan_CreatePipeline (ctx, "bsp_skybox"); + bctx->skysheet = Vulkan_CreatePipeline (ctx, "bsp_skysheet"); + bctx->turb = Vulkan_CreatePipeline (ctx, "bsp_turb"); + bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout"); + bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler"); + + for (size_t i = 0; i < frames; i++) { + __auto_type bframe = &bctx->frames.a[i]; + + DARRAY_INIT (&bframe->cmdSet, QFV_bspNumPasses); + DARRAY_RESIZE (&bframe->cmdSet, QFV_bspNumPasses); + bframe->cmdSet.grow = 0; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &bframe->cmdSet); + + for (int j = 0; j < QFV_bspNumPasses; j++) { + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + bframe->cmdSet.a[i], + va (ctx->va_ctx, "cmd:bsp:%zd:%s", i, + bsp_pass_names[j])); + } + + for (int j = 0; j < BSP_BUFFER_INFOS; j++) { + bframe->bufferInfo[j] = base_buffer_info; + bframe->descriptors[j] = base_buffer_write; + bframe->descriptors[j].dstBinding = j; + bframe->descriptors[j].pBufferInfo = &bframe->bufferInfo[j]; + } + for (int j = 0; j < BSP_IMAGE_INFOS; j++) { + bframe->imageInfo[j] = base_image_info; + bframe->imageInfo[j].sampler = bctx->sampler; + int k = j + BSP_BUFFER_INFOS; + bframe->descriptors[k] = base_image_write; + bframe->descriptors[k].dstBinding = k; + bframe->descriptors[k].pImageInfo = &bframe->imageInfo[j]; + } + } +} + +void +Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + + for (size_t i = 0; i < bctx->frames.size; i++) { + __auto_type bframe = &bctx->frames.a[i]; + free (bframe->cmdSet.a); + } + + dfunc->vkDestroyPipeline (device->dev, bctx->depth, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->gbuf, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->skybox, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->skysheet, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->turb, 0); + DARRAY_CLEAR (&bctx->texture_chains); + DARRAY_CLEAR (&bctx->frames); + QFV_DestroyStagingBuffer (bctx->light_stage); + QFV_DestroyScrap (bctx->light_scrap); + if (bctx->vertex_buffer) { + dfunc->vkDestroyBuffer (device->dev, bctx->vertex_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->vertex_memory, 0); + } + if (bctx->index_buffer) { + dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0); + } + + if (bctx->skybox_tex) { + Vulkan_UnloadTex (ctx, bctx->skybox_tex); + } + + dfunc->vkDestroyImageView (device->dev, bctx->default_skysheet->view, 0); + dfunc->vkDestroyImage (device->dev, bctx->default_skysheet->image, 0); + + dfunc->vkDestroyImageView (device->dev, bctx->default_skybox->view, 0); + dfunc->vkDestroyImage (device->dev, bctx->default_skybox->image, 0); + dfunc->vkFreeMemory (device->dev, bctx->default_skybox->memory, 0); + free (bctx->default_skybox); +} + +static inline __attribute__((const)) int +is_pow2 (unsigned x) +{ + int count; + + for (count = 0; x; x >>= 1) + if (x & 1) + count++; + return count == 1; +} + +// NOTE: this expects the destination tex_t to be set up: memory allocated +// and dimentions/format etc already set. the size of the rect to be copied +// is taken from dst. Also, dst->format and src->format must be the same, and +// either 3 or 4, or bad things will happen. Also, no clipping is done, so if +// x < 0 or y < 0 or x + dst->width > src->width +// or y + dst->height > src->height, bad things will happen. +/*XXX static void +copy_sub_tex (tex_t *src, int x, int y, tex_t *dst) +{ + int dstbytes; + int srcbytes; + int i; + + srcbytes = src->width * src->format; + dstbytes = dst->width * dst->format; + + x *= src->format; + for (i = 0; i < dst->height; i++) + memcpy (dst->data + i * dstbytes, src->data + (i + y) * srcbytes + x, + dstbytes); +}*/ + +void +Vulkan_LoadSkys (const char *sky, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + + const char *name; + int i; + tex_t *tex; + static const char *sky_suffix[] = { "ft", "bk", "up", "dn", "rt", "lf"}; + + if (bctx->skybox_tex) { + Vulkan_UnloadTex (ctx, bctx->skybox_tex); + } + bctx->skybox_tex = 0; + + if (!sky || !*sky) { + sky = r_skyname->string; + } + + if (!*sky || !strcasecmp (sky, "none")) { + Sys_MaskPrintf (SYS_VULKAN, "Skybox unloaded\n"); + return; + } + + name = va (ctx->va_ctx, "env/%s_map", sky); + tex = LoadImage (name, 1); + if (tex) { + bctx->skybox_tex = Vulkan_LoadEnvMap (ctx, tex, sky); + Sys_MaskPrintf (SYS_VULKAN, "Loaded %s\n", name); + } else { + int failed = 0; + tex_t *sides[6] = { }; + + for (i = 0; i < 6; i++) { + name = va (ctx->va_ctx, "env/%s%s", sky, sky_suffix[i]); + tex = LoadImage (name, 1); + if (!tex) { + Sys_MaskPrintf (SYS_VULKAN, "Couldn't load %s\n", name); + // also look in gfx/env, where Darkplaces looks for skies + name = va (ctx->va_ctx, "gfx/env/%s%s", sky, sky_suffix[i]); + tex = LoadImage (name, 1); + if (!tex) { + Sys_MaskPrintf (SYS_VULKAN, "Couldn't load %s\n", name); + failed = 1; + continue; + } + } + sides[i] = tex; + Sys_MaskPrintf (SYS_VULKAN, "Loaded %s\n", name); + } + if (!failed) { + bctx->skybox_tex = Vulkan_LoadEnvSides (ctx, sides, sky); + } + } + if (bctx->skybox_tex) { + Sys_MaskPrintf (SYS_VULKAN, "Skybox %s loaded\n", sky); + } +} diff --git a/libs/video/renderer/vulkan/vulkan_compose.c b/libs/video/renderer/vulkan/vulkan_compose.c new file mode 100644 index 000000000..fc7316ede --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_compose.c @@ -0,0 +1,177 @@ +/* + vulkan_compose.c + + Vulkan compose pass pipeline + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/23 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/sys.h" + +#include "QF/Vulkan/qf_compose.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +void +Vulkan_Compose_Draw (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + composectx_t *cctx = ctx->compose_context; + __auto_type frame = &ctx->frames.a[ctx->curFrame]; + composeframe_t *cframe = &cctx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = cframe->cmd; + + DARRAY_APPEND (&frame->cmdSets[QFV_passCompose], cmd); + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass, QFV_passCompose, + frame->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + cctx->pipeline); + + cframe->imageInfo[0].imageView + = ctx->attachment_views->a[QFV_attachOpaque]; + cframe->imageInfo[1].imageView + = ctx->attachment_views->a[QFV_attachTranslucent]; + dfunc->vkUpdateDescriptorSets (device->dev, 2, cframe->descriptors, 0, 0); + + VkDescriptorSet sets[] = { + cframe->descriptors[0].dstSet, + }; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + cctx->layout, 0, 1, sets, 0, 0); + + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + VkDeviceSize offset = 0; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &ctx->quad_buffer, &offset); + dfunc->vkCmdDraw (cmd, 4, 1, 0, 0); + + dfunc->vkEndCommandBuffer (cmd); +} + +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + 0, 0, 0 +}; + +void +Vulkan_Compose_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + composectx_t *cctx = calloc (1, sizeof (composectx_t)); + ctx->compose_context = cctx; + + size_t frames = ctx->frames.size; + DARRAY_INIT (&cctx->frames, frames); + DARRAY_RESIZE (&cctx->frames, frames); + cctx->frames.grow = 0; + + cctx->pipeline = Vulkan_CreatePipeline (ctx, "compose"); + cctx->layout = Vulkan_CreatePipelineLayout (ctx, "compose_layout"); + + __auto_type cmdSet = QFV_AllocCommandBufferSet (1, alloca); + + __auto_type attach = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + for (size_t i = 0; i < frames; i++) { + attach->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, + "compose_attach"); + } + __auto_type attach_pool = Vulkan_CreateDescriptorPool (ctx, + "compose_attach_pool"); + + __auto_type attach_set = QFV_AllocateDescriptorSet (device, attach_pool, + attach); + for (size_t i = 0; i < frames; i++) { + __auto_type cframe = &cctx->frames.a[i]; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); + cframe->cmd = cmdSet->a[0]; + + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + cframe->cmd, "cmd:compose"); + for (int j = 0; j < COMPOSE_IMAGE_INFOS; j++) { + cframe->imageInfo[j] = base_image_info; + cframe->imageInfo[j].sampler = 0; + cframe->descriptors[j] = base_image_write; + cframe->descriptors[j].dstSet = attach_set->a[i]; + cframe->descriptors[j].dstBinding = j; + cframe->descriptors[j].pImageInfo = &cframe->imageInfo[j]; + } + } + free (attach_set); +} + +void +Vulkan_Compose_Shutdown (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + composectx_t *cctx = ctx->compose_context; + + dfunc->vkDestroyPipeline (device->dev, cctx->pipeline, 0); + free (cctx->frames.a); + free (cctx); +} diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c new file mode 100644 index 000000000..12b3cd11b --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -0,0 +1,761 @@ +/* + vulkan_draw.c + + 2D drawing support for Vulkan + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/10 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cmem.h" +#include "QF/cvar.h" +#include "QF/draw.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/quakefs.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "compat.h" +#include "QF/Vulkan/qf_draw.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/scrap.h" +#include "QF/Vulkan/staging.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +typedef struct { + float xy[2]; + float st[2]; + float color[4]; +} drawvert_t; + +typedef struct cachepic_s { + char *name; + qpic_t *pic; +} cachepic_t; + +typedef struct drawframe_s { + size_t vert_offset; + drawvert_t *verts; + uint32_t num_quads; + VkCommandBuffer cmd; + VkDescriptorSet descriptors; +} drawframe_t; + +typedef struct drawframeset_s + DARRAY_TYPE (drawframe_t) drawframeset_t; + +typedef struct drawctx_s { + VkSampler sampler; + scrap_t *scrap; + qfv_stagebuf_t *stage; + qpic_t *conchars; + qpic_t *conback; + qpic_t *white_pic; + // use two separate cmem blocks for pics and strings (cachepic names) + // to ensure the names are never in the same cacheline as a pic since the + // names are used only for lookup + memsuper_t *pic_memsuper; + memsuper_t *string_memsuper; + hashtab_t *pic_cache; + VkBuffer vert_buffer; + VkDeviceMemory vert_memory; + VkBuffer ind_buffer; + VkDeviceMemory ind_memory; + VkPipeline pipeline; + VkPipelineLayout layout; + drawframeset_t frames; +} drawctx_t; + +// enough for a full screen of 8x8 chars at 1920x1080 plus some extras (368) +#define MAX_QUADS (32768) +#define VERTS_PER_QUAD (4) +#define INDS_PER_QUAD (5) // one per vert plus primitive reset + +static void +create_quad_buffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + drawctx_t *dctx = ctx->draw_context; + + size_t vert_size; + size_t ind_size; + size_t frames = ctx->frames.size; + VkBuffer vbuf, ibuf; + VkDeviceMemory vmem, imem; + + vert_size = frames * MAX_QUADS * VERTS_PER_QUAD * sizeof (drawvert_t); + ind_size = MAX_QUADS * INDS_PER_QUAD * sizeof (uint32_t); + + vbuf = QFV_CreateBuffer (device, vert_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + ibuf = QFV_CreateBuffer (device, ind_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + vmem = QFV_AllocBufferMemory (device, vbuf, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + vert_size, 0); + imem = QFV_AllocBufferMemory (device, ibuf, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + ind_size, 0); + QFV_BindBufferMemory (device, vbuf, vmem, 0); + QFV_BindBufferMemory (device, ibuf, imem, 0); + + dctx->vert_buffer = vbuf; + dctx->vert_memory = vmem; + dctx->ind_buffer = ibuf; + dctx->ind_memory = imem; + + void *data; + dfunc->vkMapMemory (device->dev, vmem, 0, vert_size, 0, &data); + drawvert_t *vert_data = data; + + for (size_t f = 0; f < frames; f++) { + drawframe_t *frame = &dctx->frames.a[f]; + size_t ind = f * MAX_QUADS * VERTS_PER_QUAD; + frame->vert_offset = ind * sizeof (drawvert_t); + frame->verts = vert_data + ind; + frame->num_quads = 0; + } + + // The indices will never change so pre-generate and stash them + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + uint32_t *ind = QFV_PacketExtend (packet, ind_size); + for (int i = 0; i < MAX_QUADS; i++) { + for (int j = 0; j < VERTS_PER_QUAD; j++) { + *ind++ = i * VERTS_PER_QUAD + j; + } + // mark end of primitive + *ind++ = -1; + } + + VkBufferMemoryBarrier wr_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, ibuf, 0, ind_size + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, &wr_barrier, 0, 0); + VkBufferCopy copy_region = { packet->offset, 0, ind_size }; + dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, ibuf, + 1, ©_region); + VkBufferMemoryBarrier rd_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, ibuf, 0, ind_size + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, &rd_barrier, 0, 0); + QFV_PacketSubmit (packet); +} + +static void +destroy_quad_buffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + drawctx_t *dctx = ctx->draw_context; + + dfunc->vkUnmapMemory (device->dev, dctx->vert_memory); + dfunc->vkFreeMemory (device->dev, dctx->vert_memory, 0); + dfunc->vkFreeMemory (device->dev, dctx->ind_memory, 0); + dfunc->vkDestroyBuffer (device->dev, dctx->vert_buffer, 0); + dfunc->vkDestroyBuffer (device->dev, dctx->ind_buffer, 0); +} + +static void +flush_draw_scrap (vulkan_ctx_t *ctx) +{ + QFV_ScrapFlush (ctx->draw_context->scrap); +} + +static void +pic_free (drawctx_t *dctx, qpic_t *pic) +{ + subpic_t *subpic = *(subpic_t **) pic->data; + QFV_SubpicDelete (subpic); + cmemfree (dctx->pic_memsuper, pic); +} + +static cachepic_t * +new_cachepic (drawctx_t *dctx, const char *name, qpic_t *pic) +{ + cachepic_t *cp; + size_t size = strlen (name) + 1; + + cp = cmemalloc (dctx->pic_memsuper, sizeof (cachepic_t)); + cp->name = cmemalloc (dctx->string_memsuper, size); + memcpy (cp->name, name, size); + cp->pic = pic; + return cp; +} + +static void +cachepic_free (void *_cp, void *_dctx) +{ + drawctx_t *dctx = _dctx; + cachepic_t *cp = (cachepic_t *) _cp; + pic_free (dctx, cp->pic); + cmemfree (dctx->string_memsuper, cp->name); + cmemfree (dctx->pic_memsuper, cp); +} + +static const char * +cachepic_getkey (const void *_cp, void *unused) +{ + return ((cachepic_t *) _cp)->name; +} + +static qpic_t * +pic_data (const char *name, int w, int h, const byte *data, drawctx_t *dctx) +{ + qpic_t *pic; + subpic_t *subpic; + byte *picdata; + + pic = cmemalloc (dctx->pic_memsuper, + field_offset (qpic_t, data[sizeof (subpic_t *)])); + pic->width = w; + pic->height = h; + + subpic = QFV_ScrapSubpic (dctx->scrap, w, h); + *(subpic_t **) pic->data = subpic; + + picdata = QFV_SubpicBatch (subpic, dctx->stage); + size_t size = w * h; + for (size_t i = 0; i < size; i++) { + byte pix = *data++; + byte *col = vid.palette + pix * 3; + *picdata++ = *col++; + *picdata++ = *col++; + *picdata++ = *col++; + *picdata++ = (pix == 255) - 1; + } + return pic; +} + +qpic_t * +Vulkan_Draw_MakePic (int width, int height, const byte *data, + vulkan_ctx_t *ctx) +{ + return pic_data (0, width, height, data, ctx->draw_context); +} + +void +Vulkan_Draw_DestroyPic (qpic_t *pic, vulkan_ctx_t *ctx) +{ +} + +qpic_t * +Vulkan_Draw_PicFromWad (const char *name, vulkan_ctx_t *ctx) +{ + qpic_t *wadpic = W_GetLumpName (name); + + if (!wadpic) { + return 0; + } + return pic_data (name, wadpic->width, wadpic->height, wadpic->data, + ctx->draw_context); +} + +qpic_t * +Vulkan_Draw_CachePic (const char *path, qboolean alpha, vulkan_ctx_t *ctx) +{ + qpic_t *p; + qpic_t *pic; + cachepic_t *cpic; + drawctx_t *dctx = ctx->draw_context; + + if ((cpic = Hash_Find (dctx->pic_cache, path))) { + return cpic->pic; + } + if (strlen (path) < 4 || strcmp (path + strlen (path) - 4, ".lmp") + || !(p = (qpic_t *) QFS_LoadFile (QFS_FOpenFile (path), 0))) { + return 0; + } + + pic = pic_data (path, p->width, p->height, p->data, dctx); + free (p); + cpic = new_cachepic (dctx, path, pic); + Hash_Add (dctx->pic_cache, cpic); + return pic; +} + +void +Vulkan_Draw_UncachePic (const char *path, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + Hash_Free (dctx->pic_cache, Hash_Del (dctx->pic_cache, path)); +} + +void +Vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha, + vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_Draw_Shutdown (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + drawctx_t *dctx = ctx->draw_context; + + destroy_quad_buffers (ctx); + + dfunc->vkDestroyPipeline (device->dev, dctx->pipeline, 0); + Hash_DelTable (dctx->pic_cache); + delete_memsuper (dctx->pic_memsuper); + delete_memsuper (dctx->string_memsuper); + QFV_DestroyScrap (dctx->scrap); + QFV_DestroyStagingBuffer (dctx->stage); +} + +void +Vulkan_Draw_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + drawctx_t *dctx = calloc (1, sizeof (drawctx_t)); + ctx->draw_context = dctx; + + size_t frames = ctx->frames.size; + DARRAY_INIT (&dctx->frames, frames); + DARRAY_RESIZE (&dctx->frames, frames); + dctx->frames.grow = 0; + + dctx->pic_memsuper = new_memsuper (); + dctx->string_memsuper = new_memsuper (); + dctx->pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, + dctx, 0); + + create_quad_buffers (ctx); + dctx->stage = QFV_CreateStagingBuffer (device, "draw", 4 * 1024 * 1024, + ctx->cmdpool); + dctx->scrap = QFV_CreateScrap (device, "draw_atlas", 2048, tex_rgba, + dctx->stage); + dctx->sampler = Vulkan_CreateSampler (ctx, "quakepic"); + + draw_chars = W_GetLumpName ("conchars"); + if (draw_chars) { + for (int i = 0; i < 256 * 64; i++) { + if (draw_chars[i] == 0) { + draw_chars[i] = 255; // proper transparent color + } + } + dctx->conchars = pic_data ("conchars", 128, 128, draw_chars, dctx); + } else { + qpic_t *charspic = Draw_Font8x8Pic (); + dctx->conchars = pic_data ("conchars", charspic->width, + charspic->height, charspic->data, dctx); + } + + byte white_block = 0xfe; + dctx->white_pic = pic_data ("white", 1, 1, &white_block, dctx); + + flush_draw_scrap (ctx); + + dctx->pipeline = Vulkan_CreatePipeline (ctx, "twod"); + + dctx->layout = Vulkan_CreatePipelineLayout (ctx, "twod_layout"); + + __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + for (size_t i = 0; i < layouts->size; i++) { + layouts->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, "twod_set"); + } + __auto_type pool = Vulkan_CreateDescriptorPool (ctx, "twod_pool"); + + VkDescriptorBufferInfo bufferInfo = { + ctx->matrices.buffer_2d, 0, VK_WHOLE_SIZE + }; + VkDescriptorImageInfo imageInfo = { + dctx->sampler, + QFV_ScrapImageView (dctx->scrap), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); + + __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); + for (size_t i = 0; i < frames; i++) { + __auto_type dframe = &dctx->frames.a[i]; + dframe->descriptors = sets->a[i]; + + VkWriteDescriptorSet write[] = { + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + dframe->descriptors, 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, &bufferInfo, 0 }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + dframe->descriptors, 1, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imageInfo, 0, 0 }, + }; + dfunc->vkUpdateDescriptorSets (device->dev, 2, write, 0, 0); + dframe->cmd = cmdBuffers->a[i]; + } + free (sets); +} + +static inline void +draw_pic (float x, float y, int w, int h, qpic_t *pic, + int srcx, int srcy, int srcw, int srch, + float *color, drawframe_t *frame) +{ + if (frame->num_quads + VERTS_PER_QUAD > MAX_QUADS) { + return; + } + + drawvert_t *verts = frame->verts + frame->num_quads * VERTS_PER_QUAD; + frame->num_quads += VERTS_PER_QUAD; + + subpic_t *subpic = *(subpic_t **) pic->data; + srcx += subpic->rect->x; + srcy += subpic->rect->y; + + float size = subpic->size; + float sl = (srcx + 0.03125) * size; + float sr = (srcx + srcw - 0.03125) * size; + float st = (srcy + 0.03125) * size; + float sb = (srcy + srch - 0.03125) * size; + + verts[0].xy[0] = x; + verts[0].xy[1] = y; + verts[0].st[0] = sl; + verts[0].st[1] = st; + QuatCopy (color, verts[0].color); + + verts[1].xy[0] = x; + verts[1].xy[1] = y + h; + verts[1].st[0] = sl; + verts[1].st[1] = sb; + QuatCopy (color, verts[1].color); + + verts[2].xy[0] = x + w; + verts[2].xy[1] = y; + verts[2].st[0] = sr; + verts[2].st[1] = st; + QuatCopy (color, verts[2].color); + + verts[3].xy[0] = x + w; + verts[3].xy[1] = y + h; + verts[3].st[0] = sr; + verts[3].st[1] = sb; + QuatCopy (color, verts[3].color); +} + +static inline void +queue_character (int x, int y, byte chr, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + quat_t color = {1, 1, 1, 1}; + int cx, cy; + cx = chr % 16; + cy = chr / 16; + + draw_pic (x, y, 8, 8, dctx->conchars, cx * 8, cy * 8, 8, 8, color, frame); +} + +void +Vulkan_Draw_Character (int x, int y, unsigned int chr, vulkan_ctx_t *ctx) +{ + if (chr == ' ') { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + if (x <= -8 || x >= vid.conwidth) { + return; + } + queue_character (x, y, chr, ctx); +} + +void +Vulkan_Draw_String (int x, int y, const char *str, vulkan_ctx_t *ctx) +{ + byte chr; + + if (!str || !str[0]) { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + while (*str) { + if ((chr = *str++) != ' ' && x >= -8 && x < vid.conwidth) { + queue_character (x, y, chr, ctx); + } + x += 8; + } +} + +void +Vulkan_Draw_nString (int x, int y, const char *str, int count, + vulkan_ctx_t *ctx) +{ + byte chr; + + if (!str || !str[0]) { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + while (count-- > 0 && *str) { + if ((chr = *str++) != ' ' && x >= -8 && x < vid.conwidth) { + queue_character (x, y, chr, ctx); + } + x += 8; + } +} + +void +Vulkan_Draw_AltString (int x, int y, const char *str, vulkan_ctx_t *ctx) +{ + byte chr; + + if (!str || !str[0]) { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + while (*str) { + if ((chr = *str++ | 0x80) != (' ' | 0x80) + && x >= -8 && x < vid.conwidth) { + queue_character (x, y, chr, ctx); + } + x += 8; + } +} + +void +Vulkan_Draw_CrosshairAt (int ch, int x, int y, vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_Draw_Crosshair (vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_Draw_Pic (int x, int y, qpic_t *pic, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + static quat_t color = { 1, 1, 1, 1}; + draw_pic (x, y, pic->width, pic->height, pic, + 0, 0, pic->width, pic->height, color, frame); +} + +void +Vulkan_Draw_Picf (float x, float y, qpic_t *pic, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + static quat_t color = { 1, 1, 1, 1}; + draw_pic (x, y, pic->width, pic->height, pic, + 0, 0, pic->width, pic->height, color, frame); +} + +void +Vulkan_Draw_SubPic (int x, int y, qpic_t *pic, + int srcx, int srcy, int width, int height, + vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + static quat_t color = { 1, 1, 1, 1}; + draw_pic (x, y, width, height, pic, srcx, srcy, width, height, + color, frame); +} + +void +Vulkan_Draw_ConsoleBackground (int lines, byte alpha, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + quat_t color = { 1, 1, 1, bound (0, alpha, 255) / 255.0}; + qpic_t *cpic; + cpic = Vulkan_Draw_CachePic ("gfx/conback.lmp", false, ctx); + int ofs = max (0, cpic->height - lines); + lines = min (lines, cpic->height); + draw_pic (0, 0, vid.conwidth, lines, cpic, + 0, ofs, cpic->width, lines, color, frame); +} + +void +Vulkan_Draw_TileClear (int x, int y, int w, int h, vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_Draw_Fill (int x, int y, int w, int h, int c, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + quat_t color; + + VectorScale (vid.palette + c * 3, 1.0f/255.0f, color); + color[3] = 1; + draw_pic (x, y, w, h, dctx->white_pic, 0, 0, 1, 1, color, frame); +} + +static inline void +draw_blendscreen (quat_t color, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + draw_pic (0, 0, vid.conwidth, vid.conheight, dctx->white_pic, 0, 0, 1, 1, + color, frame); +} + +void +Vulkan_Draw_FadeScreen (vulkan_ctx_t *ctx) +{ + static quat_t color = { 0, 0, 0, 0.7 }; + draw_blendscreen (color, ctx); +} + +void +Vulkan_Set2D (vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_Set2DScaled (vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_End2D (vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_DrawReset (vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_FlushText (vulkan_ctx_t *ctx) +{ + flush_draw_scrap (ctx); + + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + drawctx_t *dctx = ctx->draw_context; + drawframe_t *dframe = &dctx->frames.a[ctx->curFrame]; + + VkCommandBuffer cmd = dframe->cmd; + //FIXME which pass? + DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], cmd); + + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + dctx->vert_memory, dframe->vert_offset, + dframe->num_quads * VERTS_PER_QUAD * sizeof (drawvert_t), + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass, QFV_passTranslucent, + cframe->framebuffer, + 0, 0, 0 + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + dctx->pipeline); + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + VkDeviceSize offsets[] = {dframe->vert_offset}; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &dctx->vert_buffer, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, dctx->ind_buffer, 0, + VK_INDEX_TYPE_UINT32); + VkDescriptorSet set = dframe->descriptors; + VkPipelineLayout layout = dctx->layout; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, 0, 1, &set, 0, 0); + dfunc->vkCmdDrawIndexed (cmd, dframe->num_quads * INDS_PER_QUAD, + 1, 0, 0, 0); + + dfunc->vkEndCommandBuffer (cmd); + + dframe->num_quads = 0; +} + +void +Vulkan_Draw_BlendScreen (quat_t color, vulkan_ctx_t *ctx) +{ + if (color[3]) { + draw_blendscreen (color, ctx); + } +} diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c new file mode 100644 index 000000000..48d4cdba9 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -0,0 +1,506 @@ +/* + vulkan_lighting.c + + Vulkan lighting pass pipeline + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/23 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/dstring.h" +#include "QF/plist.h" +#include "QF/progs.h" +#include "QF/script.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "QF/Vulkan/qf_lighting.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/staging.h" + +#include "compat.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +static void +find_visible_lights (vulkan_ctx_t *ctx) +{ + //qfv_device_t *device = ctx->device; + //qfv_devfuncs_t *dfunc = device->funcs; + lightingctx_t *lctx = ctx->lighting_context; + lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; + + mleaf_t *leaf = r_viewleaf; + model_t *model = r_worldentity.renderer.model; + + if (!leaf || !model) { + return; + } + + if (leaf != lframe->leaf) { + //double start = Sys_DoubleTime (); + byte pvs[MAP_PVS_BYTES]; + + Mod_LeafPVS_set (leaf, model, 0, pvs); + memcpy (lframe->pvs, pvs, sizeof (pvs)); + for (int i = 0; i < model->brush.numleafs; i++) { + if (pvs[i / 8] & (1 << (i % 8))) { + Mod_LeafPVS_mix (model->brush.leafs + i, model, 0, lframe->pvs); + } + } + lframe->leaf = leaf; + + //double end = Sys_DoubleTime (); + //Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6); + + int visible = 0; + memset (lframe->lightvis.a, 0, lframe->lightvis.size * sizeof (byte)); + for (size_t i = 0; i < lctx->lightleafs.size; i++) { + int l = lctx->lightleafs.a[i]; + if (lframe->pvs[l / 8] & (1 << (l % 8))) { + lframe->lightvis.a[i] = 1; + visible++; + } + } + //Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible, + // lframe->lightvis.size); + } +} + +static void +update_lights (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + lightingctx_t *lctx = ctx->lighting_context; + lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; + + find_visible_lights (ctx); + + dlight_t *lights[NUM_LIGHTS]; + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + qfv_light_buffer_t *light_data = QFV_PacketExtend (packet, + sizeof (*light_data)); + + for (int i = 0; i < NUM_STYLES; i++) { + light_data->intensity[i] = d_lightstylevalue[i] / 65536.0; + } + // dynamic lights seem a tad fiant, so 16x map lights + light_data->intensity[64] = 1 / 16.0; + light_data->intensity[65] = 1 / 16.0; + light_data->intensity[66] = 1 / 16.0; + + light_data->lightCount = 0; + R_FindNearLights (r_origin, NUM_LIGHTS - 1, lights); + for (int i = 0; i < NUM_LIGHTS - 1; i++) { + if (!lights[i]) { + break; + } + light_data->lightCount++; + VectorCopy (lights[i]->color, light_data->lights[i].color); + VectorCopy (lights[i]->origin, light_data->lights[i].position); + light_data->lights[i].radius = lights[i]->radius; + light_data->lights[i].data = 64; // default dynamic light + VectorZero (light_data->lights[i].direction); + light_data->lights[i].cone = 1; + } + for (size_t i = 0; + i < lframe->lightvis.size && light_data->lightCount < NUM_LIGHTS; i++) { + if (lframe->lightvis.a[i]) { + light_data->lights[light_data->lightCount++] = lctx->lights.a[i]; + } + } + + VkBufferMemoryBarrier wr_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + lframe->light_buffer, 0, sizeof (qfv_light_buffer_t) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, wr_barriers, 0, 0); + VkBufferCopy copy_region[] = { + { packet->offset, 0, sizeof (qfv_light_buffer_t) }, + }; + dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, + lframe->light_buffer, 1, ©_region[0]); + VkBufferMemoryBarrier rd_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + lframe->light_buffer, 0, sizeof (qfv_light_buffer_t) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, rd_barriers, 0, 0); + QFV_PacketSubmit (packet); +} + +void +Vulkan_Lighting_Draw (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + update_lights (ctx); + + lightingctx_t *lctx = ctx->lighting_context; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = lframe->cmd; + + DARRAY_APPEND (&cframe->cmdSets[QFV_passLighting], cmd); + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass, QFV_passLighting, + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + lctx->pipeline); + + lframe->bufferInfo[0].buffer = lframe->light_buffer; + lframe->imageInfo[0].imageView = ctx->attachment_views->a[QFV_attachDepth]; + lframe->imageInfo[1].imageView = ctx->attachment_views->a[QFV_attachColor]; + lframe->imageInfo[2].imageView + = ctx->attachment_views->a[QFV_attachEmission]; + lframe->imageInfo[3].imageView + = ctx->attachment_views->a[QFV_attachNormal]; + lframe->imageInfo[4].imageView + = ctx->attachment_views->a[QFV_attachPosition]; + dfunc->vkUpdateDescriptorSets (device->dev, + LIGHTING_BUFFER_INFOS + LIGHTING_IMAGE_INFOS, + lframe->descriptors, 0, 0); + + VkDescriptorSet sets[] = { + lframe->descriptors[1].dstSet, + lframe->descriptors[0].dstSet, + }; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + lctx->layout, 0, 2, sets, 0, 0); + + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + VkDeviceSize offset = 0; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &ctx->quad_buffer, &offset); + dfunc->vkCmdDraw (cmd, 4, 1, 0, 0); + + dfunc->vkEndCommandBuffer (cmd); +} + +static VkDescriptorBufferInfo base_buffer_info = { + 0, 0, VK_WHOLE_SIZE +}; +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_buffer_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, 0, 0 +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + 0, 0, 0 +}; + +void +Vulkan_Lighting_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t)); + ctx->lighting_context = lctx; + + DARRAY_INIT (&lctx->lights, 16); + DARRAY_INIT (&lctx->lightleafs, 16); + + size_t frames = ctx->frames.size; + DARRAY_INIT (&lctx->frames, frames); + DARRAY_RESIZE (&lctx->frames, frames); + lctx->frames.grow = 0; + + lctx->pipeline = Vulkan_CreatePipeline (ctx, "lighting"); + lctx->layout = Vulkan_CreatePipelineLayout (ctx, "lighting_layout"); + + __auto_type lbuffers = QFV_AllocBufferSet (frames, alloca); + for (size_t i = 0; i < frames; i++) { + lbuffers->a[i] = QFV_CreateBuffer (device, sizeof (qfv_light_buffer_t), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, + lbuffers->a[i], + va (ctx->va_ctx, "buffer:lighting:%zd", i)); + } + VkMemoryRequirements requirements; + dfunc->vkGetBufferMemoryRequirements (device->dev, lbuffers->a[0], + &requirements); + lctx->light_memory = QFV_AllocBufferMemory (device, lbuffers->a[0], + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + frames * requirements.size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + lctx->light_memory, "memory:lighting"); + + + __auto_type cmdSet = QFV_AllocCommandBufferSet (1, alloca); + + __auto_type attach = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + __auto_type lights = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + for (size_t i = 0; i < frames; i++) { + attach->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, + "lighting_attach"); + lights->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, + "lighting_lights"); + } + __auto_type attach_pool = Vulkan_CreateDescriptorPool (ctx, + "lighting_attach_pool"); + __auto_type lights_pool = Vulkan_CreateDescriptorPool (ctx, + "lighting_lights_pool"); + + __auto_type attach_set = QFV_AllocateDescriptorSet (device, attach_pool, + attach); + __auto_type lights_set = QFV_AllocateDescriptorSet (device, lights_pool, + lights); + for (size_t i = 0; i < frames; i++) { + __auto_type lframe = &lctx->frames.a[i]; + + DARRAY_INIT (&lframe->lightvis, 16); + lframe->leaf = 0; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); + lframe->cmd = cmdSet->a[0]; + + lframe->light_buffer = lbuffers->a[i]; + QFV_BindBufferMemory (device, lbuffers->a[i], lctx->light_memory, + i * requirements.size); + + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + lframe->cmd, "cmd:lighting"); + for (int j = 0; j < LIGHTING_BUFFER_INFOS; j++) { + lframe->bufferInfo[j] = base_buffer_info; + lframe->descriptors[j] = base_buffer_write; + lframe->descriptors[j].dstSet = lights_set->a[i]; + lframe->descriptors[j].dstBinding = j; + lframe->descriptors[j].pBufferInfo = &lframe->bufferInfo[j]; + } + for (int j = 0; j < LIGHTING_IMAGE_INFOS; j++) { + lframe->imageInfo[j] = base_image_info; + lframe->imageInfo[j].sampler = 0; + int k = j + LIGHTING_BUFFER_INFOS; + lframe->descriptors[k] = base_image_write; + lframe->descriptors[k].dstSet = attach_set->a[i]; + lframe->descriptors[k].dstBinding = j; + lframe->descriptors[k].pImageInfo = &lframe->imageInfo[j]; + } + } + free (attach_set); + free (lights_set); +} + +void +Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + lightingctx_t *lctx = ctx->lighting_context; + + for (size_t i = 0; i < lctx->frames.size; i++) { + lightingframe_t *lframe = &lctx->frames.a[i]; + dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0); + DARRAY_CLEAR (&lframe->lightvis); + } + dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0); + dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0); + DARRAY_CLEAR (&lctx->lights); + DARRAY_CLEAR (&lctx->lightleafs); + free (lctx->frames.a); + free (lctx); +} + +static void +parse_light (qfv_light_t *light, const plitem_t *entity, + const plitem_t *targets) +{ + const char *str; + + /*Sys_Printf ("{\n"); + for (int i = PL_D_NumKeys (entity); i-- > 0; ) { + const char *field = PL_KeyAtIndex (entity, i); + const char *value = PL_String (PL_ObjectForKey (entity, field)); + Sys_Printf ("\t%s = %s\n", field, value); + } + Sys_Printf ("}\n");*/ + + light->cone = 1; + light->data = 0; + light->radius = 300; + VectorSet (1, 1, 1, light->color); + + if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { + sscanf (str, "%f %f %f", VectorExpandAddr (light->position)); + } + + if ((str = PL_String (PL_ObjectForKey (entity, "target")))) { + vec3_t position = {}; + plitem_t *target = PL_ObjectForKey (targets, str); + if (target) { + if ((str = PL_String (PL_ObjectForKey (target, "origin")))) { + sscanf (str, "%f %f %f", VectorExpandAddr (position)); + } + VectorSubtract (position, light->position, light->direction); + VectorNormalize (light->direction); + } + + float angle = 40; + if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) { + angle = atof (str); + } + light->cone = -cos (angle * M_PI / 360); // half angle + } + + if ((str = PL_String (PL_ObjectForKey (entity, "light_lev"))) + || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { + light->radius = atof (str); + } + + if ((str = PL_String (PL_ObjectForKey (entity, "style")))) { + light->data = atoi (str) & 0x3f; + } + + if ((str = PL_String (PL_ObjectForKey (entity, "color"))) + || (str = PL_String (PL_ObjectForKey (entity, "_color")))) { + sscanf (str, "%f %f %f", VectorExpandAddr (light->color)); + } +} + +void +Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) +{ + lightingctx_t *lctx = ctx->lighting_context; + plitem_t *entities = 0; + + lctx->lights.size = 0; + lctx->lightleafs.size = 0; + + script_t *script = Script_New (); + Script_Start (script, "ent data", entity_data); + + if (Script_GetToken (script, 1)) { + if (strequal (script->token->str, "(")) { + // new style (plist) entity data + entities = PL_GetPropertyList (entity_data, &ctx->hashlinks); + } else { + // old style entity data + Script_UngetToken (script); + // FIXME ED_ConvertToPlist aborts if an error is encountered. + entities = ED_ConvertToPlist (script, 0, &ctx->hashlinks); + } + } + Script_Delete (script); + + if (entities) { + plitem_t *targets = PL_NewDictionary (&ctx->hashlinks); + + // find all the targets so spotlights can be aimed + for (int i = 1; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *targetname = PL_String (PL_ObjectForKey (entity, + "targetname")); + if (targetname && !PL_ObjectForKey (targets, targetname)) { + PL_D_AddObject (targets, targetname, entity); + } + } + + for (int i = 1; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *classname = PL_String (PL_ObjectForKey (entity, + "classname")); + if (classname && strnequal (classname, "light", 5)) { + qfv_light_t light = {}; + + parse_light (&light, entity, targets); + DARRAY_APPEND (&lctx->lights, light); + mleaf_t *leaf = Mod_PointInLeaf (&light.position[0], + model); + DARRAY_APPEND (&lctx->lightleafs, leaf - model->brush.leafs); + Sys_MaskPrintf (SYS_VULKAN, + "[%g, %g, %g] %d, " + "[%g %g %g] %g, [%g %g %g] %g, %zd\n", + VectorExpand (light.color), light.data, + VectorExpand (light.position), light.radius, + VectorExpand (light.direction), light.cone, + leaf - model->brush.leafs); + } + } + for (size_t i = 0; i < ctx->frames.size; i++) { + lightingframe_t *lframe = &lctx->frames.a[i]; + DARRAY_RESIZE (&lframe->lightvis, lctx->lights.size); + } + // targets does not own the objects, so need to remove them before + // freeing targets + for (int i = PL_D_NumKeys (targets); i-- > 0; ) { + PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i)); + } + PL_Free (targets); + PL_Free (entities); + } + Sys_MaskPrintf (SYS_VULKAN, "loaded %zd lights\n", lctx->lights.size); +} diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c new file mode 100644 index 000000000..3cfbcb7ba --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -0,0 +1,287 @@ +/* + vulkan_lightmap.c + + surface-related refresh code + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2000 Joseph Carter + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "QF/cvar.h" +#include "QF/entity.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_main.h" +#include "QF/Vulkan/scrap.h" + +#include "compat.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#define LUXEL_SIZE 4 + +static inline void +add_dynamic_lights (msurface_t *surf, float *block) +{ + unsigned lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1 }; + int smax, tmax; + int s, t; + mtexinfo_t *tex; + plane_t *plane; + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + tex = surf->texinfo; + plane = surf->plane; + + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + + for (lnum = 0; lnum < r_maxdlights; lnum++) { + if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) + continue; // not lit by this light + + dlight_t *light = &r_dlights[lnum]; + + VectorSubtract (light->origin, entorigin, lightorigin); + rad = light->radius; + dist = DotProduct (lightorigin, plane->normal) - plane->dist; + rad -= fabs (dist); + + minlight = light->minlight; + if (rad < minlight) { + continue; + } + VectorMultSub (light->origin, dist, plane->normal, impact); + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + for (t = 0; t < tmax; t++) { + td = local[1] - t * 16; + if (td < 0) { + td = -td; + } + for (s = 0; s < smax; s++) { + sd = local[0] - s * 16; + if (sd < 0) { + sd = -sd; + } + if (sd > td) { + dist = sd + (td >> 1); + } else { + dist = td + (sd >> 1); + } + if (dist < minlight) { + float *out = block + (t * smax + s) * LUXEL_SIZE; + float l = (rad - dist); + VectorMultAdd (out, l, light->color, out); + out[3] = 1; + out += LUXEL_SIZE; + } + } + } + } +} + +void +Vulkan_BuildLightMap (mod_brush_t *brush, msurface_t *surf, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int smax, tmax, size; + unsigned scale; + int i; + float *out, *block; + + surf->cached_dlight = (surf->dlightframe == r_framecount); + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + size = smax * tmax * LUXEL_SIZE; + + block = QFV_SubpicBatch (surf->lightpic, bctx->light_stage); + + // set to full bright if no light data + if (!brush->lightdata) { + out = block; + while (size-- > 0) { + *out++ = 1; + } + return; + } + + // clear to no light + memset (block, 0, size * sizeof(float)); + + // add all the lightmaps + if (surf->samples) { + byte *lightmap; + + lightmap = surf->samples; + for (int maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; + maps++) { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + out = block; + for (i = 0; i < smax * tmax; i++) { + *out++ += *lightmap++ * scale / 65536.0; + *out++ += *lightmap++ * scale / 65536.0; + *out++ += *lightmap++ * scale / 65536.0; + out++; + } + } + } + // add all the dynamic lights + if (surf->dlightframe == r_framecount) { + add_dynamic_lights (surf, block); + } +} + +void +Vulkan_CalcLightmaps (vulkan_ctx_t *ctx) +{ +/* int i; + + for (i = 0; i < MAX_LIGHTMAPS; i++) { + if (!gl_lightmap_polys[i]) + continue; + if (gl_lightmap_modified[i]) { + qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures + i); + GL_UploadLightmap (i); + gl_lightmap_modified[i] = false; + } + }*/ +} + +static void +vulkan_create_surf_lightmap (msurface_t *surf, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int smax, tmax; + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + + surf->lightpic = QFV_ScrapSubpic (bctx->light_scrap, smax, tmax); + if (!surf->lightpic) { + Sys_Error ("FIXME taniwha is being lazy"); + } +} + +/* + GL_BuildLightmaps + + Builds the lightmap texture with all the surfaces from all brush models +*/ +void +Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int i, j; + model_t *m; + mod_brush_t *brush; + + QFV_ScrapClear (bctx->light_scrap); + + r_framecount = 1; // no dlightcache + + for (j = 1; j < num_models; j++) { + m = models[j]; + if (!m) + break; + if (m->path[0] == '*' || m->type != mod_brush) { + // sub model surfaces are processed as part of the main model + continue; + } + brush = &m->brush; + // non-bsp models don't have surfaces. + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; + surf->lightpic = 0; // paranoia + if (surf->flags & SURF_DRAWTURB) { + continue; + } + if (surf->flags & SURF_DRAWSKY) { + continue; + } + vulkan_create_surf_lightmap (surf, ctx); + } + } + + for (j = 1; j < num_models; j++) { + m = models[j]; + if (!m) { + break; + } + if (m->path[0] == '*' || m->type != mod_brush) { + // sub model surfaces are processed as part of the main model + continue; + } + brush = &m->brush; + // non-bsp models don't have surfaces. + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; + if (surf->lightpic) { + Vulkan_BuildLightMap (brush, surf, ctx); + } + } + } +} + +VkImageView +Vulkan_LightmapImageView (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + return QFV_ScrapImageView (bctx->light_scrap); +} + +void +Vulkan_FlushLightmaps (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + QFV_ScrapFlush (bctx->light_scrap); +} diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c new file mode 100644 index 000000000..3474b67ed --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -0,0 +1,245 @@ +/* + vulkan_main.c + + Vulkan rendering + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/19 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include "string.h" +#endif +#ifdef HAVE_STRINGS_H +# include "strings.h" +#endif + +#include "QF/cmd.h" +#include "QF/cvar.h" +#include "QF/image.h" +#include "QF/render.h" +#include "QF/screen.h" +#include "QF/sys.h" + +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_bsp.h" +//#include "QF/Vulkan/qf_iqm.h" +#include "QF/Vulkan/qf_lighting.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_main.h" +#include "QF/Vulkan/qf_particles.h" +//#include "QF/Vulkan/qf_textures.h" + +#include "mod_internal.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +static void +setup_frame (vulkan_ctx_t *ctx) +{ + R_AnimateLight (); + R_ClearEnts (); + r_framecount++; + + VectorCopy (r_refdef.viewposition, r_origin); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); + + R_SetFrustum (); + + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); +} + +static void +setup_view (vulkan_ctx_t *ctx) +{ + mat4f_t view; + static mat4f_t z_up = { + { 0, 0, -1, 0}, + {-1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 0, 1}, + }; + vec4f_t offset = { 0, 0, 0, 1 }; + + /*x = r_refdef.vrect.x; + y = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)); + w = r_refdef.vrect.width; + h = r_refdef.vrect.height; + qfeglViewport (x, y, w, h);*/ + + mat4fquat (view, qconjf (r_refdef.viewrotation)); + mmulf (view, z_up, view); + offset = -r_refdef.viewposition; + offset[3] = 1; + view[3] = mvmulf (view, offset); + memcpy (ctx->matrices.view_3d, view, sizeof (view)); +} + +static void +R_RenderEntities (vulkan_ctx_t *ctx) +{ + if (!r_drawentities->int_val) + return; +#define RE_LOOP(type_name, Type) \ + do { \ + entity_t *ent; \ + int begun = 0; \ + for (ent = r_ent_queue; ent; ent = ent->next) { \ + if (ent->renderer.model->type != mod_##type_name) \ + continue; \ + if (!begun) { \ + Vulkan_##Type##Begin (ctx); \ + begun = 1; \ + } \ + Vulkan_Draw##Type (ent, ctx); \ + } \ + if (begun) \ + Vulkan_##Type##End (ctx); \ + } while (0) + + RE_LOOP (alias, Alias); + //RE_LOOP (iqm, IQM); + //RE_LOOP (sprite, Sprite); +} + +static void +R_DrawViewModel (void) +{ + currententity = vr_data.view_model; + if (vr_data.inhibit_viewmodel + || !r_drawviewmodel->int_val + || !r_drawentities->int_val + || !currententity->renderer.model) + return; + + // hack the depth range to prevent view model from poking into walls + //qfeglDepthRangef (0, 0.3); + //glsl_R_AliasBegin (); + //glsl_R_DrawAlias (); + //glsl_R_AliasEnd (); + //qfeglDepthRangef (0, 1); +} + +void +Vulkan_RenderView (vulkan_ctx_t *ctx) +{ + double t[10] = {}; + int speeds = r_speeds->int_val; + + if (speeds) + t[0] = Sys_DoubleTime (); + setup_frame (ctx); + setup_view (ctx); + if (speeds) + t[1] = Sys_DoubleTime (); + R_MarkLeaves (); + if (speeds) + t[2] = Sys_DoubleTime (); + R_PushDlights (vec3_origin); + if (speeds) + t[3] = Sys_DoubleTime (); + Vulkan_DrawWorld (ctx); + if (speeds) + t[4] = Sys_DoubleTime (); + Vulkan_DrawSky (ctx); + if (speeds) + t[5] = Sys_DoubleTime (); + R_RenderEntities (ctx); + if (speeds) + t[6] = Sys_DoubleTime (); + Vulkan_DrawWaterSurfaces (ctx); + if (speeds) + t[7] = Sys_DoubleTime (); + Vulkan_DrawParticles (ctx); + if (speeds) + t[8] = Sys_DoubleTime (); + R_DrawViewModel (); + if (speeds) + t[9] = Sys_DoubleTime (); + if (speeds) { + Sys_Printf ("frame: %g, setup: %g, mark: %g, pushdl: %g, world: %g," + " sky: %g, ents: %g, water: %g, part: %g, view: %g\n", + (t[9] - t[0]) * 1000, (t[1] - t[0]) * 1000, + (t[2] - t[1]) * 1000, (t[3] - t[2]) * 1000, + (t[4] - t[3]) * 1000, (t[5] - t[4]) * 1000, + (t[6] - t[5]) * 1000, (t[7] - t[6]) * 1000, + (t[8] - t[7]) * 1000, (t[9] - t[8]) * 1000); + } +} + +void +Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, + vulkan_ctx_t *ctx) +{ + int i; + + for (i = 0; i < 256; i++) { + d_lightstylevalue[i] = 264; // normal light value + } + + memset (&r_worldentity, 0, sizeof (r_worldentity)); + r_worldentity.renderer.model = worldmodel; + + // Force a vis update + r_viewleaf = NULL; + R_MarkLeaves (); + + R_FreeAllEntities (); + Vulkan_ClearParticles (ctx); + Vulkan_RegisterTextures (models, num_models, ctx); + //Vulkan_BuildLightmaps (models, num_models, ctx); + Vulkan_BuildDisplayLists (models, num_models, ctx); + Vulkan_LoadLights (worldmodel, worldmodel->brush.entities, ctx); +} + +/*void +glsl_R_LineGraph (int x, int y, int *h_vals, int count) +{ +}*/ + +/*void +glsl_R_TimeRefresh_f (void) +{ + double start, stop, time; + int i; + + glsl_ctx->end_rendering (); + + start = Sys_DoubleTime (); + for (i = 0; i < 128; i++) { + r_refdef.viewangles[1] = i * (360.0 / 128.0); + Vulkan_RenderView (ctx); + glsl_ctx->end_rendering (); + } + + stop = Sys_DoubleTime (); + time = stop - start; + Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); +}*/ diff --git a/libs/video/renderer/vulkan/vulkan_matrices.c b/libs/video/renderer/vulkan/vulkan_matrices.c new file mode 100644 index 000000000..ffd36219a --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_matrices.c @@ -0,0 +1,205 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/device.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +#define MAT_SIZE (16 * sizeof (float)) + +static void +ortho_mat (float *proj, float xmin, float xmax, float ymin, float ymax, + float znear, float zfar) +{ + proj[0] = 2 / (xmax - xmin); + proj[4] = 0; + proj[8] = 0; + proj[12] = -(xmax + xmin) / (xmax - xmin); + + proj[1] = 0; + proj[5] = 2 / (ymax - ymin); + proj[9] = 0; + proj[13] = -(ymax + ymin) / (ymax - ymin); + + proj[2] = 0; + proj[6] = 0; + proj[10] = -2 / (zfar - znear); + proj[14] = -(zfar + znear) / (zfar - znear); + + proj[3] = 0; + proj[7] = 0; + proj[11] = 0; + proj[15] = 1; +} + +static void +persp_mat (float *proj, float xmin, float xmax, float ymin, float ymax, + float aspect) +{ + float fovx, fovy, neard, fard; + + fovx = r_refdef.fov_x; + fovy = r_refdef.fov_y; + neard = r_nearclip->value; + fard = r_farclip->value; + + ymax = neard * tan (fovy * M_PI / 360); // fov_2 / 2 + ymin = -ymax; + xmax = neard * tan (fovx * M_PI / 360); // fov_2 / 2 + xmin = -xmax; + + proj[0] = (2 * neard) / (xmax - xmin); + proj[4] = 0; + proj[8] = (xmax + xmin) / (xmax - xmin); + proj[12] = 0; + + proj[1] = 0; + proj[5] = -(2 * neard) / (ymax - ymin); + proj[9] = (ymax + ymin) / (ymax - ymin); + proj[13] = 0; + + proj[2] = 0; + proj[6] = 0; + proj[10] = (fard) / (neard - fard); + proj[14] = (fard * neard) / (neard - fard); + + proj[3] = 0; + proj[7] = 0; + proj[11] = -1; + proj[15] = 0; +} + +void +Vulkan_DestroyMatrices (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type mat = &ctx->matrices; + + dfunc->vkUnmapMemory (device->dev, mat->memory); + dfunc->vkFreeMemory (device->dev, mat->memory, 0); + dfunc->vkDestroyBuffer (device->dev, mat->buffer_2d, 0); + dfunc->vkDestroyBuffer (device->dev, mat->buffer_3d, 0); +} + +void +Vulkan_CreateMatrices (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type mat = &ctx->matrices; + mat->buffer_2d = QFV_CreateBuffer (device, 1 * MAT_SIZE, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + mat->buffer_3d = QFV_CreateBuffer (device, 3 * MAT_SIZE, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + + size_t size = 0; + size_t offset; + VkMemoryRequirements req; + + dfunc->vkGetBufferMemoryRequirements (device->dev, mat->buffer_2d, &req); + size += req.size; + offset = size; + + dfunc->vkGetBufferMemoryRequirements (device->dev, mat->buffer_3d, &req); + offset = (offset + req.alignment - 1) & ~(req.alignment - 1); + size += req.size; + + mat->memory = QFV_AllocBufferMemory (device, mat->buffer_2d, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + size, 0); + QFV_BindBufferMemory (device, mat->buffer_2d, mat->memory, 0); + QFV_BindBufferMemory (device, mat->buffer_3d, mat->memory, offset); + void *data; + dfunc->vkMapMemory (device->dev, mat->memory, 0, size, 0, &data); + mat->projection_2d = data; + mat->projection_3d = mat->projection_2d + offset / sizeof (float); + mat->view_3d = mat->projection_3d + 16; + mat->sky_3d = mat->view_3d + 16; +} + +void +Vulkan_CalcProjectionMatrices (vulkan_ctx_t *ctx, float aspect) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type mat = &ctx->matrices; + + int width = vid.conwidth; + int height = vid.conheight; + + ortho_mat (mat->projection_2d, 0, width, 0, height, -99999, 99999); + persp_mat (mat->projection_3d, 0, width, 0, height, aspect); +#if 0 + Sys_MaskPrintf (SYS_VULKAN, "ortho:\n"); + Sys_MaskPrintf (SYS_VULKAN, " [[%g, %g, %g, %g],\n", + QuatExpand (mat->projection_2d + 0)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_2d + 4)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_2d + 8)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g]]\n", + QuatExpand (mat->projection_2d + 12)); + Sys_MaskPrintf (SYS_VULKAN, "presp:\n"); + Sys_MaskPrintf (SYS_VULKAN, " [[%g, %g, %g, %g],\n", + QuatExpand (mat->projection_3d + 0)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_3d + 4)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_3d + 8)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g]]\n", + QuatExpand (mat->projection_3d + 12)); +#endif + VkMappedMemoryRange ranges[] = { + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, mat->memory, 0, MAT_SIZE }, + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, mat->memory, + (mat->projection_3d - mat->projection_2d) * sizeof (float), + MAT_SIZE}, + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 2, ranges); +} diff --git a/libs/video/renderer/vulkan/vulkan_particles.c b/libs/video/renderer/vulkan/vulkan_particles.c new file mode 100644 index 000000000..abb24924b --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_particles.c @@ -0,0 +1,273 @@ +/* + vulkan_particles.c + + Quake specific Vulkan particle manager + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/render.h" +#include "QF/plugin/vid_render.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/qf_particles.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +void +Vulkan_ClearParticles (struct vulkan_ctx_s *ctx) +{ +} + +void +Vulkan_InitParticles (struct vulkan_ctx_s *ctx) +{ +} + +static void +R_RocketTrail_QF (const entity_t *ent) +{ +} + +static void +R_GrenadeTrail_QF (const entity_t *ent) +{ +} + +static void +R_BloodTrail_QF (const entity_t *ent) +{ +} + +static void +R_SlightBloodTrail_QF (const entity_t *ent) +{ +} + +static void +R_WizTrail_QF (const entity_t *ent) +{ +} + +static void +R_FlameTrail_QF (const entity_t *ent) +{ +} + +static void +R_VoorTrail_QF (const entity_t *ent) +{ +} + +static void +R_GlowTrail_QF (const entity_t *ent, int glow_color) +{ +} + +static void +R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color, + int count) +{ +} + +static void +R_BloodPuffEffect_QF (const vec3_t org, int count) +{ +} + +static void +R_GunshotEffect_QF (const vec3_t org, int count) +{ +} + +static void +R_LightningBloodEffect_QF (const vec3_t org) +{ +} + +static void +R_SpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_KnightSpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_SuperSpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_WizSpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_BlobExplosion_QF (const vec3_t org) +{ +} + +static void +R_ParticleExplosion_QF (const vec3_t org) +{ +} + +static void +R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength) +{ +} + +static void +R_LavaSplash_QF (const vec3_t org) +{ +} + +static void +R_TeleportSplash_QF (const vec3_t org) +{ +} + +static void +R_DarkFieldParticles_ID (const entity_t *ent) +{ +} + +static void +R_EntityParticles_ID (const entity_t *ent) +{ +} + +static void +R_Particle_New (ptype_t type, int texnum, const vec3_t org, + float scale, const vec3_t vel, float die, + int color, float alpha, float ramp) +{ +} + +static void +R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, + float die, int color, float alpha, + float ramp) +{ +} + +static vid_particle_funcs_t vulkan_particles_QF = { + R_RocketTrail_QF, + R_GrenadeTrail_QF, + R_BloodTrail_QF, + R_SlightBloodTrail_QF, + R_WizTrail_QF, + R_FlameTrail_QF, + R_VoorTrail_QF, + R_GlowTrail_QF, + R_RunParticleEffect_QF, + R_BloodPuffEffect_QF, + R_GunshotEffect_QF, + R_LightningBloodEffect_QF, + R_SpikeEffect_QF, + R_KnightSpikeEffect_QF, + R_SuperSpikeEffect_QF, + R_WizSpikeEffect_QF, + R_BlobExplosion_QF, + R_ParticleExplosion_QF, + R_ParticleExplosion2_QF, + R_LavaSplash_QF, + R_TeleportSplash_QF, + R_DarkFieldParticles_ID, + R_EntityParticles_ID, + R_Particle_New, + R_Particle_NewRandom, +}; + +void +Vulkan_r_easter_eggs_f (cvar_t *var, struct vulkan_ctx_s *ctx) +{ + if (!easter_eggs || !r_particles_style) { + return; + } + if (easter_eggs->int_val) { + if (r_particles_style->int_val) { + //vulkan_vid_render_funcs.particles = &vulkan_particles_QF_egg; + } else { + //vulkan_vid_render_funcs.particles = &vulkan_particles_ID_egg; + } + } else { + if (r_particles_style->int_val) { + //vulkan_vid_render_funcs.particles = &vulkan_particles_QF; + } else { + //vulkan_vid_render_funcs.particles = &vulkan_particles_ID; + } + } + vulkan_vid_render_funcs.particles = &vulkan_particles_QF; +} + +void +Vulkan_r_particles_style_f (cvar_t *var, struct vulkan_ctx_s *ctx) +{ + Vulkan_r_easter_eggs_f (var, ctx); +} + +void +Vulkan_DrawParticles (struct vulkan_ctx_s *ctx) +{ +} + +void +Vulkan_Particles_Init (struct vulkan_ctx_s *ctx) +{ + /* + easter_eggs = Cvar_Get ("easter_eggs", "0", CVAR_NONE, r_easter_eggs_f, + "Enables easter eggs."); + r_particles = Cvar_Get ("r_particles", "1", CVAR_ARCHIVE, r_particles_f, + "Toggles drawing of particles."); + r_particles_max = Cvar_Get ("r_particles_max", "2048", CVAR_ARCHIVE, + r_particles_max_f, "Maximum amount of " + "particles to display. No maximum, minimum " + "is 0."); + r_particles_nearclip = Cvar_Get ("r_particles_nearclip", "32", + CVAR_ARCHIVE, r_particles_nearclip_f, + "Distance of the particle near clipping " + "plane from the player."); + r_particles_style = Cvar_Get ("r_particles_style", "1", CVAR_ARCHIVE, + r_particles_style_f, "Sets particle style. " + "0 for Id, 1 for QF."); + */ + vulkan_vid_render_funcs.particles = &vulkan_particles_QF; +} diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c new file mode 100644 index 000000000..7aa8cfc64 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -0,0 +1,452 @@ +/* + vulkan_texuture.c + + Quake specific Vulkan texuture manager + + Copyright (C) 2021 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/image.h" +#include "QF/mathlib.h" +#include "QF/quakefs.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/scrap.h" +#include "QF/Vulkan/staging.h" + +#include "r_scrap.h" +#include "vid_vulkan.h" + +void +Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, + int alpha, int count) +{ + if (alpha > 1) { + while (count-- > 0) { + int pix = *src++; + const byte *col = palette + pix * 4; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + } + } else if (alpha) { + while (count-- > 0) { + byte pix = *src++; + const byte *col = palette + pix * 3; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = 0xff; + } + } else { + while (count-- > 0) { + byte pix = *src++; + const byte *col = palette + pix * 3; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + } + } +} + +static int +tex_format (const tex_t *tex, VkFormat *format, int *bpp) +{ + switch (tex->format) { + case tex_l: + case tex_a: + *format = VK_FORMAT_R8_UNORM; + *bpp = 1; + return 1; + case tex_la: + *format = VK_FORMAT_R8G8_UNORM; + *bpp = 2; + return 1; + case tex_palette: + if (!tex->palette) { + return 0; + } + *format = VK_FORMAT_R8G8B8A8_UNORM; + *bpp = 4; + return 1; + case tex_rgb: + *format = VK_FORMAT_R8G8B8A8_UNORM; + *bpp = 4; + return 1; + case tex_rgba: + *format = VK_FORMAT_R8G8B8A8_UNORM; + *bpp = 4; + return 1; + case tex_frgba: + *format = VK_FORMAT_R32G32B32A32_SFLOAT; + *bpp = 16; + return 1; + } + return 0; +} + +static size_t +stage_tex_data (qfv_packet_t *packet, tex_t *tex, int bpp) +{ + size_t texels = tex->width * tex->height; + byte *tex_data = QFV_PacketExtend (packet, bpp * texels); + + if (tex->format == tex_palette) { + Vulkan_ExpandPalette (tex_data, tex->data, tex->palette, 1, texels); + } else { + if (tex->format == 3) { + byte *in = tex->data; + byte *out = tex_data; + while (texels-- > 0) { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = 255; + } + } else { + memcpy (tex_data, tex->data, bpp * texels); + } + } + return tex_data - (byte *) packet->stage->data; +} + +qfv_tex_t * +Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip, const char *name) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + int bpp; + VkFormat format; + + if (!tex_format (tex, &format, &bpp)) { + return 0; + } + + if (mip) { + mip = QFV_MipLevels (tex->width, tex->height); + } else { + mip = 1; + } + + //qfv_devfuncs_t *dfunc = device->funcs; + //FIXME this whole thing is ineffiecient, especially for small textures + qfv_tex_t *qtex = malloc (sizeof (qfv_tex_t)); + + VkExtent3D extent = { tex->width, tex->height, 1 }; + qtex->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, format, extent, + mip, 1, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, qtex->image, + va (ctx->va_ctx, "image:%s", name)); + qtex->memory = QFV_AllocImageMemory (device, qtex->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, qtex->memory, + va (ctx->va_ctx, "memory:%s", name)); + QFV_BindImageMemory (device, qtex->image, qtex->memory, 0); + qtex->view = QFV_CreateImageView (device, qtex->image, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, qtex->view, + va (ctx->va_ctx, "iview:%s", name)); + + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + stage_tex_data (packet, tex, bpp); + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = qtex->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + VkBufferImageCopy copy = { + packet->offset, 0, 0, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {0, 0, 0}, {tex->width, tex->height, 1}, + }; + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + qtex->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©); + if (mip == 1) { + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = qtex->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + } else { + QFV_GenerateMipMaps (device, packet->cmd, qtex->image, + mip, tex->width, tex->height, 1); + } + QFV_PacketSubmit (packet); + return qtex; +} + +static qfv_tex_t * +create_cubetex (vulkan_ctx_t *ctx, int size, VkFormat format, + const char *name) +{ + qfv_device_t *device = ctx->device; + + qfv_tex_t *qtex = malloc (sizeof (qfv_tex_t)); + + VkExtent3D extent = { size, size, 1 }; + qtex->image = QFV_CreateImage (device, 1, VK_IMAGE_TYPE_2D, format, extent, + 1, 1, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, qtex->image, + va (ctx->va_ctx, "image:envmap:%s", name)); + qtex->memory = QFV_AllocImageMemory (device, qtex->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, qtex->memory, + va (ctx->va_ctx, "memory:%s", name)); + QFV_BindImageMemory (device, qtex->image, qtex->memory, 0); + qtex->view = QFV_CreateImageView (device, qtex->image, + VK_IMAGE_VIEW_TYPE_CUBE, format, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, qtex->view, + va (ctx->va_ctx, "iview:envmap:%s", name)); + + return qtex; +} + +qfv_tex_t * +Vulkan_LoadEnvMap (vulkan_ctx_t *ctx, tex_t *tex, const char *name) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + int bpp; + VkFormat format; + + static int env_coords[][2] = { + {2, 0}, // right + {0, 0}, // left + {1, 1}, // top + {0, 1}, // bottom + {2, 1}, // front + {1, 0}, // back + }; + + if (!tex_format (tex, &format, &bpp)) { + return 0; + } + if (tex->height * 3 != tex->width * 2) { + return 0; + } + + int size = tex->height / 2; + qfv_tex_t *qtex = create_cubetex (ctx, size, format, name); + + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + stage_tex_data (packet, tex, bpp); + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = qtex->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + + VkBufferImageCopy copy[6] = { + { + 0, tex->width, 0, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {0, 0, 0}, {size, size, 1}, + }, + }; + for (int i = 0; i < 6; i++) { + int x = env_coords[i][0] * size; + int y = env_coords[i][1] * size; + int offset = x + y * tex->width; + copy[i] = copy[0]; + copy[i].bufferOffset = packet->offset + bpp * offset; + copy[i].imageSubresource.baseArrayLayer = i; + } + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + qtex->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 6, copy); + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = qtex->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + QFV_PacketSubmit (packet); + return qtex; +} + +qfv_tex_t * +Vulkan_LoadEnvSides (vulkan_ctx_t *ctx, tex_t **tex, const char *name) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + int bpp; + VkFormat format; + + if (!tex_format (tex[0], &format, &bpp)) { + return 0; + } + if (tex[0]->height != tex[0]->width) { + return 0; + } + for (int i = 1; i < 6; i++) { + if (tex[i]->format != tex[0]->format + || tex[i]->width != tex[0]->width + || tex[i]->height != tex[0]->height) { + return 0; + } + } + + int size = tex[0]->height; + qfv_tex_t *qtex = create_cubetex (ctx, size, format, name); + + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = qtex->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + + VkBufferImageCopy copy[6] = { + { + 0, 0, 0, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {0, 0, 0}, {size, size, 1}, + }, + }; + for (int i = 0; i < 6; i++) { + copy[i] = copy[0]; + copy[i].bufferOffset = stage_tex_data (packet, tex[i], bpp); + copy[i].imageSubresource.baseArrayLayer = i; + } + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + qtex->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 6, copy); + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = qtex->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + QFV_PacketSubmit (packet); + return qtex; +} + +VkImageView +Vulkan_TexImageView (qfv_tex_t *tex) +{ + return tex->view; +} + +void +Vulkan_UnloadTex (vulkan_ctx_t *ctx, qfv_tex_t *tex) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyImageView (device->dev, tex->view, 0); + dfunc->vkDestroyImage (device->dev, tex->image, 0); + dfunc->vkFreeMemory (device->dev, tex->memory, 0); + free (tex); +} + +static byte black_data[] = {0, 0, 0, 0}; +static byte white_data[] = {255, 255, 255, 255}; +static byte magenta_data[] = {255, 0, 255, 255}; +static tex_t default_black_tex = {1, 1, tex_rgba, 1, 0, black_data}; +static tex_t default_white_tex = {1, 1, tex_rgba, 1, 0, white_data}; +static tex_t default_magenta_tex = {1, 1, tex_rgba, 1, 0, magenta_data}; + +void +Vulkan_Texture_Init (vulkan_ctx_t *ctx) +{ + ctx->default_black = Vulkan_LoadTex (ctx, &default_black_tex, 1, + "default_black"); + ctx->default_white = Vulkan_LoadTex (ctx, &default_white_tex, 1, + "default_white"); + ctx->default_magenta = Vulkan_LoadTex (ctx, &default_magenta_tex, 1, + "default_magenta"); +} + +void +Vulkan_Texture_Shutdown (vulkan_ctx_t *ctx) +{ + Vulkan_UnloadTex (ctx, ctx->default_black); + Vulkan_UnloadTex (ctx, ctx->default_white); + Vulkan_UnloadTex (ctx, ctx->default_magenta); +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c new file mode 100644 index 000000000..e18b5d689 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -0,0 +1,635 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 2019 Bill Currie + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cexpr.h" +#include "QF/cmem.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/plist.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/capture.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/pipeline.h" +#include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" +#include "QF/Vulkan/staging.h" +#include "QF/Vulkan/swapchain.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" +#include "vkparse.h" + +static const char quakeforge_pipeline[] = +#include "libs/video/renderer/vulkan/qfpipeline.plc" +; + +static const char quakeforge_renderpass[] = +#include "libs/video/renderer/vulkan/deferred.plc" +; + +cvar_t *vulkan_frame_count; +cvar_t *vulkan_presentation_mode; +cvar_t *msaaSamples; + +static void +vulkan_presentation_mode_f (cvar_t *var) +{ + if (!strcmp (var->string, "immediate")) { + var->int_val = VK_PRESENT_MODE_IMMEDIATE_KHR; + } else if (!strcmp (var->string, "fifo")) { + var->int_val = VK_PRESENT_MODE_FIFO_KHR; + } else if (!strcmp (var->string, "relaxed")) { + var->int_val = VK_PRESENT_MODE_FIFO_RELAXED_KHR; + } else if (!strcmp (var->string, "mailbox")) { + var->int_val = VK_PRESENT_MODE_MAILBOX_KHR; + } else { + Sys_Printf ("Invalid presentation mode, using fifo\n"); + var->int_val = VK_PRESENT_MODE_FIFO_KHR; + } +} + +static void +vulkan_frame_count_f (cvar_t *var) +{ + if (var->int_val < 1) { + Sys_Printf ("Invalid frame count: %d. Setting to 1\n", var->int_val); + Cvar_Set (var, "1"); + } +} + +static void +msaaSamples_f (cvar_t *var) +{ + exprctx_t context = {}; + context.memsuper = new_memsuper(); + + if (cexpr_parse_enum (QFV_GetEnum ("VkSampleCountFlagBits"), var->string, + &context, &var->int_val)) { + Sys_Printf ("Invalid MSAA samples, using 1\n"); + var->int_val = VK_SAMPLE_COUNT_1_BIT; + } + delete_memsuper (context.memsuper); +} + +static void +Vulkan_Init_Cvars (void) +{ + vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE, + 0, + "enable KRONOS Validation Layer if " + "available (requires instance " + "restart)."); + // FIXME implement fallback choices (instead of just fifo) + vulkan_presentation_mode = Cvar_Get ("vulkan_presentation_mode", "mailbox", + CVAR_NONE, vulkan_presentation_mode_f, + "desired presentation mode (may fall " + "back to fifo)."); + vulkan_frame_count = Cvar_Get ("vulkan_frame_count", "3", CVAR_NONE, + vulkan_frame_count_f, + "Number of frames to render in the" + " background. More frames can increase" + " performance, but at the cost of latency." + " The default of 3 is recommended."); + msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_1_BIT", + CVAR_NONE, msaaSamples_f, + "desired MSAA sample size."); + R_Init_Cvars (); +} + +static const char *instance_extensions[] = { + VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + 0, +}; + +static const char *device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, + 0, +}; + +void +Vulkan_Init_Common (vulkan_ctx_t *ctx) +{ + Sys_MaskPrintf (SYS_VULKAN, "Vulkan_Init_Common\n"); + + QFV_InitParse (ctx); + Vulkan_Init_Cvars (); + ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, + instance_extensions);//FIXME version +} + +static void +clear_table (hashtab_t **table) +{ + if (*table) { + hashtab_t *tab = *table; + *table = 0; + Hash_DelTable (tab); + } +} + +void +Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) +{ + PL_Free (ctx->pipelineDef); + PL_Free (ctx->renderpassDef); + if (ctx->capture) { + QFV_DestroyCapture (ctx->capture); + } + if (ctx->frames.size) { + Vulkan_DestroyFrames (ctx); + } + if (ctx->swapchain) { + QFV_DestroySwapchain (ctx->swapchain); + } + QFV_DestroyStagingBuffer (ctx->staging); + Vulkan_DestroyMatrices (ctx); + ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, + ctx->surface, 0); + clear_table (&ctx->pipelineLayouts); + clear_table (&ctx->setLayouts); + clear_table (&ctx->shaderModules); + clear_table (&ctx->descriptorPools); + clear_table (&ctx->samplers); + if (ctx->device) { + QFV_DestroyDevice (ctx->device); + } + if (ctx->instance) { + QFV_DestroyInstance (ctx->instance); + } + ctx->instance = 0; + ctx->unload_vulkan (ctx); +} + +void +Vulkan_CreateDevice (vulkan_ctx_t *ctx) +{ + ctx->device = QFV_CreateDevice (ctx, device_extensions); + + //FIXME msaa and deferred rendering... + //also, location + ctx->msaaSamples = 1; + /*ctx->msaaSamples = min ((VkSampleCountFlagBits) msaaSamples->int_val, + QFV_GetMaxSampleCount (device->physDev)); + if (ctx->msaaSamples > 1) { + name = "renderpass_msaa"; + }*/ +} + +void +Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx) +{ + ctx->staging = QFV_CreateStagingBuffer (ctx->device, "vulkan_ctx", + 16*1024*1024, ctx->cmdpool); +} + +void +Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) +{ + VkSwapchainKHR old_swapchain = 0; + if (ctx->swapchain) { + old_swapchain = ctx->swapchain->swapchain; + free (ctx->swapchain); + } + ctx->swapchain = QFV_CreateSwapchain (ctx, old_swapchain); + if (old_swapchain && ctx->swapchain->swapchain != old_swapchain) { + ctx->device->funcs->vkDestroySwapchainKHR (ctx->device->dev, + old_swapchain, 0); + } +} + +static plitem_t * +qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name) +{ + if (!ctx->pipelineDef) { + ctx->pipelineDef = PL_GetPropertyList (quakeforge_pipeline, + &ctx->hashlinks); + } + + plitem_t *item = ctx->pipelineDef; + if (!item || !(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading %s\n", name); + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Found %s def\n", name); + } + return item; +} + +static plitem_t * +qfv_load_renderpass (vulkan_ctx_t *ctx, const char *name) +{ + if (!ctx->renderpassDef) { + ctx->renderpassDef = PL_GetPropertyList (quakeforge_renderpass, + &ctx->hashlinks); + } + + plitem_t *item = ctx->renderpassDef; + if (!item || !(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading %s\n", name); + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Found %s def\n", name); + } + return item; +} + +static size_t +get_image_size (VkImage image, qfv_device_t *device) +{ + qfv_devfuncs_t *dfunc = device->funcs; + size_t size; + size_t align; + + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (device->dev, image, &requirements); + size = requirements.size; + align = requirements.alignment - 1; + size = (size + align) & ~(align); + return size; +} + +void +Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) +{ + const char *name = "renderpass";//FIXME + + hashtab_t *tab = ctx->renderpasses; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".%s", name); + __auto_type renderpass = (VkRenderPass) QFV_GetHandle (tab, path); + if (renderpass) { + ctx->renderpass = renderpass; + return; + } + + plitem_t *item = qfv_load_renderpass (ctx, name); + + ctx->renderpass = QFV_ParseRenderPass (ctx, item, ctx->renderpassDef); + QFV_AddHandle (tab, path, (uint64_t) ctx->renderpass); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS, + ctx->renderpass, va (ctx->va_ctx, "renderpass:%s", + name)); + item = qfv_load_renderpass (ctx, "clearValues"); + QFV_ParseClearValues (ctx, item, ctx->renderpassDef); + + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + static float quad_vertices[] = { + -1, -1, 0, 1, + -1, 1, 0, 1, + 1, -1, 0, 1, + 1, 1, 0, 1, + }; + ctx->quad_buffer = QFV_CreateBuffer (device, sizeof (quad_vertices), + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + ctx->quad_memory = QFV_AllocBufferMemory (device, ctx->quad_buffer, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_BindBufferMemory (device, ctx->quad_buffer, ctx->quad_memory, 0); + + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + float *verts = QFV_PacketExtend (packet, sizeof (quad_vertices)); + memcpy (verts, quad_vertices, sizeof (quad_vertices)); + + VkBufferMemoryBarrier wr_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ctx->quad_buffer, 0, sizeof (quad_vertices) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, wr_barriers, 0, 0); + VkBufferCopy copy_region[] = { + { packet->offset, 0, sizeof (quad_vertices) }, + }; + dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, + ctx->quad_buffer, 1, ©_region[0]); + VkBufferMemoryBarrier rd_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ctx->quad_buffer, 0, sizeof (quad_vertices) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, rd_barriers, 0, 0); + QFV_PacketSubmit (packet); +} + +void +Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyRenderPass (device->dev, ctx->renderpass, 0); + + dfunc->vkFreeMemory (device->dev, ctx->quad_memory, 0); + dfunc->vkDestroyBuffer (device->dev, ctx->quad_buffer, 0); +} + +VkPipeline +Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name) +{ + plitem_t *item = qfv_load_pipeline (ctx, "pipelines"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading pipeline %s\n", name); + return 0; + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Found pipeline def %s\n", name); + } + VkPipeline pipeline = QFV_ParsePipeline (ctx, item, ctx->pipelineDef); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE, pipeline, + va (ctx->va_ctx, "pipeline:%s", name)); + return pipeline; +} + +VkDescriptorPool +Vulkan_CreateDescriptorPool (vulkan_ctx_t *ctx, const char *name) +{ + hashtab_t *tab = ctx->descriptorPools; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".descriptorPools.%s", name); + __auto_type pool = (VkDescriptorPool) QFV_GetHandle (tab, path); + if (pool) { + return pool; + } + + plitem_t *item = qfv_load_pipeline (ctx, "descriptorPools"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading descriptor pool %s\n", name); + return 0; + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Found descriptor pool def %s\n", + name); + } + pool = QFV_ParseDescriptorPool (ctx, item, ctx->pipelineDef); + QFV_AddHandle (tab, path, (uint64_t) pool); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, pool, + va (ctx->va_ctx, "descriptor_pool:%s", name)); + return pool; +} + +VkPipelineLayout +Vulkan_CreatePipelineLayout (vulkan_ctx_t *ctx, const char *name) +{ + hashtab_t *tab = ctx->pipelineLayouts; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".pipelineLayouts.%s", name); + __auto_type layout = (VkPipelineLayout) QFV_GetHandle (tab, path); + if (layout) { + return layout; + } + + plitem_t *item = qfv_load_pipeline (ctx, "pipelineLayouts"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading pipeline layout %s\n", name); + return 0; + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Found pipeline layout def %s\n", + name); + } + layout = QFV_ParsePipelineLayout (ctx, item, ctx->pipelineDef); + QFV_AddHandle (tab, path, (uint64_t) layout); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, layout, + va (ctx->va_ctx, "pipeline_layout:%s", name)); + return layout; +} + +VkSampler +Vulkan_CreateSampler (vulkan_ctx_t *ctx, const char *name) +{ + hashtab_t *tab = ctx->samplers; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".samplers.%s", name); + __auto_type sampler = (VkSampler) QFV_GetHandle (tab, path); + if (sampler) { + return sampler; + } + + plitem_t *item = qfv_load_pipeline (ctx, "samplers"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading sampler %s\n", name); + return 0; + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Found sampler def %s\n", name); + } + sampler = QFV_ParseSampler (ctx, item, ctx->pipelineDef); + QFV_AddHandle (tab, path, (uint64_t) sampler); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_SAMPLER, sampler, + va (ctx->va_ctx, "sampler:%s", name)); + return sampler; +} + +VkDescriptorSetLayout +Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name) +{ + hashtab_t *tab = ctx->setLayouts; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".setLayouts.%s", name); + __auto_type set = (VkDescriptorSetLayout) QFV_GetHandle (tab, path); + if (set) { + return set; + } + + plitem_t *item = qfv_load_pipeline (ctx, "setLayouts"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading descriptor set %s\n", name); + return 0; + } else { + Sys_MaskPrintf (SYS_VULKAN_PARSE, "Found descriptor set def %s\n", + name); + } + set = QFV_ParseDescriptorSetLayout (ctx, item, ctx->pipelineDef); + QFV_AddHandle (tab, path, (uint64_t) set); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, + set, va (ctx->va_ctx, "descriptor_set:%s", name)); + return set; +} + +void +Vulkan_CreateFrames (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + VkCommandPool cmdpool = ctx->cmdpool; + + if (!ctx->frames.grow) { + DARRAY_INIT (&ctx->frames, 4); + } + + DARRAY_RESIZE (&ctx->frames, vulkan_frame_count->int_val); + + __auto_type cmdBuffers = QFV_AllocCommandBufferSet (ctx->frames.size, + alloca); + QFV_AllocateCommandBuffers (device, cmdpool, 0, cmdBuffers); + + for (size_t i = 0; i < ctx->frames.size; i++) { + __auto_type frame = &ctx->frames.a[i]; + frame->framebuffer = 0; + frame->fence = QFV_CreateFence (device, 1); + frame->imageAvailableSemaphore = QFV_CreateSemaphore (device); + frame->renderDoneSemaphore = QFV_CreateSemaphore (device); + frame->cmdBuffer = cmdBuffers->a[i]; + + frame->cmdSetCount = QFV_NumPasses; + frame->cmdSets = malloc (QFV_NumPasses * sizeof (qfv_cmdbufferset_t)); + for (int j = 0; j < QFV_NumPasses; j++) { + DARRAY_INIT (&frame->cmdSets[j], 4); + } + } +} + +void +Vulkan_CreateCapture (vulkan_ctx_t *ctx) +{ + ctx->capture = QFV_CreateCapture (ctx->device, ctx->frames.size, + ctx->swapchain, ctx->cmdpool); +} + +void +Vulkan_DestroyFrames (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *df = device->funcs; + VkDevice dev = device->dev; + + for (size_t i = 0; i < ctx->frames.size; i++) { + __auto_type frame = &ctx->frames.a[i]; + df->vkDestroyFence (dev, frame->fence, 0); + df->vkDestroySemaphore (dev, frame->imageAvailableSemaphore, 0); + df->vkDestroySemaphore (dev, frame->renderDoneSemaphore, 0); + df->vkDestroyFramebuffer (dev, frame->framebuffer, 0); + for (int j = 0; j < frame->cmdSetCount; j++) { + DARRAY_CLEAR (&frame->cmdSets[j]); + } + free (frame->cmdSets); + } + + DARRAY_CLEAR (&ctx->frames); +} + +void +Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + plitem_t *item = qfv_load_renderpass (ctx, "images"); + if (!item) { + return; + } + + __auto_type images = QFV_ParseImageSet (ctx, item, ctx->renderpassDef); + ctx->attachment_images = images; + size_t memSize = 0; + for (size_t i = 0; i < images->size; i++) { + memSize += get_image_size (images->a[i], device); + } + VkDeviceMemory mem; + mem = QFV_AllocImageMemory (device, images->a[0], + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + memSize, 0); + ctx->attachmentMemory = mem; + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + mem, "memory:framebuffers"); + size_t offset = 0; + for (size_t i = 0; i < images->size; i++) { + QFV_BindImageMemory (device, images->a[i], mem, offset); + offset += get_image_size (images->a[i], device); + } + + item = qfv_load_renderpass (ctx, "imageViews"); + if (!item) { + return; + } + + __auto_type views = QFV_ParseImageViewSet (ctx, item, ctx->renderpassDef); + ctx->attachment_views = views; + + item = qfv_load_renderpass (ctx, "framebuffer"); + if (!item) { + return; + } + + ctx->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages, + malloc); + for (size_t i = 0; i < ctx->framebuffers->size; i++) { + ctx->swapImageIndex = i; + ctx->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item, + ctx->renderpassDef); + } +} + +void +Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + for (size_t i = 0; i < ctx->attachment_views->size; i++) { + dfunc->vkDestroyImageView (device->dev, ctx->attachment_views->a[i], 0); + } + for (size_t i = 0; i < ctx->attachment_images->size; i++) { + dfunc->vkDestroyImage (device->dev, ctx->attachment_images->a[i], 0); + } + dfunc->vkFreeMemory (device->dev, ctx->attachmentMemory, 0); +} diff --git a/libs/video/targets/Makefile.am b/libs/video/targets/Makefile.am deleted file mode 100644 index 871df256a..000000000 --- a/libs/video/targets/Makefile.am +++ /dev/null @@ -1,121 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CPPFLAGS= -I$(top_srcdir)/include - -lib_ldflags=-version-info $(QUAKE_LIBRARY_VERSION_INFO) \ - -rpath $(libdir) -no-undefined - -lib_LTLIBRARIES= @JOY_TARGETS@ - -noinst_LTLIBRARIES= @VID_TARGETS@ @vid_libs@ - -EXTRA_LTLIBRARIES= \ - libQFjs.la libQFfbdev.la libQFsvga.la libQFx11.la libQFsdl.la libQFwin.la \ - libvid_common.la libvid_sdl.la \ - libvid_svga.la libvid_win.la libvid_x11.la - -joy_linux_src= joy_linux.c -joy_win_src= joy_win.c -joy_null_src= joy_null.c -if JOYTYPE_LINUX -joy_src= $(joy_linux_src) -else -if JOYTYPE_WIN32 -joy_src= $(joy_win_src) -else -joy_src= $(joy_null_src) -endif -endif - -js_libs=$(top_builddir)/libs/util/libQFutil.la - -libQFjs_la_LDFLAGS= $(lib_ldflags) -libQFjs_la_LIBADD= $(js_libs) -libQFjs_la_DEPENDENCIES=$(js_libs) -libQFjs_la_CFLAGS= @PREFER_PIC@ $(JOY_CFLAGS) -libQFjs_la_SOURCES= joy.c $(joy_src) -EXTRA_libQFjs_la_SOURCES= $(joy_linux_src) $(joy_win_src) $(joy_null_src) - -libvid_common_la_SOURCES= \ - in_common.c in_event.c keys.c old_keys.c pr_keys.c vid.c -libvid_common_la_CFLAGS= @PREFER_NON_PIC@ -libvid_common_la_LDFLAGS= @STATIC@ - -libvid_x11_la_SOURCES= in_x11.c context_x11.c dga_check.c -libvid_x11_la_CFLAGS= @PREFER_NON_PIC@ $(X_CFLAGS) -libvid_x11_la_LDFLAGS= @STATIC@ - -libvid_win_la_SOURCES= in_win.c -libvid_win_la_CFLAGS= @PREFER_NON_PIC@ $(X_CFLAGS) -libvid_win_la_LDFLAGS= @STATIC@ - -libvid_svga_la_SOURCES= in_svgalib.c -libvid_svga_la_CFLAGS= @PREFER_NON_PIC@ $(SVGA_CFLAGS) -libvid_svga_la_LDFLAGS= @STATIC@ - -libvid_sdl_la_SOURCES= in_sdl.c context_sdl.c -libvid_sdl_la_CFLAGS= @PREFER_NON_PIC@ $(SDL_CFLAGS) -libvid_sdl_la_LDFLAGS= @STATIC@ - -# -# Linux FBdev -# -fbdev_c= fbset_modes_y.c fbset_modes_l.c -fbdev_h= fbset_modes_y.h -YFLAGS = -d -YACCLEX_CLEANFILES= $(fbdev_c) $(fbdev_h) -BUILT_SOURCES= $(fbdev_c) $(fbdev_h) - -fbdev_libs=libvid_common.la -libQFfbdev_la_CFLAGS= @PREFER_NON_PIC@ -libQFfbdev_la_SOURCES= fbset.c fbset_modes_y.y fbset_modes_l.l \ - in_fbdev.c vid_fbdev.c -libQFfbdev_la_LDFLAGS= @STATIC@ -libQFfbdev_la_LIBADD= $(fbdev_libs) -libQFfbdev_la_DEPENDENCIES= $(fbdev_libs) - - -# -# Simple DirectMedia Library -# -sdl_libs=libvid_common.la libvid_sdl.la -libQFsdl_la_CFLAGS= @PREFER_NON_PIC@ $(SDL_CFLAGS) -libQFsdl_la_SOURCES= vid_sdl.c -libQFsdl_la_LDFLAGS= @STATIC@ -libQFsdl_la_LIBADD= $(sdl_libs) -libQFsdl_la_DEPENDENCIES= $(sdl_libs) - -# -# SVGAlib -# -svga_libs=libvid_common.la libvid_svga.la -libQFsvga_la_CFLAGS= @PREFER_NON_PIC@ $(SVGA_CFLAGS) -libQFsvga_la_SOURCES= vid_svgalib.c -libQFsvga_la_LDFLAGS= @STATIC@ -libQFsvga_la_LIBADD= $(svga_libs) -libQFsvga_la_DEPENDENCIES= $(svga_libs) - -# -# OpenGL in Win32 -# -win_libs=libvid_common.la libvid_win.la -libQFwin_la_CFLAGS= @PREFER_NON_PIC@ $(WGL_CFLAGS) -libQFwin_la_SOURCES= vid_win.c -libQFwin_la_LDFLAGS= @STATIC@ -libQFwin_la_LIBADD= $(win_libs) -libQFwin_la_DEPENDENCIES= $(win_libs) - -# -# X11 software rendering -# -x11_libs=libvid_common.la libvid_x11.la -libQFx11_la_CFLAGS= @PREFER_NON_PIC@ $(X_CFLAGS) -libQFx11_la_SOURCES= vid_x11.c -libQFx11_la_LDFLAGS= @STATIC@ -libQFx11_la_LIBADD= $(x11_libs) -libQFx11_la_DEPENDENCIES= $(x11_libs) - -# Kill the temp files, hopefully. -CLEANFILES = *.i *.s $(YACCLEX_CLEANFILES) - -EXTRA_DIST= $(fbdev_c) $(fbdev_h) diff --git a/libs/video/targets/Makemodule.am b/libs/video/targets/Makemodule.am new file mode 100644 index 000000000..22425f7c4 --- /dev/null +++ b/libs/video/targets/Makemodule.am @@ -0,0 +1,141 @@ +lib_LTLIBRARIES += @JOY_TARGETS@ + +noinst_LTLIBRARIES += @VID_TARGETS@ @vid_libs@ + +EXTRA_LTLIBRARIES += \ + libs/video/targets/libQFjs.la \ + libs/video/targets/libQFfbdev.la \ + libs/video/targets/libQFsvga.la \ + libs/video/targets/libQFx11.la \ + libs/video/targets/libQFsdl.la \ + libs/video/targets/libQFwgl.la \ + libs/video/targets/libvid_common.la \ + libs/video/targets/libvid_sdl.la \ + libs/video/targets/libvid_svga.la \ + libs/video/targets/libvid_x11.la + +joy_linux_src= libs/video/targets/joy_linux.c +joy_win_src= libs/video/targets/joy_win.c +joy_null_src= libs/video/targets/joy_null.c +if JOYTYPE_LINUX +joy_src= $(joy_linux_src) +else +if JOYTYPE_WIN32 +joy_src= $(joy_win_src) +else +joy_src= $(joy_null_src) +endif +endif + +x11_gl_src = libs/video/targets/vid_x11_gl.c +x11_sw_src = libs/video/targets/vid_x11_sw.c +x11_vulkan_src = libs/video/targets/vid_x11_vulkan.c +if X11_VULKAN +x11_src = $(x11_gl_src) $(x11_sw_src) $(x11_vulkan_src) +else +x11_src = $(x11_gl_src) $(x11_sw_src) +endif + +js_libs = libs/util/libQFutil.la + +libs_video_targets_libQFjs_la_LDFLAGS= $(lib_ldflags) +libs_video_targets_libQFjs_la_LIBADD= $(js_libs) +libs_video_targets_libQFjs_la_DEPENDENCIES=$(js_libs) +libs_video_targets_libQFjs_la_CFLAGS= @PREFER_PIC@ $(JOY_CFLAGS) +libs_video_targets_libQFjs_la_SOURCES= libs/video/targets/joy.c $(joy_src) +EXTRA_libs_video_targets_libQFjs_la_SOURCES= $(joy_linux_src) $(joy_win_src) $(joy_null_src) + +libs_video_targets_libvid_common_la_SOURCES = \ + libs/video/targets/in_common.c \ + libs/video/targets/in_event.c \ + libs/video/targets/keys.c \ + libs/video/targets/old_keys.c \ + libs/video/targets/pr_keys.c \ + libs/video/targets/vid.c +libs_video_targets_libvid_common_la_CFLAGS= @PREFER_NON_PIC@ +libs_video_targets_libvid_common_la_LDFLAGS= @STATIC@ + +libs_video_targets_libvid_x11_la_SOURCES = \ + libs/video/targets/in_x11.c \ + libs/video/targets/context_x11.c \ + libs/video/targets/dga_check.c \ + $(x11_src) +libs_video_targets_libvid_x11_la_CFLAGS= @PREFER_NON_PIC@ $(X_CFLAGS) +libs_video_targets_libvid_x11_la_LDFLAGS= @STATIC@ +EXTRA_libs_video_targets_libvid_x11_la_SOURCES= $(x11_vulkan_src) + +libs_video_targets_libvid_svga_la_SOURCES= libs/video/targets/in_svgalib.c +libs_video_targets_libvid_svga_la_CFLAGS= @PREFER_NON_PIC@ $(SVGA_CFLAGS) +libs_video_targets_libvid_svga_la_LDFLAGS= @STATIC@ + +libs_video_targets_libvid_sdl_la_SOURCES = \ + libs/video/targets/in_sdl.c \ + libs/video/targets/context_sdl.c \ + libs/video/targets/vid_sdl_gl.c \ + libs/video/targets/vid_sdl_sw.c +libs_video_targets_libvid_sdl_la_CFLAGS= @PREFER_NON_PIC@ $(SDL_CFLAGS) +libs_video_targets_libvid_sdl_la_LDFLAGS= @STATIC@ + +# +# Linux FBdev +# +fbdev_c= libs/video/targets/fbset_modes_y.c libs/video/targets/fbset_modes_l.c +fbdev_h= libs/video/targets/fbset_modes_y.h +BUILT_SOURCES += $(fbdev_c) $(fbdev_h) + +fbdev_libs=libs/video/targets/libvid_common.la +libs_video_targets_libQFfbdev_la_CFLAGS= @PREFER_NON_PIC@ +libs_video_targets_libQFfbdev_la_SOURCES = \ + libs/video/targets/fbset.c \ + libs/video/targets/fbset_modes_y.y \ + libs/video/targets/fbset_modes_l.l \ + libs/video/targets/in_fbdev.c \ + libs/video/targets/vid_fbdev.c +libs_video_targets_libQFfbdev_la_LDFLAGS= @STATIC@ +libs_video_targets_libQFfbdev_la_LIBADD= $(fbdev_libs) +libs_video_targets_libQFfbdev_la_DEPENDENCIES= $(fbdev_libs) + + +# +# Simple DirectMedia Library +# +sdl_libs=libs/video/targets/libvid_common.la libs/video/targets/libvid_sdl.la +libs_video_targets_libQFsdl_la_CFLAGS= @PREFER_NON_PIC@ $(SDL_CFLAGS) +libs_video_targets_libQFsdl_la_SOURCES= libs/video/targets/vid_sdl.c +libs_video_targets_libQFsdl_la_LDFLAGS= @STATIC@ +libs_video_targets_libQFsdl_la_LIBADD= $(sdl_libs) +libs_video_targets_libQFsdl_la_DEPENDENCIES= $(sdl_libs) + +# +# SVGAlib +# +svga_libs=libs/video/targets/libvid_common.la libs/video/targets/libvid_svga.la +libs_video_targets_libQFsvga_la_CFLAGS= @PREFER_NON_PIC@ $(SVGA_CFLAGS) +libs_video_targets_libQFsvga_la_SOURCES= libs/video/targets/vid_svgalib.c +libs_video_targets_libQFsvga_la_LDFLAGS= @STATIC@ +libs_video_targets_libQFsvga_la_LIBADD= $(svga_libs) +libs_video_targets_libQFsvga_la_DEPENDENCIES= $(svga_libs) + +# +# OpenGL in Win32 +# +wgl_libs=libs/video/targets/libvid_common.la libs/video/targets/libvid_gl.la +libs_video_targets_libQFwgl_la_CFLAGS= @PREFER_NON_PIC@ $(WGL_CFLAGS) +libs_video_targets_libQFwgl_la_SOURCES = \ + libs/video/targets/in_win.c \ + libs/video/targets/vid_wgl.c +libs_video_targets_libQFwgl_la_LDFLAGS= @STATIC@ +libs_video_targets_libQFwgl_la_LIBADD= $(wgl_libs) +libs_video_targets_libQFwgl_la_DEPENDENCIES= $(wgl_libs) + +# +# X11 software rendering +# +x11_libs=libs/video/targets/libvid_common.la libs/video/targets/libvid_x11.la +libs_video_targets_libQFx11_la_CFLAGS= @PREFER_NON_PIC@ $(X_CFLAGS) +libs_video_targets_libQFx11_la_SOURCES= libs/video/targets/vid_x11.c +libs_video_targets_libQFx11_la_LDFLAGS= @STATIC@ +libs_video_targets_libQFx11_la_LIBADD= $(x11_libs) +libs_video_targets_libQFx11_la_DEPENDENCIES= $(x11_libs) + +EXTRA_DIST += $(fbdev_c) $(fbdev_h) diff --git a/libs/video/targets/context_sdl.c b/libs/video/targets/context_sdl.c index 105d7e1f6..21fde4b06 100644 --- a/libs/video/targets/context_sdl.c +++ b/libs/video/targets/context_sdl.c @@ -23,9 +23,6 @@ cvar_t *vid_bitdepth; -extern SDL_Surface *screen; - - void VID_SDL_GammaCheck (void) { @@ -43,10 +40,10 @@ VID_SetCaption (const char *text) if (text && *text) { char *temp = strdup (text); - SDL_WM_SetCaption (va ("%s: %s", PACKAGE_STRING, temp), NULL); + SDL_WM_SetCaption (va (0, "%s: %s", PACKAGE_STRING, temp), NULL); free (temp); } else { - SDL_WM_SetCaption (va ("%s", PACKAGE_STRING), NULL); + SDL_WM_SetCaption (va (0, "%s", PACKAGE_STRING), NULL); } } @@ -56,20 +53,14 @@ VID_SetGamma (double gamma) return SDL_SetGamma((float) gamma, (float) gamma, (float) gamma); } -void -VID_Shutdown (void) -{ - SDL_Quit (); -} - static void VID_UpdateFullscreen (cvar_t *vid_fullscreen) { if (!r_data || !viddef.initialized) return; - if ((vid_fullscreen->int_val && !(screen->flags & SDL_FULLSCREEN)) - || (!vid_fullscreen->int_val && screen->flags & SDL_FULLSCREEN)) - if (!SDL_WM_ToggleFullScreen (screen)) + if ((vid_fullscreen->int_val && !(sdl_screen->flags & SDL_FULLSCREEN)) + || (!vid_fullscreen->int_val && sdl_screen->flags & SDL_FULLSCREEN)) + if (!SDL_WM_ToggleFullScreen (sdl_screen)) Sys_Printf ("VID_UpdateFullscreen: error setting fullscreen\n"); IN_UpdateGrab (in_grab); } diff --git a/libs/video/targets/context_x11.c b/libs/video/targets/context_x11.c index 6ad810481..d2028989e 100644 --- a/libs/video/targets/context_x11.c +++ b/libs/video/targets/context_x11.c @@ -125,6 +125,8 @@ static int accel_threshold; static Atom x_net_state; static Atom x_net_fullscreen; +static cvar_t *x11_vidmode; + static void set_fullscreen (int full) { @@ -309,9 +311,9 @@ void X11_CreateNullCursor (void) { Pixmap cursormask; - XGCValues xgc; + XGCValues xgc = { }; GC gc; - XColor dummycolour; + XColor dummycolour = { }; if (nullcursor != None) return; @@ -353,7 +355,14 @@ X11_SetMouse (void) XWarpPointer (x_disp, None, x_win, 0, 0, 0, 0, 0, 0); XWarpPointer (x_disp, None, x_win, 0, 0, 0, 0, viddef.width / 2, viddef.height / 2); - XPeekIfEvent (x_disp, &ev, check_mouse_event, 0); + //FIXME this should be done in a state machine that handles events without + //blocking + double start = Sys_DoubleTime (); + while (!XCheckIfEvent (x_disp, &ev, check_mouse_event, 0)) { + if (Sys_DoubleTime () - start > 2) { + break; + } + } x_mouse_time = ev.xmotion.time; } @@ -388,6 +397,10 @@ X11_SetVidMode (int width, int height) if (vidmode_active) return; + if (!x11_vidmode->int_val) { + return; + } + if (str && (tolower (*str) == 'f')) { Cvar_Set (vid_fullscreen, "1"); } @@ -407,7 +420,7 @@ X11_SetVidMode (int width, int height) vid_gamma_avail = true; temp = X11_GetGamma (); - if (temp && temp[0] > 0) { + if (temp && (*temp)[0] > 0) { x_gamma[0] = (*temp)[0]; x_gamma[1] = (*temp)[1]; x_gamma[2] = (*temp)[2]; @@ -427,19 +440,23 @@ X11_SetVidMode (int width, int height) &vidmodes); XF86VidModeGetModeLine (x_disp, x_screen, &dotclock, &orig_data); - if (developer->int_val & SYS_VID) { - Sys_Printf ("VID: %d modes\n", nummodes); - for (i = 0; i < nummodes; i++) { - Sys_Printf ("VID: %xx%d\n", vidmodes[i]->hdisplay, - vidmodes[i]->vdisplay); - } - } - + Sys_MaskPrintf (SYS_VID, "VID: %d modes\n", nummodes); + original_mode = -1; for (i = 0; i < nummodes; i++) { - if ((vidmodes[i]->hdisplay == orig_data.hdisplay) && - (vidmodes[i]->vdisplay == orig_data.vdisplay)) { + if (original_mode == -1 + && (vidmodes[i]->hdisplay == orig_data.hdisplay) && + (vidmodes[i]->vdisplay == orig_data.vdisplay)) { original_mode = i; - break; + } + if (developer->int_val & SYS_VID) { + Sys_Printf ("VID:%c%dx%d\n", + original_mode == i ? '*' : ' ', + vidmodes[i]->hdisplay, vidmodes[i]->vdisplay); + Sys_Printf ("\t%d %d %d %d:%d %d %d:%d\n", + vidmodes[i]->hsyncstart, vidmodes[i]->hsyncend, + vidmodes[i]->htotal, vidmodes[i]->hskew, + vidmodes[i]->vsyncstart, vidmodes[i]->vsyncend, + vidmodes[i]->vtotal, vidmodes[i]->flags); } } @@ -456,8 +473,10 @@ X11_SetVidMode (int width, int height) Sys_MaskPrintf (SYS_VID, "VID: Chose video mode: %dx%d\n", viddef.width, viddef.height); + if (0) { XF86VidModeSwitchToMode (x_disp, x_screen, vidmodes[best_mode]); + } vidmode_active = true; X11_SetScreenSaver (); } else { @@ -507,6 +526,9 @@ X11_Init_Cvars (void) "Toggles fullscreen game mode"); vid_system_gamma = Cvar_Get ("vid_system_gamma", "1", CVAR_ARCHIVE, NULL, "Use system gamma control if available"); + x11_vidmode = Cvar_Get ("x11_vidmode", "0", CVAR_ROM, 0, + "Use x11 vidmode extension to set video mode " + "(not recommended for modern systems)"); } void @@ -545,7 +567,7 @@ X11_CreateWindow (int width, int height) XFree (SizeHints); } // Set window title - X11_SetCaption (va ("%s", PACKAGE_STRING)); + X11_SetCaption (va (0, "%s", PACKAGE_STRING)); // Set icon name XSetIconName (x_disp, x_win, PACKAGE_NAME); @@ -566,10 +588,11 @@ X11_CreateWindow (int width, int height) X11_WaitForEvent (ConfigureNotify); vid_context_created = true; + XRaiseWindow (x_disp, x_win); + X11_WaitForEvent (VisibilityNotify); if (vid_fullscreen->int_val) { X11_UpdateFullscreen (vid_fullscreen); } - XRaiseWindow (x_disp, x_win); } void @@ -578,7 +601,7 @@ X11_RestoreVidMode (void) #ifdef HAVE_VIDMODE if (vidmode_active) { X11_RestoreScreenSaver (); - XF86VidModeSwitchToMode (x_disp, x_screen, vidmodes[original_mode]); + //XF86VidModeSwitchToMode (x_disp, x_screen, vidmodes[original_mode]); XFree (vidmodes); vidmode_active = false; } diff --git a/libs/video/targets/in_common.c b/libs/video/targets/in_common.c index d5bdf8bda..214666e8d 100644 --- a/libs/video/targets/in_common.c +++ b/libs/video/targets/in_common.c @@ -128,8 +128,8 @@ IN_Move (void) } /* Called at shutdown */ -void -IN_Shutdown (void) +static void +IN_shutdown (void *data) { JOY_Shutdown (); @@ -142,6 +142,8 @@ IN_Shutdown (void) void IN_Init (cbuf_t *cbuf) { + Sys_RegisterShutdown (IN_shutdown, 0); + IE_Init (); IN_LL_Init (); Key_Init (cbuf); diff --git a/libs/video/targets/in_x11.c b/libs/video/targets/in_x11.c index afc206eba..83df6ebc7 100644 --- a/libs/video/targets/in_x11.c +++ b/libs/video/targets/in_x11.c @@ -599,11 +599,11 @@ XLateKey (XKeyEvent * ev, int *k, int *u) static void x11_keydest_callback (keydest_t key_dest) { - if (key_dest == key_game) { - XAutoRepeatOff (x_disp); - } else { - XAutoRepeatOn (x_disp); - } +// if (key_dest == key_game) { +// XAutoRepeatOff (x_disp); +// } else { +// XAutoRepeatOn (x_disp); +// } } static void @@ -672,7 +672,7 @@ event_focusin (XEvent *event) static void center_pointer (void) { - XEvent event; + XEvent event = {}; event.type = MotionNotify; event.xmotion.display = x_disp; @@ -792,7 +792,7 @@ IN_LL_Shutdown (void) Sys_MaskPrintf (SYS_VID, "IN_LL_Shutdown\n"); in_mouse_avail = 0; if (x_disp) { - XAutoRepeatOn (x_disp); +// XAutoRepeatOn (x_disp); dga_off (); } if (in_mouse_accel && !in_mouse_accel->int_val) diff --git a/libs/video/targets/joy.c b/libs/video/targets/joy.c index 0a209cdfe..da25db1f4 100644 --- a/libs/video/targets/joy.c +++ b/libs/video/targets/joy.c @@ -183,7 +183,7 @@ JOY_Init (void) static void joyamp_f (cvar_t *var) { - Cvar_Set (var, va ("%g", max (0.0001, var->value))); + Cvar_Set (var, va (0, "%g", max (0.0001, var->value))); } typedef struct { diff --git a/libs/video/targets/keys.c b/libs/video/targets/keys.c index ecf3aa4ce..92ee71fc0 100644 --- a/libs/video/targets/keys.c +++ b/libs/video/targets/keys.c @@ -312,6 +312,39 @@ keyname_t keynames[] = { { "K_F13", QFK_F13 }, { "K_F14", QFK_F14 }, { "K_F15", QFK_F15 }, + { "K_F16", QFK_F16 }, + { "K_F17", QFK_F17 }, + { "K_F18", QFK_F18 }, + { "K_F19", QFK_F19 }, + { "K_F20", QFK_F20 }, + { "K_F21", QFK_F21 }, + { "K_F22", QFK_F22 }, + { "K_F23", QFK_F23 }, + { "K_F24", QFK_F24 }, + { "K_F25", QFK_F25 }, + { "K_F26", QFK_F26 }, + { "K_F27", QFK_F27 }, + { "K_F28", QFK_F28 }, + { "K_F29", QFK_F29 }, + { "K_F30", QFK_F30 }, + { "K_F31", QFK_F31 }, + { "K_F32", QFK_F32 }, + { "K_F33", QFK_F33 }, + { "K_F34", QFK_F34 }, + { "K_F35", QFK_F35 }, + { "K_F36", QFK_F36 }, + { "K_F37", QFK_F37 }, + { "K_F38", QFK_F38 }, + { "K_F39", QFK_F39 }, + { "K_F40", QFK_F40 }, + { "K_F41", QFK_F41 }, + { "K_F42", QFK_F42 }, + { "K_F43", QFK_F43 }, + { "K_F44", QFK_F44 }, + { "K_F45", QFK_F45 }, + { "K_F46", QFK_F46 }, + { "K_F47", QFK_F47 }, + { "K_F48", QFK_F48 }, { "K_NUMLOCK", QFK_NUMLOCK }, { "K_CAPSLOCK", QFK_CAPSLOCK }, { "K_SCROLLOCK", QFK_SCROLLOCK }, @@ -511,7 +544,7 @@ keyname_t keynames[] = { {NULL, 0} }; -static imt_t * +static __attribute__((pure)) imt_t * key_target_find_imt (keytarget_t *kt, const char *imt_name) { imt_t *imt; @@ -809,6 +842,11 @@ Key_IMT_Drop_All_f (void) while (key_targets[kd].imts) { imt = key_targets[kd].imts; key_targets[kd].imts = imt->next; + for (int i = 0; i < QFK_LAST; i++) { + if (imt->bindings[i].str) { + free (imt->bindings[i].str); + } + } free ((char *) imt->name); free (imt); } @@ -850,7 +888,7 @@ Key_In_Bind_f (void) { int c, i; const char *imt, *key, *cmd = 0; - char cmd_buf[1024]; + dstring_t *cmd_buf = 0; c = Cmd_Argc (); @@ -865,17 +903,17 @@ Key_In_Bind_f (void) key = Cmd_Argv (2); if (c >= 4) { - cmd = cmd_buf; - cmd_buf[0] = 0; + cmd_buf = dstring_newstr (); for (i = 3; i < c; i++) { - strncat (cmd_buf, Cmd_Argv (i), sizeof (cmd_buf) - - strlen (cmd_buf)); - if (i != (c - 1)) - strncat (cmd_buf, " ", sizeof (cmd_buf) - strlen (cmd_buf)); + dasprintf (cmd_buf, "%s%s", i > 3 ? " " : "", Cmd_Argv (i)); } + cmd = cmd_buf->str; } Key_In_Bind (imt, key, cmd); + if (cmd_buf) { + dstring_delete (cmd_buf); + } } static void @@ -896,7 +934,7 @@ Key_Bind_f (void) { int c, i; const char *key, *cmd = 0; - char cmd_buf[1024]; + dstring_t *cmd_buf = 0; c = Cmd_Argc (); @@ -908,17 +946,17 @@ Key_Bind_f (void) key = OK_TranslateKeyName (Cmd_Argv (1)); if (c >= 3) { - cmd = cmd_buf; - cmd_buf[0] = 0; + cmd_buf = dstring_newstr (); for (i = 2; i < c; i++) { - strncat (cmd_buf, Cmd_Argv (i), sizeof (cmd_buf) - - strlen (cmd_buf)); - if (i != (c - 1)) - strncat (cmd_buf, " ", sizeof (cmd_buf) - strlen (cmd_buf)); + dasprintf (cmd_buf, "%s%s", i > 2 ? " " : "", Cmd_Argv (i)); } + cmd = cmd_buf->str; } Key_In_Bind ("imt_mod", key, cmd); + if (cmd_buf) { + dstring_delete (cmd_buf); + } } static void diff --git a/libs/video/targets/old_keys.c b/libs/video/targets/old_keys.c index 99b87f4c4..e96cc02ff 100644 --- a/libs/video/targets/old_keys.c +++ b/libs/video/targets/old_keys.c @@ -233,7 +233,7 @@ OK_Init (void) { old_keyname_t *ok; - old_key_table = Hash_NewTable (1021, ok_get_key, 0, 0); + old_key_table = Hash_NewTable (1021, ok_get_key, 0, 0, 0); for (ok = old_keynames; ok->old_name; ok++) Hash_Add (old_key_table, ok); } diff --git a/libs/video/targets/vid.c b/libs/video/targets/vid.c index 328e1980d..3f7ba750e 100644 --- a/libs/video/targets/vid.c +++ b/libs/video/targets/vid.c @@ -90,9 +90,9 @@ VID_GetWindowSize (int def_w, int def_h) { int pnum, conheight; - vid_width = Cvar_Get ("vid_width", va ("%d", def_w), CVAR_NONE, NULL, + vid_width = Cvar_Get ("vid_width", va (0, "%d", def_w), CVAR_NONE, NULL, "screen width"); - vid_height = Cvar_Get ("vid_height", va ("%d", def_h), CVAR_NONE, NULL, + vid_height = Cvar_Get ("vid_height", va (0, "%d", def_h), CVAR_NONE, NULL, "screen height"); vid_aspect = Cvar_Get ("vid_aspect", "4:3", CVAR_ROM, vid_aspect_f, "Physical screen aspect ratio in \"width:height\" format. " @@ -143,7 +143,7 @@ VID_GetWindowSize (int def_w, int def_h) viddef.aspect = ((vid_aspect->vec[0] * viddef.height) / (vid_aspect->vec[1] * viddef.width)); - con_width = Cvar_Get ("con_width", va ("%d", viddef.width), CVAR_NONE, + con_width = Cvar_Get ("con_width", va (0, "%d", viddef.width), CVAR_NONE, NULL, "console effective width (GL only)"); if ((pnum = COM_CheckParm ("-conwidth"))) { if (pnum >= com_argc - 1) @@ -151,20 +151,20 @@ VID_GetWindowSize (int def_w, int def_h) Cvar_Set (con_width, com_argv[pnum + 1]); } // make con_width a multiple of 8 and >= 320 - Cvar_Set (con_width, va ("%d", max (con_width->int_val & ~7, 320))); + Cvar_Set (con_width, va (0, "%d", max (con_width->int_val & ~7, 320))); Cvar_SetFlags (con_width, con_width->flags | CVAR_ROM); viddef.conwidth = con_width->int_val; conheight = (viddef.conwidth * vid_aspect->vec[1]) / vid_aspect->vec[0]; - con_height = Cvar_Get ("con_height", va ("%d", conheight), CVAR_NONE, NULL, - "console effective height (GL only)"); + con_height = Cvar_Get ("con_height", va (0, "%d", conheight), CVAR_NONE, + NULL, "console effective height (GL only)"); if ((pnum = COM_CheckParm ("-conheight"))) { if (pnum >= com_argc - 1) Sys_Error ("VID: -conheight "); Cvar_Set (con_height, com_argv[pnum + 1]); } // make con_height >= 200 - Cvar_Set (con_height, va ("%d", max (con_height->int_val, 200))); + Cvar_Set (con_height, va (0, "%d", max (con_height->int_val, 200))); Cvar_SetFlags (con_height, con_height->flags | CVAR_ROM); viddef.conheight = con_height->int_val; @@ -203,6 +203,10 @@ void VID_UpdateGamma (cvar_t *vid_gamma) { double gamma = bound (0.1, vid_gamma->value, 9.9); + byte *p24; + byte *p32; + const byte *col; + int i; viddef.recalc_refdef = 1; // force a surface cache flush @@ -210,14 +214,30 @@ VID_UpdateGamma (cvar_t *vid_gamma) Sys_MaskPrintf (SYS_VID, "Setting hardware gamma to %g\n", gamma); VID_BuildGammaTable (1.0); // hardware gamma wants a linear palette VID_SetGamma (gamma); - memcpy (viddef.palette, viddef.basepal, 256 * 3); + p24 = viddef.palette; + p32 = viddef.palette32; + col = viddef.basepal; + for (i = 0; i < 256; i++) { + *p32++ = *p24++ = *col++; + *p32++ = *p24++ = *col++; + *p32++ = *p24++ = *col++; + *p32++ = 255; + } + p32[-1] = 0; // color 255 is transparent } else { // We have to hack the palette - int i; Sys_MaskPrintf (SYS_VID, "Setting software gamma to %g\n", gamma); VID_BuildGammaTable (gamma); - for (i = 0; i < 256 * 3; i++) - viddef.palette[i] = viddef.gammatable[viddef.basepal[i]]; - viddef.set_palette (viddef.palette); // update with the new palette + p24 = viddef.palette; + p32 = viddef.palette32; + col = viddef.basepal; + for (i = 0; i < 256; i++) { + *p32++ = *p24++ = viddef.gammatable[*col++]; + *p32++ = *p24++ = viddef.gammatable[*col++]; + *p32++ = *p24++ = viddef.gammatable[*col++]; + *p32++ = 255; + } + p32[-1] = 0; // color 255 is transparent + viddef.vid_internal->set_palette (viddef.palette); // update with the new palette } } @@ -235,12 +255,13 @@ VID_InitGamma (const byte *pal) viddef.gammatable = malloc (256); viddef.basepal = pal; viddef.palette = malloc (256 * 3); + viddef.palette32 = malloc (256 * 4); if ((i = COM_CheckParm ("-gamma"))) { gamma = atof (com_argv[i + 1]); } gamma = bound (0.1, gamma, 9.9); - vid_gamma = Cvar_Get ("vid_gamma", va ("%f", gamma), CVAR_ARCHIVE, + vid_gamma = Cvar_Get ("vid_gamma", va (0, "%f", gamma), CVAR_ARCHIVE, VID_UpdateGamma, "Gamma correction"); VID_BuildGammaTable (vid_gamma->value); @@ -259,8 +280,9 @@ VID_InitBuffers (void) // Calculate the sizes we want first buffersize = viddef.rowbytes * viddef.height; zbuffersize = viddef.width * viddef.height * sizeof (*viddef.zbuffer); - if (viddef.surf_cache_size) - cachesize = viddef.surf_cache_size (viddef.width, viddef.height); + if (viddef.vid_internal->surf_cache_size) + cachesize = viddef.vid_internal->surf_cache_size (viddef.width, + viddef.height); // Free the old z-buffer if (viddef.zbuffer) { @@ -269,13 +291,13 @@ VID_InitBuffers (void) } // Free the old surface cache if (viddef.surfcache) { - if (viddef.flush_caches) - viddef.flush_caches (); + if (viddef.vid_internal->flush_caches) + viddef.vid_internal->flush_caches (); free (viddef.surfcache); viddef.surfcache = NULL; } - if (viddef.do_screen_buffer) { - viddef.do_screen_buffer (); + if (viddef.vid_internal->do_screen_buffer) { + viddef.vid_internal->do_screen_buffer (); } else { // Free the old screen buffer if (viddef.buffer) { @@ -305,6 +327,13 @@ VID_InitBuffers (void) Sys_Error ("Not enough memory for video mode"); } - if (viddef.init_caches) - viddef.init_caches (viddef.surfcache, cachesize); + if (viddef.vid_internal->init_caches) + viddef.vid_internal->init_caches (viddef.surfcache, cachesize); +} + +void +VID_ClearMemory (void) +{ + if (viddef.vid_internal->flush_caches) + viddef.vid_internal->flush_caches (); } diff --git a/libs/video/targets/vid_3dfxsvga.c b/libs/video/targets/vid_3dfxsvga.c index e7df1f342..68078703f 100644 --- a/libs/video/targets/vid_3dfxsvga.c +++ b/libs/video/targets/vid_3dfxsvga.c @@ -150,8 +150,8 @@ QFGL_LoadLibrary (void) #endif // HAVE_DLOPEN -void -VID_Shutdown (void) +static void +VID_shutdown (void) { if (!fc) return; @@ -271,6 +271,8 @@ VID_Init (byte *palette, byte *colormap) { GLint attribs[32]; + Sys_RegisterShutdown (VID_shutdown); + GLF_Init (); qf_fxMesaCreateContext = QFGL_ProcAddress (libgl_handle, diff --git a/libs/video/targets/vid_fbdev.c b/libs/video/targets/vid_fbdev.c index 36e27b0a2..a0d5702da 100644 --- a/libs/video/targets/vid_fbdev.c +++ b/libs/video/targets/vid_fbdev.c @@ -209,8 +209,8 @@ static unsigned long fb_map_length = 0; static struct fb_var_screeninfo orig_var; -void -VID_Shutdown (void) +static void +VID_shutdown (void) { Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n"); @@ -406,6 +406,8 @@ VID_Init (byte *palette, byte *colormap) if (fbdev_inited) return; + Sys_RegisterShutdown (VID_shutdown); + R_LoadModule (0, VID_SetPalette); if (COM_CheckParm ("-novideo")) { diff --git a/libs/video/targets/vid_sdl.c b/libs/video/targets/vid_sdl.c index 1a367658f..738abbb4b 100644 --- a/libs/video/targets/vid_sdl.c +++ b/libs/video/targets/vid_sdl.c @@ -54,190 +54,30 @@ HWND mainwindow; #endif -byte *VGA_pagebase; -int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes = 0; +SDL_Surface *sdl_screen = NULL; -SDL_Surface *screen = NULL; +static vid_internal_t vid_internal; -// Define GLAPIENTRY to a useful value -#ifndef GLAPIENTRY -# ifdef _WIN32 -# include -# define GLAPIENTRY WINAPI -# undef LoadImage -# else -# ifdef APIENTRY -# define GLAPIENTRY APIENTRY -# else -# define GLAPIENTRY -# endif -# endif -#endif - -static void (*set_vid_mode) (Uint32 flags); - -static void (GLAPIENTRY *qfglFinish) (void); -static int use_gl_procaddress = 0; -static cvar_t *gl_driver; - -static byte cached_palette[256 * 3]; -static int update_palette; - -static void * -QFGL_ProcAddress (const char *name, qboolean crit) -{ - void *glfunc = NULL; - - Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); - - glfunc = SDL_GL_GetProcAddress (name); - if (glfunc) { - Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); - return glfunc; - } - Sys_MaskPrintf (SYS_VID, "not found\n"); - - if (crit) { - if (strncmp ("fxMesa", name, 6) == 0) { - Sys_Printf ("This target requires a special version of Mesa with " - "support for Glide and SVGAlib.\n"); - Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); - } - Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", - name); - } - return NULL; -} +uint32_t sdl_flags; static void -sdlgl_set_vid_mode (Uint32 flags) +VID_shutdown (void *data) { - int i, j; - - flags |= SDL_OPENGL; - - // Setup GL Attributes - SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); -// SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 0); // Try for 0, 8 -// SDL_GL_SetAttribute (SDL_GL_STEREO, 1); // Someday... - - for (i = 0; i < 5; i++) { - int k; - int color[5] = {32, 24, 16, 15, 0}; - int rgba[5][4] = { - {8, 8, 8, 0}, - {8, 8, 8, 8}, - {5, 6, 5, 0}, - {5, 5, 5, 0}, - {5, 5, 5, 1}, - }; - - SDL_GL_SetAttribute (SDL_GL_RED_SIZE, rgba[i][0]); - SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgba[i][1]); - SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, rgba[i][2]); - SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, rgba[i][3]); - - for (j = 0; j < 5; j++) { - for (k = 32; k >= 16; k -= 8) { - SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, k); - if ((screen = SDL_SetVideoMode (viddef.width, viddef.height, - color[j], flags))) - goto success; - } - } - } - - Sys_Error ("Couldn't set video mode: %s", SDL_GetError ()); SDL_Quit (); - -success: - viddef.numpages = 2; - - viddef.init_gl (); -} - -static void -sdlgl_end_rendering (void) -{ - qfglFinish (); - SDL_GL_SwapBuffers (); -} - -static void -sdl_load_gl (void) -{ - viddef.get_proc_address = QFGL_ProcAddress; - viddef.end_rendering = sdlgl_end_rendering; - set_vid_mode = sdlgl_set_vid_mode; - - if (SDL_GL_LoadLibrary (gl_driver->string) != 0) - Sys_Error ("Couldn't load OpenGL library %s!", gl_driver->string); - - use_gl_procaddress = 1; - - qfglFinish = QFGL_ProcAddress ("glFinish", true); -} - -static void -sdl_update_palette (const byte *palette) -{ - SDL_Color colors[256]; - int i; - - for (i = 0; i < 256; ++i) { - colors[i].r = *palette++; - colors[i].g = *palette++; - colors[i].b = *palette++; - } - SDL_SetColors (screen, colors, 0, 256); -} - -static void -VID_SetPalette (const byte *palette) -{ - if (memcmp (cached_palette, palette, sizeof (cached_palette))) { - memcpy (cached_palette, palette, sizeof (cached_palette)); - update_palette = 1; - } -} - -static void -do_screen_buffer (void) -{ -} - -static void -sdl_set_vid_mode (Uint32 flags) -{ - // Initialize display - if (!(screen = SDL_SetVideoMode (viddef.width, viddef.height, 8, flags))) - Sys_Error ("VID: Couldn't set video mode: %s", SDL_GetError ()); - - // now know everything we need to know about the buffer - VGA_width = viddef.width; - VGA_height = viddef.height; - viddef.do_screen_buffer = do_screen_buffer; - VGA_pagebase = viddef.buffer = screen->pixels; - VGA_rowbytes = viddef.rowbytes = screen->pitch; - viddef.conbuffer = viddef.buffer; - viddef.conrowbytes = viddef.rowbytes; - viddef.direct = 0; - - VID_InitBuffers (); // allocate z buffer and surface cache } void VID_Init (byte *palette, byte *colormap) { - Uint32 flags; - - set_vid_mode = sdl_set_vid_mode; + Sys_RegisterShutdown (VID_shutdown, 0); + vid_internal.gl_context = SDL_GL_Context; + vid_internal.sw_context = SDL_SW_Context; // Load the SDL library if (SDL_Init (SDL_INIT_VIDEO) < 0) Sys_Error ("VID: Couldn't load SDL: %s", SDL_GetError ()); - R_LoadModule (sdl_load_gl, VID_SetPalette); + R_LoadModule (&vid_internal); viddef.numpages = 1; viddef.colormap8 = colormap; @@ -247,9 +87,9 @@ VID_Init (byte *palette, byte *colormap) VID_GetWindowSize (640, 480); // Set video width, height and flags - flags = (SDL_SWSURFACE | SDL_HWPALETTE); + sdl_flags = (SDL_SWSURFACE | SDL_HWPALETTE); if (vid_fullscreen->int_val) { - flags |= SDL_FULLSCREEN; + sdl_flags |= SDL_FULLSCREEN; #ifndef _WIN32 // Don't annoy Mesa/3dfx folks // doesn't hurt if not using a gl renderer // FIXME: Maybe this could be put in a different spot, but I don't @@ -261,11 +101,10 @@ VID_Init (byte *palette, byte *colormap) #endif } - set_vid_mode (flags); + vid_internal.create_context (); VID_SDL_GammaCheck (); VID_InitGamma (palette); - viddef.set_palette (viddef.palette); viddef.initialized = true; @@ -287,46 +126,8 @@ void VID_Init_Cvars () { SDL_Init_Cvars (); - gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, - "The OpenGL library to use. (path optional)"); -} - -void -VID_Update (vrect_t *rects) -{ - static SDL_Rect *sdlrects; - static int num_sdlrects; - int i, n; - vrect_t *rect; - - if (update_palette) { - update_palette = 0; - sdl_update_palette (cached_palette); - } - // Two-pass system, since Quake doesn't do it the SDL way... - - // First, count the number of rectangles - n = 0; - for (rect = rects; rect; rect = rect->next) - ++n; - - if (n > num_sdlrects) { - num_sdlrects = n; - sdlrects = realloc (sdlrects, n * sizeof (SDL_Rect)); - if (!sdlrects) - Sys_Error ("Out of memory!"); - } - - // Second, copy them to SDL rectangles and update - i = 0; - for (rect = rects; rect; rect = rect->next) { - sdlrects[i].x = rect->x; - sdlrects[i].y = rect->y; - sdlrects[i].w = rect->width; - sdlrects[i].h = rect->height; - ++i; - } - SDL_UpdateRects (screen, n, sdlrects); + SDL_GL_Init_Cvars (); + SDL_SW_Init_Cvars (); } void @@ -334,14 +135,14 @@ D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) { Uint8 *offset; - if (!screen) + if (!sdl_screen) return; if (x < 0) - x = screen->w + x - 1; - offset = (Uint8 *) screen->pixels + y * screen->pitch + x; + x = sdl_screen->w + x - 1; + offset = (Uint8 *) sdl_screen->pixels + y * sdl_screen->pitch + x; while (height--) { memcpy (offset, pbitmap, width); - offset += screen->pitch; + offset += sdl_screen->pitch; pbitmap += width; } } @@ -349,11 +150,11 @@ D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) void D_EndDirectRect (int x, int y, int width, int height) { - if (!screen) + if (!sdl_screen) return; if (x < 0) - x = screen->w + x - 1; - SDL_UpdateRect (screen, x, y, width, height); + x = sdl_screen->w + x - 1; + SDL_UpdateRect (sdl_screen, x, y, width, height); } void diff --git a/libs/video/targets/vid_sdl_gl.c b/libs/video/targets/vid_sdl_gl.c new file mode 100644 index 000000000..829ca2860 --- /dev/null +++ b/libs/video/targets/vid_sdl_gl.c @@ -0,0 +1,178 @@ +/* + vid_sdl.c + + Video driver for Sam Lantinga's Simple DirectMedia Layer + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "QF/console.h" +#include "QF/cvar.h" +#include "QF/qendian.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_sdl.h" +#include "d_iface.h" +#include "vid_internal.h" +#include "vid_gl.h" + +// Define GLAPIENTRY to a useful value +#ifndef GLAPIENTRY +# ifdef _WIN32 +# include +# define GLAPIENTRY WINAPI +# undef LoadImage +# else +# ifdef APIENTRY +# define GLAPIENTRY APIENTRY +# else +# define GLAPIENTRY +# endif +# endif +#endif + +static void (GLAPIENTRY *qfglFinish) (void); +static int use_gl_procaddress = 0; +static cvar_t *gl_driver; + +static void * +QFGL_ProcAddress (const char *name, qboolean crit) +{ + void *glfunc = NULL; + + Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); + + glfunc = SDL_GL_GetProcAddress (name); + if (glfunc) { + Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); + return glfunc; + } + Sys_MaskPrintf (SYS_VID, "not found\n"); + + if (crit) { + if (strncmp ("fxMesa", name, 6) == 0) { + Sys_Printf ("This target requires a special version of Mesa with " + "support for Glide and SVGAlib.\n"); + Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); + } + Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", + name); + } + return NULL; +} + +static void +sdlgl_set_vid_mode (gl_ctx_t *ctx) +{ + int i, j; + + sdl_flags |= SDL_OPENGL; + + // Setup GL Attributes + SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); +// SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 0); // Try for 0, 8 +// SDL_GL_SetAttribute (SDL_GL_STEREO, 1); // Someday... + + for (i = 0; i < 5; i++) { + int k; + int color[5] = {32, 24, 16, 15, 0}; + int rgba[5][4] = { + {8, 8, 8, 0}, + {8, 8, 8, 8}, + {5, 6, 5, 0}, + {5, 5, 5, 0}, + {5, 5, 5, 1}, + }; + + SDL_GL_SetAttribute (SDL_GL_RED_SIZE, rgba[i][0]); + SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgba[i][1]); + SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, rgba[i][2]); + SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, rgba[i][3]); + + for (j = 0; j < 5; j++) { + for (k = 32; k >= 16; k -= 8) { + SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, k); + if ((sdl_screen = SDL_SetVideoMode (viddef.width, viddef.height, + color[j], sdl_flags))) + goto success; + } + } + } + + Sys_Error ("Couldn't set video mode: %s", SDL_GetError ()); + SDL_Quit (); + +success: + viddef.numpages = 2; + + ctx->init_gl (); +} + +static void +sdlgl_end_rendering (void) +{ + qfglFinish (); + SDL_GL_SwapBuffers (); +} + +static void +sdl_load_gl (void) +{ + if (SDL_GL_LoadLibrary (gl_driver->string) != 0) + Sys_Error ("Couldn't load OpenGL library %s!", gl_driver->string); + + use_gl_procaddress = 1; + + qfglFinish = QFGL_ProcAddress ("glFinish", true); +} + +gl_ctx_t * +SDL_GL_Context (void) +{ + gl_ctx_t *ctx = calloc (1, sizeof (gl_ctx_t)); + ctx->load_gl = sdl_load_gl; + ctx->create_context = sdlgl_set_vid_mode; + ctx->get_proc_address = QFGL_ProcAddress; + ctx->end_rendering = sdlgl_end_rendering; + return ctx; +} + +void +SDL_GL_Init_Cvars () +{ + gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, + "The OpenGL library to use. (path optional)"); +} diff --git a/libs/video/targets/vid_sdl_sw.c b/libs/video/targets/vid_sdl_sw.c new file mode 100644 index 000000000..2d4f806d4 --- /dev/null +++ b/libs/video/targets/vid_sdl_sw.c @@ -0,0 +1,183 @@ +/* + vid_sdl.c + + Video driver for Sam Lantinga's Simple DirectMedia Layer + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "QF/console.h" +#include "QF/cvar.h" +#include "QF/qendian.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_sdl.h" +#include "d_iface.h" +#include "vid_internal.h" +#include "vid_sw.h" + +#ifdef _WIN32 // FIXME: evil hack to get full DirectSound support with SDL +#include +#include +HWND mainwindow; +#endif + +// The original defaults +#define BASEWIDTH 320 +#define BASEHEIGHT 200 + +byte *VGA_pagebase; +int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes = 0; + +// Define GLAPIENTRY to a useful value +#ifndef GLAPIENTRY +# ifdef _WIN32 +# include +# define GLAPIENTRY WINAPI +# undef LoadImage +# else +# ifdef APIENTRY +# define GLAPIENTRY APIENTRY +# else +# define GLAPIENTRY +# endif +# endif +#endif + +static byte cached_palette[256 * 3]; +static int update_palette; + +static void +sdl_update_palette (const byte *palette) +{ + SDL_Color colors[256]; + int i; + + for (i = 0; i < 256; ++i) { + colors[i].r = *palette++; + colors[i].g = *palette++; + colors[i].b = *palette++; + } + SDL_SetColors (sdl_screen, colors, 0, 256); +} + +static void +VID_SetPalette (const byte *palette) +{ + if (memcmp (cached_palette, palette, sizeof (cached_palette))) { + memcpy (cached_palette, palette, sizeof (cached_palette)); + update_palette = 1; + } +} + +static void +do_screen_buffer (void) +{ +} + +static void +sdl_set_vid_mode (sw_ctx_t *ctx) +{ + // Initialize display + if (!(sdl_screen = SDL_SetVideoMode (viddef.width, viddef.height, 8, + sdl_flags))) + Sys_Error ("VID: Couldn't set video mode: %s", SDL_GetError ()); + + // now know everything we need to know about the buffer + VGA_width = viddef.width; + VGA_height = viddef.height; + viddef.vid_internal->do_screen_buffer = do_screen_buffer; + VGA_pagebase = viddef.buffer = sdl_screen->pixels; + VGA_rowbytes = viddef.rowbytes = sdl_screen->pitch; + viddef.conbuffer = viddef.buffer; + viddef.conrowbytes = viddef.rowbytes; + viddef.direct = 0; + + VID_InitBuffers (); // allocate z buffer and surface cache +} + +static void +sdl_sw_update (vrect_t *rects) +{ + static SDL_Rect *sdlrects; + static int num_sdlrects; + int i, n; + vrect_t *rect; + + if (update_palette) { + update_palette = 0; + sdl_update_palette (cached_palette); + } + // Two-pass system, since Quake doesn't do it the SDL way... + + // First, count the number of rectangles + n = 0; + for (rect = rects; rect; rect = rect->next) + ++n; + + if (n > num_sdlrects) { + num_sdlrects = n; + sdlrects = realloc (sdlrects, n * sizeof (SDL_Rect)); + if (!sdlrects) + Sys_Error ("Out of memory!"); + } + + // Second, copy them to SDL rectangles and update + i = 0; + for (rect = rects; rect; rect = rect->next) { + sdlrects[i].x = rect->x; + sdlrects[i].y = rect->y; + sdlrects[i].w = rect->width; + sdlrects[i].h = rect->height; + ++i; + } + SDL_UpdateRects (sdl_screen, n, sdlrects); +} + +sw_ctx_t * +SDL_SW_Context (void) +{ + sw_ctx_t *ctx = calloc (1, sizeof (sw_ctx_t)); + ctx->set_palette = VID_SetPalette; + ctx->create_context = sdl_set_vid_mode; + ctx->update = sdl_sw_update; + return ctx; +} + +void +SDL_SW_Init_Cvars () +{ +} diff --git a/libs/video/targets/vid_svgalib.c b/libs/video/targets/vid_svgalib.c index df0a80685..f556ca212 100644 --- a/libs/video/targets/vid_svgalib.c +++ b/libs/video/targets/vid_svgalib.c @@ -239,8 +239,8 @@ get_mode (int width, int height, int depth) return i; } -void -VID_Shutdown (void) +static void +VID_shutdown (void) { Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n"); @@ -358,6 +358,8 @@ VID_Init (byte *palette, byte *colormap) if (svgalib_inited) return; + Sys_RegisterShutdown (VID_shutdown); + err = vga_init (); if (err) Sys_Error ("SVGALib failed to allocate a new VC"); diff --git a/libs/video/targets/vid_win.c b/libs/video/targets/vid_win.c index 247298699..af843eb05 100644 --- a/libs/video/targets/vid_win.c +++ b/libs/video/targets/vid_win.c @@ -1339,6 +1339,8 @@ win_create_context (const byte *palette) void VID_Init (byte *palette, byte *colormap) { + Sys_RegisterShutdown (VID_shutdown); + choose_visual = win_choose_visual; create_context = win_create_context; @@ -1373,8 +1375,8 @@ Cmd_AddCommand ("vid_minimize", VID_Minimize_f, ""); #endif -void -VID_Shutdown (void) +static void +VID_shutdown (void) { if (vid_initialized) { if (modestate == MS_FULLDIB) diff --git a/libs/video/targets/vid_x11.c b/libs/video/targets/vid_x11.c index 41a72f642..ce605cda7 100644 --- a/libs/video/targets/vid_x11.c +++ b/libs/video/targets/vid_x11.c @@ -44,21 +44,10 @@ # include #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include #ifdef HAVE_VIDMODE # include @@ -67,7 +56,6 @@ #include "QF/cmd.h" #include "QF/console.h" #include "QF/cvar.h" -#include "QF/qargs.h" #include "QF/qendian.h" #include "QF/screen.h" #include "QF/sys.h" @@ -79,339 +67,10 @@ #include "dga_check.h" #include "vid_internal.h" -int XShmGetEventBase (Display *x); // for broken X11 headers - -static GC x_gc; - -static qboolean doShm; -static XShmSegmentInfo x_shminfo[2]; - -static int current_framebuffer; -static XImage *x_framebuffer[2] = { 0, 0 }; +static vid_internal_t vid_internal; int VID_options_items = 1; -static byte current_palette[768]; - -typedef unsigned char PIXEL8; -typedef unsigned short PIXEL16; -typedef unsigned int PIXEL24; - -static PIXEL16 st2d_8to16table[256]; -static PIXEL24 st2d_8to24table[256]; -static int shiftmask_fl = 0; -static long r_shift, g_shift, b_shift; -static unsigned long r_mask, g_mask, b_mask; - -#define GLX_RGBA 4 // true if RGBA mode -#define GLX_DOUBLEBUFFER 5 // double buffering supported -#define GLX_RED_SIZE 8 // number of red component bits -#define GLX_GREEN_SIZE 9 // number of green component bits -#define GLX_BLUE_SIZE 10 // number of blue component bits -#define GLX_DEPTH_SIZE 12 // number of depth bits - -// GLXContext is a pointer to opaque data -typedef struct __GLXcontextRec *GLXContext; -typedef XID GLXDrawable; - -// Define GLAPIENTRY to a useful value -#ifndef GLAPIENTRY -# ifdef _WIN32 -# include -# define GLAPIENTRY WINAPI -# undef LoadImage -# else -# ifdef APIENTRY -# define GLAPIENTRY APIENTRY -# else -# define GLAPIENTRY -# endif -# endif -#endif -static GLXContext ctx = NULL; -static void *libgl_handle; -static void (*qfglXSwapBuffers) (Display *dpy, GLXDrawable drawable); -static XVisualInfo* (*qfglXChooseVisual) (Display *dpy, int screen, - int *attribList); -static GLXContext (*qfglXCreateContext) (Display *dpy, XVisualInfo *vis, - GLXContext shareList, Bool direct); -static Bool (*qfglXMakeCurrent) (Display *dpy, GLXDrawable drawable, - GLXContext ctx); -static void (GLAPIENTRY *qfglFinish) (void); -static void *(*glGetProcAddress) (const char *symbol) = NULL; -static int use_gl_procaddress = 0; -static cvar_t *gl_driver; - -static void (*choose_visual) (void); -static void (*create_context) (void); - -static void * -QFGL_GetProcAddress (void *handle, const char *name) -{ - void *glfunc = NULL; - - if (use_gl_procaddress && glGetProcAddress) - glfunc = glGetProcAddress (name); - if (!glfunc) - glfunc = dlsym (handle, name); - return glfunc; -} - -static void * -QFGL_ProcAddress (const char *name, qboolean crit) -{ - void *glfunc = NULL; - - Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); - - glfunc = QFGL_GetProcAddress (libgl_handle, name); - if (glfunc) { - Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); - return glfunc; - } - Sys_MaskPrintf (SYS_VID, "not found\n"); - - if (crit) { - if (strncmp ("fxMesa", name, 6) == 0) { - Sys_Printf ("This target requires a special version of Mesa with " - "support for Glide and SVGAlib.\n"); - Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); - } - Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", - name); - } - return NULL; -} - -static void -glx_choose_visual (void) -{ - int attrib[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 1, - None - }; - - x_visinfo = qfglXChooseVisual (x_disp, x_screen, attrib); - if (!x_visinfo) { - Sys_Error ("Error couldn't get an RGB, Double-buffered, Depth visual"); - } - x_vis = x_visinfo->visual; -} - -static void -glx_create_context (void) -{ - XSync (x_disp, 0); - ctx = qfglXCreateContext (x_disp, x_visinfo, NULL, True); - qfglXMakeCurrent (x_disp, x_win, ctx); - viddef.init_gl (); -} - -static void -glx_end_rendering (void) -{ - qfglFinish (); - qfglXSwapBuffers (x_disp, x_win); -} - -static void -glx_load_gl (void) -{ - int flags = RTLD_NOW; - - choose_visual = glx_choose_visual; - create_context = glx_create_context; - - viddef.get_proc_address = QFGL_ProcAddress; - viddef.end_rendering = glx_end_rendering; - -#ifdef RTLD_GLOBAL - flags |= RTLD_GLOBAL; -#endif - if (!(libgl_handle = dlopen (gl_driver->string, flags))) { - Sys_Error ("Couldn't load OpenGL library %s: %s", gl_driver->string, - dlerror ()); - } - glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddress"); - if (!glGetProcAddress) - glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddressARB"); - - qfglXSwapBuffers = QFGL_ProcAddress ("glXSwapBuffers", true); - qfglXChooseVisual = QFGL_ProcAddress ("glXChooseVisual", true); - qfglXCreateContext = QFGL_ProcAddress ("glXCreateContext", true); - qfglXMakeCurrent = QFGL_ProcAddress ("glXMakeCurrent", true); - - use_gl_procaddress = 1; - - qfglFinish = QFGL_ProcAddress ("glFinish", true); -} - -static void -shiftmask_init (void) -{ - unsigned long long x; - - r_mask = x_vis->red_mask; - g_mask = x_vis->green_mask; - b_mask = x_vis->blue_mask; - - for (r_shift = -8, x = 1; x < r_mask; x <<= 1) - r_shift++; - for (g_shift = -8, x = 1; x < g_mask; x <<= 1) - g_shift++; - for (b_shift = -8, x = 1; x < b_mask; x <<= 1) - b_shift++; - shiftmask_fl = 1; -} - -static PIXEL16 -xlib_rgb16 (int r, int g, int b) -{ - PIXEL16 p = 0; - - if (!shiftmask_fl) - shiftmask_init (); - - if (r_shift > 0) { - p = (r << (r_shift)) & r_mask; - } else { - if (r_shift < 0) { - p = (r >> (-r_shift)) & r_mask; - } else { - p |= (r & r_mask); - } - } - - if (g_shift > 0) { - p |= (g << (g_shift)) & g_mask; - } else { - if (g_shift < 0) { - p |= (g >> (-g_shift)) & g_mask; - } else { - p |= (g & g_mask); - } - } - - if (b_shift > 0) { - p |= (b << (b_shift)) & b_mask; - } else { - if (b_shift < 0) { - p |= (b >> (-b_shift)) & b_mask; - } else { - p |= (b & b_mask); - } - } - - return p; -} - -static PIXEL24 -xlib_rgb24 (int r, int g, int b) -{ - PIXEL24 p = 0; - - if (!shiftmask_fl) - shiftmask_init (); - - if (r_shift > 0) { - p = (r << (r_shift)) & r_mask; - } else { - if (r_shift < 0) { - p = (r >> (-r_shift)) & r_mask; - } else { - p |= (r & r_mask); - } - } - - if (g_shift > 0) { - p |= (g << (g_shift)) & g_mask; - } else { - if (g_shift < 0) { - p |= (g >> (-g_shift)) & g_mask; - } else { - p |= (g & g_mask); - } - } - - if (b_shift > 0) { - p |= (b << (b_shift)) & b_mask; - } else { - if (b_shift < 0) { - p |= (b >> (-b_shift)) & b_mask; - } else { - p |= (b & b_mask); - } - } - - return p; -} - -static void -st2_fixup (XImage *framebuf, int x, int y, int width, int height) -{ - int xi, yi; - unsigned char *src; - PIXEL16 *dest; - - if (x < 0 || y < 0) - return; - - for (yi = y; yi < (y + height); yi++) { - src = &((byte *)viddef.buffer)[yi * viddef.width]; - dest = (PIXEL16 *) &framebuf->data[yi * framebuf->bytes_per_line]; - for (xi = x; xi < x + width; xi++) { - dest[xi] = st2d_8to16table[src[xi]]; - } - } -} - -static void -st3_fixup (XImage * framebuf, int x, int y, int width, int height) -{ - int yi; - unsigned char *src; - PIXEL24 *dest; - register int count, n; - - if (x < 0 || y < 0) - return; - - for (yi = y; yi < (y + height); yi++) { - src = &((byte *)viddef.buffer)[yi * viddef.width + x]; - dest = (PIXEL24 *) &framebuf->data[yi * framebuf->bytes_per_line + x]; - - // Duff's Device - count = width; - n = (count + 7) / 8; - - switch (count % 8) { - case 0: - do { - *dest++ = st2d_8to24table[*src++]; - case 7: - *dest++ = st2d_8to24table[*src++]; - case 6: - *dest++ = st2d_8to24table[*src++]; - case 5: - *dest++ = st2d_8to24table[*src++]; - case 4: - *dest++ = st2d_8to24table[*src++]; - case 3: - *dest++ = st2d_8to24table[*src++]; - case 2: - *dest++ = st2d_8to24table[*src++]; - case 1: - *dest++ = st2d_8to24table[*src++]; - } while (--n > 0); - } - } -} - void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) { @@ -425,239 +84,10 @@ D_EndDirectRect (int x, int y, int width, int height) } static void -ResetFrameBuffer (void) +VID_shutdown (void *data) { - int mem, pwidth; - char *buf; - - if (x_framebuffer[0]) { - XDestroyImage (x_framebuffer[0]); - } - - pwidth = x_visinfo->depth / 8; - - if (pwidth == 3) - pwidth = 4; - mem = ((viddef.width * pwidth + 7) & ~7) * viddef.height; - buf = malloc (mem); - SYS_CHECKMEM (buf); - - // allocate new screen buffer - x_framebuffer[0] = XCreateImage (x_disp, x_vis, x_visinfo->depth, - ZPixmap, 0, buf, viddef.width, - viddef.height, 32, 0); - - if (!x_framebuffer[0]) { - Sys_Error ("VID: XCreateImage failed"); - } -} - -static void -ResetSharedFrameBuffers (void) -{ - int size; - int key; - int minsize = getpagesize (); - int frm; - - for (frm = 0; frm < 2; frm++) { - - // free up old frame buffer memory - if (x_framebuffer[frm]) { - XShmDetach (x_disp, &x_shminfo[frm]); - free (x_framebuffer[frm]); - shmdt (x_shminfo[frm].shmaddr); - } - // create the image - x_framebuffer[frm] = XShmCreateImage (x_disp, x_vis, x_visinfo->depth, - ZPixmap, 0, &x_shminfo[frm], - viddef.width, viddef.height); - - // grab shared memory - size = x_framebuffer[frm]->bytes_per_line * x_framebuffer[frm]->height; - - if (size < minsize) - Sys_Error ("VID: Window must use at least %d bytes", minsize); - - key = random (); - x_shminfo[frm].shmid = shmget ((key_t) key, size, IPC_CREAT | 0777); - if (x_shminfo[frm].shmid == -1) - Sys_Error ("VID: Could not get any shared memory (%s)", - strerror (errno)); - - // attach to the shared memory segment - x_shminfo[frm].shmaddr = (void *) shmat (x_shminfo[frm].shmid, 0, 0); - - Sys_MaskPrintf (SYS_VID, "VID: shared memory id=%d, addr=0x%lx\n", - x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr); - - x_framebuffer[frm]->data = x_shminfo[frm].shmaddr; - - // get the X server to attach to it - if (!XShmAttach (x_disp, &x_shminfo[frm])) - Sys_Error ("VID: XShmAttach() failed"); - XSync (x_disp, 0); - shmctl (x_shminfo[frm].shmid, IPC_RMID, 0); - - } -} - -static void -x11_init_buffers (void) -{ - if (doShm) - ResetSharedFrameBuffers (); - else - ResetFrameBuffer (); - - current_framebuffer = 0; - - viddef.direct = 0; - viddef.rowbytes = viddef.width; - if (x_visinfo->depth != 8) { - if (viddef.buffer) - free (viddef.buffer); - viddef.buffer = calloc (viddef.width, viddef.height); - if (!viddef.buffer) - Sys_Error ("Not enough memory for video mode"); - } else { - viddef.buffer = x_framebuffer[current_framebuffer]->data; - } - viddef.conbuffer = viddef.buffer; - - viddef.conrowbytes = viddef.rowbytes; -} - -static void -x11_choose_visual (void) -{ - int pnum, i; - XVisualInfo template; - int num_visuals; - int template_mask; - - template_mask = 0; - - // specify a visual id - if ((pnum = COM_CheckParm ("-visualid"))) { - if (pnum >= com_argc - 1) - Sys_Error ("VID: -visualid "); - template.visualid = atoi (com_argv[pnum + 1]); - template_mask = VisualIDMask; - } else { // If not specified, use default - // visual - template.visualid = - XVisualIDFromVisual (XDefaultVisual (x_disp, x_screen)); - template_mask = VisualIDMask; - } - - // pick a visual -- warn if more than one was available - x_visinfo = XGetVisualInfo (x_disp, template_mask, &template, - &num_visuals); - - if (x_visinfo->depth == 8 && x_visinfo->class == PseudoColor) - x_cmap = XCreateColormap (x_disp, x_win, x_vis, AllocAll); - x_vis = x_visinfo->visual; - - if (num_visuals > 1) { - Sys_MaskPrintf (SYS_VID, - "Found more than one visual id at depth %d:\n", - template.depth); - for (i = 0; i < num_visuals; i++) - Sys_MaskPrintf (SYS_VID, " -visualid %d\n", - (int) x_visinfo[i].visualid); - } else { - if (num_visuals == 0) { - if (template_mask == VisualIDMask) { - Sys_Error ("VID: Bad visual ID %ld", template.visualid); - } else { - Sys_Error ("VID: No visuals at depth %d", template.depth); - } - } - } - - Sys_MaskPrintf (SYS_VID, "Using visualid %d:\n", - (int) x_visinfo->visualid); - Sys_MaskPrintf (SYS_VID, " class %d\n", x_visinfo->class); - Sys_MaskPrintf (SYS_VID, " screen %d\n", x_visinfo->screen); - Sys_MaskPrintf (SYS_VID, " depth %d\n", x_visinfo->depth); - Sys_MaskPrintf (SYS_VID, " red_mask 0x%x\n", - (int) x_visinfo->red_mask); - Sys_MaskPrintf (SYS_VID, " green_mask 0x%x\n", - (int) x_visinfo->green_mask); - Sys_MaskPrintf (SYS_VID, " blue_mask 0x%x\n", - (int) x_visinfo->blue_mask); - Sys_MaskPrintf (SYS_VID, " colormap_size %d\n", - x_visinfo->colormap_size); - Sys_MaskPrintf (SYS_VID, " bits_per_rgb %d\n", - x_visinfo->bits_per_rgb); -} - -static void -x11_create_context (void) -{ - // create the GC - { - XGCValues xgcvalues; - int valuemask = GCGraphicsExposures; - - xgcvalues.graphics_exposures = False; - x_gc = XCreateGC (x_disp, x_win, valuemask, &xgcvalues); - } - - // even if MITSHM is available, make sure it's a local connection - if (XShmQueryExtension (x_disp)) { - char *displayname; - char *d; - - doShm = true; - - if ((displayname = XDisplayName (NULL))) { - if ((d = strchr (displayname, ':'))) - *d = '\0'; - - if (!(!strcasecmp (displayname, "unix") || !*displayname)) - doShm = false; - } - } - - if (doShm) { - x_shmeventtype = XShmGetEventBase (x_disp) + ShmCompletion; - } - - viddef.do_screen_buffer = x11_init_buffers; - VID_InitBuffers (); - -// XSynchronize (x_disp, False); -// X11_AddEvent (x_shmeventtype, event_shm); -} - -static void -VID_SetPalette (const byte *palette) -{ - int i; - XColor colors[256]; - - for (i = 0; i < 256; i++) { - st2d_8to16table[i] = xlib_rgb16 (palette[i * 3], palette[i * 3 + 1], - palette[i * 3 + 2]); - st2d_8to24table[i] = xlib_rgb24 (palette[i * 3], palette[i * 3 + 1], - palette[i * 3 + 2]); - } - - if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) { - if (palette != current_palette) { - memcpy (current_palette, palette, 768); - } - for (i = 0; i < 256; i++) { - colors[i].pixel = i; - colors[i].flags = DoRed | DoGreen | DoBlue; - colors[i].red = palette[(i * 3)] << 8; - colors[i].green = palette[(i * 3) + 1] << 8; - colors[i].blue = palette[(i * 3) + 2] << 8; - } - XStoreColors (x_disp, x_cmap, colors, 256); - } + Sys_MaskPrintf (SYS_VID, "VID_shutdown\n"); + X11_CloseDisplay (); } /* @@ -668,10 +98,15 @@ VID_SetPalette (const byte *palette) void VID_Init (byte *palette, byte *colormap) { - choose_visual = x11_choose_visual; - create_context = x11_create_context; + Sys_RegisterShutdown (VID_shutdown, 0); - R_LoadModule (glx_load_gl, VID_SetPalette); + vid_internal.gl_context = X11_GL_Context; + vid_internal.sw_context = X11_SW_Context; +#ifdef HAVE_VULKAN + vid_internal.vulkan_context = X11_Vulkan_Context; +#endif + + R_LoadModule (&vid_internal); viddef.numpages = 2; viddef.colormap8 = colormap; @@ -681,14 +116,14 @@ VID_Init (byte *palette, byte *colormap) VID_GetWindowSize (640, 480); X11_OpenDisplay (); - choose_visual (); + vid_internal.choose_visual (); X11_SetVidMode (viddef.width, viddef.height); X11_CreateWindow (viddef.width, viddef.height); X11_CreateNullCursor (); // hide mouse pointer - create_context (); + vid_internal.create_context (); VID_InitGamma (palette); - viddef.set_palette (viddef.palette); + viddef.vid_internal->set_palette (viddef.palette); Sys_MaskPrintf (SYS_VID, "Video mode %dx%d initialized.\n", viddef.width, viddef.height); @@ -701,33 +136,19 @@ void VID_Init_Cvars () { X11_Init_Cvars (); - gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, - "The OpenGL library to use. (path optional)"); -} - -/* - VID_Shutdown - - Restore video mode -*/ -void -VID_Shutdown (void) -{ - Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n"); - X11_CloseDisplay (); +#ifdef HAVE_VULKAN + X11_Vulkan_Init_Cvars (); +#endif + X11_GL_Init_Cvars (); } +#if 0 static int config_notify = 0; static int config_notify_width; static int config_notify_height; -/* - VID_Update - - Flush the given rectangles from the view buffer to the screen. -*/ -void -VID_Update (vrect_t *rects) +static void +update () { /* If the window changes dimension, skip this frame. */ if (config_notify) { @@ -742,43 +163,8 @@ VID_Update (vrect_t *rects) Con_CheckResize (); return; } - - while (rects) { - switch (x_visinfo->depth) { - case 16: - st2_fixup (x_framebuffer[current_framebuffer], - rects->x, rects->y, rects->width, rects->height); - break; - case 24: - st3_fixup (x_framebuffer[current_framebuffer], - rects->x, rects->y, rects->width, rects->height); - break; - } - if (doShm) { - if (!XShmPutImage (x_disp, x_win, x_gc, - x_framebuffer[current_framebuffer], - rects->x, rects->y, rects->x, rects->y, - rects->width, rects->height, True)) { - Sys_Error ("VID_Update: XShmPutImage failed"); - } - oktodraw = false; - while (!oktodraw) - X11_ProcessEvent (); - rects = rects->next; - - current_framebuffer = !current_framebuffer; - } else { - if (XPutImage (x_disp, x_win, x_gc, x_framebuffer[0], - rects->x, rects->y, rects->x, rects->y, - rects->width, rects->height)) { - Sys_Error ("VID_Update: XPutImage failed"); - } - rects = rects->next; - } - } - XSync (x_disp, False); - r_data->scr_fullupdate = 0; } +#endif void VID_LockBuffer (void) @@ -796,10 +182,10 @@ VID_SetCaption (const char *text) if (text && *text) { char *temp = strdup (text); - X11_SetCaption (va ("%s: %s", PACKAGE_STRING, temp)); + X11_SetCaption (va (0, "%s: %s", PACKAGE_STRING, temp)); free (temp); } else { - X11_SetCaption (va ("%s", PACKAGE_STRING)); + X11_SetCaption (va (0, "%s", PACKAGE_STRING)); } } diff --git a/libs/video/targets/vid_x11_gl.c b/libs/video/targets/vid_x11_gl.c new file mode 100644 index 000000000..28b2f3294 --- /dev/null +++ b/libs/video/targets/vid_x11_gl.c @@ -0,0 +1,209 @@ +/* + vid_x11_gl.c + + GLX X11 video driver + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 contributors of the QuakeForge project + Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include + +#include "QF/cvar.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_x11.h" +#include "r_internal.h" +#include "vid_internal.h" +#include "vid_gl.h" + +#define GLX_RGBA 4 // true if RGBA mode +#define GLX_DOUBLEBUFFER 5 // double buffering supported +#define GLX_RED_SIZE 8 // number of red component bits +#define GLX_GREEN_SIZE 9 // number of green component bits +#define GLX_BLUE_SIZE 10 // number of blue component bits +#define GLX_DEPTH_SIZE 12 // number of depth bits + +typedef XID GLXDrawable; + +// Define GLAPIENTRY to a useful value +#ifndef GLAPIENTRY +# ifdef _WIN32 +# include +# define GLAPIENTRY WINAPI +# undef LoadImage +# else +# ifdef APIENTRY +# define GLAPIENTRY APIENTRY +# else +# define GLAPIENTRY +# endif +# endif +#endif +static void *libgl_handle; +static void (*qfglXSwapBuffers) (Display *dpy, GLXDrawable drawable); +static XVisualInfo* (*qfglXChooseVisual) (Display *dpy, int screen, + int *attribList); +static GLXContext (*qfglXCreateContext) (Display *dpy, XVisualInfo *vis, + GLXContext shareList, Bool direct); +static Bool (*qfglXMakeCurrent) (Display *dpy, GLXDrawable drawable, + GLXContext ctx); +static void (GLAPIENTRY *qfglFinish) (void); +static void *(*glGetProcAddress) (const char *symbol) = NULL; +static int use_gl_procaddress = 0; + +static cvar_t *gl_driver; + +static void * +QFGL_GetProcAddress (void *handle, const char *name) +{ + void *glfunc = NULL; + + if (use_gl_procaddress && glGetProcAddress) + glfunc = glGetProcAddress (name); + if (!glfunc) + glfunc = dlsym (handle, name); + return glfunc; +} + +static void * +QFGL_ProcAddress (const char *name, qboolean crit) +{ + void *glfunc = NULL; + + Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); + + glfunc = QFGL_GetProcAddress (libgl_handle, name); + if (glfunc) { + Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); + return glfunc; + } + Sys_MaskPrintf (SYS_VID, "not found\n"); + + if (crit) { + if (strncmp ("fxMesa", name, 6) == 0) { + Sys_Printf ("This target requires a special version of Mesa with " + "support for Glide and SVGAlib.\n"); + Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); + } + Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", + name); + } + return NULL; +} + +static void +glx_choose_visual (gl_ctx_t *ctx) +{ + int attrib[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None + }; + + x_visinfo = qfglXChooseVisual (x_disp, x_screen, attrib); + if (!x_visinfo) { + Sys_Error ("Error couldn't get an RGB, Double-buffered, Depth visual"); + } + x_vis = x_visinfo->visual; +} + +static void +glx_create_context (gl_ctx_t *ctx) +{ + XSync (x_disp, 0); + ctx->context = qfglXCreateContext (x_disp, x_visinfo, NULL, True); + qfglXMakeCurrent (x_disp, x_win, ctx->context); + ctx->init_gl (); +} + +static void +glx_end_rendering (void) +{ + qfglFinish (); + qfglXSwapBuffers (x_disp, x_win); +} + +static void +glx_load_gl (void) +{ + libgl_handle = dlopen (gl_driver->string, RTLD_NOW); + if (!libgl_handle) { + Sys_Error ("Couldn't load OpenGL library %s: %s", gl_driver->string, + dlerror ()); + } + glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddress"); + if (!glGetProcAddress) + glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddressARB"); + + qfglXSwapBuffers = QFGL_ProcAddress ("glXSwapBuffers", true); + qfglXChooseVisual = QFGL_ProcAddress ("glXChooseVisual", true); + qfglXCreateContext = QFGL_ProcAddress ("glXCreateContext", true); + qfglXMakeCurrent = QFGL_ProcAddress ("glXMakeCurrent", true); + + use_gl_procaddress = 1; + + qfglFinish = QFGL_ProcAddress ("glFinish", true); +} + +gl_ctx_t * +X11_GL_Context (void) +{ + gl_ctx_t *ctx = calloc (1, sizeof (gl_ctx_t)); + ctx->load_gl = glx_load_gl; + ctx->choose_visual = glx_choose_visual; + ctx->create_context = glx_create_context; + ctx->get_proc_address = QFGL_ProcAddress; + ctx->end_rendering = glx_end_rendering; + return ctx; +} + +void +X11_GL_Init_Cvars (void) +{ + gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, + "The OpenGL library to use. (path optional)"); +} diff --git a/libs/video/targets/vid_x11_sw.c b/libs/video/targets/vid_x11_sw.c new file mode 100644 index 000000000..9c734a635 --- /dev/null +++ b/libs/video/targets/vid_x11_sw.c @@ -0,0 +1,542 @@ +/* + vid_x11_sw.c + + Software X11 video driver (8/32 bit) + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 contributors of the QuakeForge project + Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QF/cvar.h" +#include "QF/qargs.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_x11.h" +#include "r_internal.h" +#include "vid_internal.h" +#include "vid_sw.h" + +int XShmGetEventBase (Display *x); // for broken X11 headers + +static GC x_gc; + +static qboolean doShm; +static XShmSegmentInfo x_shminfo[2]; + +static int current_framebuffer; +static XImage *x_framebuffer[2] = { 0, 0 }; + +typedef unsigned char PIXEL8; +typedef unsigned short PIXEL16; +typedef unsigned int PIXEL24; + +static PIXEL16 st2d_8to16table[256]; +static PIXEL24 st2d_8to24table[256]; + +static byte current_palette[768]; +static int shiftmask_fl = 0; +static long r_shift, g_shift, b_shift; +static unsigned long r_mask, g_mask, b_mask; + +static void +shiftmask_init (void) +{ + unsigned long long x; + + r_mask = x_vis->red_mask; + g_mask = x_vis->green_mask; + b_mask = x_vis->blue_mask; + + for (r_shift = -8, x = 1; x < r_mask; x <<= 1) + r_shift++; + for (g_shift = -8, x = 1; x < g_mask; x <<= 1) + g_shift++; + for (b_shift = -8, x = 1; x < b_mask; x <<= 1) + b_shift++; + shiftmask_fl = 1; +} + +static PIXEL16 +xlib_rgb16 (int r, int g, int b) +{ + PIXEL16 p = 0; + + if (!shiftmask_fl) + shiftmask_init (); + + if (r_shift > 0) { + p = (r << (r_shift)) & r_mask; + } else { + if (r_shift < 0) { + p = (r >> (-r_shift)) & r_mask; + } else { + p |= (r & r_mask); + } + } + + if (g_shift > 0) { + p |= (g << (g_shift)) & g_mask; + } else { + if (g_shift < 0) { + p |= (g >> (-g_shift)) & g_mask; + } else { + p |= (g & g_mask); + } + } + + if (b_shift > 0) { + p |= (b << (b_shift)) & b_mask; + } else { + if (b_shift < 0) { + p |= (b >> (-b_shift)) & b_mask; + } else { + p |= (b & b_mask); + } + } + + return p; +} + +static PIXEL24 +xlib_rgb24 (int r, int g, int b) +{ + PIXEL24 p = 0; + + if (!shiftmask_fl) + shiftmask_init (); + + if (r_shift > 0) { + p = (r << (r_shift)) & r_mask; + } else { + if (r_shift < 0) { + p = (r >> (-r_shift)) & r_mask; + } else { + p |= (r & r_mask); + } + } + + if (g_shift > 0) { + p |= (g << (g_shift)) & g_mask; + } else { + if (g_shift < 0) { + p |= (g >> (-g_shift)) & g_mask; + } else { + p |= (g & g_mask); + } + } + + if (b_shift > 0) { + p |= (b << (b_shift)) & b_mask; + } else { + if (b_shift < 0) { + p |= (b >> (-b_shift)) & b_mask; + } else { + p |= (b & b_mask); + } + } + + return p; +} + +static void +VID_SetPalette (const byte *palette) +{ + int i; + XColor colors[256]; + + for (i = 0; i < 256; i++) { + st2d_8to16table[i] = xlib_rgb16 (palette[i * 3], palette[i * 3 + 1], + palette[i * 3 + 2]); + st2d_8to24table[i] = xlib_rgb24 (palette[i * 3], palette[i * 3 + 1], + palette[i * 3 + 2]); + } + + if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) { + if (palette != current_palette) { + memcpy (current_palette, palette, 768); + } + for (i = 0; i < 256; i++) { + colors[i].pixel = i; + colors[i].flags = DoRed | DoGreen | DoBlue; + colors[i].red = palette[(i * 3)] << 8; + colors[i].green = palette[(i * 3) + 1] << 8; + colors[i].blue = palette[(i * 3) + 2] << 8; + } + XStoreColors (x_disp, x_cmap, colors, 256); + } +} + +static void +st2_fixup (XImage *framebuf, int x, int y, int width, int height) +{ + int xi, yi; + unsigned char *src; + PIXEL16 *dest; + + if (x < 0 || y < 0) + return; + + for (yi = y; yi < (y + height); yi++) { + src = &((byte *)viddef.buffer)[yi * viddef.width]; + dest = (PIXEL16 *) &framebuf->data[yi * framebuf->bytes_per_line]; + for (xi = x; xi < x + width; xi++) { + dest[xi] = st2d_8to16table[src[xi]]; + } + } +} + +static void +st3_fixup (XImage * framebuf, int x, int y, int width, int height) +{ + int yi; + unsigned char *src; + PIXEL24 *dest; + register int count, n; + + if (x < 0 || y < 0) + return; + + for (yi = y; yi < (y + height); yi++) { + src = &((byte *)viddef.buffer)[yi * viddef.width + x]; + dest = (PIXEL24 *) &framebuf->data[yi * framebuf->bytes_per_line + x]; + + // Duff's Device + count = width; + n = (count + 7) / 8; + + switch (count % 8) { + case 0: + do { + *dest++ = st2d_8to24table[*src++]; + case 7: + *dest++ = st2d_8to24table[*src++]; + case 6: + *dest++ = st2d_8to24table[*src++]; + case 5: + *dest++ = st2d_8to24table[*src++]; + case 4: + *dest++ = st2d_8to24table[*src++]; + case 3: + *dest++ = st2d_8to24table[*src++]; + case 2: + *dest++ = st2d_8to24table[*src++]; + case 1: + *dest++ = st2d_8to24table[*src++]; + } while (--n > 0); + } + } +} + +/* + Flush the given rectangles from the view buffer to the screen. +*/ +static void +x11_sw_update (vrect_t *rects) +{ + while (rects) { + switch (x_visinfo->depth) { + case 16: + st2_fixup (x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->width, rects->height); + break; + case 24: + st3_fixup (x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->width, rects->height); + break; + } + if (doShm) { + if (!XShmPutImage (x_disp, x_win, x_gc, + x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->x, rects->y, + rects->width, rects->height, True)) { + Sys_Error ("VID_Update: XShmPutImage failed"); + } + oktodraw = false; + while (!oktodraw) + X11_ProcessEvent (); + rects = rects->next; + + current_framebuffer = !current_framebuffer; + } else { + if (XPutImage (x_disp, x_win, x_gc, x_framebuffer[0], + rects->x, rects->y, rects->x, rects->y, + rects->width, rects->height)) { + Sys_Error ("VID_Update: XPutImage failed"); + } + rects = rects->next; + } + } + XSync (x_disp, False); + r_data->scr_fullupdate = 0; +} + +static void +x11_choose_visual (sw_ctx_t *ctx) +{ + int pnum, i; + XVisualInfo template; + int num_visuals; + int template_mask; + + // specify a visual id + if ((pnum = COM_CheckParm ("-visualid"))) { + if (pnum >= com_argc - 1) + Sys_Error ("VID: -visualid "); + template.visualid = atoi (com_argv[pnum + 1]); + template_mask = VisualIDMask; + } else { // If not specified, use default + // visual + template.visualid = + XVisualIDFromVisual (XDefaultVisual (x_disp, x_screen)); + template_mask = VisualIDMask; + } + + // pick a visual -- warn if more than one was available + x_visinfo = XGetVisualInfo (x_disp, template_mask, &template, + &num_visuals); + + if (x_visinfo->depth == 8 && x_visinfo->class == PseudoColor) + x_cmap = XCreateColormap (x_disp, x_win, x_vis, AllocAll); + x_vis = x_visinfo->visual; + + if (num_visuals > 1) { + Sys_MaskPrintf (SYS_VID, + "Found more than one visual id at depth %d:\n", + template.depth); + for (i = 0; i < num_visuals; i++) + Sys_MaskPrintf (SYS_VID, " -visualid %d\n", + (int) x_visinfo[i].visualid); + } else { + if (num_visuals == 0) { + if (template_mask == VisualIDMask) { + Sys_Error ("VID: Bad visual ID %ld", template.visualid); + } else { + Sys_Error ("VID: No visuals at depth %d", template.depth); + } + } + } + + Sys_MaskPrintf (SYS_VID, "Using visualid %d:\n", + (int) x_visinfo->visualid); + Sys_MaskPrintf (SYS_VID, " class %d\n", x_visinfo->class); + Sys_MaskPrintf (SYS_VID, " screen %d\n", x_visinfo->screen); + Sys_MaskPrintf (SYS_VID, " depth %d\n", x_visinfo->depth); + Sys_MaskPrintf (SYS_VID, " red_mask 0x%x\n", + (int) x_visinfo->red_mask); + Sys_MaskPrintf (SYS_VID, " green_mask 0x%x\n", + (int) x_visinfo->green_mask); + Sys_MaskPrintf (SYS_VID, " blue_mask 0x%x\n", + (int) x_visinfo->blue_mask); + Sys_MaskPrintf (SYS_VID, " colormap_size %d\n", + x_visinfo->colormap_size); + Sys_MaskPrintf (SYS_VID, " bits_per_rgb %d\n", + x_visinfo->bits_per_rgb); +} + +static void +ResetFrameBuffer (void) +{ + int mem, pwidth; + char *buf; + + if (x_framebuffer[0]) { + XDestroyImage (x_framebuffer[0]); + } + + pwidth = x_visinfo->depth / 8; + + if (pwidth == 3) + pwidth = 4; + mem = ((viddef.width * pwidth + 7) & ~7) * viddef.height; + buf = malloc (mem); + SYS_CHECKMEM (buf); + + // allocate new screen buffer + x_framebuffer[0] = XCreateImage (x_disp, x_vis, x_visinfo->depth, + ZPixmap, 0, buf, viddef.width, + viddef.height, 32, 0); + + if (!x_framebuffer[0]) { + Sys_Error ("VID: XCreateImage failed"); + } +} + +static void +ResetSharedFrameBuffers (void) +{ + int size; + int key; + int minsize = getpagesize (); + int frm; + + for (frm = 0; frm < 2; frm++) { + + // free up old frame buffer memory + if (x_framebuffer[frm]) { + XShmDetach (x_disp, &x_shminfo[frm]); + free (x_framebuffer[frm]); + shmdt (x_shminfo[frm].shmaddr); + } + // create the image + x_framebuffer[frm] = XShmCreateImage (x_disp, x_vis, x_visinfo->depth, + ZPixmap, 0, &x_shminfo[frm], + viddef.width, viddef.height); + + // grab shared memory + size = x_framebuffer[frm]->bytes_per_line * x_framebuffer[frm]->height; + + if (size < minsize) + Sys_Error ("VID: Window must use at least %d bytes", minsize); + + key = random (); + x_shminfo[frm].shmid = shmget ((key_t) key, size, IPC_CREAT | 0777); + if (x_shminfo[frm].shmid == -1) + Sys_Error ("VID: Could not get any shared memory (%s)", + strerror (errno)); + + // attach to the shared memory segment + x_shminfo[frm].shmaddr = (void *) shmat (x_shminfo[frm].shmid, 0, 0); + + Sys_MaskPrintf (SYS_VID, "VID: shared memory id=%d, addr=0x%lx\n", + x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr); + + x_framebuffer[frm]->data = x_shminfo[frm].shmaddr; + + // get the X server to attach to it + if (!XShmAttach (x_disp, &x_shminfo[frm])) + Sys_Error ("VID: XShmAttach() failed"); + XSync (x_disp, 0); + shmctl (x_shminfo[frm].shmid, IPC_RMID, 0); + + } +} + +static void +x11_init_buffers (void) +{ + if (doShm) + ResetSharedFrameBuffers (); + else + ResetFrameBuffer (); + + current_framebuffer = 0; + + viddef.direct = 0; + viddef.rowbytes = viddef.width; + if (x_visinfo->depth != 8) { + if (viddef.buffer) + free (viddef.buffer); + viddef.buffer = calloc (viddef.width, viddef.height); + if (!viddef.buffer) + Sys_Error ("Not enough memory for video mode"); + } else { + viddef.buffer = x_framebuffer[current_framebuffer]->data; + } + viddef.conbuffer = viddef.buffer; + + viddef.conrowbytes = viddef.rowbytes; +} + +static void +x11_create_context (sw_ctx_t *ctx) +{ + // create the GC + { + XGCValues xgcvalues; + int valuemask = GCGraphicsExposures; + + xgcvalues.graphics_exposures = False; + x_gc = XCreateGC (x_disp, x_win, valuemask, &xgcvalues); + } + + // even if MITSHM is available, make sure it's a local connection + if (XShmQueryExtension (x_disp)) { + char *displayname; + char *d; + + doShm = true; + + if ((displayname = XDisplayName (NULL))) { + if ((d = strchr (displayname, ':'))) + *d = '\0'; + + if (!(!strcasecmp (displayname, "unix") || !*displayname)) + doShm = false; + } + } + + if (doShm) { + x_shmeventtype = XShmGetEventBase (x_disp) + ShmCompletion; + } + + viddef.vid_internal->do_screen_buffer = x11_init_buffers; + VID_InitBuffers (); + +// XSynchronize (x_disp, False); +// X11_AddEvent (x_shmeventtype, event_shm); +} + +sw_ctx_t * +X11_SW_Context (void) +{ + sw_ctx_t *ctx = calloc (1, sizeof (sw_ctx_t)); + ctx->set_palette = VID_SetPalette; + ctx->choose_visual = x11_choose_visual; + ctx->create_context = x11_create_context; + ctx->update = x11_sw_update; + return ctx; +} + +void +X11_SW_Init_Cvars (void) +{ +} diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c new file mode 100644 index 000000000..d64bed09f --- /dev/null +++ b/libs/video/targets/vid_x11_vulkan.c @@ -0,0 +1,225 @@ +/* + vid_x11_vulkan.c + + Vulkan X11 video driver + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 contributors of the QuakeForge project + Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#define VK_NO_PROTOTYPES +#define VK_USE_PLATFORM_XLIB_KHR +#include + +#include "QF/cvar.h" +#include "QF/set.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "QF/Vulkan/instance.h" + +#include "context_x11.h" +#include "vid_internal.h" +#include "vid_vulkan.h" + +static cvar_t *vulkan_library_name; + +typedef struct vulkan_presentation_s { +#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#include "QF/Vulkan/funclist.h" + + Display *display; + Window window; + int num_visuals; + XVisualInfo *visinfo; + set_t *usable_visuals; +} vulkan_presentation_t; + +static const char *required_extensions[] = { + VK_KHR_XLIB_SURFACE_EXTENSION_NAME, + 0 +}; + +static void *vulkan_library; + +static void +load_vulkan_library (vulkan_ctx_t *ctx) +{ + vulkan_library = dlopen (vulkan_library_name->string, + RTLD_DEEPBIND | RTLD_NOW); + if (!vulkan_library) { + Sys_Error ("Couldn't load vulkan library %s: %s", + vulkan_library_name->name, dlerror ()); + } + + #define EXPORTED_VULKAN_FUNCTION(name) \ + ctx->name = (PFN_##name) dlsym (vulkan_library, #name); \ + if (!ctx->name) { \ + Sys_Error ("Couldn't find exported vulkan function %s", #name); \ + } + + #define GLOBAL_LEVEL_VULKAN_FUNCTION(name) \ + ctx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (0, #name); \ + if (!ctx->name) { \ + Sys_Error ("Couldn't find global-level function %s", #name); \ + } + + #include "QF/Vulkan/funclist.h" +} + +static void +unload_vulkan_library (vulkan_ctx_t *ctx) +{ + dlclose (vulkan_library); + vulkan_library = 0; +} + +static void +x11_vulkan_init_presentation (vulkan_ctx_t *ctx) +{ + ctx->presentation = calloc (1, sizeof (vulkan_presentation_t)); + vulkan_presentation_t *pres = ctx->presentation; + qfv_instance_t *instance = ctx->instance; + VkInstance inst = instance->instance; + +#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (instance->extension_enabled (instance, ext)) { \ + pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \ + if (!pres->name) { \ + Sys_Error ("Couldn't find instance-level function %s", #name); \ + } \ + } +#include "QF/Vulkan/funclist.h" + + XVisualInfo template; + Visual *defaultVisual = XDefaultVisual (x_disp, x_screen); + template.visualid = XVisualIDFromVisual (defaultVisual); + int template_mask = VisualIDMask; + pres->display = x_disp; + pres->usable_visuals = set_new (); + pres->visinfo = XGetVisualInfo (x_disp, template_mask, &template, + &pres->num_visuals); +} + +static int +x11_vulkan_get_presentation_support (vulkan_ctx_t *ctx, + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex) +{ + if (!ctx->presentation) { + x11_vulkan_init_presentation (ctx); + } + vulkan_presentation_t *pres = ctx->presentation; + + set_empty (pres->usable_visuals); + for (int i = 0; i < pres->num_visuals; i++) { + VisualID visID = pres->visinfo[i].visualid; + + if (pres->vkGetPhysicalDeviceXlibPresentationSupportKHR ( + physicalDevice, queueFamilyIndex, pres->display, visID)) { + set_add (pres->usable_visuals, i); + } + } + return !set_is_empty (pres->usable_visuals); +} + +static void +x11_vulkan_choose_visual (vulkan_ctx_t *ctx) +{ + vulkan_presentation_t *pres = ctx->presentation; + set_iter_t *first = set_first (pres->usable_visuals); + if (first) { + x_visinfo = pres->visinfo + first->element; + x_vis = x_visinfo->visual; + set_del_iter (first); + } +} + +static void +x11_vulkan_create_window (vulkan_ctx_t *ctx) +{ + vulkan_presentation_t *pres = ctx->presentation; + pres->window = x_win; +} + +static VkSurfaceKHR +x11_vulkan_create_surface (vulkan_ctx_t *ctx) +{ + vulkan_presentation_t *pres = ctx->presentation; + VkInstance inst = ctx->instance->instance; + VkSurfaceKHR surface; + VkXlibSurfaceCreateInfoKHR createInfo = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .flags = 0, + .dpy = pres->display, + .window = pres->window + }; + + if (pres->vkCreateXlibSurfaceKHR (inst, &createInfo, 0, &surface) + != VK_SUCCESS) { + return 0; + } + return surface; +} + +vulkan_ctx_t * +X11_Vulkan_Context (void) +{ + vulkan_ctx_t *ctx = calloc (1, sizeof (vulkan_ctx_t)); + ctx->load_vulkan = load_vulkan_library; + ctx->unload_vulkan = unload_vulkan_library; + ctx->get_presentation_support = x11_vulkan_get_presentation_support; + ctx->choose_visual = x11_vulkan_choose_visual; + ctx->create_window = x11_vulkan_create_window; + ctx->create_surface = x11_vulkan_create_surface; + ctx->required_extensions = required_extensions; + ctx->va_ctx = va_create_context (4); + return ctx; +} + +void +X11_Vulkan_Init_Cvars (void) +{ + vulkan_library_name = Cvar_Get ("vulkan_library", "libvulkan.so.1", + CVAR_ROM, 0, + "the name of the vulkan shared library"); +} diff --git a/m4/quakeforge.m4 b/m4/quakeforge.m4 index 2c3139733..984cd71f7 100644 --- a/m4/quakeforge.m4 +++ b/m4/quakeforge.m4 @@ -93,7 +93,7 @@ AC_DEFUN([QF_NEED], [m4_map_args_w([$2], [$1_need_], [=yes], [;])]) AC_DEFUN([QF_PROCESS_NEED_subroutine], [m4_foreach_w([qfn_need], [$5], [if test x"${$2[_need_]qfn_need}" = xyes; then - $4="${$4} $1[]qfn_need[]$3" + $4="${$4} m4_join([/],[$6],[$1])[]qfn_need[]$3" fi ])]) @@ -105,8 +105,8 @@ fi ])]) AC_DEFUN([QF_PROCESS_NEED_LIBS], -[m4_define([qfn_ext], m4_default($3,[la])) -QF_PROCESS_NEED_subroutine([lib$1_],[$1],[.]qfn_ext,[$1_libs],[$2]) +[m4_define([qfn_ext], m4_default($4,[la])) +QF_PROCESS_NEED_subroutine([lib$1_],[$1],[.]qfn_ext,[$1_libs],[$2],[$3]) QF_SUBST([$1_libs])]) AC_DEFUN([QF_PROCESS_NEED_DIRS], @@ -122,11 +122,11 @@ AC_DEFINE_UNQUOTED(m4_toupper(qfn_default), ["${qfn_default}"], [Define to defau ]) AC_DEFUN([QF_PROCESS_NEED_PLUGINS], -[QF_PROCESS_NEED_subroutine([$1_],[$1],[.la],[$1_plugins],[$2]) +[QF_PROCESS_NEED_subroutine([$1_],[$1],[.la],[$1_plugins],[$2],[$3]) QF_SUBST([$1_plugins]) -QF_DEFAULT_PLUGIN([$1],[$2],[$3]) -AC_DEFINE_UNQUOTED(m4_toupper(m4_default($3,$1)[_plugin_protos]), [], [list of $1 plugin prototypes]) -AC_DEFINE_UNQUOTED(m4_toupper(m4_default($3,$1)[_plugin_list]), [{0, 0}], [list of $1 plugins]) +QF_DEFAULT_PLUGIN([$1],[$2],[$4]) +AC_DEFINE_UNQUOTED(m4_toupper(m4_default($4,$1)[_plugin_protos]), [], [list of $1 plugin prototypes]) +AC_DEFINE_UNQUOTED(m4_toupper(m4_default($4,$1)[_plugin_list]), [{0, 0}], [list of $1 plugins]) ]) AC_DEFUN([QF_STATIC_PLUGIN_LIBS], @@ -147,7 +147,7 @@ fi AC_DEFINE_UNQUOTED(m4_toupper([$1_plugin_list]), [${$1_plugin_list}], [list of $1 plugins])]) AC_DEFUN([QF_PROCESS_NEED_STATIC_PLUGINS], -[QF_PROCESS_NEED_subroutine([$1_],[$1],[.la],m4_default($4,$1)[_static_plugins],[$2]) +[QF_PROCESS_NEED_subroutine([$1_],[$1],[.la],m4_default($4,$1)[_static_plugins],[$2],[$3]) QF_SUBST(m4_default($4,$1)[_static_plugins]) QF_DEFAULT_PLUGIN([$1],[$2],[$4]) QF_STATIC_PLUGIN_LIBS(m4_default($4,$1),[$1],[$2],[$3]) diff --git a/nq/Makefile.am b/nq/Makefile.am deleted file mode 100644 index 77e3cbf5b..000000000 --- a/nq/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source diff --git a/nq/Makemodule.am b/nq/Makemodule.am new file mode 100644 index 000000000..7e28f6401 --- /dev/null +++ b/nq/Makemodule.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in +include nq/include/Makemodule.am +include nq/source/Makemodule.am diff --git a/nq/include/Makefile.am b/nq/include/Makefile.am deleted file mode 100644 index 60374efe3..000000000 --- a/nq/include/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -## Process this file with automake to produce Makefile.in -EXTRA_DIST= chase.h cl_skin.h client.h game.h host.h protocol.h server.h \ - sv_pr_cmds.h sv_progs.h diff --git a/nq/include/Makemodule.am b/nq/include/Makemodule.am new file mode 100644 index 000000000..ba1076749 --- /dev/null +++ b/nq/include/Makemodule.am @@ -0,0 +1,11 @@ +## Process this file with automake to produce Makefile.in +EXTRA_DIST += \ + nq/include/chase.h \ + nq/include/cl_skin.h \ + nq/include/client.h \ + nq/include/game.h \ + nq/include/host.h \ + nq/include/protocol.h \ + nq/include/server.h \ + nq/include/sv_pr_cmds.h \ + nq/include/sv_progs.h diff --git a/nq/include/client.h b/nq/include/client.h index e6dc80e97..e3f053016 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -38,6 +38,8 @@ #include "QF/render.h" #include "client/entities.h" +#include "client/state.h" +#include "client/view.h" #include "game.h" #include "netmain.h" @@ -53,16 +55,6 @@ typedef struct usercmd_s { float upmove; } usercmd_t; -typedef struct { - struct info_s *info; - struct info_key_s *name; - float entertime; - int frags; - int topcolor; - int bottomcolor; -} scoreboard_t; - - // client_state_t should hold all pieces of the client state typedef enum { @@ -142,7 +134,7 @@ extern client_static_t cls; /* the client_state_t structure is wiped completely at every server signon */ -typedef struct { +typedef struct client_state_s { qboolean loading; int movemessages; // Since connecting to this server throw out @@ -153,7 +145,7 @@ typedef struct { // information for local display int stats[MAX_CL_STATS]; // Health, etc float item_gettime[32]; // cl.time of aquiring item, for blinking - float faceanimtime; // Use anim frame if cl.time < this + float faceanimtime; // Use anim frame if cl.time < this cshift_t cshifts[NUM_CSHIFTS]; // Color shifts for damage, powerups cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types @@ -162,14 +154,12 @@ typedef struct { // server each frame. The server sets punchangle when the view is temporarily // offset, and an angle reset commands at the start of each level and after // teleporting. - int mindex; - vec3_t mviewangles[2]; // During demo playback viewangles is lerped + int frameIndex; + vec3_t frameViewAngles[2]; // During demo playback viewangles is lerped // between these - vec3_t viewangles; - vec3_t mvelocity[2]; // Update by server, used for lean+bob + vec4f_t frameVelocity[2]; // Update by server, used for lean+bob // (0 is newest) - vec3_t velocity; // Lerped between mvelocity[0] and [1] - vec3_t punchangle; // Temporary offset + viewstate_t viewstate; // pitch drifting vars float idealpitch; @@ -179,13 +169,12 @@ typedef struct { double laststop; qboolean paused; // Sent over by server - int onground; float viewheight; float crouch; // Local amount for smoothing stepups qboolean inwater; int intermission; // Don't change view angle, full screen, etc - int completed_time; // Latched at intermission start + int completed_time; // Latched from time at intermission start double mtime[2]; // The timestamp of last two messages double time; // Clients view of time, should be between @@ -194,7 +183,8 @@ typedef struct { double oldtime; // Previous cl.time, time-oldtime is used // to decay light values and smooth step ups - float last_received_message; // (realtime) for net trouble icon + double last_ping_request; // while showing scoreboard + double last_servermessage; // (realtime) for net trouble icon /* information that is static for the entire time connected to a server */ @@ -208,14 +198,20 @@ typedef struct { char levelname[40]; // for display on solo scoreboard int spectator; + int playernum; int viewentity; // cl_entitites[cl.viewentity] = player unsigned protocol; + float stdver; int gametype; int maxclients; + // serverinfo mirrors int chase; int sv_cshifts; + int no_pogo_stick; + int teamplay; int watervis; int fpd; + int fbskins; // refresh related state struct model_s *worldmodel; // cl_entitites[0].model @@ -224,8 +220,8 @@ typedef struct { int cdtrack; // cd audio -// frag scoreboard - scoreboard_t *scores; // [cl.maxclients] +// all player information + player_info_t *players; lightstyle_t lightstyle[MAX_LIGHTSTYLES]; } client_state_t; @@ -286,7 +282,7 @@ extern void (*write_angles) (sizebuf_t *sb, const vec3_t angles); struct cbuf_s; void CL_Init (struct cbuf_s *cbuf); void CL_InitCvars (void); -void CL_Shutdown (void); +void CL_ClearMemory (void); void CL_EstablishConnection (const char *host); void CL_Signon1 (void); @@ -304,10 +300,6 @@ void CL_Input_Init (void); void CL_SendCmd (void); void CL_SendMove (usercmd_t *cmd); -void CL_ParseParticleEffect (void); -void CL_ParseTEnt (void); -void CL_UpdateTEnts (void); - void CL_ClearState (void); int CL_ReadFromServer (void); @@ -344,13 +336,7 @@ void V_SetContentsColor (int contents); void V_PrepBlend (void); // cl_tent -void CL_TEnts_Init (void); -void CL_ClearTEnts (void); -void CL_Init_Entity (struct entity_s *ent); -void CL_ParseTEnt (void); void CL_SignonReply (void); -void CL_TransformEntity (struct entity_s *ent, const vec3_t - angles, qboolean force); void CL_RelinkEntities (void); void CL_ClearEnts (void); diff --git a/nq/include/host.h b/nq/include/host.h index 2e17ca341..9300abbfe 100644 --- a/nq/include/host.h +++ b/nq/include/host.h @@ -61,11 +61,11 @@ void Host_ClearMemory (void); void Host_ServerFrame (void); void Host_InitCommands (void); void Host_Init (void); -void Host_Shutdown(void); -void Host_Error (const char *error, ...) __attribute__((format(printf,1,2))); -void Host_EndGame (const char *message, ...) __attribute__((format(printf,1,2))); +void Host_Shutdown(void *data); +void Host_Error (const char *error, ...) __attribute__((format(printf,1,2), noreturn)); +void Host_EndGame (const char *message, ...) __attribute__((format(printf,1,2), noreturn)); void Host_Frame (float time); -void Host_Quit_f (void); +void Host_Quit_f (void) __attribute__((noreturn)); void Host_ClientCommands (const char *fmt, ...) __attribute__((format(printf,1,2))); void Host_ShutdownServer (qboolean crash); diff --git a/nq/include/server.h b/nq/include/server.h index 0d83a4e7c..4960fee5c 100644 --- a/nq/include/server.h +++ b/nq/include/server.h @@ -255,7 +255,7 @@ void SV_DropClient (qboolean crash); void SV_SendClientMessages (void); void SV_ClearDatagram (void); -int SV_ModelIndex (const char *name); +int SV_ModelIndex (const char *name) __attribute__((pure)); void SV_SetIdealPitch (void); @@ -268,7 +268,7 @@ void SV_ClientPrintf (const char *fmt, ...) __attribute__((format(printf,1,2))); void SV_BroadcastPrintf (const char *fmt, ...) __attribute__((format(printf,1,2))); struct trace_s SV_PushEntity (edict_t *ent, vec3_t push); -int SV_EntCanSupportJump (edict_t *ent); +int SV_EntCanSupportJump (edict_t *ent) __attribute__((pure)); int SV_FlyMove (edict_t *ent, float time, struct trace_s *steptrace); void SV_CheckVelocity (edict_t *ent); qboolean SV_RunThink (edict_t *ent); diff --git a/nq/include/sv_progs.h b/nq/include/sv_progs.h index e1b8d4e4a..71a371f48 100644 --- a/nq/include/sv_progs.h +++ b/nq/include/sv_progs.h @@ -105,22 +105,17 @@ typedef struct pr_int_t velocity; //vec3_t pr_int_t angles; //vec3_t pr_int_t avelocity; //vec3_t - pr_int_t basevelocity; //vec3_t pr_int_t punchangle; //vec3_t pr_int_t classname; //string_t pr_int_t model; //string_t pr_int_t frame; //float pr_int_t skin; //float pr_int_t effects; //float - pr_int_t drawPercent; //float pr_int_t gravity; //float - pr_int_t mass; //float - pr_int_t light_level; //float pr_int_t mins; //vec3_t pr_int_t maxs; //vec3_t pr_int_t size; //vec3_t pr_int_t touch; //func_t - pr_int_t use; //func_t pr_int_t think; //func_t pr_int_t blocked; //func_t pr_int_t nextthink; //float @@ -139,7 +134,6 @@ typedef struct pr_int_t items2; //float pr_int_t takedamage; //float pr_int_t chain; //int - pr_int_t deadflag; //float pr_int_t view_ofs; //vec3_t pr_int_t button0; //float pr_int_t button1; //float @@ -148,25 +142,19 @@ typedef struct pr_int_t fixangle; //float pr_int_t v_angle; //vec3_t pr_int_t idealpitch; //float - pr_int_t pitch_speed; //float pr_int_t netname; //string_t pr_int_t enemy; //int pr_int_t flags; //float pr_int_t colormap; //float pr_int_t team; //float - pr_int_t max_health; //float pr_int_t teleport_time; //float - pr_int_t armortype; //float pr_int_t armorvalue; //float pr_int_t waterlevel; //float pr_int_t watertype; //float pr_int_t ideal_yaw; //float pr_int_t yaw_speed; //float - pr_int_t aiment; //int pr_int_t goalentity; //int pr_int_t spawnflags; //float - pr_int_t target; //string_t - pr_int_t targetname; //string_t pr_int_t dmg_take; //float pr_int_t dmg_save; //float pr_int_t dmg_inflictor; //int @@ -174,16 +162,6 @@ typedef struct pr_int_t movedir; //vec3_t pr_int_t message; //string_t pr_int_t sounds; //float - pr_int_t noise; //string_t - pr_int_t noise1; //string_t - pr_int_t noise2; //string_t - pr_int_t noise3; //string_t - pr_int_t dmg; //float - pr_int_t dmgtime; //float - pr_int_t air_finished; //float - pr_int_t pain_finished; //float - pr_int_t radsuit_finished; //float - pr_int_t speed; //float pr_int_t rotated_bbox; //int pr_int_t alpha; //float @@ -208,8 +186,13 @@ extern progs_t sv_pr_state; #define SVstring(e,f) SVFIELD (e, f, string) #define SVfunc(e,f) SVFIELD (e, f, func) #define SVentity(e,f) SVFIELD (e, f, entity) -#define SVvector(e,f) SVFIELD (e, f, vector) +#define SVvector(e,f) (&SVFIELD (e, f, vector)) #define SVinteger(e,f) SVFIELD (e, f, integer) +#if TYPECHECK_PROGS +#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__)) +#else +#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f) +#endif typedef struct edict_leaf_s { struct edict_leaf_s *next; diff --git a/nq/source/Makefile.am b/nq/source/Makefile.am deleted file mode 100644 index cb1f589ff..000000000 --- a/nq/source/Makefile.am +++ /dev/null @@ -1,177 +0,0 @@ -## Process this file with automake to produce Makefile.in -# -# Makefile.am -# -# Automake-using build system for QuakeForge -# -# Copyright (C) 2000 Jeff Teunissen -# -# This Makefile 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: -# -# Free Software Foundation, Inc. -# 59 Temple Place - Suite 330 -# Boston, MA 02111-1307, USA -# -# $Id$ -# -AUTOMAKE_OPTIONS= foreign - -# Stuff that is common to both client and server -# -AM_CPPFLAGS= -I$(top_srcdir)/include -I$(top_srcdir)/nq/include -SDL_LIBS = @SDL_LIBS@ -AM_CFLAGS= @PTHREAD_CFLAGS@ - -bin_PROGRAMS= @NQ_TARGETS@ - -EXTRA_PROGRAMS= nq-fbdev nq-sdl nq-svga nq-win nq-x11 nq-server - -noinst_LIBRARIES= @nq_libs@ -EXTRA_LIBRARIES=libnq_client.a libnq_common.a libnq_sdl.a libnq_server.a - -libnq_common_a_SOURCES=game.c world.c -libnq_sdl_a_SOURCES= sys_sdl.c -libnq_sdl_a_CFLAGS= $(SDL_CFLAGS) - -common_ldflags= -export-dynamic @PTHREAD_LDFLAGS@ - -cl_plugin_LIBS= \ - @server_static_plugin_libs@ \ - @client_static_plugin_libs@ - -client_LIBFILES= \ - $(top_builddir)/libs/video/targets/libQFjs.la \ - $(top_builddir)/libs/audio/libQFcd.la \ - $(top_builddir)/libs/audio/libQFsound.la - -server_LIBFILES= \ - @server_static_plugin_libs@ \ - $(top_builddir)/libs/models/libQFmodels.la - -common_LIBFILES= \ - $(top_builddir)/libs/net/libnet_main.la \ - $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/image/libQFimage.la \ - $(top_builddir)/libs/gib/libQFgib.la \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(top_builddir)/libs/util/libQFutil.la - -client_LIBS= $(client_LIBFILES) $(common_LIBFILES) - -server_LIBS= $(server_LIBFILES) $(common_LIBFILES) $(NET_LIBS) -server_LIB_DEPS=$(server_LIBFILES) $(common_LIBFILES) - -libnq_client_a_SOURCES= \ - cl_chase.c cl_cmd.c cl_demo.c cl_ents.c cl_input.c cl_main.c \ - cl_screen.c cl_parse.c cl_tent.c cl_view.c sbar.c - -libnq_server_a_SOURCES= \ - host.c host_cmd.c sv_cl_phys.c sv_cvar.c sv_main.c \ - sv_move.c sv_phys.c sv_pr_cmds.c sv_progs.c sv_user.c - -client_libs= libnq_server.a libnq_client.a libnq_common.a \ - $(top_builddir)/libs/client/libQFclient.la -server_libs = libnq_server.a libnq_common.a - -# Software-rendering targets - -# ... Linux FBDev -nq_fbdev_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFfbdev.la \ - $(client_LIBS) -nq_fbdev_SOURCES= sys_unix.c -nq_fbdev_LDADD= $(nq_fbdev_libs) $(NET_LIBS) -nq_fbdev_LDFLAGS= $(common_ldflags) -nq_fbdev_DEPENDENCIES= $(nq_fbdev_libs) - -# ... SDL, version 1.2 and higher -nq_sdl_libs= \ - libnq_sdl.a \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFsdl.la \ - $(client_LIBS) -nq_sdl_SOURCES=sdl_link.c -nq_sdl_LDADD= $(nq_sdl_libs) $(SDL_LIBS) $(NET_LIBS) -nq_sdl_LDFLAGS= $(common_ldflags) -nq_sdl_DEPENDENCIES= $(nq_sdl_libs) - -# ... Linux SVGAlib -nq_svga_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFsvga.la \ - $(client_LIBS) -nq_svga_SOURCES= sys_unix.c -nq_svga_LDADD= $(nq_svga_libs) $(SVGA_LIBS) $(NET_LIBS) -nq_svga_LDFLAGS= $(common_ldflags) -nq_svga_DEPENDENCIES= $(nq_svga_libs) - -# ... X11 -nq_x11_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFx11.la \ - $(client_LIBS) -nq_x11_SOURCES= sys_unix.c -nq_x11_LDADD= $(nq_x11_libs) \ - $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ - $(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(DL_LIBS) -nq_x11_LDFLAGS= $(common_ldflags) -nq_x11_DEPENDENCIES= $(nq_x11_libs) - -# OpenGL-using targets - -# ... Microsoft Windows -nq_win_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFwin.la \ - $(client_LIBS) -nq_win_SOURCES= sys_win.c -nq_win_LDADD= $(nq_win_libs) -lgdi32 -lcomctl32 -lwinmm $(NET_LIBS) -nq_win_LDFLAGS= $(common_ldflags) -nq_win_DEPENDENCIES= $(nq_win_libs) - -# Dedicated Server -if SYSTYPE_WIN32 -ded_sources= sys_wind.c sv_ded.c -else -ded_sources= sys_unixd.c sv_ded.c -endif -EXTRA_DIST=sys_wind.c sys_unixd.c sv_ded.c - -nq_server_LDFLAGS= $(common_ldflags) -nq_server_SOURCES= $(ded_sources) -nq_server_LDADD= $(server_libs) $(server_LIBS) -nq_server_DEPENDENCIES= $(server_libs) $(server_LIB_DEPS) - -# Stuff that doesn't get linked into an executable NEEDS to be mentioned here, -# or it won't be distributed with 'make dist' - -# Kill the temp files, hopefully. -CLEANFILES = *.i *.s $(YACCLEX_CLEANFILES) diff --git a/nq/source/Makemodule.am b/nq/source/Makemodule.am new file mode 100644 index 000000000..6caa9fe32 --- /dev/null +++ b/nq/source/Makemodule.am @@ -0,0 +1,165 @@ +## Process this file with automake to produce Makefile.in +# +# Makefile.am +# +# Automake-using build system for QuakeForge +# +# Copyright (C) 2000 Jeff Teunissen +# +# This Makefile 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: +# +# Free Software Foundation, Inc. +# 59 Temple Place - Suite 330 +# Boston, MA 02111-1307, USA +# +# $Id$ +# + +# Stuff that is common to both client and server +# +bin_PROGRAMS += @NQ_TARGETS@ + +EXTRA_PROGRAMS += nq-fbdev nq-sdl nq-svga nq-wgl nq-x11 nq-server + +noinst_LIBRARIES += @nq_libs@ +EXTRA_LIBRARIES += nq/source/libnq_client.a nq/source/libnq_common.a nq/source/libnq_sdl.a nq/source/libnq_server.a + +nq_source_libnq_common_a_SOURCES= nq/source/game.c nq/source/world.c +nq_source_libnq_sdl_a_SOURCES= nq/source/sys_sdl.c +nq_source_libnq_sdl_a_CFLAGS= $(SDL_CFLAGS) + +nq_cl_plugin_LIBS= \ + @server_static_plugin_libs@ \ + @client_static_plugin_libs@ + +nq_client_LIBFILES= \ + libs/entity/libQFentity.la \ + libs/video/targets/libQFjs.la \ + libs/audio/libQFcd.la \ + libs/audio/libQFsound.la + +nq_server_LIBFILES= \ + @server_static_plugin_libs@ \ + libs/models/libQFmodels.la + +nq_common_LIBFILES= \ + libs/net/libnet_main.la \ + libs/console/libQFconsole.la \ + libs/image/libQFimage.la \ + libs/gib/libQFgib.la \ + libs/ruamoko/libQFruamoko.la \ + libs/gamecode/libQFgamecode.la \ + libs/util/libQFutil.la + +nq_client_LIBS= $(nq_client_LIBFILES) $(nq_common_LIBFILES) + +nq_server_LIBS= $(nq_server_LIBFILES) $(nq_common_LIBFILES) $(NET_LIBS) +nq_server_LIB_DEPS=$(nq_server_LIBFILES) $(nq_common_LIBFILES) + +nq_source_libnq_client_a_SOURCES= \ + nq/source/cl_chase.c nq/source/cl_cmd.c nq/source/cl_demo.c nq/source/cl_ents.c nq/source/cl_input.c nq/source/cl_main.c \ + nq/source/cl_screen.c nq/source/cl_parse.c nq/source/cl_view.c nq/source/sbar.c + +nq_source_libnq_server_a_SOURCES= \ + nq/source/host.c nq/source/host_cmd.c nq/source/sv_cl_phys.c nq/source/sv_cvar.c nq/source/sv_main.c \ + nq/source/sv_move.c nq/source/sv_phys.c nq/source/sv_pr_cmds.c nq/source/sv_progs.c nq/source/sv_user.c + +nq_client_libs= nq/source/libnq_server.a nq/source/libnq_client.a nq/source/libnq_common.a \ + libs/client/libQFclient.la +server_libs = nq/source/libnq_server.a nq/source/libnq_common.a + +# Software-rendering targets + +# ... Linux FBDev +nq_fbdev_libs= \ + $(nq_client_libs) \ + $(nq_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFfbdev.la \ + $(nq_client_LIBS) +nq_fbdev_SOURCES= nq/source/sys_unix.c +nq_fbdev_LDADD= $(nq_fbdev_libs) $(NET_LIBS) +nq_fbdev_LDFLAGS= $(common_ldflags) +nq_fbdev_DEPENDENCIES= $(nq_fbdev_libs) + +# ... SDL, version 1.2 and higher +nq_sdl_libs= \ + nq/source/libnq_sdl.a \ + $(nq_client_libs) \ + $(nq_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFsdl.la \ + $(nq_client_LIBS) +nq_sdl_SOURCES=nq/source/sdl_link.c +nq_sdl_LDADD= $(nq_sdl_libs) $(SDL_LIBS) $(NET_LIBS) +nq_sdl_LDFLAGS= $(common_ldflags) +nq_sdl_DEPENDENCIES= $(nq_sdl_libs) + +# ... Linux SVGAlib +nq_svga_libs= \ + $(nq_client_libs) \ + $(nq_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFsvga.la \ + $(nq_client_LIBS) +nq_svga_SOURCES= nq/source/sys_unix.c +nq_svga_LDADD= $(nq_svga_libs) $(SVGA_LIBS) $(NET_LIBS) +nq_svga_LDFLAGS= $(common_ldflags) +nq_svga_DEPENDENCIES= $(nq_svga_libs) + +# ... X11 +nq_x11_libs= \ + $(nq_client_libs) \ + $(nq_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFx11.la \ + $(nq_client_LIBS) +nq_x11_SOURCES= nq/source/sys_unix.c +nq_x11_LDADD= $(nq_x11_libs) \ + $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ + $(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(DL_LIBS) +nq_x11_LDFLAGS= $(common_ldflags) +nq_x11_DEPENDENCIES= $(nq_x11_libs) + +# OpenGL-using targets + +# ... SGI/Microsoft WGL (Windows OpenGL) +nq_wgl_libs= \ + $(nq_client_libs) \ + $(nq_cl_plugin_LIBS) \ + $(opengl_QFLIBS) \ + libs/video/targets/libQFwgl.la \ + $(nq_client_LIBS) +nq_wgl_SOURCES= nq/source/sys_win.c +nq_wgl_LDADD= $(nq_wgl_libs) -lgdi32 -lcomctl32 -lwinmm $(NET_LIBS) +nq_wgl_LDFLAGS= $(common_ldflags) +nq_wgl_DEPENDENCIES= $(nq_wgl_libs) + +# Dedicated Server +if SYSTYPE_WIN32 +ded_sources= nq/source/sys_wind.c nq/source/sv_ded.c +else +ded_sources= nq/source/sys_unixd.c nq/source/sv_ded.c +endif +EXTRA_DIST += nq/source/sys_wind.c nq/source/sys_unixd.c nq/source/sv_ded.c + +nq_server_LDFLAGS= $(common_ldflags) +nq_server_SOURCES= $(ded_sources) +nq_server_LDADD= $(server_libs) $(nq_server_LIBS) +nq_server_DEPENDENCIES= $(server_libs) $(nq_server_LIB_DEPS) diff --git a/nq/source/cl_chase.c b/nq/source/cl_chase.c index c492ff609..6f0c430c6 100644 --- a/nq/source/cl_chase.c +++ b/nq/source/cl_chase.c @@ -41,15 +41,19 @@ #include "QF/mathlib.h" #include "QF/plugin/vid_render.h" +#include "QF/simd/vec4f.h" -#include "chase.h" -#include "client.h" #include "world.h" -vec3_t camera_origin = {0,0,0}; -vec3_t camera_angles = {0,0,0}; -vec3_t player_origin = {0,0,0}; -vec3_t player_angles = {0,0,0}; +#include "nq/include/chase.h" +#include "nq/include/client.h" + + +vec4f_t camera_origin = {0,0,0,1}; +vec4f_t player_origin = {0,0,0,1}; +vec4f_t player_angles = {0,0,0,1}; + +vec3_t camera_angles = {0,0,0}; vec3_t chase_angles; vec3_t chase_dest; @@ -85,7 +89,7 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) memset (&trace, 0, sizeof (trace)); trace.fraction = 1; - MOD_TraceLine (cl.worldmodel->hulls, 0, start, end, &trace); + MOD_TraceLine (cl.worldmodel->brush.hulls, 0, start, end, &trace); VectorCopy (trace.endpos, impact); } @@ -93,19 +97,17 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) void Chase_Update (void) { - float pitch, yaw, fwd; - int i; - usercmd_t cmd; // movement direction - vec3_t forward, up, right, stop, dir; + float pitch, yaw, fwd; + usercmd_t cmd; // movement direction + vec4f_t forward = {}, up = {}, right = {}, stop = {}, dir = {}; // lazy camera, look toward player entity if (chase_active->int_val == 2 || chase_active->int_val == 3) { // control camera angles with key/mouse/joy-look - - camera_angles[PITCH] += cl.viewangles[PITCH] - player_angles[PITCH]; - camera_angles[YAW] += cl.viewangles[YAW] - player_angles[YAW]; - camera_angles[ROLL] += cl.viewangles[ROLL] - player_angles[ROLL]; + vec3_t d; + VectorSubtract (cl.viewstate.angles, player_angles, d); + VectorAdd (camera_angles, d, camera_angles); if (chase_active->int_val == 2) { if (camera_angles[PITCH] < -60) @@ -117,48 +119,48 @@ Chase_Update (void) // move camera, it's not enough to just change the angles because // the angles are automatically changed to look toward the player - if (chase_active->int_val == 3) - VectorCopy (r_data->refdef->vieworg, player_origin); + if (chase_active->int_val == 3) { + player_origin = r_data->refdef->viewposition; + } - AngleVectors (camera_angles, forward, right, up); - VectorScale (forward, chase_back->value, forward); - VectorSubtract (player_origin, forward, camera_origin); + AngleVectors (camera_angles, &forward[0], &right[0], &up[0]); + camera_origin = player_origin - chase_back->value * forward; if (chase_active->int_val == 2) { - VectorCopy (r_data->refdef->vieworg, player_origin); + player_origin = r_data->refdef->viewposition; // don't let camera get too low - if (camera_origin[2] < player_origin[2] + chase_up->value) + if (camera_origin[2] < player_origin[2] + chase_up->value) { camera_origin[2] = player_origin[2] + chase_up->value; + } } // don't let camera get too far from player - VectorSubtract (camera_origin, player_origin, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - player_origin; + forward = normalf (dir); - if (VectorLength (dir) > chase_back->value) { - VectorScale (forward, chase_back->value, dir); - VectorAdd (player_origin, dir, camera_origin); + if (magnitudef (dir)[0] > chase_back->value) { + camera_origin = player_origin + forward * chase_back->value; } // check for walls between player and camera - VectorScale (forward, 8, forward); - VectorAdd (camera_origin, forward, camera_origin); - TraceLine (player_origin, camera_origin, stop); - if (VectorLength (stop) != 0) - VectorSubtract (stop, forward, camera_origin); + camera_origin += 8 * forward; + //FIXME + TraceLine (&player_origin[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop - forward; + } - VectorSubtract (camera_origin, r_data->refdef->vieworg, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - r_data->refdef->viewposition; + forward = normalf (dir); if (chase_active->int_val == 2) { if (dir[1] == 0 && dir[0] == 0) { // look straight up or down -// camera_angles[YAW] = r_data->refdef->viewangles[YAW]; +// camera_angles[YAW] = r_data->refdef->viewstate.angles[YAW]; if (dir[2] > 0) camera_angles[PITCH] = 90; else @@ -181,13 +183,13 @@ Chase_Update (void) } } - VectorCopy (camera_angles, r_data->refdef->viewangles);// rotate camera - VectorCopy (camera_origin, r_data->refdef->vieworg); // move camera + AngleQuat (camera_angles, &r_data->refdef->viewrotation[0]);//FIXME rotate camera + r_data->refdef->viewposition = camera_origin; // move camera // get basic movement from keyboard memset (&cmd, 0, sizeof (cmd)); -// VectorCopy (cl.viewangles, cmd.angles); +// VectorCopy (cl.viewstate.angles, cmd.angles); if (in_strafe.state & 1) { cmd.sidemove += cl_sidespeed->value * CL_KeyState (&in_right); @@ -207,54 +209,54 @@ Chase_Update (void) } // mouse and joystick controllers add to movement - VectorSet (0, cl.viewangles[1] - camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); - VectorScale (forward, viewdelta.position[2] * m_forward->value, - forward); - VectorScale (right, viewdelta.position[0] * m_side->value, right); - VectorAdd (forward, right, dir); + VectorSet (0, cl.viewstate.angles[1] - camera_angles[1], 0, dir); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME + forward *= viewdelta.position[2] * m_forward->value; + right *= viewdelta.position[0] * m_side->value; + dir = forward + right; cmd.forwardmove += dir[0]; cmd.sidemove -= dir[1]; VectorSet (0, camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME VectorScale (forward, cmd.forwardmove, forward); VectorScale (right, cmd.sidemove, right); VectorAdd (forward, right, dir); if (dir[1] || dir[0]) { - cl.viewangles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); - if (cl.viewangles[YAW] < 0) cl.viewangles[YAW] += 360; -// if (cl.viewangles[YAW] < 180) -// cl.viewangles[YAW] += 180; -// else -// cl.viewangles[YAW] -= 180; + cl.viewstate.angles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); + if (cl.viewstate.angles[YAW] < 0) { + cl.viewstate.angles[YAW] += 360; + } } - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; // remember the new angle to calculate the difference next frame - VectorCopy (cl.viewangles, player_angles); + VectorCopy (cl.viewstate.angles, player_angles); return; } // regular camera, faces same direction as player - AngleVectors (cl.viewangles, forward, right, up); + //FIXME + AngleVectors (cl.viewstate.angles, &forward[0], &right[0], &up[0]); // calc exact destination - for (i = 0; i < 3; i++) - camera_origin[i] = r_data->refdef->vieworg[i] - - forward[i] * chase_back->value - right[i] * chase_right->value; + camera_origin = r_data->refdef->viewposition + - forward * chase_back->value - right * chase_right->value; + // chase_up is world up camera_origin[2] += chase_up->value; // check for walls between player and camera - TraceLine (r_data->refdef->vieworg, camera_origin, stop); - if (VectorLength (stop) != 0) - for (i = 0; i < 3; i++) - camera_origin[i] = stop[i] + forward[i] * 8; + //FIXME + TraceLine (&r_data->refdef->viewposition[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop + forward * 8; + } - VectorCopy (camera_origin, r_data->refdef->vieworg); + r_data->refdef->viewposition = camera_origin; } diff --git a/nq/source/cl_cmd.c b/nq/source/cl_cmd.c index fabc6e226..33689dc5e 100644 --- a/nq/source/cl_cmd.c +++ b/nq/source/cl_cmd.c @@ -40,7 +40,7 @@ #include "QF/sizebuf.h" #include "QF/sys.h" -#include "client.h" +#include "nq/include/client.h" /* diff --git a/nq/source/cl_demo.c b/nq/source/cl_demo.c index 026c59fbb..03950998a 100644 --- a/nq/source/cl_demo.c +++ b/nq/source/cl_demo.c @@ -46,9 +46,10 @@ #include "QF/sys.h" #include "QF/va.h" -#include "client.h" #include "compat.h" -#include "host.h" + +#include "nq/include/client.h" +#include "nq/include/host.h" typedef struct { int frames; @@ -56,15 +57,15 @@ typedef struct { double fps; } td_stats_t; -int demo_timeframes_isactive; -int demo_timeframes_index; -char demoname[1024]; -double *demo_timeframes_array; +static int demo_timeframes_isactive; +static int demo_timeframes_index; +static dstring_t *demoname; +static double *demo_timeframes_array; #define CL_TIMEFRAMES_ARRAYBLOCK 4096 -int timedemo_count; -int timedemo_runs; -td_stats_t *timedemo_data; +static int timedemo_count; +static int timedemo_runs; +static td_stats_t *timedemo_data; static void CL_FinishTimeDemo (void); static void CL_TimeFrames_DumpLog (void); @@ -104,7 +105,7 @@ CL_WriteDemoMessage (sizebuf_t *msg) len = LittleLong (msg->cursize); Qwrite (cls.demofile, &len, 4); for (i = 0; i < 3; i++) { - f = LittleFloat (cl.viewangles[i]); + f = LittleFloat (cl.viewstate.angles[i]); Qwrite (cls.demofile, &f, 4); } Qwrite (cls.demofile, msg->data, msg->cursize); @@ -181,10 +182,14 @@ read_demopacket (void) if (net_message->message->cursize > MAX_DEMMSG) Host_Error ("Demo message > MAX_DEMMSG: %d/%d", net_message->message->cursize, MAX_DEMMSG); - VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); + VectorCopy (cl.frameViewAngles[0], cl.frameViewAngles[1]); for (i = 0; i < 3; i++) { r = Qread (cls.demofile, &f, 4); - cl.mviewangles[0][i] = LittleFloat (f); + if (r != 4) { + CL_StopPlayback (); + return 0; + } + cl.frameViewAngles[0][i] = LittleFloat (f); } r = Qread (cls.demofile, net_message->message->data, net_message->message->cursize); @@ -307,7 +312,7 @@ CL_Record_f (void) // start up the map if (c > 2) - Cmd_ExecuteString (va ("map %s", Cmd_Argv (2)), src_command); + Cmd_ExecuteString (va (0, "map %s", Cmd_Argv (2)), src_command); CL_Record (Cmd_Argv (1), track); } @@ -333,7 +338,7 @@ demo_default_name (const char *argv1) strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); // the leading path-name is to be removed from cl.worldmodel->name - mapname = QFS_SkipPath (cl.worldmodel->name); + mapname = QFS_SkipPath (cl.worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended @@ -450,7 +455,7 @@ CL_StartDemo (void) CL_Disconnect (); // open the demo file - name = dstring_strdup (demoname); + name = dstring_strdup (demoname->str); QFS_DefaultExtension (name, ".dem"); Sys_Printf ("Playing demo from %s.\n", name->str); @@ -499,7 +504,7 @@ CL_PlayDemo_f (void) switch (Cmd_Argc ()) { case 1: - if (!demoname[0]) + if (!demoname->str[0]) goto playdemo_error; // fall through case 2: @@ -519,7 +524,7 @@ playdemo_error: timedemo_runs = timedemo_count = 1; // make sure looped timedemos stop if (Cmd_Argc () > 1) - strncpy (demoname, Cmd_Argv (1), sizeof (demoname)); + dstring_copystr (demoname, Cmd_Argv (1)); CL_StartDemo (); } @@ -627,7 +632,7 @@ CL_TimeDemo_f (void) timedemo_data = 0; } timedemo_data = calloc (timedemo_runs, sizeof (td_stats_t)); - strncpy (demoname, Cmd_Argv (1), sizeof (demoname)); + dstring_copystr (demoname, Cmd_Argv (1)); CL_StartTimeDemo (); timedemo_runs = timedemo_count = max (count, 1); timedemo_data = calloc (timedemo_runs, sizeof (td_stats_t)); @@ -636,6 +641,7 @@ CL_TimeDemo_f (void) void CL_Demo_Init (void) { + demoname = dstring_newstr (); demo_timeframes_isactive = 0; demo_timeframes_index = 0; demo_timeframes_array = NULL; diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index b6bac93cd..79a0f9234 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -32,10 +32,11 @@ #include "QF/cmd.h" #include "QF/console.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/input.h" #include "QF/keys.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/screen.h" #include "QF/skin.h" @@ -44,12 +45,16 @@ #include "QF/plugin/vid_render.h" -#include "chase.h" -#include "client.h" #include "compat.h" -#include "host.h" -#include "host.h" -#include "server.h" + +#include "client/effects.h" +#include "client/temp_entities.h" + +#include "nq/include/chase.h" +#include "nq/include/client.h" +#include "nq/include/host.h" +#include "nq/include/host.h" +#include "nq/include/server.h" entity_t cl_entities[MAX_EDICTS]; double cl_msgtime[MAX_EDICTS]; @@ -60,82 +65,15 @@ CL_ClearEnts (void) { size_t i; + for (i = 0; i < MAX_EDICTS; i++) { + CL_Init_Entity (cl_entities + i); + } + // clear other arrays - memset (cl_entities, 0, sizeof (cl_entities)); i = nq_entstates.num_frames * nq_entstates.num_entities; memset (nq_entstates.frame[0], 0, i * sizeof (entity_state_t)); memset (cl_msgtime, 0, sizeof (cl_msgtime)); memset (cl_forcelink, 0, sizeof (cl_forcelink)); - - for (i = 0; i < MAX_EDICTS; i++) - CL_Init_Entity (cl_entities + i); -} - -static void -CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, - byte glow_color) -{ - float radius; - dlight_t *dl; - static quat_t normal = {0.4, 0.2, 0.05, 0.7}; - static quat_t red = {0.5, 0.05, 0.05, 0.7}; - static quat_t blue = {0.05, 0.05, 0.5, 0.7}; - static quat_t purple = {0.5, 0.05, 0.5, 0.7}; - - effects &= EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT; - if (!effects) { - if (!glow_size) - return; - } - - dl = r_funcs->R_AllocDlight (key); - if (!dl) - return; - VectorCopy (org, dl->origin); - - if (effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT)) { - radius = 200 + (rand () & 31); - if (effects & EF_BRIGHTLIGHT) { - radius += 200; - dl->origin[2] += 16; - } - if (effects & EF_DIMLIGHT) - if (effects & ~EF_DIMLIGHT) - radius -= 100; - dl->radius = radius; - dl->die = cl.time + 0.1; - - switch (effects & (EF_RED | EF_BLUE)) { - case EF_RED | EF_BLUE: - QuatCopy (purple, dl->color); - break; - case EF_RED: - QuatCopy (red, dl->color); - break; - case EF_BLUE: - QuatCopy (blue, dl->color); - break; - default: - QuatCopy (normal, dl->color); - break; - } - } - - if (glow_size) { - dl->radius += glow_size < 128 ? glow_size * 8.0 : - (glow_size - 256) * 8.0; - dl->die = cl.time + 0.1; - if (glow_color) { - if (glow_color == 255) { - dl->color[0] = dl->color[1] = dl->color[2] = 1.0; - } else { - byte *tempcolor; - - tempcolor = (byte *) &d_8to24table[glow_color]; - VectorScale (tempcolor, 1 / 255.0, dl->color); - } - } - } } /* @@ -175,114 +113,28 @@ CL_LerpPoint (void) return frac; } -void -CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force) -{ - vec3_t ang; - vec_t *forward, *left, *up; - - if (VectorIsZero (angles)) { - VectorSet (1, 0, 0, ent->transform + 0); - VectorSet (0, 1, 0, ent->transform + 4); - VectorSet (0, 0, 1, ent->transform + 8); - } else if (force || !VectorCompare (angles, ent->angles)) { - forward = ent->transform + 0; - left = ent->transform + 4; - up = ent->transform + 8; - VectorCopy (angles, ang); - if (ent->model && ent->model->type == mod_alias) { - // stupid quake bug - // why, oh, why, do alias models pitch in the opposite direction - // to everything else? - ang[PITCH] = -ang[PITCH]; - } - AngleVectors (ang, forward, left, up); - VectorNegate (left, left); // AngleVectors is right-handed - } - VectorCopy (angles, ent->angles); - ent->transform[3] = 0; - ent->transform[7] = 0; - ent->transform[11] = 0; - VectorCopy (ent->origin, ent->transform + 12); - ent->transform[15] = 1; -} - -static void -CL_ModelEffects (entity_t *ent, int num, int glow_color) -{ - dlight_t *dl; - model_t *model = ent->model; - - if (model->flags & EF_ROCKET) { - dl = r_funcs->R_AllocDlight (num); - if (dl) { - VectorCopy (ent->origin, dl->origin); - dl->radius = 200.0; - dl->die = cl.time + 0.1; - //FIXME VectorCopy (r_firecolor->vec, dl->color); - VectorSet (0.9, 0.7, 0.0, dl->color); - dl->color[3] = 0.7; - } - r_funcs->particles->R_RocketTrail (ent); - } else if (model->flags & EF_GRENADE) - r_funcs->particles->R_GrenadeTrail (ent); - else if (model->flags & EF_GIB) - r_funcs->particles->R_BloodTrail (ent); - else if (model->flags & EF_ZOMGIB) - r_funcs->particles->R_SlightBloodTrail (ent); - else if (model->flags & EF_TRACER) - r_funcs->particles->R_WizTrail (ent); - else if (model->flags & EF_TRACER2) - r_funcs->particles->R_FlameTrail (ent); - else if (model->flags & EF_TRACER3) - r_funcs->particles->R_VoorTrail (ent); - else if (model->flags & EF_GLOWTRAIL) - if (r_funcs->particles->R_GlowTrail) - r_funcs->particles->R_GlowTrail (ent, glow_color); -} - -static void -CL_EntityEffects (int num, entity_t *ent, entity_state_t *state) -{ - dlight_t *dl; - - if (state->effects & EF_BRIGHTFIELD) - r_funcs->particles->R_EntityParticles (ent); - if (state->effects & EF_MUZZLEFLASH) { - vec_t *fv = ent->transform; - - dl = r_funcs->R_AllocDlight (num); - if (dl) { - VectorMultAdd (ent->origin, 18, fv, dl->origin); - dl->origin[2] += 16; - dl->radius = 200 + (rand () & 31); - dl->die = cl.time + 0.1; - dl->minlight = 32; - dl->color[0] = 0.2; - dl->color[1] = 0.1; - dl->color[2] = 0.05; - dl->color[3] = 0.7; - } - } -} - static void set_entity_model (entity_t *ent, int modelindex) { int i = ent - cl_entities; - ent->model = cl.model_precache[modelindex]; + renderer_t *renderer = &ent->renderer; + animation_t *animation = &ent->animation; + renderer->model = cl.model_precache[modelindex]; // automatic animation (torches, etc) can be either all together // or randomized - if (ent->model) { - if (ent->model->synctype == ST_RAND) - ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff; - else - ent->syncbase = 0.0; + if (renderer->model) { + if (renderer->model->synctype == ST_RAND) { + animation->syncbase = (float) (rand () & 0x7fff) / 0x7fff; + } else { + animation->syncbase = 0.0; + } } else { cl_forcelink[i] = true; // hack to make null model players work } - if (i <= cl.maxclients) - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, i); + animation->nolerp = 1; // don't try to lerp when the model has changed + if (i <= cl.maxclients) { + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, i); + } } void @@ -290,10 +142,11 @@ CL_RelinkEntities (void) { entity_t *ent; entity_state_t *new, *old; - float bobjrotate, frac, f, d; + renderer_t *renderer; + animation_t *animation; + float bobjrotate, frac, f; int i, j; int entvalid; - vec3_t delta; int model_flags; r_data->player_entity = &cl_entities[cl.viewentity]; @@ -302,41 +155,46 @@ CL_RelinkEntities (void) frac = CL_LerpPoint (); // interpolate player info - for (i = 0; i < 3; i++) - cl.velocity[i] = cl.mvelocity[1][i] + - frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + cl.viewstate.velocity = cl.frameVelocity[1] + + frac * (cl.frameVelocity[0] - cl.frameVelocity[1]); if (cls.demoplayback) { // interpolate the angles + vec3_t d; + VectorSubtract (cl.frameViewAngles[0], cl.frameViewAngles[1], d); for (j = 0; j < 3; j++) { - d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; - if (d > 180) - d -= 360; - else if (d < -180) - d += 360; - cl.viewangles[j] = cl.mviewangles[1][j] + frac * d; + if (d[j] > 180) { + d[j] -= 360; + } else if (d[j] < -180) { + d[j] += 360; + } } + VectorMultAdd (cl.frameViewAngles[1], frac, d, cl.viewstate.angles); } bobjrotate = anglemod (100 * cl.time); // start on the entity after the world for (i = 1; i < cl.num_entities; i++) { - new = &nq_entstates.frame[0 + cl.mindex][i]; - old = &nq_entstates.frame[1 - cl.mindex][i]; + new = &nq_entstates.frame[0 + cl.frameIndex][i]; + old = &nq_entstates.frame[1 - cl.frameIndex][i]; ent = &cl_entities[i]; + renderer = &ent->renderer; + animation = &ent->animation; + // if the object wasn't included in the last packet, remove it entvalid = cl_msgtime[i] == cl.mtime[0]; if (entvalid && !new->modelindex) { - VectorCopy (new->origin, ent->origin); - VectorCopy (new->angles, ent->angles); + CL_TransformEntity (ent, new->scale / 16.0, new->angles, + new->origin); entvalid = 0; } if (!entvalid) { - ent->model = NULL; - ent->pose1 = ent->pose2 = -1; - if (ent->efrag) + renderer->model = NULL; + animation->pose1 = animation->pose2 = -1; + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); // just became empty + } continue; } @@ -347,58 +205,59 @@ CL_RelinkEntities (void) old->modelindex = new->modelindex; set_entity_model (ent, new->modelindex); } - ent->frame = new->frame; + animation->frame = new->frame; if (cl_forcelink[i] || new->colormap != old->colormap) { old->colormap = new->colormap; - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, new->colormap); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + new->colormap); } if (cl_forcelink[i] || new->skinnum != old->skinnum) { old->skinnum = new->skinnum; - ent->skinnum = new->skinnum; + renderer->skinnum = new->skinnum; if (i <= cl.maxclients) { - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, i); - mod_funcs->Skin_SetTranslation (i, cl.scores[i - 1].topcolor, - cl.scores[i - 1].bottomcolor); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + i); + mod_funcs->Skin_SetTranslation (i, cl.players[i - 1].topcolor, + cl.players[i - 1].bottomcolor); } } - ent->scale = new->scale / 16.0; - VectorCopy (ent_colormod[new->colormod], ent->colormod); - ent->colormod[3] = ENTALPHA_DECODE (new->alpha); + VectorCopy (ent_colormod[new->colormod], renderer->colormod); + renderer->colormod[3] = ENTALPHA_DECODE (new->alpha); model_flags = 0; - if (ent->model) - model_flags = ent->model->flags; + if (renderer->model) { + model_flags = renderer->model->flags; + } if (cl_forcelink[i]) { // The entity was not updated in the last message so move to the // final spot - ent->pose1 = ent->pose2 = -1; - VectorCopy (new->origin, ent->origin); - if (!(model_flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles, true); + animation->pose1 = animation->pose2 = -1; + CL_TransformEntity (ent, new->scale / 16.0, new->angles, + new->origin); if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + } + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } - VectorCopy (ent->origin, ent->old_origin); + ent->old_origin = new->origin; } else { + vec4f_t delta = new->origin - old->origin; f = frac; - VectorCopy (ent->origin, ent->old_origin); - VectorSubtract (new->origin, old->origin, delta); + ent->old_origin = Transform_GetWorldPosition (ent->transform); // If the delta is large, assume a teleport and don't lerp if (fabs (delta[0]) > 100 || fabs (delta[1] > 100) || fabs (delta[2]) > 100) { // assume a teleportation, not a motion - VectorCopy (new->origin, ent->origin); - if (!(model_flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles, true); - ent->pose1 = ent->pose2 = -1; + CL_TransformEntity (ent, new->scale / 16.0, new->angles, + new->origin); + animation->pose1 = animation->pose2 = -1; } else { - vec3_t angles, d; // interpolate the origin and angles - VectorMultAdd (old->origin, f, delta, ent->origin); + vec3_t angles, d; + vec4f_t origin = old->origin + f * delta; if (!(model_flags & EF_ROTATE)) { VectorSubtract (new->angles, old->angles, d); for (j = 0; j < 3; j++) { @@ -408,17 +267,19 @@ CL_RelinkEntities (void) d[j] += 360; } VectorMultAdd (old->angles, f, d, angles); - CL_TransformEntity (ent, angles, false); } + CL_TransformEntity (ent, new->scale / 16.0, angles, origin); } if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) { - if (!VectorCompare (ent->origin, ent->old_origin)) { + if (ent->visibility.efrag) { + vec4f_t org + = Transform_GetWorldPosition (ent->transform); + if (!VectorCompare (org, ent->old_origin)) {//FIXME r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } else { - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } } @@ -428,16 +289,20 @@ CL_RelinkEntities (void) vec3_t angles; VectorCopy (new->angles, angles); angles[YAW] = bobjrotate; - CL_TransformEntity (ent, angles, false); + CL_TransformEntity (ent, new->scale / 16.0, angles, new->origin); + } + CL_EntityEffects (i, ent, new, cl.time); + vec4f_t org = Transform_GetWorldPosition (ent->transform); + CL_NewDlight (i, org, new->effects, new->glow_size, + new->glow_color, cl.time); + if (VectorDistance_fast (old->origin, org) > (256 * 256)) { + old->origin = org; } - CL_EntityEffects (i, ent, new); - CL_NewDlight (i, ent->origin, new->effects, new->glow_size, - new->glow_color); - if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) - VectorCopy (ent->origin, old->origin); if (model_flags & ~EF_ROTATE) - CL_ModelEffects (ent, i, new->glow_color); + CL_ModelEffects (ent, i, new->glow_color, cl.time); cl_forcelink[i] = false; } + cl.viewstate.origin + = Transform_GetWorldPosition (cl_entities[cl.viewentity].transform); } diff --git a/nq/source/cl_input.c b/nq/source/cl_input.c index f4d175723..58787e7e7 100644 --- a/nq/source/cl_input.c +++ b/nq/source/cl_input.c @@ -44,10 +44,11 @@ #include "QF/plugin/vid_render.h" -#include "chase.h" -#include "client.h" #include "compat.h" -#include "host.h" + +#include "nq/include/chase.h" +#include "nq/include/client.h" +#include "nq/include/host.h" /* KEY BUTTONS @@ -76,8 +77,9 @@ int in_impulse; void (*write_angles) (sizebuf_t *sb, const vec3_t angles); static void -KeyPress (kbutton_t *b) +KeyPress (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -106,8 +108,9 @@ KeyPress (kbutton_t *b) } static void -KeyRelease (kbutton_t *b) +KeyRelease (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -140,25 +143,7 @@ KeyRelease (kbutton_t *b) } static void -IN_KLookPress (void) -{ - KeyPress (&in_klook); -} - -static void -IN_KLookRelease (void) -{ - KeyRelease (&in_klook); -} - -static void -IN_MLookPress (void) -{ - KeyPress (&in_mlook); -} - -static void -IN_MLookRelease (void) +IN_MLookRelease (void *data) { KeyRelease (&in_mlook); if (!freelook && lookspring->int_val) @@ -166,187 +151,7 @@ IN_MLookRelease (void) } static void -IN_UpPress (void) -{ - KeyPress (&in_up); -} - -static void -IN_UpRelease (void) -{ - KeyRelease (&in_up); -} - -static void -IN_DownPress (void) -{ - KeyPress (&in_down); -} - -static void -IN_DownRelease (void) -{ - KeyRelease (&in_down); -} - -static void -IN_LeftPress (void) -{ - KeyPress (&in_left); -} - -static void -IN_LeftRelease (void) -{ - KeyRelease (&in_left); -} - -static void -IN_RightPress (void) -{ - KeyPress (&in_right); -} - -static void -IN_RightRelease (void) -{ - KeyRelease (&in_right); -} - -static void -IN_ForwardPress (void) -{ - KeyPress (&in_forward); -} - -static void -IN_ForwardRelease (void) -{ - KeyRelease (&in_forward); -} - -static void -IN_BackPress (void) -{ - KeyPress (&in_back); -} - -static void -IN_BackRelease (void) -{ - KeyRelease (&in_back); -} - -static void -IN_LookupPress (void) -{ - KeyPress (&in_lookup); -} - -static void -IN_LookupRelease (void) -{ - KeyRelease (&in_lookup); -} - -static void -IN_LookdownPress (void) -{ - KeyPress (&in_lookdown); -} - -static void -IN_LookdownRelease (void) -{ - KeyRelease (&in_lookdown); -} - -static void -IN_MoveleftPress (void) -{ - KeyPress (&in_moveleft); -} - -static void -IN_MoveleftRelease (void) -{ - KeyRelease (&in_moveleft); -} - -static void -IN_MoverightPress (void) -{ - KeyPress (&in_moveright); -} - -static void -IN_MoverightRelease (void) -{ - KeyRelease (&in_moveright); -} - -static void -IN_SpeedPress (void) -{ - KeyPress (&in_speed); -} - -static void -IN_SpeedRelease (void) -{ - KeyRelease (&in_speed); -} - -static void -IN_StrafePress (void) -{ - KeyPress (&in_strafe); -} - -static void -IN_StrafeRelease (void) -{ - KeyRelease (&in_strafe); -} - -static void -IN_AttackPress (void) -{ - KeyPress (&in_attack); -} - -static void -IN_AttackRelease (void) -{ - KeyRelease (&in_attack); -} - -static void -IN_UsePress (void) -{ - KeyPress (&in_use); -} - -static void -IN_UseRelease (void) -{ - KeyRelease (&in_use); -} - -static void -IN_JumpPress (void) -{ - KeyPress (&in_jump); -} - -static void -IN_JumpRelease (void) -{ - KeyRelease (&in_jump); -} - -static void -IN_Impulse (void) +IN_Impulse (void *data) { in_impulse = atoi (Cmd_Argv (1)); } @@ -437,35 +242,35 @@ CL_AdjustAngles (void) yawspeed *= host_frametime; if (!(in_strafe.state & 1)) { - cl.viewangles[YAW] -= yawspeed * CL_KeyState (&in_right); - cl.viewangles[YAW] += yawspeed * CL_KeyState (&in_left); - cl.viewangles[YAW] = anglemod (cl.viewangles[YAW]); + cl.viewstate.angles[YAW] -= yawspeed * CL_KeyState (&in_right); + cl.viewstate.angles[YAW] += yawspeed * CL_KeyState (&in_left); + cl.viewstate.angles[YAW] = anglemod (cl.viewstate.angles[YAW]); } if (in_klook.state & 1) { V_StopPitchDrift (); - cl.viewangles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); - cl.viewangles[PITCH] += pitchspeed * CL_KeyState (&in_back); + cl.viewstate.angles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); + cl.viewstate.angles[PITCH] += pitchspeed * CL_KeyState (&in_back); } up = CL_KeyState (&in_lookup); down = CL_KeyState (&in_lookdown); - cl.viewangles[PITCH] -= pitchspeed * up; - cl.viewangles[PITCH] += pitchspeed * down; + cl.viewstate.angles[PITCH] -= pitchspeed * up; + cl.viewstate.angles[PITCH] += pitchspeed * down; if (up || down) V_StopPitchDrift (); // FIXME: Need to clean up view angle limits - if (cl.viewangles[PITCH] > 80) - cl.viewangles[PITCH] = 80; - if (cl.viewangles[PITCH] < -70) - cl.viewangles[PITCH] = -70; + if (cl.viewstate.angles[PITCH] > 80) + cl.viewstate.angles[PITCH] = 80; + if (cl.viewstate.angles[PITCH] < -70) + cl.viewstate.angles[PITCH] = -70; - if (cl.viewangles[ROLL] > 50) - cl.viewangles[ROLL] = 50; - if (cl.viewangles[ROLL] < -50) - cl.viewangles[ROLL] = -50; + if (cl.viewstate.angles[ROLL] > 50) + cl.viewstate.angles[ROLL] = 50; + if (cl.viewstate.angles[ROLL] < -50) + cl.viewstate.angles[ROLL] = -50; } /* @@ -476,8 +281,9 @@ CL_AdjustAngles (void) void CL_BaseMove (usercmd_t *cmd) { - if (cls.state != ca_active) + if (cls.state != ca_active) { return; + } CL_AdjustAngles (); @@ -515,12 +321,13 @@ CL_BaseMove (usercmd_t *cmd) IN_Move (); // adjust for chase camera angles + /*FIXME:chase figure out just what this does and get it working if (cl.chase && (chase_active->int_val == 2 || chase_active->int_val == 3)) { vec3_t forward, right, up, f, r; vec3_t dir = {0, 0, 0}; - dir[1] = r_data->refdef->viewangles[1] - cl.viewangles[1]; + dir[1] = r_data->refdef->viewangles[1] - cl.viewstate.angles[1]; AngleVectors (dir, forward, right, up); VectorScale (forward, cmd->forwardmove, f); VectorScale (right, cmd->sidemove, r); @@ -531,16 +338,18 @@ CL_BaseMove (usercmd_t *cmd) viewdelta.position[2] = f[0] + r[0]; viewdelta.position[0] = (f[1] + r[1]) * -1; } + */ cmd->forwardmove += viewdelta.position[2] * m_forward->value; cmd->sidemove += viewdelta.position[0] * m_side->value; cmd->upmove += viewdelta.position[1]; - cl.viewangles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; - cl.viewangles[YAW] += viewdelta.angles[YAW] * m_yaw->value; - cl.viewangles[ROLL] += viewdelta.angles[ROLL]; + cl.viewstate.angles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; + cl.viewstate.angles[YAW] += viewdelta.angles[YAW] * m_yaw->value; + cl.viewstate.angles[ROLL] += viewdelta.angles[ROLL]; if (freelook && !(in_strafe.state & 1)) { - cl.viewangles[PITCH] = bound (-70, cl.viewangles[PITCH], 80); + cl.viewstate.angles[PITCH] + = bound (-70, cl.viewstate.angles[PITCH], 80); } } @@ -563,7 +372,7 @@ CL_SendMove (usercmd_t *cmd) MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times - write_angles (&buf, cl.viewangles); + write_angles (&buf, cl.viewstate.angles); MSG_WriteShort (&buf, cmd->forwardmove); MSG_WriteShort (&buf, cmd->sidemove); @@ -603,76 +412,86 @@ CL_SendMove (usercmd_t *cmd) void CL_Input_Init (void) { - Cmd_AddCommand ("+moveup", IN_UpPress, "When active the player is " - "swimming up in a liquid"); - Cmd_AddCommand ("-moveup", IN_UpRelease, "When active the player is not " - "swimming up in a liquid"); - Cmd_AddCommand ("+movedown", IN_DownPress, "When active the player is " - "swimming down in a liquid"); - Cmd_AddCommand ("-movedown", IN_DownRelease, "When active the player is " - "not swimming down in a liquid"); - Cmd_AddCommand ("+left", IN_LeftPress, "When active the player is turning " - "left"); - Cmd_AddCommand ("-left", IN_LeftRelease, "When active the player is not " - "turning left"); - Cmd_AddCommand ("+right", IN_RightPress, "When active the player is " - "turning right"); - Cmd_AddCommand ("-right", IN_RightRelease, "When active the player is not " - "turning right"); - Cmd_AddCommand ("+forward", IN_ForwardPress, "When active the player is " - "moving forward"); - Cmd_AddCommand ("-forward", IN_ForwardRelease, "When active the player is " - "not moving forward"); - Cmd_AddCommand ("+back", IN_BackPress, "When active the player is moving " - "backwards"); - Cmd_AddCommand ("-back", IN_BackRelease, "When active the player is not " - "moving backwards"); - Cmd_AddCommand ("+lookup", IN_LookupPress, "When active the player's view " - "is looking up"); - Cmd_AddCommand ("-lookup", IN_LookupRelease, "When active the player's " - "view is not looking up"); - Cmd_AddCommand ("+lookdown", IN_LookdownPress, "When active the player's " - "view is looking down"); - Cmd_AddCommand ("-lookdown", IN_LookdownRelease, "When active the " - "player's view is not looking up"); - Cmd_AddCommand ("+strafe", IN_StrafePress, "When active, +left and +right " - "function like +moveleft and +moveright"); - Cmd_AddCommand ("-strafe", IN_StrafeRelease, "When active, +left and " - "+right stop functioning like +moveleft and +moveright"); - Cmd_AddCommand ("+moveleft", IN_MoveleftPress, "When active the player is " - "strafing left"); - Cmd_AddCommand ("-moveleft", IN_MoveleftRelease, "When active the player " - "is not strafing left"); - Cmd_AddCommand ("+moveright", IN_MoverightPress, "When active the player " - "is strafing right"); - Cmd_AddCommand ("-moveright", IN_MoverightRelease, "When active the " - "player is not strafing right"); - Cmd_AddCommand ("+speed", IN_SpeedPress, "When active the player is " - "running"); - Cmd_AddCommand ("-speed", IN_SpeedRelease, "When active the player is not " - "running"); - Cmd_AddCommand ("+attack", IN_AttackPress, "When active player is " - "firing/using current weapon"); - Cmd_AddCommand ("-attack", IN_AttackRelease, "When active player is not " - "firing/using current weapon"); - Cmd_AddCommand ("+use", IN_UsePress, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("-use", IN_UseRelease, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("+jump", IN_JumpPress, "When active the player is " - "jumping"); - Cmd_AddCommand ("-jump", IN_JumpRelease, "When active the player is not " - "jumping"); - Cmd_AddCommand ("impulse", IN_Impulse, "Call a game function or QuakeC " - "function."); - Cmd_AddCommand ("+klook", IN_KLookPress, "When active, +forward and +back " - "perform +lookup and +lookdown"); - Cmd_AddCommand ("-klook", IN_KLookRelease, "When active, +forward and " - "+back don't perform +lookup and +lookdown"); - Cmd_AddCommand ("+mlook", IN_MLookPress, "When active moving the mouse or " - "joystick forwards and backwards performs +lookup and " - "+lookdown"); - Cmd_AddCommand ("-mlook", IN_MLookRelease, "When active moving the mouse " - "or joystick forwards and backwards doesn't perform " - "+lookup and +lookdown"); + Cmd_AddDataCommand ("+moveup", KeyPress, &in_up, + "When active the player is swimming up in a liquid"); + Cmd_AddDataCommand ("-moveup", KeyRelease, &in_up, + "When active the player is not swimming up in a " + "liquid"); + Cmd_AddDataCommand ("+movedown", KeyPress, &in_down, + "When active the player is swimming down in a liquid"); + Cmd_AddDataCommand ("-movedown", KeyRelease, &in_down, + "When active the player is not swimming down in a " + "liquid"); + Cmd_AddDataCommand ("+left", KeyPress, &in_left, + "When active the player is turning left"); + Cmd_AddDataCommand ("-left", KeyRelease, &in_left, + "When active the player is not turning left"); + Cmd_AddDataCommand ("+right", KeyPress, &in_right, + "When active the player is turning right"); + Cmd_AddDataCommand ("-right", KeyRelease, &in_right, + "When active the player is not turning right"); + Cmd_AddDataCommand ("+forward", KeyPress, &in_forward, + "When active the player is moving forward"); + Cmd_AddDataCommand ("-forward", KeyRelease, &in_forward, + "When active the player is not moving forward"); + Cmd_AddDataCommand ("+back", KeyPress, &in_back, + "When active the player is moving backwards"); + Cmd_AddDataCommand ("-back", KeyRelease, &in_back, + "When active the player is not moving backwards"); + Cmd_AddDataCommand ("+lookup", KeyPress, &in_lookup, + "When active the player's view is looking up"); + Cmd_AddDataCommand ("-lookup", KeyRelease, &in_lookup, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+lookdown", KeyPress, &in_lookdown, + "When active the player's view is looking down"); + Cmd_AddDataCommand ("-lookdown", KeyRelease, &in_lookdown, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+strafe", KeyPress, &in_strafe, + "When active, +left and +right function like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("-strafe", KeyRelease, &in_strafe, + "When active, +left and +right stop functioning like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("+moveleft", KeyPress, &in_moveleft, + "When active the player is strafing left"); + Cmd_AddDataCommand ("-moveleft", KeyRelease, &in_moveleft, + "When active the player is not strafing left"); + Cmd_AddDataCommand ("+moveright", KeyPress, &in_moveright, + "When active the player is strafing right"); + Cmd_AddDataCommand ("-moveright", KeyRelease, &in_moveright, + "When active the player is not strafing right"); + Cmd_AddDataCommand ("+speed", KeyPress, &in_speed, + "When active the player is running"); + Cmd_AddDataCommand ("-speed", KeyRelease, &in_speed, + "When active the player is not running"); + Cmd_AddDataCommand ("+attack", KeyPress, &in_attack, + "When active player is firing/using current weapon"); + Cmd_AddDataCommand ("-attack", KeyRelease, &in_attack, + "When active player is not firing/using current " + "weapon"); + Cmd_AddDataCommand ("+use", KeyPress, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("-use", KeyRelease, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("+jump", KeyPress, &in_jump, + "When active the player is jumping"); + Cmd_AddDataCommand ("-jump", KeyRelease, &in_jump, + "When active the player is not jumping"); + Cmd_AddDataCommand ("impulse", IN_Impulse, 0, + "Call a game function or QuakeC function."); + Cmd_AddDataCommand ("+klook", KeyPress, &in_klook, + "When active, +forward and +back perform +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-klook", KeyRelease, &in_klook, + "When active, +forward and +back don't perform " + "+lookup and +lookdown"); + Cmd_AddDataCommand ("+mlook", KeyPress, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards performs +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-mlook", IN_MLookRelease, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards doesn't perform +lookup and +lookdown"); } diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 7f6dd9e82..1bb8ffeb8 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -34,11 +34,12 @@ #include "QF/console.h" #include "QF/cvar.h" #include "QF/draw.h" +#include "QF/entity.h" #include "QF/input.h" #include "QF/joystick.h" #include "QF/keys.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/screen.h" #include "QF/skin.h" @@ -48,16 +49,18 @@ #include "QF/plugin/console.h" #include "QF/plugin/vid_render.h" -#include "chase.h" -#include "cl_skin.h" -#include "client.h" -#include "clview.h" #include "compat.h" -#include "host.h" -#include "host.h" -#include "server.h" #include "sbar.h" +#include "client/temp_entities.h" + +#include "nq/include/chase.h" +#include "nq/include/cl_skin.h" +#include "nq/include/client.h" +#include "nq/include/host.h" +#include "nq/include/host.h" +#include "nq/include/server.h" + CLIENT_PLUGIN_PROTOS static plugin_list_t client_plugin_list[] = { CLIENT_PLUGIN_LIST @@ -105,7 +108,7 @@ CL_WriteConfiguration (void) // dedicated servers initialize the host but don't parse and set the // config.cfg cvars if (host_initialized && !isDedicated && cl_writecfg->int_val) { - char *path = va ("%s/config.cfg", qfs_gamedir->dir.def); + char *path = va (0, "%s/config.cfg", qfs_gamedir->dir.def); f = QFS_WOpen (path, 0); if (!f) { Sys_Printf ("Couldn't write config.cfg.\n"); @@ -120,14 +123,18 @@ CL_WriteConfiguration (void) } } -void -CL_Shutdown (void) +static void +CL_Shutdown (void *data) { CL_WriteConfiguration (); - CDAudio_Shutdown (); - S_Shutdown (); - IN_Shutdown (); - VID_Shutdown (); +} + +void +CL_ClearMemory (void) +{ + VID_ClearMemory (); + if (r_data) + r_data->force_fullscreen = 0; } void @@ -201,11 +208,11 @@ CL_ClearState (void) if (cl.edicts) PL_Free (cl.edicts); - if (cl.scores) { + if (cl.players) { int i; for (i = 0; i < cl.maxclients; i++) - Info_Destroy (cl.scores[i].info); + Info_Destroy (cl.players[i].userinfo); } // wipe the entire cl structure @@ -339,10 +346,11 @@ CL_SignonReply (void) case so_spawn: MSG_WriteByte (&cls.message, clc_stringcmd); - MSG_WriteString (&cls.message, va ("name \"%s\"\n", cl_name->string)); + MSG_WriteString (&cls.message, va (0, "name \"%s\"\n", + cl_name->string)); MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, - va ("color %i %i\n", (cl_color->int_val) >> 4, + va (0, "color %i %i\n", (cl_color->int_val) >> 4, (cl_color->int_val) & 15)); MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, "spawn"); @@ -384,7 +392,8 @@ CL_NextDemo (void) } } - Cbuf_InsertText (host_cbuf, va ("playdemo %s\n", cls.demos[cls.demonum])); + Cbuf_InsertText (host_cbuf, va (0, "playdemo %s\n", + cls.demos[cls.demonum])); cls.demonum++; } @@ -396,13 +405,15 @@ CL_PrintEntities_f (void) for (i = 0, ent = cl_entities; i < cl.num_entities; i++, ent++) { Sys_Printf ("%3i:", i); - if (!ent->model) { + if (!ent->renderer.model) { Sys_Printf ("EMPTY\n"); continue; } - Sys_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", - ent->model->name, ent->frame, VectorExpand (ent->origin), - VectorExpand (ent->angles)); + vec4f_t org = Transform_GetWorldPosition (ent->transform); + vec4f_t rot = Transform_GetWorldRotation (ent->transform); + Sys_Printf ("%s:%2i "VEC4F_FMT" "VEC4F_FMT"\n", + ent->renderer.model->path, ent->animation.frame, + VEC4_EXP (org), VEC4_EXP (rot)); } } @@ -415,9 +426,14 @@ int CL_ReadFromServer (void) { int ret; + TEntContext_t tentCtx = { + Transform_GetWorldPosition (cl_entities[cl.viewentity].transform), + cl.worldmodel, cl.viewentity + }; cl.oldtime = cl.time; cl.time += host_frametime; + cl.viewstate.frametime = host_frametime; do { ret = CL_GetMessage (); @@ -426,7 +442,6 @@ CL_ReadFromServer (void) if (!ret) break; - cl.last_received_message = realtime; CL_ParseServerMessage (); } while (ret && cls.state >= ca_connected); @@ -434,7 +449,7 @@ CL_ReadFromServer (void) Sys_Printf ("\n"); CL_RelinkEntities (); - CL_UpdateTEnts (); + CL_UpdateTEnts (cl.time, &tentCtx); // bring the links up to date return 0; @@ -521,7 +536,7 @@ CL_SetState (cactive_t state) static void Force_CenterView_f (void) { - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; } void @@ -529,6 +544,8 @@ CL_Init (cbuf_t *cbuf) { byte *basepal, *colormap; + Sys_RegisterShutdown (CL_Shutdown, 0); + basepal = (byte *) QFS_LoadHunkFile (QFS_FOpenFile ("gfx/palette.lmp")); if (!basepal) Sys_Error ("Couldn't load gfx/palette.lmp"); diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index ea12152ff..84c185c65 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -41,10 +41,11 @@ #include "QF/console.h" #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/entity.h" #include "QF/idparse.h" #include "QF/input.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/sys.h" #include "QF/screen.h" #include "QF/skin.h" @@ -53,12 +54,15 @@ #include "QF/plugin/vid_render.h" -#include "client.h" +#include "client/temp_entities.h" + #include "compat.h" -#include "host.h" #include "sbar.h" -#include "server.h" -#include "game.h" + +#include "nq/include/client.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/game.h" const char *svc_strings[] = { "svc_bad", @@ -300,7 +304,7 @@ map_ent (const char *mapname) edicts = ED_Parse (&edpr, buf); free (buf); } else { - edicts = ED_Parse (&edpr, cl.model_precache[1]->entities); + edicts = ED_Parse (&edpr, cl.model_precache[1]->brush.entities); } free (name); return edicts; @@ -314,7 +318,7 @@ CL_NewMap (const char *mapname) Hunk_Check (); // make sure nothing is hurt Sbar_CenterPrint (0); - if (cl.model_precache[1] && cl.model_precache[1]->entities) { + if (cl.model_precache[1] && cl.model_precache[1]->brush.entities) { cl.edicts = map_ent (mapname); if (cl.edicts) { cl.worldspawn = PL_ObjectAtIndex (cl.edicts, 0); @@ -361,12 +365,13 @@ CL_ParseServerInfo (void) Sys_Printf ("Bad maxclients (%u) from server\n", cl.maxclients); goto done; } - cl.scores = Hunk_AllocName (cl.maxclients * sizeof (*cl.scores), "scores"); + cl.players = Hunk_AllocName (cl.maxclients * sizeof (*cl.players), + "players"); for (i = 0; i < cl.maxclients; i++) { - cl.scores[i].info = Info_ParseString ("name\\", 0, 0); - cl.scores[i].name = Info_Key (cl.scores[i].info, "name"); - cl.scores[i].topcolor = 0; - cl.scores[i].bottomcolor = 0; + cl.players[i].userinfo = Info_ParseString ("name\\", 0, 0); + cl.players[i].name = Info_Key (cl.players[i].userinfo, "name"); + cl.players[i].topcolor = 0; + cl.players[i].bottomcolor = 0; } // parse gametype @@ -432,7 +437,7 @@ CL_ParseServerInfo (void) } // local state - cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; + cl_entities[0].renderer.model = cl.worldmodel = cl.model_precache[1]; if (!centerprint) centerprint = dstring_newstr (); else @@ -488,7 +493,7 @@ CL_ParseUpdate (int bits) num = MSG_ReadByte (net_message); baseline = CL_EntityNum (num); - state = &nq_entstates.frame[0 + cl.mindex][num]; + state = &nq_entstates.frame[0 + cl.frameIndex][num]; for (i = 0; i < 16; i++) if (bits & (1 << i)) @@ -590,7 +595,7 @@ CL_ParseUpdate (int bits) //VectorCopy (state->msg_origins[0], state->msg_origins[1]); //VectorCopy (state->msg_origins[0], ent->origin); //VectorCopy (state->msg_angles[0], state->msg_angles[1]); - //CL_TransformEntity (ent, state->msg_angles[0], true); + //CL_TransformEntity (ent, state->msg_angles[0]); //state->forcelink = true; cl_forcelink[num] = true; } @@ -617,7 +622,8 @@ CL_ParseBaseline (entity_state_t *baseline, int version) baseline->colormap = MSG_ReadByte (net_message); baseline->skinnum = MSG_ReadByte (net_message); - MSG_ReadCoordAngleV (net_message, baseline->origin, baseline->angles); + MSG_ReadCoordAngleV (net_message, &baseline->origin[0], baseline->angles); + baseline->origin[3] = 1;//FIXME if (bits & B_ALPHA) baseline->alpha = MSG_ReadByte (net_message); @@ -656,18 +662,19 @@ CL_ParseClientdata (void) else cl.idealpitch = 0; - VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); + cl.frameVelocity[1] = cl.frameVelocity[0]; + vec3_t punchangle = { }; for (i = 0; i < 3; i++) { - if (bits & (SU_PUNCH1 << i)) - cl.punchangle[i] = ((signed char) MSG_ReadByte (net_message)); - else - cl.punchangle[i] = 0; + if (bits & (SU_PUNCH1 << i)) { + punchangle[i] = ((signed char) MSG_ReadByte (net_message)); + } if (bits & (SU_VELOCITY1 << i)) - cl.mvelocity[0][i] = ((signed char) MSG_ReadByte (net_message)) + cl.frameVelocity[0][i] = ((signed char) MSG_ReadByte (net_message)) * 16; else - cl.mvelocity[0][i] = 0; + cl.frameVelocity[0][i] = 0; } + AngleQuat (punchangle, &cl.viewstate.punchangle[0]);//FIXME //FIXME //if (!VectorCompare (v_punchangles[0], cl.punchangle[0])) { @@ -686,7 +693,7 @@ CL_ParseClientdata (void) cl.stats[STAT_ITEMS] = i; } - cl.onground = (bits & SU_ONGROUND) ? 0 : -1; + cl.viewstate.onground = (bits & SU_ONGROUND) ? 0 : -1; cl.inwater = (bits & SU_INWATER) != 0; if (bits & SU_WEAPONFRAME) @@ -765,9 +772,9 @@ CL_ParseClientdata (void) cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte (net_message) << 8; if (bits & SU_WEAPONALPHA) { byte alpha = MSG_ReadByte (net_message); - cl.viewent.colormod[3] = ENTALPHA_DECODE (alpha); + cl.viewent.renderer.colormod[3] = ENTALPHA_DECODE (alpha); } else { - cl.viewent.colormod[3] = 1.0; + cl.viewent.renderer.colormod[3] = 1.0; } } @@ -784,17 +791,17 @@ CL_ParseStatic (int version) // copy it to the current state //FIXME alpha & lerp - ent->model = cl.model_precache[baseline.modelindex]; - ent->frame = baseline.frame; - ent->skin = 0; - ent->skinnum = baseline.skinnum; - VectorCopy (ent_colormod[baseline.colormod], ent->colormod); - ent->colormod[3] = ENTALPHA_DECODE (baseline.alpha); - ent->scale = baseline.scale / 16.0; - VectorCopy (baseline.origin, ent->origin); - CL_TransformEntity (ent, baseline.angles, true); + ent->renderer.model = cl.model_precache[baseline.modelindex]; + ent->animation.frame = baseline.frame; + ent->renderer.skin = 0; + ent->renderer.skinnum = baseline.skinnum; + VectorCopy (ent_colormod[baseline.colormod], ent->renderer.colormod); + ent->renderer.colormod[3] = ENTALPHA_DECODE (baseline.alpha); - r_funcs->R_AddEfrags (ent); + CL_TransformEntity (ent, baseline.scale / 16.0, baseline.angles, + baseline.origin); + + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } static void @@ -834,13 +841,19 @@ CL_ParseServerMessage (void) static dstring_t *stuffbuf; signon_t so; + cl.last_servermessage = realtime; + TEntContext_t tentCtx = { + Transform_GetWorldPosition (cl_entities[cl.viewentity].transform), + cl.worldmodel, cl.viewentity + }; + // if recording demos, copy the message out if (cl_shownet->int_val == 1) Sys_Printf ("%i ", net_message->message->cursize); else if (cl_shownet->int_val == 2) Sys_Printf ("------------------\n"); - cl.onground = -1; // unless the server says otherwise + cl.viewstate.onground = -1; // unless the server says otherwise // parse the message MSG_BeginReading (net_message); @@ -865,7 +878,7 @@ CL_ParseServerMessage (void) continue; } - SHOWNET (va ("%s(%d)", svc_strings[cmd], cmd)); + SHOWNET (va (0, "%s(%d)", svc_strings[cmd], cmd)); // other commands switch (cmd) { @@ -910,7 +923,7 @@ CL_ParseServerMessage (void) case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (net_message); - cl.mindex = !cl.mindex; + cl.frameIndex = !cl.frameIndex; break; case svc_print: @@ -939,7 +952,7 @@ CL_ParseServerMessage (void) case svc_setangle: { - vec_t *dest = cl.viewangles; + vec_t *dest = cl.viewstate.angles; MSG_ReadAngleV (net_message, dest); break; @@ -985,7 +998,7 @@ CL_ParseServerMessage (void) if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > " "MAX_SCOREBOARD"); - Info_SetValueForKey (cl.scores[i].info, "name", + Info_SetValueForKey (cl.players[i].userinfo, "name", MSG_ReadString (net_message), 0); break; @@ -995,7 +1008,7 @@ CL_ParseServerMessage (void) if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > " "MAX_SCOREBOARD"); - cl.scores[i].frags = (short) MSG_ReadShort (net_message); + cl.players[i].frags = (short) MSG_ReadShort (net_message); break; case svc_clientdata: @@ -1018,17 +1031,19 @@ CL_ParseServerMessage (void) byte col = MSG_ReadByte (net_message); byte top = col >> 4; byte bot = col & 0xf; - if (top != cl.scores[i].topcolor - || bot != cl.scores[i].bottomcolor) + if (top != cl.players[i].topcolor + || bot != cl.players[i].bottomcolor) mod_funcs->Skin_SetTranslation (i + 1, top, bot); - cl.scores[i].topcolor = top; - cl.scores[i].bottomcolor = bot; - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, i + 1); + cl.players[i].topcolor = top; + cl.players[i].bottomcolor = bot; + ent->renderer.skin + = mod_funcs->Skin_SetColormap (ent->renderer.skin, + i + 1); } break; case svc_particle: - CL_ParseParticleEffect (); + CL_ParseParticleEffect (net_message); break; case svc_damage: @@ -1048,7 +1063,7 @@ CL_ParseServerMessage (void) break; case svc_temp_entity: - CL_ParseTEnt (); + CL_ParseTEnt_nq (net_message, cl.time, &tentCtx); break; case svc_setpause: diff --git a/nq/source/cl_screen.c b/nq/source/cl_screen.c index 1a0f8e7be..ca4c3ee8f 100644 --- a/nq/source/cl_screen.c +++ b/nq/source/cl_screen.c @@ -46,15 +46,16 @@ #include "QF/plugin/vid_render.h" -#include "client.h" #include "sbar.h" +#include "nq/include/client.h" + static qpic_t *scr_net; static void SCR_DrawNet (void) { - if (realtime - cl.last_received_message < 0.3) + if (realtime - cl.last_servermessage < 0.3) return; if (cls.demoplayback) return; @@ -85,7 +86,9 @@ SCR_CShift (void) int contents = CONTENTS_EMPTY; if (cls.state == ca_active && cl.worldmodel) { - leaf = Mod_PointInLeaf (r_data->refdef->vieworg, cl.worldmodel); + //FIXME + leaf = Mod_PointInLeaf (&r_data->refdef->viewposition[0], + cl.worldmodel); contents = leaf->contents; } V_SetContentsColor (contents); @@ -145,5 +148,5 @@ CL_UpdateScreen (double realtime) scr_funcs_normal[3] = r_funcs->SCR_DrawPause; V_PrepBlend (); - r_funcs->SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); + SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); } diff --git a/nq/source/cl_tent.c b/nq/source/cl_tent.c deleted file mode 100644 index 11c5c9fde..000000000 --- a/nq/source/cl_tent.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - cl_tent.c - - client side temporary entities - - Copyright (C) 1996-1997 Id Software, Inc. - - 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: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#include -#include - -#include "QF/model.h" -#include "QF/msg.h" -#include "QF/sound.h" -#include "QF/sys.h" - -#include "QF/plugin/vid_render.h" - -#include "client.h" -#include "compat.h" - -typedef struct tent_s { - struct tent_s *next; - entity_t ent; -} tent_t; - -#define TEMP_BATCH 64 -static tent_t *temp_entities = 0; - -typedef struct { - int entity; - struct model_s *model; - float endtime; - vec3_t start, end; - tent_t *tents; - int seed; -} beam_t; - -#define BEAM_SEED_INTERVAL 72 -#define BEAM_SEED_PRIME 3191 - -typedef struct { - float start; - tent_t *tent; -} explosion_t; - -typedef struct tent_obj_s { - struct tent_obj_s *next; - union { - beam_t beam; - explosion_t ex; - } to; -} tent_obj_t; - -static tent_obj_t *tent_objects; -static tent_obj_t *cl_beams; -static tent_obj_t *cl_explosions; - -static sfx_t *cl_sfx_wizhit; -static sfx_t *cl_sfx_knighthit; -static sfx_t *cl_sfx_tink1; -static sfx_t *cl_sfx_ric1; -static sfx_t *cl_sfx_ric2; -static sfx_t *cl_sfx_ric3; -static sfx_t *cl_sfx_r_exp3; - -static model_t *cl_mod_beam; -static model_t *cl_mod_bolt; -static model_t *cl_mod_bolt2; -static model_t *cl_mod_bolt3; -static model_t *cl_spr_explod; - -static void -CL_TEnts_Precache (int phase) -{ - if (!phase) - return; - cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); - cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); - cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); - cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); - cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); - cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); - cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); - - cl_mod_bolt = Mod_ForName ("progs/bolt.mdl", true); - cl_mod_bolt2 = Mod_ForName ("progs/bolt2.mdl", true); - cl_mod_bolt3 = Mod_ForName ("progs/bolt3.mdl", true); - cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - cl_mod_beam = Mod_ForName ("progs/beam.mdl", false); - if (!cl_mod_beam) - cl_mod_beam = cl_mod_bolt; -} - -void -CL_TEnts_Init (void) -{ - QFS_GamedirCallback (CL_TEnts_Precache); - CL_TEnts_Precache (1); -} - -void -CL_Init_Entity (entity_t *ent) -{ - memset (ent, 0, sizeof (*ent)); - - ent->skin = 0; - QuatSet (1.0, 1.0, 1.0, 1.0, ent->colormod); - ent->scale = 1.0; - ent->pose1 = ent->pose2 = -1; -} - -static tent_t * -new_temp_entity (void) -{ - tent_t *tent; - if (!temp_entities) { - int i; - - temp_entities = malloc (TEMP_BATCH * sizeof (tent_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) { - temp_entities[i].next = &temp_entities[i + 1]; - } - temp_entities[i].next = 0; - } - tent = temp_entities; - temp_entities = tent->next; - tent->next = 0; - CL_Init_Entity (&tent->ent); - return tent; -} - -static void -free_temp_entities (tent_t *tents) -{ - tent_t **t = &tents; - - while (*t) - t = &(*t)->next; - *t = temp_entities; - temp_entities = tents; -} - -static tent_obj_t * -new_tent_object (void) -{ - tent_obj_t *tobj; - if (!tent_objects) { - int i; - - tent_objects = malloc (TEMP_BATCH * sizeof (tent_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) - tent_objects[i].next = &tent_objects[i + 1]; - tent_objects[i].next = 0; - } - tobj = tent_objects; - tent_objects = tobj->next; - tobj->next = 0; - return tobj; -} - -static void -free_tent_objects (tent_obj_t *tobjs) -{ - tent_obj_t **t = &tobjs; - - while (*t) - t = &(*t)->next; - *t = tent_objects; - tent_objects = tobjs; -} - -void -CL_ClearTEnts (void) -{ - tent_t *t; - tent_obj_t *to; - - for (to = cl_beams; to; to = to->next) { - for (t = to->to.beam.tents; t; t = t->next) - t->ent.efrag = 0; - free_temp_entities (to->to.beam.tents); - } - free_tent_objects (cl_beams); - cl_beams = 0; - - for (to = cl_explosions; to; to = to->next) { - for (t = to->to.ex.tent; t; t = t->next) - t->ent.efrag = 0; - free_temp_entities (to->to.ex.tent); - } - free_tent_objects (cl_explosions); - cl_explosions = 0; -} - -static inline void -beam_clear (beam_t *b) -{ - if (b->tents) { - tent_t *t; - - for (t = b->tents; t; t = t->next) { - r_funcs->R_RemoveEfrags (&t->ent); - t->ent.efrag = 0; - } - free_temp_entities (b->tents); - b->tents = 0; - } -} - -static inline void -beam_setup (beam_t *b, qboolean transform) -{ - tent_t *tent; - float forward, pitch, yaw, d; - int ent_count; - vec3_t dist, org, ang; - unsigned seed; - - // calculate pitch and yaw - VectorSubtract (b->end, b->start, dist); - - if (dist[1] == 0 && dist[0] == 0) { - yaw = 0; - if (dist[2] > 0) - pitch = 90; - else - pitch = 270; - } else { - yaw = (int) (atan2 (dist[1], dist[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - - forward = sqrt (dist[0] * dist[0] + dist[1] * dist[1]); - pitch = (int) (atan2 (dist[2], forward) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - - // add new entities for the lightning - VectorCopy (b->start, org); - d = VectorNormalize (dist); - VectorScale (dist, 30, dist); - ent_count = ceil (d / 30); - d = 0; - - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % - BEAM_SEED_INTERVAL); - - ang[ROLL] = 0; - while (ent_count--) { - tent = new_temp_entity (); - tent->next = b->tents; - b->tents = tent; - - VectorMultAdd (org, d, dist, tent->ent.origin); - d += 1.0; - tent->ent.model = b->model; - ang[PITCH] = pitch; - ang[YAW] = yaw; - if (transform) { - seed = seed * BEAM_SEED_PRIME; - ang[ROLL] = seed % 360; - CL_TransformEntity (&tent->ent, ang, true); - } - VectorCopy (ang, tent->ent.angles); - r_funcs->R_AddEfrags (&tent->ent); - } -} - -static void -CL_ParseBeam (model_t *m) -{ - tent_obj_t *to; - beam_t *b; - int ent; - vec3_t start, end; - - ent = MSG_ReadShort (net_message); - - MSG_ReadCoordV (net_message, start); - MSG_ReadCoordV (net_message, end); - - to = 0; - if (ent) { - for (to = cl_beams; to; to = to->next) - if (to->to.beam.entity == ent) - break; - } - if (!to) { - to = new_tent_object (); - to->next = cl_beams; - cl_beams = to; - to->to.beam.tents = 0; - to->to.beam.entity = ent; - } - b = &to->to.beam; - - beam_clear (b); - b->model = m; - b->endtime = cl.time + 0.2; - b->seed = rand (); - VectorCopy (end, b->end); - if (b->entity != cl.viewentity) { - // this will be done in CL_UpdateBeams - VectorCopy (start, b->start); - beam_setup (b, true); - } -} - -void -CL_ParseTEnt (void) -{ - byte type; - dlight_t *dl; - tent_obj_t *to; - explosion_t *ex; - int colorStart, colorLength; - quat_t col; - vec3_t pos; - sfx_t *spike_sound[] = { - cl_sfx_ric3, cl_sfx_ric3, cl_sfx_ric2, cl_sfx_ric1, - }; - - type = MSG_ReadByte (net_message); - switch (type) { - case TE_WIZSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_WizSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); - break; - - case TE_KNIGHTSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_KnightSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); - break; - - case TE_SPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } - break; - - case TE_SUPERSPIKE: // super spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SuperSpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } - break; - - case TE_EXPLOSION: // rocket explosion - // particles - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_ParticleExplosion (pos); - - // light - dl = r_funcs->R_AllocDlight (0); - if (dl) { - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - QuatSet (1.0, 0.5, 0.25, 0.7, dl->color); - } - - // sound - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - - // sprite - to = new_tent_object (); - to->next = cl_explosions; - cl_explosions = to; - ex = &to->to.ex; - ex->tent = new_temp_entity (); - - VectorCopy (pos, ex->tent->ent.origin); - ex->start = cl.time; - //FIXME need better model management - if (!cl_spr_explod->cache.data) - cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - ex->tent->ent.model = cl_spr_explod; - CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true); - break; - - case TE_TAREXPLOSION: // tarbaby explosion - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_BlobExplosion (pos); - - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - break; - - case TE_LIGHTNING1: // lightning bolts - CL_ParseBeam (cl_mod_bolt); - break; - - case TE_LIGHTNING2: // lightning bolts - CL_ParseBeam (cl_mod_bolt2); - break; - - case TE_LIGHTNING3: // lightning bolts - CL_ParseBeam (cl_mod_bolt3); - break; - - case TE_LIGHTNING4NEH: // Nehahra lightning - CL_ParseBeam (Mod_ForName (MSG_ReadString (net_message), true)); - break; - - // PGM 01/21/97 - case TE_BEAM: // grappling hook beam - CL_ParseBeam (cl_mod_beam); - break; - // PGM 01/21/97 - - case TE_LAVASPLASH: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_LavaSplash (pos); - break; - - case TE_TELEPORT: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_TeleportSplash (pos); - break; - - case TE_EXPLOSION2: // color mapped explosion - MSG_ReadCoordV (net_message, pos); - colorStart = MSG_ReadByte (net_message); - colorLength = MSG_ReadByte (net_message); - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - r_funcs->particles->R_ParticleExplosion2 (pos, colorStart, - colorLength); - dl = r_funcs->R_AllocDlight (0); - if (!dl) - break; - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - colorStart = (colorStart + (rand () % colorLength)) * 3; - VectorScale (&r_data->vid->palette[colorStart], 1.0 / 255.0, - dl->color); - dl->color[3] = 0.7; - break; - - case TE_EXPLOSION3: // Nehahra colored light explosion - MSG_ReadCoordV (net_message, pos); - MSG_ReadCoordV (net_message, col); // OUCH! - col[3] = 0.7; - r_funcs->particles->R_ParticleExplosion (pos); - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - dl = r_funcs->R_AllocDlight (0); - if (dl) { - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - QuatCopy (col, dl->color); - } - break; - - case TE_GUNSHOT: // bullet hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_GunshotEffect (pos, 20); - break; - - default: - Sys_Error ("CL_ParseTEnt: bad type %d", type); - } -} - -static void -CL_UpdateBeams (void) -{ - tent_obj_t **to; - beam_t *b; - unsigned seed; - tent_t *t; - - // update lightning - for (to = &cl_beams; *to; ) { - b = &(*to)->to.beam; - if (!b->endtime) - continue; - if (!b->model || b->endtime < cl.time) { - tent_obj_t *_to; - b->endtime = 0; - beam_clear (b); - _to = *to; - *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; - continue; - } - to = &(*to)->next; - - // if coming from the player, update the start position - if (b->entity == cl.viewentity) { - beam_clear (b); - VectorCopy (cl_entities[cl.viewentity].origin, b->start); - beam_setup (b, false); - } - - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % - BEAM_SEED_INTERVAL); - - // add new entities for the lightning - for (t = b->tents; t; t = t->next) { - seed = seed * BEAM_SEED_PRIME; - t->ent.angles[ROLL] = seed % 360; - CL_TransformEntity (&t->ent, t->ent.angles, true); - } - } -} - -static void -CL_UpdateExplosions (void) -{ - int f; - tent_obj_t **to; - explosion_t *ex; - entity_t *ent; - - for (to = &cl_explosions; *to; ) { - ex = &(*to)->to.ex; - ent = &ex->tent->ent; - f = 10 * (cl.time - ex->start); - if (f >= ent->model->numframes) { - tent_obj_t *_to; - r_funcs->R_RemoveEfrags (ent); - ent->efrag = 0; - free_temp_entities (ex->tent); - _to = *to; - *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; - continue; - } - to = &(*to)->next; - - ent->frame = f; - if (!ent->efrag) - r_funcs->R_AddEfrags (ent); - } -} - -void -CL_UpdateTEnts (void) -{ - CL_UpdateBeams (); - CL_UpdateExplosions (); -} - -/* - CL_ParseParticleEffect - - Parse an effect out of the server message -*/ -void -CL_ParseParticleEffect (void) -{ - int i, count, color; - vec3_t org, dir; - - MSG_ReadCoordV (net_message, org); - for (i = 0; i < 3; i++) - dir[i] = ((signed char) MSG_ReadByte (net_message)) * (15.0 / 16.0); - count = MSG_ReadByte (net_message); - color = MSG_ReadByte (net_message); - - if (count == 255) - r_funcs->particles->R_ParticleExplosion (org); - else - r_funcs->particles->R_RunParticleEffect (org, dir, color, count); -} diff --git a/nq/source/cl_view.c b/nq/source/cl_view.c index 6def74958..d21f267b1 100644 --- a/nq/source/cl_view.c +++ b/nq/source/cl_view.c @@ -30,16 +30,19 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/msg.h" #include "QF/screen.h" +#include "QF/simd/vec4f.h" + #include "QF/plugin/vid_render.h" -#include "chase.h" -#include "client.h" #include "compat.h" -#include "host.h" -#include "clview.h" + +#include "nq/include/chase.h" +#include "nq/include/client.h" +#include "nq/include/host.h" /* The view is allowed to move slightly from it's true position for bobbing, @@ -77,6 +80,10 @@ cvar_t *v_idlescale; float v_dmg_time, v_dmg_roll, v_dmg_pitch; +vec4f_t v_idle_yaw; +vec4f_t v_idle_roll; +vec4f_t v_idle_pitch; + cshift_t cshift_empty = { {130, 80, 50}, 0}; cshift_t cshift_water = { {130, 80, 50}, 128}; cshift_t cshift_slime = { {0, 25, 5}, 150}; @@ -86,7 +93,7 @@ cshift_t cshift_bonus = { {215, 186, 60}, 50}; #define sqr(x) ((x) * (x)) float -V_CalcRoll (const vec3_t angles, const vec3_t velocity) +V_CalcRoll (const vec3_t angles, vec4f_t velocity) { float side, sign, value; vec3_t forward, right, up; @@ -109,7 +116,7 @@ V_CalcRoll (const vec3_t angles, const vec3_t velocity) static float V_CalcBob (void) { - vec_t *velocity = cl.velocity; + vec4f_t velocity = cl.viewstate.velocity; float cycle; static double bobtime; static float bob; @@ -117,10 +124,10 @@ V_CalcBob (void) if (cl.spectator) return 0; - if (cl.onground == -1) + if (cl.viewstate.onground == -1) return bob; // just use old value - bobtime += host_frametime; + bobtime += cl.viewstate.frametime; cycle = bobtime - (int) (bobtime / cl_bobcycle->value) * cl_bobcycle->value; cycle /= cl_bobcycle->value; @@ -131,8 +138,8 @@ V_CalcBob (void) // bob is proportional to velocity in the xy plane // (don't count Z, or jumping messes it up) - - bob = sqrt (sqr (velocity[0]) + sqr (velocity[1])) * cl_bob->value; + velocity[2] = 0; + bob = sqrt (dotf (velocity, velocity)[0]) * cl_bob->value; bob = bob * 0.3 + bob * 0.7 * sin (cycle * M_PI); if (bob > 4) bob = 4; @@ -179,9 +186,9 @@ static void V_DriftPitch (void) { float delta, move; - usercmd_t *cmd = &cl.cmd; + float forwardmove = cl.viewstate.movecmd[0]; - if (noclip_anglehack || cl.onground == -1 || cls.demoplayback) { + if (noclip_anglehack || cl.viewstate.onground == -1 || cls.demoplayback) { cl.driftmove = 0; cl.pitchvel = 0; return; @@ -189,10 +196,10 @@ V_DriftPitch (void) // don't count small mouse motion if (cl.nodrift) { - if (fabs (cmd->forwardmove) < cl_forwardspeed->value) + if (fabs (forwardmove) < cl_forwardspeed->value) cl.driftmove = 0; else - cl.driftmove += host_frametime; + cl.driftmove += cl.viewstate.frametime; if (cl.driftmove > v_centermove->value) { V_StartPitchDrift (); @@ -200,28 +207,28 @@ V_DriftPitch (void) return; } - delta = cl.idealpitch - cl.viewangles[PITCH]; + delta = cl.idealpitch - cl.viewstate.angles[PITCH]; if (!delta) { cl.pitchvel = 0; return; } - move = host_frametime * cl.pitchvel; - cl.pitchvel += host_frametime * v_centerspeed->value; + move = cl.viewstate.frametime * cl.pitchvel; + cl.pitchvel += cl.viewstate.frametime * v_centerspeed->value; if (delta > 0) { if (move > delta) { cl.pitchvel = 0; move = delta; } - cl.viewangles[PITCH] += move; + cl.viewstate.angles[PITCH] += move; } else if (delta < 0) { if (move > -delta) { cl.pitchvel = 0; move = -delta; } - cl.viewangles[PITCH] -= move; + cl.viewstate.angles[PITCH] -= move; } } @@ -230,11 +237,10 @@ V_DriftPitch (void) void V_ParseDamage (void) { - entity_t *ent = &cl_entities[cl.viewentity]; float count, side; int armor, blood; - vec_t *origin = ent->origin; - vec_t *angles = ent->angles; + vec4f_t origin = cl.viewstate.origin; + vec_t *angles = cl.viewstate.angles; vec3_t from, forward, right, up; armor = MSG_ReadByte (net_message); @@ -390,7 +396,7 @@ V_CalcPowerupCshift (void) LordHavoc made this a real, true alpha blend. Cleaned it up a bit, but otherwise this is his code. --KB */ -void +static void V_CalcBlend (void) { float a2, a3; @@ -478,74 +484,41 @@ V_PrepBlend (void) /* VIEW RENDERING */ -static float -angledelta (float a) -{ - a = anglemod (a); - if (a > 180) - a -= 360; - return a; -} - static void CalcGunAngle (void) { - float yaw, pitch, move; - static float oldpitch = 0, oldyaw = 0; - - yaw = r_data->refdef->viewangles[YAW]; - pitch = -r_data->refdef->viewangles[PITCH]; - - yaw = angledelta (yaw - r_data->refdef->viewangles[YAW]) * 0.4; - yaw = bound (-10, yaw, 10); - pitch = angledelta (-pitch - r_data->refdef->viewangles[PITCH]) * 0.4; - pitch = bound (-10, pitch, 10); - - move = host_frametime * 20; - if (yaw > oldyaw) { - if (oldyaw + move < yaw) - yaw = oldyaw + move; - } else { - if (oldyaw - move > yaw) - yaw = oldyaw - move; - } - - if (pitch > oldpitch) { - if (oldpitch + move < pitch) - pitch = oldpitch + move; - } else { - if (oldpitch - move > pitch) - pitch = oldpitch - move; - } - - oldyaw = yaw; - oldpitch = pitch; - - cl.viewent.angles[YAW] = r_data->refdef->viewangles[YAW] + yaw; - cl.viewent.angles[PITCH] = -(r_data->refdef->viewangles[PITCH] + pitch); + vec4f_t rotation = r_data->refdef->viewrotation; + //FIXME make child of camera + Transform_SetWorldRotation (cl.viewent.transform, rotation); } static void V_BoundOffsets (void) { - entity_t *ent = &cl_entities[cl.viewentity]; - vec_t *origin = ent->origin; + vec4f_t offset = r_data->refdef->viewposition + - cl.viewstate.origin; // absolutely bound refresh reletive to entity clipping hull // so the view can never be inside a solid wall - if (r_data->refdef->vieworg[0] < origin[0] - 14) - r_data->refdef->vieworg[0] = origin[0] - 14; - else if (r_data->refdef->vieworg[0] > origin[0] + 14) - r_data->refdef->vieworg[0] = origin[0] + 14; - if (r_data->refdef->vieworg[1] < origin[1] - 14) - r_data->refdef->vieworg[1] = origin[1] - 14; - else if (r_data->refdef->vieworg[1] > origin[1] + 14) - r_data->refdef->vieworg[1] = origin[1] + 14; - if (r_data->refdef->vieworg[2] < origin[2] - 22) - r_data->refdef->vieworg[2] = origin[2] - 22; - else if (r_data->refdef->vieworg[2] > origin[2] + 30) - r_data->refdef->vieworg[2] = origin[2] + 30; + offset[0] = bound (-14, offset[0], 14); + offset[1] = bound (-14, offset[1], 14); + offset[2] = bound (-22, offset[2], 30); + r_data->refdef->viewposition = cl.viewstate.origin + offset; +} + +static vec4f_t +idle_quat (vec4f_t axis, cvar_t *cycle, cvar_t *level) +{ + vec4f_t identity = { 0, 0, 0, 1 }; + if (!level || !cycle) { + return identity; + } + float scale = sin (cl.time * cycle->value); + float ang = scale * level->value * v_idlescale->value; + float c = cos (ang); + float s = sin (ang); + return axis * s + identity * c; } /* @@ -556,19 +529,21 @@ V_BoundOffsets (void) static void V_AddIdle (void) { - r_data->refdef->viewangles[ROLL] += v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - r_data->refdef->viewangles[PITCH] += v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - r_data->refdef->viewangles[YAW] += v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + vec4f_t roll = idle_quat ((vec4f_t) { 1, 0, 0, 0}, + v_iroll_cycle, v_iroll_level); + vec4f_t pitch = idle_quat ((vec4f_t) { 0, 1, 0, 0}, + v_ipitch_cycle, v_ipitch_level); + vec4f_t yaw = idle_quat ((vec4f_t) { 0, 0, 1, 0}, + v_iyaw_cycle, v_iyaw_level); + vec4f_t rot = normalf (qmulf (yaw, qmulf (pitch, roll))); - cl.viewent.angles[ROLL] -= v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - cl.viewent.angles[PITCH] -= v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - cl.viewent.angles[YAW] -= v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + // rotate the view + r_data->refdef->viewrotation = qmulf (rot, r_data->refdef->viewrotation); + + // counter-rotate the weapon + rot = qmulf (qconjf (rot), + Transform_GetWorldRotation (cl.viewent.transform)); + Transform_SetWorldRotation (cl.viewent.transform, rot); } /* @@ -579,41 +554,39 @@ V_AddIdle (void) static void V_CalcViewRoll (void) { - float side; - vec_t *angles = cl_entities[cl.viewentity].angles; - vec_t *velocity = cl.velocity; + vec_t *angles = cl.viewstate.angles; + vec4f_t velocity = cl.viewstate.velocity; + vec3_t ang = { }; - side = V_CalcRoll (angles, velocity); - r_data->refdef->viewangles[ROLL] += side; + ang[ROLL] = V_CalcRoll (angles, velocity); if (v_dmg_time > 0) { - r_data->refdef->viewangles[ROLL] += - v_dmg_time / v_kicktime->value * v_dmg_roll; - r_data->refdef->viewangles[PITCH] += - v_dmg_time / v_kicktime->value * v_dmg_pitch; - v_dmg_time -= host_frametime; + ang[ROLL] += v_dmg_time / v_kicktime->value * v_dmg_roll; + ang[PITCH] += v_dmg_time / v_kicktime->value * v_dmg_pitch; + v_dmg_time -= cl.viewstate.frametime; } - if (cl.stats[STAT_HEALTH] <= 0) - r_data->refdef->viewangles[ROLL] = 80; // dead view angle + if (cl.viewstate.flags & VF_DEAD) { // VF_GIB will also set VF_DEAD + ang[ROLL] = 80; // dead view angle + } + + vec4f_t rot; + AngleQuat (ang, &rot[0]);//FIXME + r_data->refdef->viewrotation = qmulf (r_data->refdef->viewrotation, rot); } static void V_CalcIntermissionRefdef (void) { - // ent is the player model (visible when out of body) - entity_t *ent = &cl_entities[cl.viewentity]; entity_t *view; float old; - vec_t *origin = ent->origin; - vec_t *angles = ent->angles; // view is the weapon model (visible only from inside body) view = &cl.viewent; - VectorCopy (origin, r_data->refdef->vieworg); - VectorCopy (angles, r_data->refdef->viewangles); - view->model = NULL; + r_data->refdef->viewposition = cl.viewstate.origin; + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME + view->renderer.model = NULL; // always idle in intermission old = v_idlescale->value; @@ -625,109 +598,98 @@ V_CalcIntermissionRefdef (void) static void V_CalcRefdef (void) { - // ent is the player model (visible when out of body) - entity_t *ent = &cl_entities[cl.viewentity]; // view is the weapon model (visible only from inside body) entity_t *view = &cl.viewent; float bob; static float oldz = 0; - int i; - vec3_t forward, right, up; - vec_t *origin = ent->origin; - vec_t *viewangles = cl.viewangles; + vec4f_t forward = {}, right = {}, up = {}; + vec4f_t origin = cl.viewstate.origin; + vec_t *viewangles = cl.viewstate.angles; V_DriftPitch (); bob = V_CalcBob (); // refresh position - VectorCopy (origin, r_data->refdef->vieworg); - r_data->refdef->vieworg[2] += cl.viewheight + bob; + r_data->refdef->viewposition = origin; + r_data->refdef->viewposition[2] += cl.viewheight + bob; // never let it sit exactly on a node line, because a water plane can // disappear when viewed with the eye exactly on it. // server protocol specifies to only 1/8 pixel, so add 1/16 in each axis - r_data->refdef->vieworg[0] += 1.0 / 16; - r_data->refdef->vieworg[1] += 1.0 / 16; - r_data->refdef->vieworg[2] += 1.0 / 16; + r_data->refdef->viewposition += (vec4f_t) { 1.0/16, 1.0/16, 1.0/16, 0}; - VectorCopy (viewangles, r_data->refdef->viewangles); + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME V_CalcViewRoll (); V_AddIdle (); // offsets - AngleVectors (viewangles, forward, right, up); + //FIXME semi-duplicates AngleQuat (also, vec3_t vs vec4f_t) + AngleVectors (viewangles, &forward[0], &right[0], &up[0]); // don't allow cheats in multiplayer // FIXME check for dead if (cl.maxclients == 1) { - for (i = 0; i < 3; i++) { - r_data->refdef->vieworg[i] += scr_ofsx->value * forward[i] + - scr_ofsy->value * right[i] + - scr_ofsz->value * up[i]; - } + r_data->refdef->viewposition += scr_ofsx->value * forward + + scr_ofsy->value * right + + scr_ofsz->value * up; } V_BoundOffsets (); // set up gun position - VectorCopy (viewangles, view->angles); - CalcGunAngle (); - VectorCopy (origin, view->origin); - view->origin[2] += cl.viewheight; - - for (i = 0; i < 3; i++) { - view->origin[i] += forward[i] * bob * 0.4; -// view->origin[i] += right[i] * bob * 0.4; -// view->origin[i] += up[i] * bob * 0.8; - } - view->origin[2] += bob; + origin += (vec4f_t) { 0, 0, cl.viewheight, 0 }; + origin += forward * bob * 0.4f + (vec4f_t) { 0, 0, bob, 0 }; // fudge position around to keep amount of weapon visible // roughly equal with different FOV - if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) + if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) { ; - else if (r_data->scr_viewsize->int_val == 110) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 100) - view->origin[2] += 2; - else if (r_data->scr_viewsize->int_val == 90) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 80) - view->origin[2] += 0.5; + } else if (r_data->scr_viewsize->int_val == 110) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 100) { + origin += (vec4f_t) { 0, 0, 2, 0}; + } else if (r_data->scr_viewsize->int_val == 90) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 80) { + origin += (vec4f_t) { 0, 0, 0.5, 0}; + } - view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; - view->frame = cl.stats[STAT_WEAPONFRAME]; - view->skin = 0; + view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; + view->animation.frame = cl.stats[STAT_WEAPONFRAME]; + view->renderer.skin = 0; // set up the refresh position - VectorAdd (r_data->refdef->viewangles, cl.punchangle, - r_data->refdef->viewangles); + r_data->refdef->viewrotation = qmulf (cl.viewstate.punchangle, + r_data->refdef->viewrotation); // smooth out stair step ups - if ((cl.onground != -1) && (origin[2] - oldz > 0)) { + if ((cl.viewstate.onground != -1) && (origin[2] - oldz > 0)) { float steptime; - steptime = cl.time - cl.oldtime; - if (steptime < 0) - steptime = 0; + steptime = cl.viewstate.frametime; oldz += steptime * 80; if (oldz > origin[2]) oldz = origin[2]; if (origin[2] - oldz > 12) oldz = origin[2] - 12; - r_data->refdef->vieworg[2] += oldz - origin[2]; - view->origin[2] += oldz - origin[2]; - } else + r_data->refdef->viewposition[2] += oldz - origin[2]; + origin[2] += oldz - origin[2]; + } else { oldz = origin[2]; + } + { + // FIXME sort out the alias model specific negation + vec3_t ang = {-viewangles[0], viewangles[1], viewangles[2]}; + CL_TransformEntity (view, 1, ang, origin); + } - if (cl.chase && chase_active->int_val) + if (cl.chase && chase_active->int_val) { Chase_Update (); - - CL_TransformEntity (view, view->angles, true); + } } /* @@ -739,8 +701,11 @@ V_CalcRefdef (void) void V_RenderView (void) { - if (cls.state != ca_active) + if (cls.state != ca_active) { + r_data->refdef->viewposition = (vec4f_t) { 0, 0, 0, 1 }; + r_data->refdef->viewrotation = (vec4f_t) { 0, 0, 0, 1 }; return; + } if (cl.intermission) { // intermission / finale rendering V_CalcIntermissionRefdef (); diff --git a/nq/source/game.c b/nq/source/game.c index f67104472..356cbb05b 100644 --- a/nq/source/game.c +++ b/nq/source/game.c @@ -35,8 +35,8 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "game.h" -#include "server.h" +#include "nq/include/game.h" +#include "nq/include/server.h" qboolean standard_quake = false; diff --git a/nq/source/host.c b/nq/source/host.c index f6b59cf8b..bb4721677 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -56,11 +56,12 @@ #include "QF/plugin/vid_render.h" #include "buildnum.h" -#include "chase.h" #include "compat.h" -#include "host.h" -#include "server.h" -#include "sv_progs.h" + +#include "nq/include/chase.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" /* @@ -495,8 +496,7 @@ void Host_ClearMemory (void) { Sys_MaskPrintf (SYS_DEV, "Clearing memory\n"); - if (viddef.flush_caches) - viddef.flush_caches (); + CL_ClearMemory (); Mod_ClearAll (); if (host_hunklevel) Hunk_FreeToLowMark (host_hunklevel); @@ -504,8 +504,6 @@ Host_ClearMemory (void) cls.signon = 0; memset (&sv, 0, sizeof (sv)); memset (&cl, 0, sizeof (cl)); - if (r_data) - r_data->force_fullscreen = 0; } /* @@ -531,7 +529,7 @@ Host_FilterTime (float time) //FIXME not having the framerate cap is nice, but it breaks net play timedifference = (timescale / 72.0) - (realtime - oldrealtime); - if (!cls.timedemo && (timedifference > 0)) + if (!cls.demoplayback && (timedifference > 0)) return timedifference; // framerate is too high host_frametime = realtime - oldrealtime; @@ -543,7 +541,7 @@ Host_FilterTime (float time) if (host_framerate->value > 0) host_frametime = host_framerate->value; else // don't allow really long or short frames - host_frametime = bound (0.001, host_frametime, 0.1); + host_frametime = bound (0.000, host_frametime, 0.1); return 0; } @@ -698,7 +696,7 @@ _Host_Frame (float time) if (cls.demo_capture) { tex_t *tex = r_funcs->SCR_CaptureBGR (); - WritePNGqfs (va ("%s/qfmv%06d.png", qfs_gamedir->dir.shots, + WritePNGqfs (va (0, "%s/qfmv%06d.png", qfs_gamedir->dir.shots, cls.demo_capture++), tex->data, tex->width, tex->height); free (tex); @@ -861,7 +859,7 @@ Host_Init_Memory (void) Sys_Error ("Only %4.1f megs of memory reported, can't execute game", mem_size / (float) 0x100000); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); @@ -896,14 +894,9 @@ Host_Init (void) Game_Init (); - PR_Init_Cvars (); - SV_Progs_Init_Cvars (); - if (!isDedicated) CL_InitCvars (); - PR_Init (); - if (isDedicated) { PI_RegisterPlugins (server_plugin_list); Con_Init ("server"); @@ -962,7 +955,7 @@ Host_Init (void) better to run quit through here before final handoff to the sys code. */ void -Host_Shutdown (void) +Host_Shutdown (void *data) { static qboolean isdown = false; @@ -971,11 +964,4 @@ Host_Shutdown (void) return; } isdown = true; - - - NET_Shutdown (); - if (cls.state != ca_dedicated) { - CL_Shutdown (); - } - Con_Shutdown (); } diff --git a/nq/source/host_cmd.c b/nq/source/host_cmd.c index 1a827f15b..2a579032c 100644 --- a/nq/source/host_cmd.c +++ b/nq/source/host_cmd.c @@ -44,19 +44,20 @@ #include "QF/keys.h" #include "QF/model.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/screen.h" #include "QF/script.h" #include "QF/sys.h" #include "QF/va.h" -#include "client.h" #include "compat.h" -#include "host.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/client.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + int current_skill; void @@ -78,7 +79,7 @@ Host_Status_f (void) int minutes; int hours = 0; int j; - void (*print) (const char *fmt, ...); + __attribute__((format(printf, 1, 2))) void (*print) (const char *fmt, ...); if (cmd_source == src_command) { if (!sv.active) { @@ -90,7 +91,7 @@ Host_Status_f (void) print = SV_ClientPrintf; print ("host: %s\n", Cvar_VariableString ("hostname")); - print ("version: %4.2f\n", PACKAGE_VERSION); + print ("version: %4.2s\n", PACKAGE_VERSION); if (tcpipAvailable) print ("tcp/ip: %s\n", my_tcpip_address); print ("map: %s\n", sv.name); @@ -238,13 +239,13 @@ nice_time (float time) int t = time + 0.5; if (t < 60) { - return va ("%ds", t); + return va (0, "%ds", t); } else if (t < 3600) { - return va ("%dm%02ds", t / 60, t % 60); + return va (0, "%dm%02ds", t / 60, t % 60); } else if (t < 86400) { - return va ("%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); + return va (0, "%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); } else { - return va ("%dd%02dh%02dm%02ds", + return va (0, "%dd%02dh%02dm%02ds", t / 86400, (t / 3600) % 24, (t / 60) % 60, t % 60); } } @@ -278,7 +279,7 @@ Host_Map_f (void) } // check to make sure the level exists - expanded = va ("maps/%s.bsp", Cmd_Argv (1)); + expanded = va (0, "maps/%s.bsp", Cmd_Argv (1)); f = QFS_FOpenFile (expanded); if (!f) { Sys_Printf ("Can't find %s\n", expanded); @@ -394,7 +395,7 @@ spawn_parms_array (void) const char *parm; for (i = 0; i < NUM_SPAWN_PARMS; i++) { - parm = va ("%.9g", svs.clients->spawn_parms[i]); + parm = va (0, "%.9g", svs.clients->spawn_parms[i]); PL_A_AddObject (parms, PL_NewString (parm)); } return parms; @@ -433,18 +434,18 @@ entities_array (void) static plitem_t * game_dict (void) { - plitem_t *game = PL_NewDictionary (); + plitem_t *game = PL_NewDictionary (0); PL_D_AddObject (game, "comment", - PL_NewString (va ("%-21s kills:%3i/%3i", cl.levelname, + PL_NewString (va (0, "%-21s kills:%3i/%3i", cl.levelname, cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]))); PL_D_AddObject (game, "spawn_parms", spawn_parms_array ()); PL_D_AddObject (game, "current_skill", - PL_NewString (va ("%d", current_skill))); + PL_NewString (va (0, "%d", current_skill))); PL_D_AddObject (game, "name", PL_NewString (sv.name)); // sv.time is a double, so it gets 17 digits - PL_D_AddObject (game, "time", PL_NewString (va ("%.17g", sv.time))); + PL_D_AddObject (game, "time", PL_NewString (va (0, "%.17g", sv.time))); PL_D_AddObject (game, "lightstyles", lightstyles_array ()); PL_D_AddObject (game, "globals", ED_GlobalsDict (&sv_pr_state)); PL_D_AddObject (game, "entities", entities_array ()); @@ -454,7 +455,7 @@ game_dict (void) static plitem_t * convert_to_game_dict (script_t *script) { - plitem_t *game = PL_NewDictionary (); + plitem_t *game = PL_NewDictionary (0); plitem_t *item; plitem_t *list; int skill; @@ -477,7 +478,7 @@ convert_to_game_dict (script_t *script) // values Script_GetToken (script, 1); skill = (int) (atof (script->token->str) + 0.1); - PL_D_AddObject (game, "current_skill", PL_NewString (va ("%d", skill))); + PL_D_AddObject (game, "current_skill", PL_NewString (va (0, "%d", skill))); Script_GetToken (script, 1); PL_D_AddObject (game, "name", PL_NewString (script->token->str)); @@ -499,7 +500,7 @@ convert_to_game_dict (script_t *script) PL_D_AddObject (game, "lightstyles", item); // load the edicts out of the savegame file - list = ED_ConvertToPlist (script, 0); + list = ED_ConvertToPlist (script, 0, 0); item = PL_RemoveObjectAtIndex (list, 0); PL_D_AddObject (game, "globals", item); PL_D_AddObject (game, "entities", list); @@ -646,7 +647,7 @@ Host_Loadgame_f (void) Sys_Printf ("Unexpected EOF reading %s\n", name->str); goto end; } - game = PL_GetPropertyList (script->p); + game = PL_GetPropertyList (script->p, 0); } else { sscanf (script->token->str, "%i", &version); if (version != SAVEGAME_VERSION) { @@ -657,6 +658,7 @@ Host_Loadgame_f (void) game = convert_to_game_dict (script); } + memset (spawn_parms, 0, sizeof (spawn_parms)); item = PL_ObjectForKey (game, "spawn_parms"); for (i = 0; i < NUM_SPAWN_PARMS; i++) { if (i >= PL_A_NumObjects (item)) @@ -692,7 +694,6 @@ Host_Loadgame_f (void) ED_InitGlobals (&sv_pr_state, PL_ObjectForKey (game, "globals")); list = PL_ObjectForKey (game, "entities"); - entnum = 0; count = PL_A_NumObjects (list); if (count > sv.max_edicts) Host_Error ("too many entities in saved game. adjust max_edicts\n"); @@ -700,7 +701,7 @@ Host_Loadgame_f (void) plitem_t *entity = PL_ObjectAtIndex (list, entnum); edict_t *ent = EDICT_NUM (&sv_pr_state, entnum); - memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); + memset (&E_fld (ent, 0), 0, sv_pr_state.progs->entityfields * 4); ent->free = false; ED_InitEntity (&sv_pr_state, entity, ent); @@ -751,7 +752,7 @@ Host_Name_f (void) if (cmd_source == src_command) { if (strcmp (cl_name->string, newName) == 0) return; - Cvar_Set (cl_name, va ("%.15s", newName)); + Cvar_Set (cl_name, va (0, "%.15s", newName)); if (cls.state >= ca_connected) CL_Cmd_ForwardToServer (); return; @@ -989,7 +990,7 @@ Host_Spawn_f (void) } else { // set up the edict ent = host_client->edict; - memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); + memset (&E_fld (ent, 0), 0, sv_pr_state.progs->entityfields * 4); SVfloat (ent, colormap) = NUM_FOR_EDICT (&sv_pr_state, ent); SVfloat (ent, team) = (host_client->colors & 15) + 1; SVstring (ent, netname) = PR_SetString (&sv_pr_state, diff --git a/nq/source/sbar.c b/nq/source/sbar.c index e77ff103a..506cb7fa3 100644 --- a/nq/source/sbar.c +++ b/nq/source/sbar.c @@ -53,11 +53,12 @@ #include "QF/plugin/console.h" #include "QF/plugin/vid_render.h" -#include "client.h" #include "compat.h" -#include "game.h" #include "sbar.h" -#include "server.h" + +#include "nq/include/client.h" +#include "nq/include/game.h" +#include "nq/include/server.h" int sb_updates; // if >= vid.numpages, no update needed @@ -352,7 +353,7 @@ draw_num (view_t *view, int x, int y, int num, int digits, int color) static inline void draw_smallnum (view_t *view, int x, int y, int n, int packed, int colored) { - char num[4]; + char num[12]; packed = packed != 0; // ensure 0 or 1 @@ -519,7 +520,7 @@ Sbar_SortFrags (void) // sort by frags scoreboardlines = 0; for (i = 0; i < cl.maxclients; i++) { - if (cl.scores[i].name->value[0]) { + if (cl.players[i].name->value[0]) { fragsort[scoreboardlines] = i; scoreboardlines++; } @@ -527,7 +528,8 @@ Sbar_SortFrags (void) for (i = 0; i < scoreboardlines; i++) { for (j = 0; j < (scoreboardlines - 1 - i); j++) { - if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j + 1]].frags) { + if (cl.players[fragsort[j]].frags + < cl.players[fragsort[j + 1]].frags) { k = fragsort[j]; fragsort[j] = fragsort[j + 1]; fragsort[j + 1] = k; @@ -574,7 +576,7 @@ draw_frags (view_t *view) int i, k, l, p = -1; int top, bottom; int x; - scoreboard_t *s; + player_info_t *s; if (cl.maxclients == 1) return; @@ -588,7 +590,7 @@ draw_frags (view_t *view) for (i = 0; i < l; i++) { k = fragsort[i]; - s = &cl.scores[k]; + s = &cl.players[k]; if (!s->name->value[0]) continue; @@ -800,11 +802,11 @@ static void draw_rogue_face (view_t *view) { int top, bottom; - scoreboard_t *s; + player_info_t *s; // PGM 01/19/97 - team color drawing - s = &cl.scores[cl.viewentity - 1]; + s = &cl.players[cl.viewentity - 1]; top = Sbar_ColorForMap (s->topcolor); bottom = Sbar_ColorForMap (s->bottomcolor); @@ -1032,7 +1034,7 @@ Sbar_DeathmatchOverlay (view_t *view) int i, k, l; int top, bottom; int x, y; - scoreboard_t *s; + player_info_t *s; r_data->scr_copyeverything = 1; r_data->scr_fullupdate = 0; @@ -1049,7 +1051,7 @@ Sbar_DeathmatchOverlay (view_t *view) y = 40; for (i = 0; i < l; i++) { k = fragsort[i]; - s = &cl.scores[k]; + s = &cl.players[k]; if (!s->name->value[0]) continue; @@ -1647,8 +1649,8 @@ Sbar_Init (void) Key_KeydestCallback (sbar_keydest_callback); for (i = 0; i < 10; i++) { - sb_nums[0][i] = r_funcs->Draw_PicFromWad (va ("num_%i", i)); - sb_nums[1][i] = r_funcs->Draw_PicFromWad (va ("anum_%i", i)); + sb_nums[0][i] = r_funcs->Draw_PicFromWad (va (0, "num_%i", i)); + sb_nums[1][i] = r_funcs->Draw_PicFromWad (va (0, "anum_%i", i)); } sb_nums[0][10] = r_funcs->Draw_PicFromWad ("num_minus"); @@ -1675,19 +1677,19 @@ Sbar_Init (void) for (i = 0; i < 5; i++) { sb_weapons[2 + i][0] = - r_funcs->Draw_PicFromWad (va ("inva%i_shotgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_shotgun", i + 1)); sb_weapons[2 + i][1] = - r_funcs->Draw_PicFromWad (va ("inva%i_sshotgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_sshotgun", i + 1)); sb_weapons[2 + i][2] = - r_funcs->Draw_PicFromWad (va ("inva%i_nailgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_nailgun", i + 1)); sb_weapons[2 + i][3] = - r_funcs->Draw_PicFromWad (va ("inva%i_snailgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_snailgun", i + 1)); sb_weapons[2 + i][4] = - r_funcs->Draw_PicFromWad (va ("inva%i_rlaunch", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_rlaunch", i + 1)); sb_weapons[2 + i][5] = - r_funcs->Draw_PicFromWad (va ("inva%i_srlaunch", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_srlaunch", i + 1)); sb_weapons[2 + i][6] = - r_funcs->Draw_PicFromWad (va ("inva%i_lightng", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_lightng", i + 1)); } sb_ammo[0] = r_funcs->Draw_PicFromWad ("sb_shells"); @@ -1752,15 +1754,15 @@ Sbar_Init (void) for (i = 0; i < 5; i++) { hsb_weapons[2 + i][0] = - r_funcs->Draw_PicFromWad (va ("inva%i_laser", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_laser", i + 1)); hsb_weapons[2 + i][1] = - r_funcs->Draw_PicFromWad (va ("inva%i_mjolnir", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_mjolnir", i + 1)); hsb_weapons[2 + i][2] = - r_funcs->Draw_PicFromWad (va ("inva%i_gren_prox", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_gren_prox", i + 1)); hsb_weapons[2 + i][3] = - r_funcs->Draw_PicFromWad (va ("inva%i_prox_gren", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_prox_gren", i + 1)); hsb_weapons[2 + i][4] = - r_funcs->Draw_PicFromWad (va ("inva%i_prox", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_prox", i + 1)); } hsb_items[0] = r_funcs->Draw_PicFromWad ("sb_wsuit"); diff --git a/nq/source/sv_cl_phys.c b/nq/source/sv_cl_phys.c index accf26af9..1b9517ccc 100644 --- a/nq/source/sv_cl_phys.c +++ b/nq/source/sv_cl_phys.c @@ -31,11 +31,12 @@ #include "QF/cvar.h" #include "QF/sys.h" -#include "host.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + #define sv_frametime host_frametime cvar_t *sv_nostep; diff --git a/nq/source/sv_cvar.c b/nq/source/sv_cvar.c index 4d9082c96..0e8e35383 100644 --- a/nq/source/sv_cvar.c +++ b/nq/source/sv_cvar.c @@ -32,7 +32,7 @@ #include "QF/cvar.h" -#include "server.h" +#include "nq/include/server.h" void Cvar_Info (cvar_t *var) diff --git a/nq/source/sv_ded.c b/nq/source/sv_ded.c index 37fd93f2b..f79659f57 100644 --- a/nq/source/sv_ded.c +++ b/nq/source/sv_ded.c @@ -36,8 +36,8 @@ #include "QF/plugin/vid_render.h" -#include "host.h" -#include "server.h" +#include "nq/include/host.h" +#include "nq/include/server.h" client_state_t cl; client_static_t cls; @@ -68,6 +68,11 @@ CL_UpdateScreen (double realtime) { } +void +CL_ClearMemory (void) +{ +} + void CL_Cmd_ForwardToServer (void) { @@ -93,11 +98,6 @@ CL_EstablishConnection (const char *host) { } -void -CL_Shutdown () -{ -} - void CL_Init (struct cbuf_s *cbuf) { @@ -113,7 +113,7 @@ CL_NextDemo (void) { } -int +__attribute__((const)) int CL_ReadFromServer (void) { return 0; @@ -156,7 +156,7 @@ S_UnblockSound (void) } plugin_t *console_client_PluginInfo (void); -plugin_t * +__attribute__((const)) plugin_t * console_client_PluginInfo (void) { return 0; diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index 25def54ac..93aa3fba8 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -36,16 +36,17 @@ #include "QF/va.h" #include "compat.h" -#include "host.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + server_t sv; server_static_t svs; double sv_frametime; -char localmodels[MAX_MODELS][5]; // inline model names for precache +char localmodels[MAX_MODELS][6]; // inline model names for precache int sv_protocol = PROTOCOL_FITZQUAKE; @@ -388,7 +389,7 @@ SV_ClearDatagram (void) */ int fatbytes; -byte fatpvs[MAX_MAP_LEAFS / 8]; +byte fatpvs[MAP_PVS_BYTES]; static void SV_AddToFatPVS (vec3_t org, mnode_t *node) @@ -431,9 +432,9 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node) static byte * SV_FatPVS (vec3_t org) { - fatbytes = (sv.worldmodel->numleafs + 31) >> 3; + fatbytes = (sv.worldmodel->brush.numleafs + 31) >> 3; memset (fatpvs, 0, fatbytes); - SV_AddToFatPVS (org, sv.worldmodel->nodes); + SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); return fatpvs; } @@ -1036,7 +1037,8 @@ SV_CreateBaseline (void) MSG_WriteByte (&sv.signon, baseline->colormap); MSG_WriteByte (&sv.signon, baseline->skinnum); - MSG_WriteCoordAngleV (&sv.signon, baseline->origin, baseline->angles); + MSG_WriteCoordAngleV (&sv.signon, &baseline->origin[0],//FIXME + baseline->angles); if (bits & B_ALPHA) MSG_WriteByte (&sv.signon, baseline->alpha); @@ -1188,16 +1190,16 @@ SV_SpawnServer (const char *server) sv.model_precache[0] = sv_pr_state.pr_strings; sv.model_precache[1] = sv.modelname; - for (i = 1; i < sv.worldmodel->numsubmodels; i++) { + for (i = 1; i < sv.worldmodel->brush.numsubmodels; i++) { sv.model_precache[1 + i] = localmodels[i]; sv.models[i + 1] = Mod_ForName (localmodels[i], false); } // load the rest of the entities ent = EDICT_NUM (&sv_pr_state, 0); - memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); + memset (&E_fld (ent, 0), 0, sv_pr_state.progs->entityfields * 4); ent->free = false; - SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->name); + SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->path); SVfloat (ent, modelindex) = 1; // world model SVfloat (ent, solid) = SOLID_BSP; SVfloat (ent, movetype) = MOVETYPE_PUSH; @@ -1213,13 +1215,13 @@ SV_SpawnServer (const char *server) *sv_globals.serverflags = svs.serverflags; *sv_globals.time = sv.time; - ent_file = QFS_VOpenFile (va ("maps/%s.ent", server), 0, + ent_file = QFS_VOpenFile (va (0, "maps/%s.ent", server), 0, sv.worldmodel->vpath); if ((buf = QFS_LoadFile (ent_file, 0))) { ED_LoadFromFile (&sv_pr_state, (char *) buf); free (buf); } else { - ED_LoadFromFile (&sv_pr_state, sv.worldmodel->entities); + ED_LoadFromFile (&sv_pr_state, sv.worldmodel->brush.entities); } sv.active = true; diff --git a/nq/source/sv_move.c b/nq/source/sv_move.c index 013e4d48e..494fc7083 100644 --- a/nq/source/sv_move.c +++ b/nq/source/sv_move.c @@ -28,10 +28,11 @@ # include "config.h" #endif -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + #define STEPSIZE 18 int c_yes, c_no; diff --git a/nq/source/sv_phys.c b/nq/source/sv_phys.c index 795fc0f6d..f36dcfde9 100644 --- a/nq/source/sv_phys.c +++ b/nq/source/sv_phys.c @@ -31,10 +31,11 @@ #include "QF/cvar.h" #include "QF/sys.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + /* pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index c95669eb4..0489b4f4c 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -46,11 +46,12 @@ #include "QF/va.h" #include "compat.h" -#include "host.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + /* BUILT-IN FUNCTIONS */ @@ -538,7 +539,7 @@ PF_checkpos (progs_t *pr) { } -byte checkpvs[MAX_MAP_LEAFS / 8]; +byte checkpvs[MAP_PVS_BYTES]; static int PF_newcheckclient (progs_t *pr, int check) @@ -584,7 +585,7 @@ PF_newcheckclient (progs_t *pr, int check) VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org); leaf = Mod_PointInLeaf (org, sv.worldmodel); pvs = Mod_LeafPVS (leaf, sv.worldmodel); - memcpy (checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3); + memcpy (checkpvs, pvs, (sv.worldmodel->brush.numleafs + 7) >> 3); return i; } @@ -629,7 +630,7 @@ PF_checkclient (progs_t *pr) self = PROG_TO_EDICT (pr, *sv_globals.self); VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view); leaf = Mod_PointInLeaf (view, sv.worldmodel); - l = (leaf - sv.worldmodel->leafs) - 1; + l = (leaf - sv.worldmodel->brush.leafs) - 1; if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) { c_notvis++; RETURN_EDICT (pr, sv.edicts); @@ -1069,7 +1070,7 @@ PF_changeyaw (progs_t *pr) #define MSG_ALL 2 // reliable to all #define MSG_INIT 3 // write to the init string -static sizebuf_t * +static __attribute__((pure)) sizebuf_t * WriteDest (progs_t *pr) { int entnum; @@ -1279,7 +1280,7 @@ PF_changelevel (progs_t *pr) svs.changelevel_issued = true; s = P_GSTRING (pr, 0); - Cbuf_AddText (host_cbuf, va ("changelevel %s\n", s)); + Cbuf_AddText (host_cbuf, va (0, "changelevel %s\n", s)); } // entity (entity ent) testentitypos diff --git a/nq/source/sv_progs.c b/nq/source/sv_progs.c index 37b915e9c..0c79f57bd 100644 --- a/nq/source/sv_progs.c +++ b/nq/source/sv_progs.c @@ -41,16 +41,18 @@ #include "QF/sys.h" #include "compat.h" -#include "host.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + progs_t sv_pr_state; sv_globals_t sv_globals; sv_funcs_t sv_funcs; sv_fields_t sv_fields; +edict_t sv_edicts[MAX_EDICTS]; sv_data_t sv_data[MAX_EDICTS]; cvar_t *sv_progs; @@ -255,7 +257,6 @@ static sv_def_t nq_fields[] = { {ev_vector, 36, "maxs", &sv_fields.maxs}, {ev_vector, 39, "size", &sv_fields.size}, {ev_func, 42, "touch", &sv_fields.touch}, - {ev_func, 43, "use", &sv_fields.use}, {ev_func, 44, "think", &sv_fields.think}, {ev_func, 45, "blocked", &sv_fields.blocked}, {ev_float, 46, "nextthink", &sv_fields.nextthink}, @@ -273,7 +274,6 @@ static sv_def_t nq_fields[] = { {ev_float, 58, "items", &sv_fields.items}, {ev_float, 59, "takedamage", &sv_fields.takedamage}, {ev_entity, 60, "chain", &sv_fields.chain}, - {ev_float, 61, "deadflag", &sv_fields.deadflag}, {ev_vector, 62, "view_ofs", &sv_fields.view_ofs}, {ev_float, 65, "button0", &sv_fields.button0}, {ev_float, 66, "button1", &sv_fields.button1}, @@ -287,19 +287,14 @@ static sv_def_t nq_fields[] = { {ev_float, 76, "flags", &sv_fields.flags}, {ev_float, 77, "colormap", &sv_fields.colormap}, {ev_float, 78, "team", &sv_fields.team}, - {ev_float, 79, "max_health", &sv_fields.max_health}, {ev_float, 80, "teleport_time", &sv_fields.teleport_time}, - {ev_float, 81, "armortype", &sv_fields.armortype}, {ev_float, 82, "armorvalue", &sv_fields.armorvalue}, {ev_float, 83, "waterlevel", &sv_fields.waterlevel}, {ev_float, 84, "watertype", &sv_fields.watertype}, {ev_float, 85, "ideal_yaw", &sv_fields.ideal_yaw}, {ev_float, 86, "yaw_speed", &sv_fields.yaw_speed}, - {ev_entity, 87, "aiment", &sv_fields.aiment}, {ev_entity, 88, "goalentity", &sv_fields.goalentity}, {ev_float, 89, "spawnflags", &sv_fields.spawnflags}, - {ev_string, 90, "target", &sv_fields.target}, - {ev_string, 91, "targetname", &sv_fields.targetname}, {ev_float, 92, "dmg_take", &sv_fields.dmg_take}, {ev_float, 93, "dmg_save", &sv_fields.dmg_save}, {ev_entity, 94, "dmg_inflictor", &sv_fields.dmg_inflictor}, @@ -307,10 +302,6 @@ static sv_def_t nq_fields[] = { {ev_vector, 96, "movedir", &sv_fields.movedir}, {ev_string, 99, "message", &sv_fields.message}, {ev_float, 100, "sounds", &sv_fields.sounds}, - {ev_string, 101, "noise", &sv_fields.noise}, - {ev_string, 102, "noise1", &sv_fields.noise1}, - {ev_string, 103, "noise2", &sv_fields.noise2}, - {ev_string, 104, "noise3", &sv_fields.noise3}, {ev_void, 0, 0}, }; @@ -328,19 +319,7 @@ static sv_def_t nq_opt_fields[] = { {ev_integer, 0, "rotated_bbox", &sv_fields.rotated_bbox}, {ev_float, 0, "alpha", &sv_fields.alpha}, {ev_float, 0, "gravity", &sv_fields.gravity}, - // Quake 2 fields? - {ev_float, 0, "dmg", &sv_fields.dmg}, - {ev_float, 0, "dmgtime", &sv_fields.dmgtime}, - {ev_float, 0, "air_finished", &sv_fields.air_finished}, - {ev_float, 0, "pain_finished", &sv_fields.pain_finished}, - {ev_float, 0, "radsuit_finished", &sv_fields.radsuit_finished}, - {ev_float, 0, "speed", &sv_fields.speed}, - {ev_float, 0, "basevelocity", &sv_fields.basevelocity}, - {ev_float, 0, "drawPercent", &sv_fields.drawPercent}, - {ev_float, 0, "mass", &sv_fields.mass}, - {ev_float, 0, "light_level", &sv_fields.light_level}, {ev_float, 0, "items2", &sv_fields.items2}, - {ev_float, 0, "pitch_speed", &sv_fields.pitch_speed}, {ev_float, 0, "lastruntime", &sv_fields.lastruntime}, {ev_void, 0, 0}, }; @@ -361,6 +340,9 @@ set_address (sv_def_t *def, void *address) case ev_quat: *(float **)def->field = (float *) address; break; + case ev_double: + *(double **)def->field = (double *) address; + break; case ev_string: case ev_entity: case ev_field: @@ -376,7 +358,7 @@ set_address (sv_def_t *def, void *address) static int resolve_globals (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -422,7 +404,7 @@ resolve_functions (progs_t *pr, sv_def_t *def, int mode) static int resolve_fields (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -471,12 +453,32 @@ resolve (progs_t *pr) return ret; } +static int +sv_init_edicts (progs_t *pr) +{ + int i; + + memset (sv_edicts, 0, sizeof (sv_edicts)); + memset (sv_data, 0, sizeof (sv_data)); + + // init the data field of the edicts + for (i = 0; i < sv.max_edicts; i++) { + edict_t *ent = EDICT_NUM (&sv_pr_state, i); + ent->pr = &sv_pr_state; + ent->entnum = i; + ent->edict = EDICT_TO_PROG (&sv_pr_state, ent); + ent->edata = &sv_data[i]; + SVdata (ent)->edict = ent; + } + + return 1; +} + void SV_LoadProgs (void) { const char *progs_name = "progs.dat"; const char *range; - int i; if (strequal (sv_progs_ext->string, "qf")) { sv_range = PR_RANGE_QF; @@ -498,27 +500,22 @@ SV_LoadProgs (void) if (*sv_progs->string) progs_name = sv_progs->string; - PR_LoadProgs (&sv_pr_state, progs_name, sv.max_edicts, - sv_progs_zone->int_val * 1024); + sv_pr_state.max_edicts = sv.max_edicts; + sv_pr_state.zone_size = sv_progs_zone->int_val * 1024; + sv.edicts = sv_edicts; + + PR_LoadProgs (&sv_pr_state, progs_name); if (!sv_pr_state.progs) Host_Error ("SV_LoadProgs: couldn't load %s", progs_name); - - memset (sv_data, 0, sizeof (sv_data)); - - // init the data field of the edicts - for (i = 0; i < sv.max_edicts; i++) { - edict_t *ent = EDICT_NUM (&sv_pr_state, i); - ent->entnum = i; - ent->edata = &sv_data[i]; - SVdata (ent)->edict = ent; - } } void SV_Progs_Init (void) { + SV_Progs_Init_Cvars (); + pr_gametype = "netquake"; - sv_pr_state.edicts = &sv.edicts; + sv_pr_state.pr_edicts = &sv.edicts; sv_pr_state.num_edicts = &sv.num_edicts; sv_pr_state.reserved_edicts = &svs.maxclients; sv_pr_state.unlink = SV_UnlinkEdict; @@ -527,6 +524,9 @@ SV_Progs_Init (void) sv_pr_state.bi_map = bi_map; sv_pr_state.resolve = resolve; + PR_AddLoadFunc (&sv_pr_state, sv_init_edicts); + PR_Init (&sv_pr_state); + SV_PR_Cmds_Init (); Cmd_AddCommand ("edict", ED_PrintEdict_f, "Report information on a given " @@ -544,6 +544,7 @@ SV_Progs_Init (void) void SV_Progs_Init_Cvars (void) { + PR_Init_Cvars (); sv_progs = Cvar_Get ("sv_progs", "", CVAR_NONE, NULL, "Override the default game progs."); sv_progs_zone = Cvar_Get ("sv_progs_zone", "256", CVAR_NONE, NULL, diff --git a/nq/source/sv_user.c b/nq/source/sv_user.c index c1db350a8..95bd01ac9 100644 --- a/nq/source/sv_user.c +++ b/nq/source/sv_user.c @@ -42,11 +42,12 @@ #include "QF/msg.h" #include "QF/sys.h" -#include "host.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/host.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + cvar_t *sv_rollangle; cvar_t *sv_rollspeed; diff --git a/nq/source/sys_sdl.c b/nq/source/sys_sdl.c index 3f4fa726e..ddc4a8df7 100644 --- a/nq/source/sys_sdl.c +++ b/nq/source/sys_sdl.c @@ -51,11 +51,11 @@ #include "QF/qargs.h" #include "QF/sys.h" -#include "client.h" -#include "host.h" +#include "nq/include/client.h" +#include "nq/include/host.h" #ifdef _WIN32 -# include "winquake.h" +# include "nq/include/winquake.h" #endif int qf_sdl_link; @@ -85,7 +85,7 @@ startup (void) } static void -shutdown_f (void) +shutdown_f (void *data) { #ifndef _WIN32 // change stdin to blocking @@ -113,8 +113,8 @@ SDL_main (int argc, char *argv[]) isDedicated = (COM_CheckParm ("-dedicated") != 0); - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/nq/source/sys_unix.c b/nq/source/sys_unix.c index ec21a1d7b..20cce79a5 100644 --- a/nq/source/sys_unix.c +++ b/nq/source/sys_unix.c @@ -49,13 +49,13 @@ #include "QF/qargs.h" #include "QF/sys.h" -#include "client.h" -#include "host.h" +#include "nq/include/client.h" +#include "nq/include/host.h" qboolean isDedicated = false; static void -shutdown_f (void) +shutdown_f (void *data) { // change stdin to blocking fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK); @@ -75,8 +75,8 @@ main (int argc, const char **argv) isDedicated = (COM_CheckParm ("-dedicated") != 0); - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/nq/source/sys_unixd.c b/nq/source/sys_unixd.c index 55d956268..18e45a8ad 100644 --- a/nq/source/sys_unixd.c +++ b/nq/source/sys_unixd.c @@ -48,12 +48,12 @@ #include "QF/qargs.h" #include "QF/sys.h" -#include "host.h" +#include "nq/include/host.h" qboolean isDedicated = true; static void -shutdown_f (void) +shutdown_f (void *data) { // change stdin to blocking fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK); @@ -86,8 +86,8 @@ main (int argc, const char **argv) host_parms.argc = com_argc; host_parms.argv = com_argv; - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/nq/source/sys_win.c b/nq/source/sys_win.c index 421690748..ee040f956 100644 --- a/nq/source/sys_win.c +++ b/nq/source/sys_win.c @@ -36,8 +36,8 @@ #include "QF/screen.h" #include "QF/sys.h" -#include "client.h" -#include "host.h" +#include "nq/include/client.h" +#include "nq/include/host.h" qboolean isDedicated = false; @@ -104,7 +104,7 @@ startup (void) } static void -shutdown_f (void) +shutdown_f (void *data) { if (tevent) CloseHandle (tevent); @@ -207,8 +207,8 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, if (!isDedicated) init_handles (hInstance); - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/nq/source/sys_wind.c b/nq/source/sys_wind.c index b38461448..69393dfd6 100644 --- a/nq/source/sys_wind.c +++ b/nq/source/sys_wind.c @@ -34,12 +34,12 @@ #include "QF/qargs.h" #include "QF/sys.h" -#include "host.h" +#include "nq/include/host.h" qboolean isDedicated = true; static void -shutdown_f (void) +shutdown_f (void *data) { } @@ -69,8 +69,8 @@ main (int argc, const char **argv) host_parms.argc = com_argc; host_parms.argv = com_argv; - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/nq/source/world.c b/nq/source/world.c index e00208900..5f8bce898 100644 --- a/nq/source/world.c +++ b/nq/source/world.c @@ -43,10 +43,11 @@ #include "QF/sys.h" #include "compat.h" -#include "server.h" -#include "sv_progs.h" #include "world.h" +#include "nq/include/server.h" +#include "nq/include/sv_progs.h" + #define always_inline inline __attribute__((__always_inline__)) #define EDICT_LEAFS 32 @@ -244,7 +245,7 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, PR_GetString (&sv_pr_state, SVstring (ent, classname))); - hull_list = model->hull_list; + hull_list = model->brush.hull_list; } if (hull_list) { // decide which clipping hull to use, based on the size @@ -424,7 +425,7 @@ SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) leaf = (mleaf_t *) node; edict_leaf = alloc_edict_leaf (); - edict_leaf->leafnum = leaf - sv.worldmodel->leafs - 1; + edict_leaf->leafnum = leaf - sv.worldmodel->brush.leafs - 1; edict_leaf->next = SVdata (ent)->leafs; SVdata (ent)->leafs = edict_leaf; return; @@ -496,7 +497,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) // link to PVS leafs free_edict_leafs (&SVdata (ent)->leafs); if (SVfloat (ent, modelindex)) - SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); + SV_FindTouchedLeafs (ent, sv.worldmodel->brush.nodes); if (SVfloat (ent, solid) == SOLID_NOT) return; @@ -559,7 +560,7 @@ SV_PointContents (const vec3_t p) { int cont; - cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + cont = SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) cont = CONTENTS_WATER; return cont; @@ -568,7 +569,7 @@ SV_PointContents (const vec3_t p) int SV_TruePointContents (const vec3_t p) { - return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + return SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); } /* @@ -705,7 +706,7 @@ ctl_pretest_triggers (edict_t *touch, moveclip_t *clip) return 1; } -static always_inline int +static always_inline __attribute__((pure)) int ctl_pretest_other (edict_t *touch, moveclip_t *clip) { if (SVfloat (touch, solid) == SOLID_NOT) @@ -902,7 +903,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin) vec3_t boxmins, boxmaxs, offset; // check world first - hull = &sv.worldmodel->hulls[1]; + hull = &sv.worldmodel->brush.hulls[1]; if (SV_HullPointContents (hull, hull->firstclipnode, origin) != CONTENTS_EMPTY) return sv.edicts; diff --git a/pkg-config/Makefile.am b/pkg-config/Makefile.am deleted file mode 100644 index 48f4005f1..000000000 --- a/pkg-config/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -pkgdatadir=@libdir@/pkgconfig - -pkgdata_DATA=quakeforge.pc qfcc.pc - -EXTRA_DIST=quakeforge.pc.in qfcc.pc.in diff --git a/pkg-config/Makemodule.am b/pkg-config/Makemodule.am new file mode 100644 index 000000000..dca513fae --- /dev/null +++ b/pkg-config/Makemodule.am @@ -0,0 +1,5 @@ +pkgconfigdir = @libdir@/pkgconfig + +pkgconfig_DATA = pkg-config/quakeforge.pc pkg-config/qfcc.pc + +EXTRA_DIST += pkg-config/quakeforge.pc.in pkg-config/qfcc.pc.in diff --git a/qtv/Makefile.am b/qtv/Makefile.am deleted file mode 100644 index 77e3cbf5b..000000000 --- a/qtv/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source diff --git a/qtv/Makemodule.am b/qtv/Makemodule.am new file mode 100644 index 000000000..562039b04 --- /dev/null +++ b/qtv/Makemodule.am @@ -0,0 +1,2 @@ +include qtv/include/Makemodule.am +include qtv/source/Makemodule.am diff --git a/qtv/include/Makefile.am b/qtv/include/Makefile.am deleted file mode 100644 index 19df055f3..000000000 --- a/qtv/include/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST = client.h connection.h qtv.h server.h diff --git a/qtv/include/Makemodule.am b/qtv/include/Makemodule.am new file mode 100644 index 000000000..346c1716d --- /dev/null +++ b/qtv/include/Makemodule.am @@ -0,0 +1,5 @@ +EXTRA_DIST += \ + qtv/include/client.h \ + qtv/include/connection.h \ + qtv/include/qtv.h \ + qtv/include/server.h diff --git a/qtv/include/connection.h b/qtv/include/connection.h index d02e4b971..18bbbc277 100644 --- a/qtv/include/connection.h +++ b/qtv/include/connection.h @@ -36,7 +36,7 @@ /** \defgroup qtv_connection Connection Management \ingroup qtv */ -//@{ +///@{ typedef struct connection_s { netadr_t address; ///< Address of the remote end. @@ -77,6 +77,6 @@ void Connection_Del (connection_t *con); */ connection_t *Connection_Find (netadr_t *address); -//@} +///@} #endif//__connection_h diff --git a/qtv/include/qtv.h b/qtv/include/qtv.h index 57947af16..732febfb3 100644 --- a/qtv/include/qtv.h +++ b/qtv/include/qtv.h @@ -40,7 +40,7 @@ /** \defgroup qtv_general General Functions \ingroup qtv */ -//@{ +///@{ #define PORT_QTV 27501 ///< Default port to listen for connecting clients. @@ -91,6 +91,6 @@ void qtv_end_redirect (void); void qtv_sbar_init (void); -//@} +///@} #endif//__qtv_h diff --git a/qtv/source/Makefile.am b/qtv/source/Makemodule.am similarity index 61% rename from qtv/source/Makefile.am rename to qtv/source/Makemodule.am index fa73f8de8..3560edecf 100644 --- a/qtv/source/Makefile.am +++ b/qtv/source/Makemodule.am @@ -27,27 +27,18 @@ # $Id$ # -AUTOMAKE_OPTIONS= foreign +bin_PROGRAMS += @QTV_TARGETS@ -AM_CPPFLAGS= -I$(top_srcdir)/include -I$(top_srcdir)/qtv/include - -bin_PROGRAMS= @QTV_TARGETS@ - -EXTRA_PROGRAMS= qtv - -common_ldflags= -export-dynamic +EXTRA_PROGRAMS += qtv-server qtv_LIBS= \ @server_static_plugin_libs@ \ - $(top_builddir)/libs/qw/libqw.a \ - $(top_builddir)/libs/net/libnet_chan.la \ - $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/util/libQFutil.la + libs/qw/libqw.a \ + libs/net/libnet_chan.la \ + libs/console/libQFconsole.la \ + libs/util/libQFutil.la -qtv_SOURCES= client.c connection.c qtv.c sbar.c server.c sv_parse.c -qtv_LDADD= $(qtv_LIBS) $(NET_LIBS) $(DL_LIBS) $(CURSES_LIBS) -qtv_LDFLAGS= $(common_ldflags) -qtv_DEPENDENCIES= $(qtv_LIBS) - -# Kill the temp files, hopefully. -CLEANFILES = *.i *.s +qtv_server_SOURCES= qtv/source/client.c qtv/source/connection.c qtv/source/qtv.c qtv/source/sbar.c qtv/source/server.c qtv/source/sv_parse.c +qtv_server_LDADD= $(qtv_LIBS) $(NET_LIBS) $(DL_LIBS) $(CURSES_LIBS) +qtv_server_LDFLAGS= $(common_ldflags) +qtv_server_DEPENDENCIES= $(qtv_LIBS) diff --git a/qtv/source/client.c b/qtv/source/client.c index d53849f7f..43e3f424f 100644 --- a/qtv/source/client.c +++ b/qtv/source/client.c @@ -55,10 +55,10 @@ #include "qw/msg_ucmd.h" #include "qw/protocol.h" -#include "client.h" -#include "connection.h" -#include "qtv.h" -#include "server.h" +#include "qtv/include/client.h" +#include "qtv/include/connection.h" +#include "qtv/include/qtv.h" +#include "qtv/include/server.h" int client_count; static client_t *clients; @@ -177,9 +177,9 @@ cl_prespawn_f (client_t *cl, void *unused) if (buf >= sv->num_signon_buffers) buf = 0; if (buf == sv->num_signon_buffers - 1) - cmd = va ("cmd spawn %i 0\n", cl->server->spawncount); + cmd = va (0, "cmd spawn %i 0\n", cl->server->spawncount); else - cmd = va ("cmd prespawn %i %i\n", cl->server->spawncount, buf + 1); + cmd = va (0, "cmd prespawn %i %i\n", cl->server->spawncount, buf + 1); size = sv->signon_buffer_size[buf] + 1 + strlen (cmd) + 1; msg = MSG_ReliableCheckBlock (&cl->backbuf, size); SZ_Write (msg, sv->signon_buffers[buf], sv->signon_buffer_size[buf]); @@ -446,9 +446,9 @@ spectator_move (client_t *cl, usercmd_t *ucmd) AngleVectors (cl->state.cmd.angles, forward, right, up); - speed = DotProduct (cl->state.velocity, cl->state.velocity); + speed = DotProduct (cl->state.es.velocity, cl->state.es.velocity); if (speed < 1) { - VectorZero (cl->state.velocity); + VectorZero (cl->state.es.velocity); } else { speed = sqrt (speed); drop = 0; @@ -462,7 +462,7 @@ spectator_move (client_t *cl, usercmd_t *ucmd) newspeed = 0; newspeed /= speed; - VectorScale (cl->state.velocity, newspeed, cl->state.velocity); + VectorScale (cl->state.es.velocity, newspeed, cl->state.es.velocity); } fmove = ucmd->forwardmove; @@ -484,7 +484,7 @@ spectator_move (client_t *cl, usercmd_t *ucmd) wishspeed = sv->movevars.spectatormaxspeed; } - currentspeed = DotProduct (cl->state.velocity, wishdir); + currentspeed = DotProduct (cl->state.es.velocity, wishdir); addspeed = wishspeed - currentspeed; if (addspeed <= 0) return; @@ -492,10 +492,10 @@ spectator_move (client_t *cl, usercmd_t *ucmd) if (accelspeed > addspeed) accelspeed = addspeed; - VectorMultAdd (cl->state.velocity, accelspeed, wishdir, - cl->state.velocity); - VectorMultAdd (cl->state.origin, frametime, cl->state.velocity, - cl->state.origin); + VectorMultAdd (cl->state.es.velocity, accelspeed, wishdir, + cl->state.es.velocity); + VectorMultAdd (cl->state.es.origin, frametime, cl->state.es.velocity, + cl->state.es.origin); } static void @@ -612,7 +612,7 @@ client_parse_message (client_t *cl) break; case clc_tmove: MSG_ReadCoordV (net_message, o); - VectorCopy (o, cl->state.origin); + VectorCopy (o, cl->state.es.origin); break; case clc_upload: size = MSG_ReadShort (net_message); @@ -627,18 +627,18 @@ static void write_player (int num, plent_state_t *pl, server_t *sv, sizebuf_t *msg) { int i; - int pflags = (pl->flags & (PF_GIB | PF_DEAD)) + int pflags = (pl->es.flags & (PF_GIB | PF_DEAD)) | PF_MSEC | PF_COMMAND; int qf_bits = 0; - if (pl->modelindex != sv->playermodel) + if (pl->es.modelindex != sv->playermodel) pflags |= PF_MODEL; for (i = 0; i < 3; i++) - if (pl->velocity[i]) + if (pl->es.velocity[i]) pflags |= PF_VELOCITY1 << i; - if (pl->effects & 0xff) + if (pl->es.effects & 0xff) pflags |= PF_EFFECTS; - if (pl->skinnum) + if (pl->es.skinnum) pflags |= PF_SKINNUM; qf_bits = 0; @@ -670,21 +670,22 @@ write_player (int num, plent_state_t *pl, server_t *sv, sizebuf_t *msg) // } else if (ent == clent) { // // don't send a lot of data on personal entity // pflags &= ~(PF_MSEC | PF_COMMAND); -// if (pl->weaponframe) +// if (pl->es.weaponframe) // pflags |= PF_WEAPONFRAME; // } // if (client->spec_track && client->spec_track - 1 == j -// && pl->weaponframe) +// && pl->es.weaponframe) // pflags |= PF_WEAPONFRAME; MSG_WriteByte (msg, svc_playerinfo); MSG_WriteByte (msg, num); MSG_WriteShort (msg, pflags); - MSG_WriteCoordV (msg, pl->origin); + MSG_WriteCoordV (msg, &pl->es.origin[0]);//FIXME + pl->es.origin[3] = 1; - MSG_WriteByte (msg, pl->frame); + MSG_WriteByte (msg, pl->es.frame); if (pflags & PF_MSEC) { //msec = 1000 * (sv.time - cl->localtime); @@ -699,36 +700,36 @@ write_player (int num, plent_state_t *pl, server_t *sv, sizebuf_t *msg) for (i = 0; i < 3; i++) if (pflags & (PF_VELOCITY1 << i)) - MSG_WriteShort (msg, pl->velocity[i]); + MSG_WriteShort (msg, pl->es.velocity[i]); if (pflags & PF_MODEL) - MSG_WriteByte (msg, pl->modelindex); + MSG_WriteByte (msg, pl->es.modelindex); if (pflags & PF_SKINNUM) - MSG_WriteByte (msg, pl->skinnum); + MSG_WriteByte (msg, pl->es.skinnum); if (pflags & PF_EFFECTS) - MSG_WriteByte (msg, pl->effects); + MSG_WriteByte (msg, pl->es.effects); if (pflags & PF_WEAPONFRAME) - MSG_WriteByte (msg, pl->weaponframe); + MSG_WriteByte (msg, pl->es.weaponframe); if (pflags & PF_QF) { MSG_WriteByte (msg, qf_bits); if (qf_bits & PF_ALPHA) - MSG_WriteByte (msg, pl->alpha); + MSG_WriteByte (msg, pl->es.alpha); if (qf_bits & PF_SCALE) - MSG_WriteByte (msg, pl->scale); + MSG_WriteByte (msg, pl->es.scale); if (qf_bits & PF_EFFECTS2) - MSG_WriteByte (msg, pl->effects >> 8); + MSG_WriteByte (msg, pl->es.effects >> 8); if (qf_bits & PF_GLOWSIZE) - MSG_WriteByte (msg, pl->scale); + MSG_WriteByte (msg, pl->es.glow_size); if (qf_bits & PF_GLOWCOLOR) - MSG_WriteByte (msg, pl->glow_color); + MSG_WriteByte (msg, pl->es.glow_color); if (qf_bits & PF_COLORMOD) - MSG_WriteByte (msg, pl->colormod); + MSG_WriteByte (msg, pl->es.colormod); if (qf_bits & PF_FRAME2) - MSG_WriteByte (msg, pl->frame >> 8); + MSG_WriteByte (msg, pl->es.frame >> 8); } } #if 0 @@ -1204,7 +1205,7 @@ Client_Init (void) { size_t i; - ucmd_table = Hash_NewTable (251, ucmds_getkey, 0, 0); + ucmd_table = Hash_NewTable (251, ucmds_getkey, 0, 0, 0); for (i = 0; i < sizeof (ucmds) / sizeof (ucmds[0]); i++) Hash_Add (ucmd_table, &ucmds[i]); } @@ -1234,7 +1235,7 @@ Client_New (client_t *cl) MSG_WriteByte (&cl->netchan.message, sv->cdtrack); MSG_WriteByte (&cl->netchan.message, svc_stufftext); MSG_WriteString (&cl->netchan.message, - va ("fullserverinfo \"%s\"\n", + va (0, "fullserverinfo \"%s\"\n", Info_MakeString (sv->info, 0))); } diff --git a/qtv/source/connection.c b/qtv/source/connection.c index 0ff5d4464..e670880f3 100644 --- a/qtv/source/connection.c +++ b/qtv/source/connection.c @@ -46,7 +46,7 @@ #include "QF/hash.h" #include "QF/sys.h" -#include "connection.h" +#include "qtv/include/connection.h" static hashtab_t *connections; @@ -79,7 +79,7 @@ connection_compare (const void *_c1, const void *_c2, void *unused) void Connection_Init (void) { - connections = Hash_NewTable (1023, 0, connection_free, 0); + connections = Hash_NewTable (1023, 0, connection_free, 0, 0); Hash_SetHashCompare (connections, connection_get_hash, connection_compare); } diff --git a/qtv/source/qtv.c b/qtv/source/qtv.c index 7f12d013f..049f0a568 100644 --- a/qtv/source/qtv.c +++ b/qtv/source/qtv.c @@ -56,14 +56,15 @@ #include "QF/plugin/console.h" +#include "compat.h" +#include "netchan.h" + #include "qw/protocol.h" -#include "client.h" -#include "compat.h" -#include "connection.h" -#include "netchan.h" -#include "qtv.h" -#include "server.h" +#include "qtv/include/client.h" +#include "qtv/include/connection.h" +#include "qtv/include/qtv.h" +#include "qtv/include/server.h" #undef qtv_print @@ -87,7 +88,7 @@ redirect_t qtv_redirected; client_t *qtv_redirect_client; dstring_t outputbuf = {&dstring_default_mem}; -static void +static __attribute__((format(printf, 1, 0))) void qtv_print (const char *fmt, va_list args) { static int pending; @@ -213,17 +214,15 @@ qtv_memory_init (void) Cvar_SetFlags (qtv_mem_size, qtv_mem_size->flags | CVAR_ROM); mem_size = (int) (qtv_mem_size->value * 1024 * 1024); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); Memory_Init (mem_base, mem_size); } static void -qtv_shutdown (void) +qtv_shutdown (void *data) { - NET_Shutdown (); - Con_Shutdown (); Cbuf_Delete (qtv_cbuf); Cbuf_ArgsDelete (qtv_args); } @@ -238,7 +237,7 @@ qtv_quit_f (void) static void qtv_net_init (void) { - qtv_port = Cvar_Get ("qtv_port", va ("%d", PORT_QTV), 0, 0, + qtv_port = Cvar_Get ("qtv_port", va (0, "%d", PORT_QTV), 0, 0, "udp port to use"); sv_timeout = Cvar_Get ("sv_timeout", "60", 0, 0, "server timeout"); NET_Init (qtv_port->int_val); @@ -253,7 +252,7 @@ qtv_init (void) qtv_cbuf = Cbuf_New (&id_interp); qtv_args = Cbuf_ArgsNew (); - Sys_RegisterShutdown (qtv_shutdown); + Sys_RegisterShutdown (qtv_shutdown, 0); Sys_Init (); COM_ParseConfig (); diff --git a/qtv/source/sbar.c b/qtv/source/sbar.c index 73015d00a..c6e9ead8a 100644 --- a/qtv/source/sbar.c +++ b/qtv/source/sbar.c @@ -37,10 +37,11 @@ #include "QF/plugin/console.h" -#include "client.h" -#include "server.h" #include "sv_console.h" -#include "qtv.h" + +#include "qtv/include/client.h" +#include "qtv/include/server.h" +#include "qtv/include/qtv.h" static void draw_clients (view_t *view) @@ -51,7 +52,7 @@ draw_clients (view_t *view) const char *s; char *d; - str = va ("[CL: %3d]", client_count); + str = va (0, "[CL: %3d]", client_count); for (s = str, d = sb->text + view->xrel; *s; s++) *d++ = *s; } @@ -65,7 +66,7 @@ draw_servers (view_t *view) const char *s; char *d; - str = va ("[SV: %2d]", server_count); + str = va (0, "[SV: %2d]", server_count); for (s = str, d = sb->text + view->xrel; *s; s++) *d++ = *s; } diff --git a/qtv/source/server.c b/qtv/source/server.c index 6375177a2..00778acea 100644 --- a/qtv/source/server.c +++ b/qtv/source/server.c @@ -54,10 +54,10 @@ #include "qw/protocol.h" -#include "client.h" -#include "connection.h" -#include "qtv.h" -#include "server.h" +#include "qtv/include/client.h" +#include "qtv/include/connection.h" +#include "qtv/include/qtv.h" +#include "qtv/include/server.h" int server_count; static hashtab_t *server_hash; @@ -452,7 +452,8 @@ sv_new_f (void) sv->qport = qport->int_val; sv->info = Info_ParseString ("", MAX_INFO_STRING, 0); Info_SetValueForStarKey (sv->info, "*ver", - va ("%s QTV %s", QW_VERSION, PACKAGE_VERSION), 0); + va (0, "%s QTV %s", QW_VERSION, PACKAGE_VERSION), + 0); Info_SetValueForStarKey (sv->info, "*qsg_version", QW_QSG_VERSION, 0); Info_SetValueForKey (sv->info, "name", "QTV Proxy", 0); Hash_Add (server_hash, sv); @@ -493,7 +494,7 @@ sv_list_f (void) qtv_printf ("no servers\n"); return; } - list = malloc (count * sizeof (server_t **)); + list = malloc (count * sizeof (server_t *)); for (l = &servers, count = 0; *l; l = &(*l)->next, count++) list[count] = *l; qsort (list, count, sizeof (*list), server_compare); @@ -508,7 +509,7 @@ sv_list_f (void) } static void -server_shutdown (void) +server_shutdown (void *data) { Hash_FlushTable (server_hash); Hash_DelTable (server_hash); @@ -540,8 +541,8 @@ server_run (server_t *sv) void Server_Init (void) { - Sys_RegisterShutdown (server_shutdown); - server_hash = Hash_NewTable (61, server_get_key, server_free, 0); + Sys_RegisterShutdown (server_shutdown, 0); + server_hash = Hash_NewTable (61, server_get_key, server_free, 0, 0); Cmd_AddCommand ("sv_new", sv_new_f, "Add a new server"); Cmd_AddCommand ("sv_del", sv_del_f, "Remove an existing server"); Cmd_AddCommand ("sv_list", sv_list_f, "List available servers"); @@ -628,7 +629,7 @@ Server_Broadcast (server_t *sv, int reliable, int all, const byte *msg, void Server_BroadcastCommand (server_t *sv, const char *cmd) { - const char *msg = va ("%c%s", svc_stufftext, cmd); + const char *msg = va (0, "%c%s", svc_stufftext, cmd); int len = strlen (msg) + 1; Server_Broadcast (sv, 1, 1, (const byte *) msg, len); } diff --git a/qtv/source/sv_parse.c b/qtv/source/sv_parse.c index 48198e809..fcf5c3616 100644 --- a/qtv/source/sv_parse.c +++ b/qtv/source/sv_parse.c @@ -56,10 +56,10 @@ #include "qw/msg_ucmd.h" #include "qw/protocol.h" -#include "client.h" -#include "connection.h" -#include "qtv.h" -#include "server.h" +#include "qtv/include/client.h" +#include "qtv/include/connection.h" +#include "qtv/include/qtv.h" +#include "qtv/include/server.h" static void sv_serverdata (server_t *sv, qmsg_t *msg) @@ -118,7 +118,7 @@ sv_serverdata (server_t *sv, qmsg_t *msg) MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("soundlist %i %i", sv->spawncount, 0)); + va (0, "soundlist %i %i", sv->spawncount, 0)); sv->next_run = realtime; } @@ -147,11 +147,11 @@ sv_soundlist (server_t *sv, qmsg_t *msg) if (n) { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("soundlist %d %d", sv->spawncount, n)); + va (0, "soundlist %d %d", sv->spawncount, n)); } else { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("modellist %d %d", sv->spawncount, 0)); + va (0, "modellist %d %d", sv->spawncount, 0)); } sv->next_run = realtime; } @@ -183,11 +183,11 @@ sv_modellist (server_t *sv, qmsg_t *msg) if (n) { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("modellist %d %d", sv->spawncount, n)); + va (0, "modellist %d %d", sv->spawncount, n)); } else { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("prespawn %d 0 0", sv->spawncount)); + va (0, "prespawn %d 0 0", sv->spawncount)); sv->signon = 1; } sv->next_run = realtime; @@ -213,7 +213,7 @@ sv_skins_f (server_t *sv) // to get everything ready at the last miniute before we start getting // actual in-game update messages MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); - MSG_WriteString (&sv->netchan.message, va ("begin %d", sv->spawncount)); + MSG_WriteString (&sv->netchan.message, va (0, "begin %d", sv->spawncount)); sv->next_run = realtime; sv->connected = 2; sv->delta = -1; @@ -514,9 +514,9 @@ parse_player_delta (qmsg_t *msg, plent_state_t *from, plent_state_t *to) int i; int flags; - flags = to->flags = MSG_ReadShort (msg); - MSG_ReadCoordV (msg, to->origin); - to->frame = (to->frame & 0xff00) | MSG_ReadByte (msg); + flags = to->es.flags = MSG_ReadShort (msg); + MSG_ReadCoordV (msg, &to->es.origin[0]); + to->es.frame = (to->es.frame & 0xff00) | MSG_ReadByte (msg); if (flags & PF_MSEC) to->msec = MSG_ReadByte (msg); // qtv_printf ("%02x\n", msg->message->data[msg->readcount]); @@ -524,36 +524,36 @@ parse_player_delta (qmsg_t *msg, plent_state_t *from, plent_state_t *to) MSG_ReadDeltaUsercmd (msg, &from->cmd, &to->cmd); for (i = 0; i < 3; i++) { if (flags & (PF_VELOCITY1 << i)) - to->velocity[i] = (short) MSG_ReadShort (msg); + to->es.velocity[i] = (short) MSG_ReadShort (msg); } if (flags & PF_MODEL) - to->modelindex = MSG_ReadByte (msg); + to->es.modelindex = MSG_ReadByte (msg); if (flags & PF_SKINNUM) - to->skinnum = MSG_ReadByte (msg); + to->es.skinnum = MSG_ReadByte (msg); if (flags & PF_EFFECTS) - to->effects = (to->effects & 0xff00) | MSG_ReadByte (msg);; + to->es.effects = (to->es.effects & 0xff00) | MSG_ReadByte (msg); if (flags & PF_WEAPONFRAME) - to->weaponframe = MSG_ReadByte (msg); + to->es.weaponframe = MSG_ReadByte (msg); if (flags & PF_QF) { int bits; bits = MSG_ReadByte (msg); if (bits & PF_ALPHA) - to->alpha = MSG_ReadByte (msg); + to->es.alpha = MSG_ReadByte (msg); if (bits & PF_SCALE) - to->scale = MSG_ReadByte (msg); + to->es.scale = MSG_ReadByte (msg); if (bits & PF_EFFECTS2) - to->effects = (to->effects & 0x00ff) - | (MSG_ReadByte (msg) << 8); + to->es.effects = (to->es.effects & 0x00ff) + | (MSG_ReadByte (msg) << 8); if (bits & PF_GLOWSIZE) - to->glow_size = MSG_ReadByte (msg); + to->es.glow_size = MSG_ReadByte (msg); if (bits & PF_GLOWCOLOR) - to->glow_color = MSG_ReadByte (msg); + to->es.glow_color = MSG_ReadByte (msg); if (bits & PF_COLORMOD) - to->colormod = MSG_ReadByte (msg); + to->es.colormod = MSG_ReadByte (msg); if (bits & PF_FRAME2) - to->frame = (to->frame & 0xff) - | (MSG_ReadByte (msg) << 8); + to->es.frame = (to->es.frame & 0xff) + | (MSG_ReadByte (msg) << 8); } } @@ -567,12 +567,12 @@ sv_playerinfo (server_t *sv, qmsg_t *msg) int fromind, toind; static plent_state_t null_player_state; - if (!null_player_state.alpha) { - null_player_state.alpha = 255; - null_player_state.scale = 16; - null_player_state.glow_size = 0; - null_player_state.glow_color = 254; - null_player_state.colormod = 255; + if (!null_player_state.es.alpha) { + null_player_state.es.alpha = 255; + null_player_state.es.scale = 16; + null_player_state.es.glow_size = 0; + null_player_state.es.glow_color = 254; + null_player_state.es.colormod = 255; } fromind = MSG_ReadByte (msg); toind = sv->netchan.incoming_sequence & UPDATE_MASK; @@ -752,7 +752,8 @@ parse_baseline (qmsg_t *msg, entity_state_t *ent) ent->frame = MSG_ReadByte (msg); ent->colormap = MSG_ReadByte (msg); ent->skinnum = MSG_ReadByte (msg); - MSG_ReadCoordAngleV (msg, ent->origin, ent->angles); + MSG_ReadCoordAngleV (msg, &ent->origin[0], ent->angles); //FIXME + ent->origin[3] = 1; ent->colormod = 255; ent->alpha = 255; ent->scale = 16; diff --git a/qw/Makefile.am b/qw/Makefile.am deleted file mode 100644 index 77e3cbf5b..000000000 --- a/qw/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source diff --git a/qw/Makemodule.am b/qw/Makemodule.am new file mode 100644 index 000000000..9fca70d9b --- /dev/null +++ b/qw/Makemodule.am @@ -0,0 +1,2 @@ +include qw/include/Makemodule.am +include qw/source/Makemodule.am diff --git a/qw/include/Makefile.am b/qw/include/Makefile.am deleted file mode 100644 index 67535b195..000000000 --- a/qw/include/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST = \ - chase.h cl_cam.h cl_chat.h cl_demo.h cl_ents.h cl_http.h cl_input.h \ - cl_main.h cl_parse.h cl_pred.h cl_skin.h cl_slist.h cl_tent.h \ - client.h crudefile.h game.h host.h map_cfg.h server.h sv_gib.h \ - sv_demo.h sv_pr_cmds.h sv_pr_cpqw.h sv_pr_qwe.h sv_progs.h sv_qtv.h \ - sv_recorder.h diff --git a/qw/include/Makemodule.am b/qw/include/Makemodule.am new file mode 100644 index 000000000..c30d5decf --- /dev/null +++ b/qw/include/Makemodule.am @@ -0,0 +1,27 @@ +EXTRA_DIST += \ + qw/include/chase.h \ + qw/include/cl_cam.h \ + qw/include/cl_chat.h \ + qw/include/cl_demo.h \ + qw/include/cl_ents.h \ + qw/include/cl_http.h \ + qw/include/cl_input.h \ + qw/include/cl_main.h \ + qw/include/cl_parse.h \ + qw/include/cl_pred.h \ + qw/include/cl_skin.h \ + qw/include/cl_slist.h \ + qw/include/client.h \ + qw/include/crudefile.h \ + qw/include/game.h \ + qw/include/host.h \ + qw/include/map_cfg.h \ + qw/include/server.h \ + qw/include/sv_gib.h \ + qw/include/sv_demo.h \ + qw/include/sv_pr_cmds.h \ + qw/include/sv_pr_cpqw.h \ + qw/include/sv_pr_qwe.h \ + qw/include/sv_progs.h \ + qw/include/sv_qtv.h \ + qw/include/sv_recorder.h diff --git a/qw/include/cl_cam.h b/qw/include/cl_cam.h index 2bd74f644..0fbb1c0e7 100644 --- a/qw/include/cl_cam.h +++ b/qw/include/cl_cam.h @@ -43,9 +43,9 @@ extern int spec_track; // player# of who we are tracking extern int ideal_track; void Cam_Lock (int playernum); -int Cam_TrackNum (void); -qboolean Cam_DrawViewModel(void); -qboolean Cam_DrawPlayer(int playernum); +int Cam_TrackNum (void) __attribute__((pure)); +qboolean Cam_DrawViewModel(void) __attribute__((pure)); +qboolean Cam_DrawPlayer(int playernum) __attribute__((pure)); void Cam_Track(usercmd_t *cmd); void Cam_FinishMove(usercmd_t *cmd); void Cam_Reset(void); diff --git a/qw/include/cl_ents.h b/qw/include/cl_ents.h index 275cd04f6..b56e162d9 100644 --- a/qw/include/cl_ents.h +++ b/qw/include/cl_ents.h @@ -34,11 +34,9 @@ void CL_SetSolidPlayers (int playernum); void CL_ClearPredict (void); void CL_SetUpPlayerPrediction(qboolean dopred); -void CL_TransformEntity (struct entity_s * ent, const vec3_t angles, - qboolean force); +void CL_ClearEnts (void); void CL_EmitEntities (void); void CL_ClearProjectiles (void); -void CL_ParseProjectiles (qboolean nail2); void CL_ParsePacketEntities (qboolean delta); void CL_SetSolidEntities (void); void CL_ParsePlayerinfo (void); diff --git a/qw/include/cl_parse.h b/qw/include/cl_parse.h index 12bc89e12..b624dd0d3 100644 --- a/qw/include/cl_parse.h +++ b/qw/include/cl_parse.h @@ -40,7 +40,6 @@ extern int parsecountmod; extern double parsecounttime; extern int cl_playerindex; extern int cl_flagindex; -extern int cl_spikeindex; extern int viewentity; extern int cl_h_playerindex; extern int cl_gib1index; @@ -52,7 +51,7 @@ void CL_ParseServerMessage (void); void CL_ParseClientdata (void); void CL_NewTranslation (int slot, struct skin_s *skin); qboolean CL_CheckOrDownloadFile (const char *filename); -qboolean CL_IsUploading(void); +qboolean CL_IsUploading(void) __attribute__((pure)); void CL_NextUpload(void); void CL_FinishDownload (void); void CL_FailDownload (void); diff --git a/qw/include/client.h b/qw/include/client.h index 23d22e893..c7994c81d 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -28,6 +28,7 @@ #ifndef _CLIENT_H #define _CLIENT_H +#include "QF/entity.h" #include "QF/info.h" #include "QF/quakefs.h" #include "QF/vid.h" @@ -36,6 +37,8 @@ #include "QF/plugin/vid_render.h" #include "client/entities.h" +#include "client/state.h" +#include "client/view.h" #include "netchan.h" #include "qw/bothdefs.h" @@ -62,31 +65,6 @@ typedef struct player_state_s { } player_state_t; -typedef struct player_info_s { - int userid; - struct info_s *userinfo; - - // scoreboard information - struct info_key_s *name; - struct info_key_s *team; - struct info_key_s *chat; - float entertime; - int frags; - int ping; - byte pl; - - // skin information - int topcolor; - int bottomcolor; - struct info_key_s *skinname; - struct skin_s *skin; - - int spectator; - int stats[MAX_CL_STATS]; // health, etc - int prevcount; -} player_info_t; - - typedef struct { // generated on client side usercmd_t cmd; // cmd that generated the frame @@ -195,7 +173,7 @@ extern client_static_t cls; /* the client_state_t structure is wiped completely at every server signon */ -typedef struct { +typedef struct client_state_s { qboolean loading; int movemessages; // Since connecting to this server throw out @@ -207,26 +185,19 @@ typedef struct { int prev_sequence; // information for local display - int stats[MAX_CL_STATS]; // health, etc + int stats[MAX_CL_STATS]; // Health, etc float item_gettime[32]; // cl.time of aquiring item, for blinking float faceanimtime; // Use anim frame if cl.time < this cshift_t cshifts[NUM_CSHIFTS]; // Color shifts for damage, powerups cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types -// the client maintains its own idea of view angles, which are sent to the -// server each frame. And reset only at level change and teleport times - vec3_t viewangles; - // the client simulates or interpolates movement to get these values double time; // this is the time value that the client // is rendering at. always <= realtime - vec3_t simorg; - vec3_t simvel; - vec3_t simangles; - - vec3_t punchangle; // temporary view kick from weapon firing - +// the client maintains its own idea of view angles, which are sent to the +// server each frame. And reset only at level change and teleport times + viewstate_t viewstate; // pitch drifting vars float idealpitch; float pitchvel; @@ -235,12 +206,12 @@ typedef struct { double laststop; qboolean paused; // Sent over by server - int onground; // -1 when in air float viewheight; - float crouch; // local amount for smoothing stepups + float crouch; // Local amount for smoothing stepups + qboolean inwater; - int intermission; // don't change view angle, full screen, etc - int completed_time; // latched from time at intermission start + int intermission; // Don't change view angle, full screen, etc + int completed_time; // Latched from time at intermission start int servercount; // server identification for prespawns struct info_s *serverinfo; @@ -250,7 +221,7 @@ typedef struct { // can't render a frame yet double last_ping_request; // while showing scoreboard - double last_servermessage; + double last_servermessage; // (realtime) for net trouble icon /* information that is static for the entire time connected to a server */ @@ -268,8 +239,10 @@ typedef struct { char levelname[40]; // for display on solo scoreboard int spectator; int playernum; - int viewentity; + int viewentity; // cl_entitites[cl.viewentity] = player + unsigned protocol; float stdver; + int gametype; int maxclients; // serverinfo mirrors int chase; @@ -282,13 +255,13 @@ typedef struct { // refresh related state struct model_s *worldmodel; // cl_entitites[0].model - int num_entities; // stored bottom up in cl_entities array + int num_entities; // held in cl_entities array entity_t viewent; // the weapon model int cdtrack; // cd audio // all player information - player_info_t players[MAX_CLIENTS]; + player_info_t *players; lightstyle_t lightstyle[MAX_LIGHTSTYLES]; } client_state_t; @@ -341,7 +314,9 @@ extern struct cvar_s *cl_fb_players; extern client_state_t cl; -extern entity_t *cl_static_entities; +typedef struct entitystateset_s DARRAY_TYPE (struct entity_state_s) + entitystateset_t; +extern entitystateset_t cl_static_entities; extern entity_t cl_entities[512]; extern byte cl_entity_valid[2][512]; diff --git a/qw/include/crudefile.h b/qw/include/crudefile.h index 384b6126c..be827be33 100644 --- a/qw/include/crudefile.h +++ b/qw/include/crudefile.h @@ -35,6 +35,6 @@ void CF_Close (int desc); const char * CF_Read (int desc); int CF_Write (int desc, const char *buf); int CF_EOF (int desc); -int CF_Quota (void); +int CF_Quota (void) __attribute__((pure)); #endif // _CRUDEFILE_H diff --git a/qw/include/host.h b/qw/include/host.h index 87404b019..27ad77325 100644 --- a/qw/include/host.h +++ b/qw/include/host.h @@ -50,9 +50,9 @@ extern int host_framecount; // incremented every frame, never reset void Host_ServerFrame (void); void Host_InitCommands (void); void Host_Init (void); -void Host_Shutdown(void); -void Host_Error (const char *error, ...) __attribute__((format(printf,1,2))); -void Host_EndGame (const char *message, ...) __attribute__((format(printf,1,2))); +void Host_Shutdown(void *data); +void Host_Error (const char *error, ...) __attribute__((format(printf,1,2), noreturn)); +void Host_EndGame (const char *message, ...) __attribute__((format(printf,1,2), noreturn)); void Host_Frame (float time); void Host_Quit_f (void); void Host_ClientCommands (const char *fmt, ...) __attribute__((format(printf,1,2))); diff --git a/qw/include/server.h b/qw/include/server.h index dbda77e12..b32a46c63 100644 --- a/qw/include/server.h +++ b/qw/include/server.h @@ -73,7 +73,7 @@ typedef struct { unsigned int model_player_checksum; unsigned int eyes_player_checksum; - char name[64]; // map name + char *name; // map name char modelname[MAX_QPATH]; // maps/.bsp, for model_precache[0] struct model_s *worldmodel; const char *model_precache[MAX_MODELS]; // NULL terminated @@ -488,15 +488,15 @@ client_t *SV_AllocClient (int spectator, int server); void SV_SavePenaltyFilter (client_t *cl, filtertype_t type, double pentime); double SV_RestorePenaltyFilter (client_t *cl, filtertype_t type); -void SV_Shutdown (void); +void SV_Shutdown (void *data); void SV_Frame (float time); void SV_FinalMessage (const char *message); void SV_DropClient (client_t *drop); -int SV_CalcPing (client_t *cl); +int SV_CalcPing (client_t *cl) __attribute__((pure)); void SV_FullClientUpdate (client_t *client, sizebuf_t *buf); void SV_FullClientUpdateToClient (client_t *client, backbuf_t *backbuf); -int SV_ModelIndex (const char *name); +int SV_ModelIndex (const char *name) __attribute__((pure)); qboolean SV_CheckBottom (struct edict_s *ent); qboolean SV_movestep (struct edict_s *ent, const vec3_t move, @@ -549,12 +549,12 @@ struct trace_s; int SV_FlyMove (struct edict_s *ent, float time, struct trace_s *steptrace); struct trace_s SV_PushEntity (struct edict_s *ent, vec3_t push, unsigned traceflags); -int SV_EntCanSupportJump (struct edict_s *ent); +int SV_EntCanSupportJump (struct edict_s *ent) __attribute__((pure)); // // sv_send.c // -void SV_Print (const char *fmt, va_list args); +void SV_Print (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); void SV_Printf (const char *fmt, ...) __attribute__((format(printf,1,2))); void SV_SendClientMessages (void); void SV_GetStats (struct edict_s *ent, int spectator, int stats[]); @@ -611,7 +611,7 @@ extern struct dstring_s outputbuf; // sv_ccmds.c // void SV_Status_f (void); -const char *SV_Current_Map (void); +const char *SV_Current_Map (void) __attribute__((pure)); void SV_SetLocalinfo (const char *key, const char *value); diff --git a/qw/include/sv_progs.h b/qw/include/sv_progs.h index ca96f7de5..88fe18c24 100644 --- a/qw/include/sv_progs.h +++ b/qw/include/sv_progs.h @@ -193,8 +193,13 @@ extern progs_t sv_pr_state; #define SVstring(e,f) SVFIELD (e, f, string) #define SVfunc(e,f) SVFIELD (e, f, func) #define SVentity(e,f) SVFIELD (e, f, entity) -#define SVvector(e,f) SVFIELD (e, f, vector) +#define SVvector(e,f) (&SVFIELD (e, f, vector)) #define SVinteger(e,f) SVFIELD (e, f, integer) +#if TYPECHECK_PROGS +#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__)) +#else +#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f) +#endif typedef struct edict_leaf_s { struct edict_leaf_s *next; diff --git a/qw/include/sv_recorder.h b/qw/include/sv_recorder.h index 80b55d419..f8be8b97f 100644 --- a/qw/include/sv_recorder.h +++ b/qw/include/sv_recorder.h @@ -42,12 +42,12 @@ recorder_t *SVR_AddUser (void (*writer)(void *, struct sizebuf_s *, int), int demo, void *user); void SVR_RemoveUser (recorder_t *r); struct sizebuf_s *SVR_WriteBegin (byte type, int to, int size); -struct sizebuf_s *SVR_Datagram (void); +struct sizebuf_s *SVR_Datagram (void) __attribute__((const)); void SVR_ForceFrame (void); void SVR_Pause (recorder_t *r); void SVR_Continue (recorder_t *r); void SVR_SetDelta (recorder_t *r, int delta, int in_frame); void SVR_SendMessages (void); -int SVR_NumRecorders (void); +int SVR_NumRecorders (void) __attribute__((pure)); #endif//__sv_recorder_h diff --git a/qw/source/Makefile.am b/qw/source/Makefile.am deleted file mode 100644 index 858e25e17..000000000 --- a/qw/source/Makefile.am +++ /dev/null @@ -1,192 +0,0 @@ -## Process this file with automake to produce Makefile.in -# -# Makefile.am -# -# Automake-using build system for QuakeForge -# -# Copyright (C) 2000 Jeff Teunissen -# -# This Makefile 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: -# -# Free Software Foundation, Inc. -# 59 Temple Place - Suite 330 -# Boston, MA 02111-1307, USA -# -# $Id$ -# - -AUTOMAKE_OPTIONS= foreign - -# Stuff that is common to both client and server -AM_CPPFLAGS= -I$(top_srcdir)/include -I$(top_srcdir)/qw/include @LIBCURL_CFLAGS@ -SDL_LIBS = @SDL_LIBS@ -AM_CFLAGS= @PTHREAD_CFLAGS@ - -bin_PROGRAMS= @QW_TARGETS@ - -EXTRA_PROGRAMS= \ - qw-client-fbdev qw-client-sdl qw-client-svga qw-client-win qw-client-x11 \ - qw-server qw-master - -noinst_LIBRARIES= @qw_libs@ -EXTRA_LIBRARIES=libqw_client.a libqw_common.a libqw_sdl.a libqw_server.a - - -libqw_common_a_SOURCES=\ - game.c map_cfg.c pmove.c pmovetst.c net_packetlog.c -libqw_sdl_a_SOURCES=cl_sys_sdl.c -libqw_sdl_a_CFLAGS=$(SDL_CFLAGS) - -common_ldflags= -export-dynamic @PTHREAD_LDFLAGS@ - -# Server builds -# -# ... System type -if SYSTYPE_WIN32 -syssv_SRC= sv_sys_win.c -else -syssv_SRC= sv_sys_unix.c -endif - -EXTRA_DIST=sv_sys_win.c sv_sys_unix.c - -libqw_server_a_SOURCES= \ - crudefile.c sv_ccmds.c sv_demo.c sv_ents.c sv_gib.c sv_init.c sv_main.c \ - sv_move.c sv_phys.c sv_pr_cmds.c sv_pr_cpqw.c sv_pr_qwe.c sv_progs.c \ - sv_qtv.c sv_recorder.c sv_sbar.c sv_send.c sv_user.c world.c - -qw_server_LIBS= \ - @server_static_plugin_libs@ \ - $(top_builddir)/libs/qw/libqw.a \ - $(top_builddir)/libs/net/libnet_chan.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/gib/libQFgib.la \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/util/libQFutil.la - -qw_server_deps=libqw_server.a libqw_common.a $(qw_server_LIBS) -qw_server_SOURCES= $(syssv_SRC) -qw_server_LDADD= $(qw_server_deps) $(NET_LIBS) $(DL_LIBS) $(CURSES_LIBS) -qw_server_LDFLAGS= $(common_ldflags) -qw_server_DEPENDENCIES= $(qw_server_deps) - -qw_master_deps=$(top_builddir)/libs/util/libQFutil.la -qw_master_SOURCES= master.c -qw_master_LDADD= $(qw_master_deps) $(NET_LIBS) -qw_master_DEPENDENCIES= $(qw_master_deps) -qw_master_LDFLAGS= $(common_ldflags) - -cl_plugin_LIBS= \ - @client_static_plugin_libs@ - -qw_client_LIBS= \ - $(top_builddir)/libs/qw/libqw.a \ - $(top_builddir)/libs/net/libnet_chan.la \ - $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/video/targets/libQFjs.la \ - $(top_builddir)/libs/audio/libQFcd.la \ - $(top_builddir)/libs/audio/libQFsound.la \ - $(top_builddir)/libs/image/libQFimage.la \ - $(top_builddir)/libs/gib/libQFgib.la \ - $(top_builddir)/libs/ruamoko/libQFruamoko.la \ - $(top_builddir)/libs/util/libQFutil.la - -client_LIBS= $(qw_client_LIBS) -client_libs= libqw_client.a libqw_common.a \ - $(top_builddir)/libs/client/libQFclient.la - -libqw_client_a_SOURCES= \ - cl_cam.c cl_chase.c cl_chat.c cl_cmd.c cl_cvar.c cl_demo.c \ - cl_entparse.c cl_ents.c cl_http.c cl_input.c cl_main.c cl_ngraph.c \ - cl_parse.c cl_pred.c cl_rss.c cl_screen.c cl_skin.c cl_slist.c \ - cl_tent.c cl_view.c \ - locs.c sbar.c teamplay.c - -# Software-rendering clients - -# ... Linux FBDev -qw_client_fbdev_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFfbdev.la \ - $(client_LIBS) -qw_client_fbdev_SOURCES= cl_sys_unix.c -qw_client_fbdev_LDADD= $(qw_client_fbdev_libs) $(NET_LIBS) $(LIBCURL_LIBS) -qw_client_fbdev_LDFLAGS= $(common_ldflags) -qw_client_fbdev_DEPENDENCIES= $(qw_client_fbdev_libs) - -# ... Simple DirectMedia Layer, version 1.2 and higher -qw_client_sdl_libs= \ - libqw_sdl.a \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFsdl.la \ - $(client_LIBS) -qw_client_sdl_SOURCES=sdl_link.c -qw_client_sdl_LDADD= libqw_sdl.a $(qw_client_sdl_libs) $(SDL_LIBS) $(NET_LIBS) $(LIBCURL_LIBS) -qw_client_sdl_LDFLAGS= $(common_ldflags) -qw_client_sdl_DEPENDENCIES= libqw_sdl.a $(qw_client_sdl_libs) - -# ... Linux SVGAlib -qw_client_svga_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFsvga.la \ - $(client_LIBS) -qw_client_svga_SOURCES= cl_sys_unix.c -qw_client_svga_LDADD= $(qw_client_svga_libs) $(SVGA_LIBS) $(NET_LIBS) $(LIBCURL_LIBS) -qw_client_svga_LDFLAGS= $(common_ldflags) -qw_client_svga_DEPENDENCIES= $(qw_client_svga_libs) - -# ... X11 -qw_client_x11_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFx11.la \ - $(client_LIBS) -qw_client_x11_SOURCES= cl_sys_unix.c -qw_client_x11_LDADD= $(qw_client_x11_libs) \ - $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ - $(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(LIBCURL_LIBS) $(DL_LIBS) -qw_client_x11_LDFLAGS= $(common_ldflags) -qw_client_x11_DEPENDENCIES= $(qw_client_x11_libs) - -# ... Microsoft Windows -qw_client_win_libs= \ - $(client_libs) \ - $(cl_plugin_LIBS) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFwin.la \ - $(client_LIBS) -qw_client_win_SOURCES= cl_sys_win.c -qw_client_win_LDADD= $(qw_client_win_libs) -lgdi32 -lwinmm $(NET_LIBS) $(LIBCURL_LIBS) -qw_client_win_LDFLAGS= $(common_ldflags) -qw_client_win_DEPENDENCIES= $(qw_client_win_libs) - -# Stuff that doesn't get linked into an executable NEEDS to be mentioned here, -# or it won't be distributed with 'make dist' - -# Kill the temp files, hopefully. -CLEANFILES = *.i *.s $(YACCLEX_CLEANFILES) diff --git a/qw/source/Makemodule.am b/qw/source/Makemodule.am new file mode 100644 index 000000000..bad7bd189 --- /dev/null +++ b/qw/source/Makemodule.am @@ -0,0 +1,176 @@ +## Process this file with automake to produce Makefile.in +# +# Makefile.am +# +# Automake-using build system for QuakeForge +# +# Copyright (C) 2000 Jeff Teunissen +# +# This Makefile 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: +# +# Free Software Foundation, Inc. +# 59 Temple Place - Suite 330 +# Boston, MA 02111-1307, USA +# +# $Id$ +# + +bin_PROGRAMS += @QW_TARGETS@ + +EXTRA_PROGRAMS += \ + qw-client-fbdev qw-client-sdl qw-client-svga qw-client-wgl qw-client-x11 \ + qw-server qw-master + +noinst_LIBRARIES += @qw_libs@ +EXTRA_LIBRARIES += qw/source/libqw_client.a qw/source/libqw_common.a qw/source/libqw_sdl.a qw/source/libqw_server.a + + +qw_source_libqw_common_a_SOURCES=\ + qw/source/game.c qw/source/map_cfg.c qw/source/pmove.c qw/source/pmovetst.c qw/source/net_packetlog.c +qw_source_libqw_sdl_a_SOURCES=qw/source/cl_sys_sdl.c +qw_source_libqw_sdl_a_CFLAGS=$(SDL_CFLAGS) + +# Server builds +# +# ... System type +if SYSTYPE_WIN32 +syssv_SRC= qw/source/sv_sys_win.c +else +syssv_SRC= qw/source/sv_sys_unix.c +endif + +EXTRA_DIST+=qw/source/sv_sys_win.c qw/source/sv_sys_unix.c + +qw_source_libqw_server_a_SOURCES= \ + qw/source/crudefile.c qw/source/sv_ccmds.c qw/source/sv_demo.c qw/source/sv_ents.c qw/source/sv_gib.c qw/source/sv_init.c qw/source/sv_main.c \ + qw/source/sv_move.c qw/source/sv_phys.c qw/source/sv_pr_cmds.c qw/source/sv_pr_cpqw.c qw/source/sv_pr_qwe.c qw/source/sv_progs.c \ + qw/source/sv_qtv.c qw/source/sv_recorder.c qw/source/sv_sbar.c qw/source/sv_send.c qw/source/sv_user.c qw/source/world.c + +qw_server_LIBS= \ + @server_static_plugin_libs@ \ + libs/qw/libqw.a \ + libs/net/libnet_chan.la \ + libs/models/libQFmodels.la \ + libs/gib/libQFgib.la \ + libs/ruamoko/libQFruamoko.la \ + libs/gamecode/libQFgamecode.la \ + libs/console/libQFconsole.la \ + libs/util/libQFutil.la + +qw_server_deps=qw/source/libqw_server.a qw/source/libqw_common.a $(qw_server_LIBS) +qw_server_SOURCES= $(syssv_SRC) +qw_server_LDADD= $(qw_server_deps) $(NET_LIBS) $(DL_LIBS) $(CURSES_LIBS) +qw_server_LDFLAGS= $(common_ldflags) +qw_server_DEPENDENCIES= $(qw_server_deps) + +qw_master_deps=libs/util/libQFutil.la +qw_master_SOURCES= qw/source/master.c +qw_master_LDADD= $(qw_master_deps) $(NET_LIBS) +qw_master_DEPENDENCIES= $(qw_master_deps) +qw_master_LDFLAGS= $(common_ldflags) + +qw_cl_plugin_LIBS= \ + @client_static_plugin_libs@ + +qw_client_LIBS= \ + libs/qw/libqw.a \ + libs/net/libnet_chan.la \ + libs/entity/libQFentity.la \ + libs/console/libQFconsole.la \ + libs/video/targets/libQFjs.la \ + libs/audio/libQFcd.la \ + libs/audio/libQFsound.la \ + libs/image/libQFimage.la \ + libs/gib/libQFgib.la \ + libs/ruamoko/libQFruamoko.la \ + libs/util/libQFutil.la +qw_client_libs= qw/source/libqw_client.a qw/source/libqw_common.a \ + libs/client/libQFclient.la + +qw_source_libqw_client_a_SOURCES= \ + qw/source/cl_cam.c qw/source/cl_chase.c qw/source/cl_chat.c qw/source/cl_cmd.c qw/source/cl_cvar.c qw/source/cl_demo.c \ + qw/source/cl_entparse.c qw/source/cl_ents.c qw/source/cl_http.c qw/source/cl_input.c qw/source/cl_main.c qw/source/cl_ngraph.c \ + qw/source/cl_parse.c qw/source/cl_pred.c qw/source/cl_rss.c qw/source/cl_screen.c qw/source/cl_skin.c qw/source/cl_slist.c \ + qw/source/cl_view.c \ + qw/source/sbar.c qw/source/teamplay.c + +# Software-rendering clients + +# ... Linux FBDev +qw_client_fbdev_libs= \ + $(qw_client_libs) \ + $(qw_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFfbdev.la \ + $(qw_client_LIBS) +qw_client_fbdev_SOURCES= qw/source/cl_sys_unix.c +qw_client_fbdev_LDADD= $(qw_client_fbdev_libs) $(NET_LIBS) $(LIBCURL_LIBS) +qw_client_fbdev_LDFLAGS= $(common_ldflags) +qw_client_fbdev_DEPENDENCIES= $(qw_client_fbdev_libs) + +# ... Simple DirectMedia Layer, version 1.2 and higher +qw_client_sdl_libs= \ + qw/source/libqw_sdl.a \ + $(qw_client_libs) \ + $(qw_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFsdl.la \ + $(qw_client_LIBS) +qw_client_sdl_SOURCES=qw/source/sdl_link.c +qw_client_sdl_LDADD= qw/source/libqw_sdl.a $(qw_client_sdl_libs) $(SDL_LIBS) $(NET_LIBS) $(LIBCURL_LIBS) +qw_client_sdl_LDFLAGS= $(common_ldflags) +qw_client_sdl_DEPENDENCIES= qw/source/libqw_sdl.a $(qw_client_sdl_libs) + +# ... Linux SVGAlib +qw_client_svga_libs= \ + $(qw_client_libs) \ + $(qw_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFsvga.la \ + $(qw_client_LIBS) +qw_client_svga_SOURCES= qw/source/cl_sys_unix.c +qw_client_svga_LDADD= $(qw_client_svga_libs) $(SVGA_LIBS) $(NET_LIBS) $(LIBCURL_LIBS) +qw_client_svga_LDFLAGS= $(common_ldflags) +qw_client_svga_DEPENDENCIES= $(qw_client_svga_libs) + +# ... X11 +qw_client_x11_libs= \ + $(qw_client_libs) \ + $(qw_cl_plugin_LIBS) \ + libs/video/renderer/libQFrenderer.la \ + libs/models/libQFmodels.la \ + libs/video/targets/libQFx11.la \ + $(qw_client_LIBS) +qw_client_x11_SOURCES= qw/source/cl_sys_unix.c +qw_client_x11_LDADD= $(qw_client_x11_libs) \ + $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ + $(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(LIBCURL_LIBS) $(DL_LIBS) +qw_client_x11_LDFLAGS= $(common_ldflags) +qw_client_x11_DEPENDENCIES= $(qw_client_x11_libs) + +# ... SGI/Microsoft WGL (Windows OpenGL) +qw_client_wgl_libs= \ + $(qw_client_libs) \ + $(qw_cl_plugin_LIBS) \ + $(opengl_LIBS) \ + libs/video/targets/libQFwgl.la \ + $(qw_client_LIBS) +qw_client_wgl_SOURCES= qw/source/cl_sys_win.c +qw_client_wgl_LDADD= $(qw_client_wgl_libs) -lgdi32 -lwinmm $(NET_LIBS) $(LIBCURL_LIBS) +qw_client_wgl_LDFLAGS= $(common_ldflags) +qw_client_wgl_DEPENDENCIES= $(qw_client_wgl_libs) diff --git a/qw/source/cl_cam.c b/qw/source/cl_cam.c index f7e9adf44..383bc313a 100644 --- a/qw/source/cl_cam.c +++ b/qw/source/cl_cam.c @@ -45,14 +45,15 @@ #include "QF/cvar.h" #include "QF/msg.h" -#include "chase.h" -#include "cl_cam.h" -#include "cl_input.h" -#include "client.h" #include "compat.h" -#include "qw/pmove.h" #include "sbar.h" +#include "qw/include/chase.h" +#include "qw/include/cl_cam.h" +#include "qw/include/cl_input.h" +#include "qw/include/client.h" +#include "qw/pmove.h" + #define PM_SPECTATORMAXSPEED 500 #define PM_STOPSPEED 100 #define PM_MAXSPEED 320 @@ -217,23 +218,23 @@ Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec, vectoangles (vec, v); VectorCopy (v, pmove.angles); VectorNormalize (vec); - VectorMultAdd (player->pls.origin, 800, vec, v); + VectorMultAdd (player->pls.es.origin, 800, vec, v); // v is endpos // fake a player move - trace = Cam_DoTrace (player->pls.origin, v); + trace = Cam_DoTrace (&player->pls.es.origin[0], v);//FIXME if ( /* trace.inopen || */ trace.inwater) return 9999; VectorCopy (trace.endpos, vec); - len = VectorDistance (trace.endpos, player->pls.origin); + len = VectorDistance (trace.endpos, player->pls.es.origin); if (len < 32 || len > 800) return 9999; if (checkvis) { - trace = Cam_DoTrace (self->pls.origin, vec); + trace = Cam_DoTrace (&self->pls.es.origin[0], vec);//FIXME if (trace.fraction != 1 || trace.inwater) return 9999; - len = VectorDistance (trace.endpos, self->pls.origin); + len = VectorDistance (trace.endpos, self->pls.es.origin); } return len; @@ -241,17 +242,17 @@ Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec, // Is player visible? static qboolean -Cam_IsVisible (player_state_t * player, vec3_t vec) +Cam_IsVisible (player_state_t *player, vec3_t vec) { float d; trace_t trace; vec3_t v; - trace = Cam_DoTrace (player->pls.origin, vec); + trace = Cam_DoTrace (&player->pls.es.origin[0], vec);//FIXME if (trace.fraction != 1 || /* trace.inopen || */ trace.inwater) return false; // check distance, don't let the player get too far away or too close - VectorSubtract (player->pls.origin, vec, v); + VectorSubtract (player->pls.es.origin, vec, v); d = VectorLength (v); return (d > 16.0); @@ -438,23 +439,23 @@ Cam_Track (usercmd_t *cmd) if (cl_chasecam->int_val) { cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; - VectorCopy (player->viewangles, cl.viewangles); - VectorCopy (player->pls.origin, desired_position); - if (memcmp (&desired_position, &self->pls.origin, + VectorCopy (player->viewangles, cl.viewstate.angles); + VectorCopy (player->pls.es.origin, desired_position); + if (memcmp (&desired_position, &self->pls.es.origin, sizeof (desired_position)) != 0) { if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoordV (&cls.netchan.message, desired_position); } // move there locally immediately - VectorCopy (desired_position, self->pls.origin); + VectorCopy (desired_position, self->pls.es.origin); } - self->pls.weaponframe = player->pls.weaponframe; + self->pls.es.weaponframe = player->pls.es.weaponframe; } else { // Ok, move to our desired position and set our angles to view // the player - VectorSubtract (desired_position, self->pls.origin, vec); + VectorSubtract (desired_position, self->pls.es.origin, vec); len = VectorLength (vec); cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; if (len > 16) { // close enough? @@ -464,11 +465,11 @@ Cam_Track (usercmd_t *cmd) } } // move there locally immediately - VectorCopy (desired_position, self->pls.origin); + VectorCopy (desired_position, self->pls.es.origin); - VectorSubtract (player->pls.origin, desired_position, vec); - vectoangles (vec, cl.viewangles); - cl.viewangles[0] = -cl.viewangles[0]; + VectorSubtract (player->pls.es.origin, desired_position, vec); + vectoangles (vec, cl.viewstate.angles); + cl.viewstate.angles[0] = -cl.viewstate.angles[0]; } } @@ -519,7 +520,7 @@ Cam_SetView (void) player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; - VectorSubtract (player->pls.origin, cl.simorg, vec); + VectorSubtract (player->pls.es.origin, cl.simorg, vec); if (cam_forceview) { cam_forceview = false; vectoangles (vec, cam_viewangles); @@ -535,8 +536,8 @@ Cam_SetView (void) adjustang (cam_viewangles[YAW], vec2[YAW], cl_camera_maxyaw->value); } - VectorCopy (cam_viewangles, cl.viewangles); - VectorCopy (cl.viewangles, cl.simangles); + VectorCopy (cam_viewangles, cl.viewstate.angles); + VectorCopy (cl.viewstate.angles, cl.simangles); cl.simangles[ROLL] = 0; // FIXME @@@ } #endif @@ -559,7 +560,7 @@ Cam_FinishMove (usercmd_t *cmd) player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; - VectorSubtract (player->pls.origin, self->pls.origin, vec); + VectorSubtract (player->pls.es.origin, self->pls.es.origin, vec); if (cam_forceview) { cam_forceview = false; vectoangles (vec, cam_viewangles); @@ -575,7 +576,7 @@ Cam_FinishMove (usercmd_t *cmd) adjustang (cam_viewangles[YAW], vec2[YAW], cl_camera_maxyaw->value); } - VectorCopy (cam_viewangles, cl.viewangles); + VectorCopy (cam_viewangles, cl.viewstate.angles); } #endif @@ -586,7 +587,7 @@ Cam_FinishMove (usercmd_t *cmd) if (autocam > CAM_TRACK) { Cam_Unlock (); - VectorCopy (cl.viewangles, cmd->angles); + VectorCopy (cl.viewstate.angles, cmd->angles); return; } } else diff --git a/qw/source/cl_chase.c b/qw/source/cl_chase.c index 26f5b02b4..68c9e207a 100644 --- a/qw/source/cl_chase.c +++ b/qw/source/cl_chase.c @@ -41,16 +41,19 @@ #include "QF/mathlib.h" #include "QF/plugin/vid_render.h" +#include "QF/simd/vec4f.h" -#include "chase.h" -#include "cl_input.h" -#include "client.h" +#include "qw/include/chase.h" +#include "qw/include/cl_input.h" +#include "qw/include/client.h" #include "world.h" -vec3_t camera_origin = {0,0,0}; -vec3_t camera_angles = {0,0,0}; -vec3_t player_origin = {0,0,0}; -vec3_t player_angles = {0,0,0}; + +vec4f_t camera_origin = {0,0,0,1}; +vec4f_t player_origin = {0,0,0,1}; +vec4f_t player_angles = {0,0,0,1}; + +vec3_t camera_angles = {0,0,0}; vec3_t chase_angles; vec3_t chase_dest; @@ -86,7 +89,7 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) memset (&trace, 0, sizeof (trace)); trace.fraction = 1; - MOD_TraceLine (cl.worldmodel->hulls, 0, start, end, &trace); + MOD_TraceLine (cl.worldmodel->brush.hulls, 0, start, end, &trace); VectorCopy (trace.endpos, impact); } @@ -94,19 +97,17 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) void Chase_Update (void) { - float pitch, yaw, fwd; - int i; - usercmd_t cmd; // movement direction - vec3_t forward, up, right, stop, dir; + float pitch, yaw, fwd; + usercmd_t cmd; // movement direction + vec4f_t forward = {}, up = {}, right = {}, stop = {}, dir = {}; // lazy camera, look toward player entity if (chase_active->int_val == 2 || chase_active->int_val == 3) { // control camera angles with key/mouse/joy-look - - camera_angles[PITCH] += cl.viewangles[PITCH] - player_angles[PITCH]; - camera_angles[YAW] += cl.viewangles[YAW] - player_angles[YAW]; - camera_angles[ROLL] += cl.viewangles[ROLL] - player_angles[ROLL]; + vec3_t d; + VectorSubtract (cl.viewstate.angles, player_angles, d); + VectorAdd (camera_angles, d, camera_angles); if (chase_active->int_val == 2) { if (camera_angles[PITCH] < -60) @@ -118,48 +119,48 @@ Chase_Update (void) // move camera, it's not enough to just change the angles because // the angles are automatically changed to look toward the player - if (chase_active->int_val == 3) - VectorCopy (r_data->refdef->vieworg, player_origin); + if (chase_active->int_val == 3) { + player_origin = r_data->refdef->viewposition; + } - AngleVectors (camera_angles, forward, right, up); - VectorScale (forward, chase_back->value, forward); - VectorSubtract (player_origin, forward, camera_origin); + AngleVectors (camera_angles, &forward[0], &right[0], &up[0]); + camera_origin = player_origin - chase_back->value * forward; if (chase_active->int_val == 2) { - VectorCopy (r_data->refdef->vieworg, player_origin); + player_origin = r_data->refdef->viewposition; // don't let camera get too low - if (camera_origin[2] < player_origin[2] + chase_up->value) + if (camera_origin[2] < player_origin[2] + chase_up->value) { camera_origin[2] = player_origin[2] + chase_up->value; + } } // don't let camera get too far from player - VectorSubtract (camera_origin, player_origin, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - player_origin; + forward = normalf (dir); - if (VectorLength (dir) > chase_back->value) { - VectorScale (forward, chase_back->value, dir); - VectorAdd (player_origin, dir, camera_origin); + if (magnitudef (dir)[0] > chase_back->value) { + camera_origin = player_origin + forward * chase_back->value; } // check for walls between player and camera - VectorScale (forward, 8, forward); - VectorAdd (camera_origin, forward, camera_origin); - TraceLine (player_origin, camera_origin, stop); - if (VectorLength (stop) != 0) - VectorSubtract (stop, forward, camera_origin); + camera_origin += 8 * forward; + //FIXME + TraceLine (&player_origin[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop - forward; + } - VectorSubtract (camera_origin, r_data->refdef->vieworg, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - r_data->refdef->viewposition; + forward = normalf (dir); if (chase_active->int_val == 2) { if (dir[1] == 0 && dir[0] == 0) { // look straight up or down -// camera_angles[YAW] = r_data->refdef->viewangles[YAW]; +// camera_angles[YAW] = r_data->refdef->viewstate.angles[YAW]; if (dir[2] > 0) camera_angles[PITCH] = 90; else @@ -182,13 +183,13 @@ Chase_Update (void) } } - VectorCopy (camera_angles, r_data->refdef->viewangles);// rotate camera - VectorCopy (camera_origin, r_data->refdef->vieworg); // move camera + AngleQuat (camera_angles, &r_data->refdef->viewrotation[0]);//FIXME rotate camera + r_data->refdef->viewposition = camera_origin; // move camera // get basic movement from keyboard memset (&cmd, 0, sizeof (cmd)); -// VectorCopy (cl.viewangles, cmd.angles); +// VectorCopy (cl.viewstate.angles, cmd.angles); if (in_strafe.state & 1) { cmd.sidemove += cl_sidespeed->value * CL_KeyState (&in_right); @@ -208,54 +209,54 @@ Chase_Update (void) } // mouse and joystick controllers add to movement - VectorSet (0, cl.viewangles[1] - camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); - VectorScale (forward, viewdelta.position[2] * m_forward->value, - forward); - VectorScale (right, viewdelta.position[0] * m_side->value, right); - VectorAdd (forward, right, dir); + VectorSet (0, cl.viewstate.angles[1] - camera_angles[1], 0, dir); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME + forward *= viewdelta.position[2] * m_forward->value; + right *= viewdelta.position[0] * m_side->value; + dir = forward + right; cmd.forwardmove += dir[0]; cmd.sidemove -= dir[1]; VectorSet (0, camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME VectorScale (forward, cmd.forwardmove, forward); VectorScale (right, cmd.sidemove, right); VectorAdd (forward, right, dir); if (dir[1] || dir[0]) { - cl.viewangles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); - if (cl.viewangles[YAW] < 0) cl.viewangles[YAW] += 360; -// if (cl.viewangles[YAW] < 180) -// cl.viewangles[YAW] += 180; -// else -// cl.viewangles[YAW] -= 180; + cl.viewstate.angles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); + if (cl.viewstate.angles[YAW] < 0) { + cl.viewstate.angles[YAW] += 360; + } } - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; // remember the new angle to calculate the difference next frame - VectorCopy (cl.viewangles, player_angles); + VectorCopy (cl.viewstate.angles, player_angles); return; } // regular camera, faces same direction as player - AngleVectors (cl.viewangles, forward, right, up); + //FIXME + AngleVectors (cl.viewstate.angles, &forward[0], &right[0], &up[0]); // calc exact destination - for (i = 0; i < 3; i++) - camera_origin[i] = r_data->refdef->vieworg[i] - - forward[i] * chase_back->value - right[i] * chase_right->value; + camera_origin = r_data->refdef->viewposition + - forward * chase_back->value - right * chase_right->value; + // chase_up is world up camera_origin[2] += chase_up->value; // check for walls between player and camera - TraceLine (r_data->refdef->vieworg, camera_origin, stop); - if (VectorLength (stop) != 0) - for (i = 0; i < 3; i++) - camera_origin[i] = stop[i] + forward[i] * 8; + //FIXME + TraceLine (&r_data->refdef->viewposition[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop + forward * 8; + } - VectorCopy (camera_origin, r_data->refdef->vieworg); + r_data->refdef->viewposition = camera_origin; } diff --git a/qw/source/cl_chat.c b/qw/source/cl_chat.c index 2b40e64dd..fbc26b983 100644 --- a/qw/source/cl_chat.c +++ b/qw/source/cl_chat.c @@ -44,8 +44,8 @@ #include "QF/sys.h" #include "QF/va.h" -#include "client.h" -#include "cl_chat.h" +#include "qw/include/client.h" +#include "qw/include/cl_chat.h" llist_t *ignore_list, *dead_ignore_list; @@ -80,7 +80,8 @@ CL_Ignore_Sanity_Check (void) static qboolean live_iterator (ignore_t *ig, llist_node_t *node) { - Sys_Printf ("%5i - %s\n", ig->uid, Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); + Sys_Printf ("%5i - %s\n", ig->uid, + Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); return true; } @@ -115,7 +116,8 @@ CL_Ignore_f (void) new->slot = i; new->uid = uid; llist_append (ignore_list, new); - Sys_Printf ("User %i (%s) is now ignored.\n", uid, Info_ValueForKey (cl.players[i].userinfo, "name")); + Sys_Printf ("User %i (%s) is now ignored.\n", uid, + Info_ValueForKey (cl.players[i].userinfo, "name")); return; } } @@ -136,11 +138,14 @@ CL_Unignore_f (void) else { uid = atoi (Cmd_Argv (1)); if ((node = llist_findnode (ignore_list, &uid))) { - Sys_Printf ("User %i (%s) is no longer ignored.\n", uid, Info_ValueForKey (cl.players[LLIST_DATA (node, ignore_t)->slot].userinfo, "name")); + int slot = LLIST_DATA (node, ignore_t)->slot; + Sys_Printf ("User %i (%s) is no longer ignored.\n", uid, + Info_ValueForKey (cl.players[slot].userinfo, "name")); CL_Ignore_Free (llist_remove (node), 0); return; } - Sys_Printf ("User %i does not exist or is not presently ignored.\n", uid); + Sys_Printf ("User %i does not exist or is not presently ignored.\n", + uid); } } @@ -159,7 +164,8 @@ static qboolean cam_iterator (ignore_t *ig, llist_node_t *node) llist_remove (node); return true; } - dsprintf (g_cam_test, "%s: ", Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); + dsprintf (g_cam_test, "%s: ", + Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); if (!strncmp (g_cam_test->str, g_cam_str, g_cam_test->size - 1)) { return g_cam_allowed = false; } else @@ -187,9 +193,11 @@ CL_Chat_User_Disconnected (int uid) if ((ig = llist_remove (llist_findnode (ignore_list, &uid)))) { if (ig->lastname) free ((void *)ig->lastname); - ig->lastname = strdup (Info_ValueForKey (cl.players[ig->slot].userinfo, "name")); + ig->lastname = strdup (Info_ValueForKey (cl.players[ig->slot].userinfo, + "name")); llist_append (dead_ignore_list, ig); - Sys_Printf ("Ignored user %i (%s) left the server. Now ignoring by name...\n", ig->uid, ig->lastname); + Sys_Printf ("Ignored user %i (%s) left the server. " + "Now ignoring by name...\n", ig->uid, ig->lastname); } } @@ -215,8 +223,12 @@ CL_Chat_Check_Name (const char *name, int slot) if (g_ccn_found) { g_ccn_found->slot = slot; g_ccn_found->uid = cl.players[slot].userid; - llist_append (ignore_list, llist_remove (llist_getnode (dead_ignore_list, g_ccn_found))); - Sys_Printf ("User %i (%s) is using an ignored name. Now ignoring by user id...\n", g_ccn_found->uid, g_ccn_found->lastname); + llist_append (ignore_list, + llist_remove (llist_getnode (dead_ignore_list, + g_ccn_found))); + Sys_Printf ("User %i (%s) is using an ignored name. " + "Now ignoring by user id...\n", g_ccn_found->uid, + g_ccn_found->lastname); } } @@ -233,7 +245,7 @@ CL_ChatInfo (int val) val = 0; if (cls.chat != val) { cls.chat = val; - Cbuf_AddText(cl_cbuf, va ("setinfo chat \"%d\"\n", val)); + Cbuf_AddText(cl_cbuf, va (0, "setinfo chat \"%d\"\n", val)); } } diff --git a/qw/source/cl_cmd.c b/qw/source/cl_cmd.c index 1b02d4581..3b0f7b072 100644 --- a/qw/source/cl_cmd.c +++ b/qw/source/cl_cmd.c @@ -37,12 +37,33 @@ #include "QF/cbuf.h" #include "QF/cmd.h" +#include "QF/dstring.h" #include "QF/msg.h" #include "QF/sys.h" #include "QF/teamplay.h" -#include "client.h" +#include "qw/include/client.h" +static void +send_say (const char *str) +{ + static dstring_t *teambuf; + const char *s; + + if (!teambuf) { + teambuf = dstring_newstr (); + } + + s = Team_ParseSay (teambuf, Cmd_Args (1)); + if (*s && *s < 32 && *s != 10) { + // otherwise the server would eat leading characters + // less than 32 or greater than 127 + SZ_Print (&cls.netchan.message, "\""); + SZ_Print (&cls.netchan.message, s); + SZ_Print (&cls.netchan.message, "\""); + } else + SZ_Print (&cls.netchan.message, s); +} /* CL_Cmd_ForwardToServer @@ -70,21 +91,10 @@ CL_Cmd_ForwardToServer (void) if (!strcasecmp (Cmd_Argv (0), "say") || !strcasecmp (Cmd_Argv (0), "say_team")) { - const char *s; - - s = Team_ParseSay (Cmd_Args (1)); - if (*s && *s < 32 && *s != 10) { - // otherwise the server would eat leading characters - // less than 32 or greater than 127 - SZ_Print (&cls.netchan.message, "\""); - SZ_Print (&cls.netchan.message, s); - SZ_Print (&cls.netchan.message, "\""); - } else - SZ_Print (&cls.netchan.message, s); - return; + send_say(Cmd_Args (1)); + } else { + SZ_Print (&cls.netchan.message, Cmd_Args (1)); } - - SZ_Print (&cls.netchan.message, Cmd_Args (1)); } } diff --git a/qw/source/cl_cvar.c b/qw/source/cl_cvar.c index c92322c7c..f9e116ae9 100644 --- a/qw/source/cl_cvar.c +++ b/qw/source/cl_cvar.c @@ -39,9 +39,10 @@ #include "QF/msg.h" #include "QF/va.h" -#include "client.h" #include "compat.h" +#include "qw/include/client.h" + void Cvar_Info (cvar_t *var) { @@ -52,7 +53,7 @@ Cvar_Info (cvar_t *var) if (cls.state >= ca_connected && !cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va ("setinfo \"%s\" \"%s\"\n", var->name, + va (0, "setinfo \"%s\" \"%s\"\n", var->name, var->string)); } } diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index 31ce11620..df54decd7 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -54,13 +54,14 @@ #include "QF/sys.h" #include "QF/va.h" -#include "cl_cam.h" -#include "cl_demo.h" -#include "cl_ents.h" -#include "cl_main.h" -#include "client.h" #include "compat.h" -#include "host.h" + +#include "qw/include/cl_cam.h" +#include "qw/include/cl_demo.h" +#include "qw/include/cl_ents.h" +#include "qw/include/cl_main.h" +#include "qw/include/client.h" +#include "qw/include/host.h" #include "qw/pmove.h" typedef struct { @@ -69,14 +70,14 @@ typedef struct { double fps; } td_stats_t; -int demo_timeframes_isactive; -int demo_timeframes_index; +static int demo_timeframes_isactive; +static int demo_timeframes_index; static int demotime_cached; static float cached_demotime; static byte cached_newtime; -float nextdemotime; -char demoname[1024]; -double *demo_timeframes_array; +static float nextdemotime; +static dstring_t *demoname; +static double *demo_timeframes_array; #define CL_TIMEFRAMES_ARRAYBLOCK 4096 int timedemo_count; @@ -332,7 +333,7 @@ nextdemomessage: cls.netchan.outgoing_sequence++; for (i = 0; i < 3; i++) { Qread (cls.demofile, &f, 4); - cl.viewangles[i] = LittleFloat (f); + cl.viewstate.angles[i] = LittleFloat (f); } break; @@ -461,7 +462,7 @@ CL_WriteDemoCmd (usercmd_t *pcmd) Qwrite (cls.demofile, &cmd, sizeof (cmd)); for (i = 0; i < 3; i++) { - fl = LittleFloat (cl.viewangles[i]); + fl = LittleFloat (cl.viewstate.angles[i]); Qwrite (cls.demofile, &fl, 4); } @@ -633,7 +634,7 @@ demo_default_name (const char *argv1) strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); // the leading path-name is to be removed from cl.worldmodel->name - mapname = QFS_SkipPath (cl.worldmodel->name); + mapname = QFS_SkipPath (cl.worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended @@ -651,9 +652,8 @@ demo_start_recording (int track) { byte buf_data[MAX_MSGLEN + 10]; // + 10 for header char *s; - int n, i, j; + int n, i; int seq = 1; - entity_t *ent; entity_state_t *es, blankes; player_info_t *player; sizebuf_t buf; @@ -696,7 +696,7 @@ demo_start_recording (int track) // send server info string MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("fullserverinfo \"%s\"\n", + MSG_WriteString (&buf, va (0, "fullserverinfo \"%s\"\n", Info_MakeString (cl.serverinfo, 0))); // flush packet @@ -754,21 +754,18 @@ demo_start_recording (int track) SZ_Clear (&buf); } // spawnstatic - for (ent = cl_static_entities; ent; ent = ent->unext) { + for (size_t staticIndex = 0; staticIndex < cl_static_entities.size; + staticIndex++) { + entity_state_t *es = &cl_static_entities.a[staticIndex]; + MSG_WriteByte (&buf, svc_spawnstatic); - for (j = 1; j < cl.nummodels; j++) - if (ent->model == cl.model_precache[j]) - break; - if (j == cl.nummodels) - MSG_WriteByte (&buf, 0); - else - MSG_WriteByte (&buf, j); + MSG_WriteByte (&buf, es->modelindex); - MSG_WriteByte (&buf, ent->frame); + MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, ent->skinnum); - MSG_WriteCoordAngleV (&buf, ent->origin, ent->angles); + MSG_WriteByte (&buf, es->skinnum); + MSG_WriteCoordAngleV (&buf, &es->origin[0], &es->angles[0]); if (buf.cursize > MAX_MSGLEN / 2) { CL_WriteRecordDemoMessage (&buf, seq++); @@ -792,7 +789,7 @@ demo_start_recording (int track) MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, es->colormap); MSG_WriteByte (&buf, es->skinnum); - MSG_WriteCoordAngleV (&buf, es->origin, es->angles); + MSG_WriteCoordAngleV (&buf, &es->origin[0], es->angles);//FIXME if (buf.cursize > MAX_MSGLEN / 2) { CL_WriteRecordDemoMessage (&buf, seq++); @@ -802,7 +799,7 @@ demo_start_recording (int track) } MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("cmd spawn %i 0\n", cl.servercount)); + MSG_WriteString (&buf, va (0, "cmd spawn %i 0\n", cl.servercount)); if (buf.cursize) { CL_WriteRecordDemoMessage (&buf, seq++); @@ -862,7 +859,7 @@ demo_start_recording (int track) // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("skins\n")); + MSG_WriteString (&buf, va (0, "skins\n")); CL_WriteRecordDemoMessage (&buf, seq++); @@ -990,12 +987,12 @@ CL_StartDemo (void) int type; // open the demo file - name = dstring_strdup (demoname); + name = dstring_strdup (demoname->str); QFS_DefaultExtension (name, ".mvd"); cls.demofile = QFS_FOpenFile (name->str); if (!cls.demofile) { - dstring_copystr (name, demoname); + dstring_copystr (name, demoname->str); QFS_DefaultExtension (name, ".qwd"); cls.demofile = QFS_FOpenFile (name->str); } @@ -1050,7 +1047,7 @@ CL_PlayDemo_f (void) { switch (Cmd_Argc ()) { case 1: - if (!demoname[0]) + if (!demoname->str[0]) goto playdemo_error; // fall through case 2: @@ -1072,7 +1069,7 @@ playdemo_error: CL_Disconnect (); if (Cmd_Argc () > 1) - strncpy (demoname, Cmd_Argv (1), sizeof (demoname)); + dstring_copystr (demoname, Cmd_Argv (1)); CL_StartDemo (); } @@ -1182,7 +1179,7 @@ CL_TimeDemo_f (void) timedemo_data = 0; } timedemo_data = calloc (timedemo_runs, sizeof (td_stats_t)); - strncpy (demoname, Cmd_Argv (1), sizeof (demoname)); + dstring_copystr (demoname, Cmd_Argv (1)); CL_StartTimeDemo (); timedemo_runs = timedemo_count = max (count, 1); timedemo_data = calloc (timedemo_runs, sizeof (td_stats_t)); @@ -1191,6 +1188,8 @@ CL_TimeDemo_f (void) void CL_Demo_Init (void) { + demoname = dstring_newstr (); + demo_timeframes_isactive = 0; demo_timeframes_index = 0; demo_timeframes_array = NULL; diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index ffad98174..7100d2726 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -36,26 +36,26 @@ #endif #include "QF/cvar.h" -#include "QF/locs.h" #include "QF/msg.h" #include "QF/render.h" #include "QF/skin.h" #include "QF/sys.h" -#include "qw/msg_ucmd.h" - -#include "qw/bothdefs.h" -#include "cl_cam.h" -#include "cl_ents.h" -#include "cl_main.h" -#include "cl_parse.h" -#include "cl_pred.h" -#include "cl_tent.h" #include "compat.h" -#include "d_iface.h" -#include "host.h" + +#include "client/temp_entities.h" +#include "client/view.h" + +#include "qw/msg_ucmd.h" #include "qw/pmove.h" -#include "clview.h" +#include "qw/bothdefs.h" + +#include "qw/include/cl_cam.h" +#include "qw/include/cl_ents.h" +#include "qw/include/cl_main.h" +#include "qw/include/cl_parse.h" +#include "qw/include/cl_pred.h" +#include "qw/include/host.h" static struct predicted_player { int flags; @@ -130,6 +130,8 @@ CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits) if (bits & U_ANGLE3) to->angles[2] = MSG_ReadAngle (net_message); + to->origin[3] = 1; + if (bits & U_SOLID) { // FIXME } @@ -360,7 +362,7 @@ CL_ParseDemoPlayerinfo (int num) info = &cl.players[num]; state = &cl.frames[parsecountmod].playerstate[num]; - state->pls.number = num; + state->pls.es.number = num; if (info->prevcount > cl.parsecount || !cl.parsecount) { prevstate = &dummy; @@ -383,25 +385,25 @@ CL_ParseDemoPlayerinfo (int num) memcpy (state, prevstate, sizeof (player_state_t)); flags = MSG_ReadShort (net_message); - state->pls.flags = TranslateFlags (flags); + state->pls.es.flags = TranslateFlags (flags); state->messagenum = cl.parsecount; state->pls.cmd.msec = 0; - state->pls.frame = MSG_ReadByte (net_message); + state->pls.es.frame = MSG_ReadByte (net_message); state->state_time = parsecounttime; for (i=0; i <3; i++) if (flags & (DF_ORIGIN << i)) - state->pls.origin[i] = MSG_ReadCoord (net_message); + state->pls.es.origin[i] = MSG_ReadCoord (net_message); for (i=0; i <3; i++) if (flags & (DF_ANGLES << i)) state->pls.cmd.angles[i] = MSG_ReadAngle16 (net_message); if (flags & DF_MODEL) - state->pls.modelindex = MSG_ReadByte (net_message); + state->pls.es.modelindex = MSG_ReadByte (net_message); if (flags & DF_SKINNUM) - state->pls.skinnum = MSG_ReadByte (net_message); + state->pls.es.skinnum = MSG_ReadByte (net_message); if (flags & DF_EFFECTS) - state->pls.effects = MSG_ReadByte (net_message); + state->pls.es.effects = MSG_ReadByte (net_message); if (flags & DF_WEAPONFRAME) - state->pls.weaponframe = MSG_ReadByte (net_message); + state->pls.es.weaponframe = MSG_ReadByte (net_message); VectorCopy (state->pls.cmd.angles, state->viewangles); } @@ -422,14 +424,15 @@ CL_ParsePlayerinfo (void) state = &cl.frames[parsecountmod].playerstate[num]; - state->pls.number = num; + state->pls.es.number = num; - flags = state->pls.flags = MSG_ReadShort (net_message); + flags = state->pls.es.flags = MSG_ReadShort (net_message); state->messagenum = cl.parsecount; - MSG_ReadCoordV (net_message, state->pls.origin); + MSG_ReadCoordV (net_message, &state->pls.es.origin[0]);//FIXME + state->pls.es.origin[3] = 1; - state->pls.frame = MSG_ReadByte (net_message); + state->pls.es.frame = MSG_ReadByte (net_message); // the other player's last move was likely some time // before the packet was sent out, so accurately track @@ -445,30 +448,30 @@ CL_ParsePlayerinfo (void) for (i = 0; i < 3; i++) { if (flags & (PF_VELOCITY1 << i)) - state->pls.velocity[i] = (short) MSG_ReadShort (net_message); + state->pls.es.velocity[i] = (short) MSG_ReadShort (net_message); else - state->pls.velocity[i] = 0; + state->pls.es.velocity[i] = 0; } if (flags & PF_MODEL) i = MSG_ReadByte (net_message); else i = cl_playerindex; - state->pls.modelindex = i; + state->pls.es.modelindex = i; if (flags & PF_SKINNUM) - state->pls.skinnum = MSG_ReadByte (net_message); + state->pls.es.skinnum = MSG_ReadByte (net_message); else - state->pls.skinnum = 0; + state->pls.es.skinnum = 0; if (flags & PF_EFFECTS) - state->pls.effects = MSG_ReadByte (net_message); + state->pls.es.effects = MSG_ReadByte (net_message); else - state->pls.effects = 0; + state->pls.es.effects = 0; if (flags & PF_WEAPONFRAME) - state->pls.weaponframe = MSG_ReadByte (net_message); + state->pls.es.weaponframe = MSG_ReadByte (net_message); else - state->pls.weaponframe = 0; + state->pls.es.weaponframe = 0; VectorCopy (state->pls.cmd.angles, state->viewangles); @@ -482,20 +485,20 @@ CL_ParsePlayerinfo (void) bits = MSG_ReadByte (net_message); if (bits & PF_ALPHA) { val = MSG_ReadByte (net_message); - ent->colormod[3] = val / 255.0; + ent->renderer.colormod[3] = val / 255.0; } if (bits & PF_SCALE) { val = MSG_ReadByte (net_message); - ent->scale = val / 16.0; + state->pls.es.scale = val; } if (bits & PF_EFFECTS2) { - state->pls.effects |= MSG_ReadByte (net_message) << 8; + state->pls.es.effects |= MSG_ReadByte (net_message) << 8; } if (bits & PF_GLOWSIZE) { - state->pls.glow_size = MSG_ReadByte (net_message); + state->pls.es.glow_size = MSG_ReadByte (net_message); } if (bits & PF_GLOWCOLOR) { - state->pls.glow_color = MSG_ReadByte (net_message); + state->pls.es.glow_color = MSG_ReadByte (net_message); } if (bits & PF_COLORMOD) { float r = 1.0, g = 1.0, b = 1.0; @@ -505,10 +508,10 @@ CL_ParsePlayerinfo (void) g = (float) ((val >> 2) & 7) * (1.0 / 7.0); b = (float) (val & 3) * (1.0 / 3.0); } - VectorSet (r, g, b, ent->colormod); + VectorSet (r, g, b, ent->renderer.colormod); } if (bits & PF_FRAME2) { - state->pls.frame |= MSG_ReadByte (net_message) << 8; + state->pls.es.frame |= MSG_ReadByte (net_message) << 8; } } } @@ -542,7 +545,7 @@ CL_SetSolidEntities (void) continue; if (!cl.model_precache[state->modelindex]) continue; - if (cl.model_precache[state->modelindex]->hulls[1].firstclipnode + if (cl.model_precache[state->modelindex]->brush.hulls[1].firstclipnode || cl.model_precache[state->modelindex]->clipbox) { if (pmove.numphysent == MAX_PHYSENTS) { Sys_Printf ("WARNING: entity physent overflow, email " @@ -599,22 +602,23 @@ CL_SetUpPlayerPrediction (qboolean dopred) if (state->messagenum != cl.parsecount) continue; // not present this frame - if (!state->pls.modelindex) + if (!state->pls.es.modelindex) continue; pplayer->active = true; - pplayer->flags = state->pls.flags; + pplayer->flags = state->pls.es.flags; // note that the local player is special, since he moves locally // we use his last predicted postition if (j == cl.playernum) { VectorCopy (cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK]. - playerstate[cl.playernum].pls.origin, pplayer->origin); + playerstate[cl.playernum].pls.es.origin, + pplayer->origin); } else { // predict only half the move to minimize overruns msec = 500 * (playertime - state->state_time); if (msec <= 0 || !dopred) { - VectorCopy (state->pls.origin, pplayer->origin); + VectorCopy (state->pls.es.origin, pplayer->origin); // Sys_MaskPrintf (SYS_DEV, "nopredict\n"); } else { // predict players movement @@ -622,7 +626,7 @@ CL_SetUpPlayerPrediction (qboolean dopred) // Sys_MaskPrintf (SYS_DEV, "predict: %i\n", msec); CL_PredictUsercmd (state, &exact, &state->pls.cmd, false); - VectorCopy (exact.pls.origin, pplayer->origin); + VectorCopy (exact.pls.es.origin, pplayer->origin); } } } diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index edd048090..9da38dc9c 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -36,27 +36,31 @@ #endif #include "QF/cvar.h" -#include "QF/locs.h" +#include "QF/entity.h" #include "QF/msg.h" #include "QF/render.h" #include "QF/skin.h" #include "QF/sys.h" -#include "qw/msg_ucmd.h" - -#include "qw/bothdefs.h" -#include "chase.h" -#include "cl_cam.h" -#include "cl_ents.h" -#include "cl_main.h" -#include "cl_parse.h" -#include "cl_pred.h" -#include "cl_tent.h" #include "compat.h" #include "d_iface.h" -#include "host.h" + +#include "client/effects.h" +#include "client/locs.h" +#include "client/temp_entities.h" +#include "client/view.h" + +#include "qw/bothdefs.h" +#include "qw/msg_ucmd.h" #include "qw/pmove.h" -#include "clview.h" + +#include "qw/include/chase.h" +#include "qw/include/cl_cam.h" +#include "qw/include/cl_ents.h" +#include "qw/include/cl_main.h" +#include "qw/include/cl_parse.h" +#include "qw/include/cl_pred.h" +#include "qw/include/host.h" entity_t cl_player_ents[MAX_CLIENTS]; entity_t cl_flag_ents[MAX_CLIENTS]; @@ -79,73 +83,6 @@ CL_ClearEnts (void) CL_Init_Entity (&cl_player_ents[i]); } -static void -CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, - byte glow_color) -{ - float radius; - dlight_t *dl; - static quat_t normal = {0.4, 0.2, 0.05, 0.7}; - static quat_t red = {0.5, 0.05, 0.05, 0.7}; - static quat_t blue = {0.05, 0.05, 0.5, 0.7}; - static quat_t purple = {0.5, 0.05, 0.5, 0.7}; - - effects &= EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT; - if (!effects) { - if (!glow_size) - return; - } - - dl = r_funcs->R_AllocDlight (key); - if (!dl) - return; - VectorCopy (org, dl->origin); - - if (effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT)) { - radius = 200 + (rand () & 31); - if (effects & EF_BRIGHTLIGHT) { - radius += 200; - dl->origin[2] += 16; - } - if (effects & EF_DIMLIGHT) - if (effects & ~EF_DIMLIGHT) - radius -= 100; - dl->radius = radius; - dl->die = cl.time + 0.1; - - switch (effects & (EF_RED | EF_BLUE)) { - case EF_RED | EF_BLUE: - QuatCopy (purple, dl->color); - break; - case EF_RED: - QuatCopy (red, dl->color); - break; - case EF_BLUE: - QuatCopy (blue, dl->color); - break; - default: - QuatCopy (normal, dl->color); - break; - } - } - - if (glow_size) { - dl->radius += glow_size < 128 ? glow_size * 8.0 : - (glow_size - 256) * 8.0; - dl->die = cl.time + 0.1; - if (glow_color) { - if (glow_color == 255) { - dl->color[0] = dl->color[1] = dl->color[2] = 1.0; - } else { - byte *tempcolor; - - tempcolor = (byte *) &d_8to24table[glow_color]; - VectorScale (tempcolor, 1 / 255.0, dl->color); - } - } - } -} - // Hack hack hack static inline int is_dead_body (entity_state_t *s1) @@ -168,85 +105,22 @@ is_gib (entity_state_t *s1) return 0; } -void -CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force) -{ - vec3_t ang; - vec_t *forward, *left, *up; - - if (VectorIsZero (angles)) { - VectorSet (1, 0, 0, ent->transform + 0); - VectorSet (0, 1, 0, ent->transform + 4); - VectorSet (0, 0, 1, ent->transform + 8); - } else if (force || !VectorCompare (angles, ent->angles)) { - forward = ent->transform + 0; - left = ent->transform + 4; - up = ent->transform + 8; - VectorCopy (angles, ang); - if (ent->model && ent->model->type == mod_alias) { - // stupid quake bug - // why, oh, why, do alias models pitch in the opposite direction - // to everything else? - ang[PITCH] = -ang[PITCH]; - } - AngleVectors (ang, forward, left, up); - VectorNegate (left, left); // AngleVectors is right-handed - } - VectorCopy (angles, ent->angles); - ent->transform[3] = 0; - ent->transform[7] = 0; - ent->transform[11] = 0; - VectorCopy (ent->origin, ent->transform + 12); - ent->transform[15] = 1; -} - -static void -CL_ModelEffects (entity_t *ent, int num, int glow_color) -{ - dlight_t *dl; - model_t *model = ent->model; - - // add automatic particle trails - if (model->flags & EF_ROCKET) { - dl = r_funcs->R_AllocDlight (num); - if (dl) { - VectorCopy (ent->origin, dl->origin); - dl->radius = 200.0; - dl->die = cl.time + 0.1; - //FIXME VectorCopy (r_firecolor->vec, dl->color); - VectorSet (0.9, 0.7, 0.0, dl->color); - dl->color[3] = 0.7; - } - r_funcs->particles->R_RocketTrail (ent); - } else if (model->flags & EF_GRENADE) - r_funcs->particles->R_GrenadeTrail (ent); - else if (model->flags & EF_GIB) - r_funcs->particles->R_BloodTrail (ent); - else if (model->flags & EF_ZOMGIB) - r_funcs->particles->R_SlightBloodTrail (ent); - else if (model->flags & EF_TRACER) - r_funcs->particles->R_WizTrail (ent); - else if (model->flags & EF_TRACER2) - r_funcs->particles->R_FlameTrail (ent); - else if (model->flags & EF_TRACER3) - r_funcs->particles->R_VoorTrail (ent); - else if (model->flags & EF_GLOWTRAIL) - if (r_funcs->particles->R_GlowTrail) - r_funcs->particles->R_GlowTrail (ent, glow_color); -} - static void set_entity_model (entity_t *ent, int modelindex) { - ent->model = cl.model_precache[modelindex]; + renderer_t *renderer = &ent->renderer; + animation_t *animation = &ent->animation; + renderer->model = cl.model_precache[modelindex]; // automatic animation (torches, etc) can be either all together // or randomized - if (ent->model) { - if (ent->model->synctype == ST_RAND) - ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff; - else - ent->syncbase = 0.0; + if (renderer->model) { + if (renderer->model->synctype == ST_RAND) { + animation->syncbase = (float) (rand () & 0x7fff) / 0x7fff; + } else { + animation->syncbase = 0.0; + } } + animation->nolerp = 1; // don't try to lerp when the model has changed } static void @@ -256,34 +130,39 @@ CL_LinkPacketEntities (void) float frac, f; entity_t *ent; entity_state_t *new, *old; - vec3_t delta; + renderer_t *renderer; + animation_t *animation; frac = 1; for (i = 0; i < 512; i++) { new = &qw_entstates.frame[cl.link_sequence & UPDATE_MASK][i]; old = &qw_entstates.frame[cl.prev_sequence & UPDATE_MASK][i]; ent = &cl_entities[i]; + renderer = &ent->renderer; + animation = &ent->animation; forcelink = cl_entity_valid[0][i] != cl_entity_valid[1][i]; cl_entity_valid[1][i] = cl_entity_valid[0][i]; // if the object wasn't included in the last packet, remove it if (!cl_entity_valid[0][i]) { - ent->model = NULL; - ent->pose1 = ent->pose2 = -1; - if (ent->efrag) + renderer->model = NULL; + animation->pose1 = animation->pose2 = -1; + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); // just became empty + } continue; } // spawn light flashes, even ones coming from invisible objects CL_NewDlight (i, new->origin, new->effects, new->glow_size, - new->glow_color); + new->glow_color, cl.time); // if set to invisible, skip if (!new->modelindex || (cl_deadbodyfilter->int_val && is_dead_body (new)) || (cl_gibfilter->int_val && is_gib (new))) { - if (ent->efrag) + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); + } continue; } @@ -294,66 +173,66 @@ CL_LinkPacketEntities (void) old->modelindex = new->modelindex; set_entity_model (ent, new->modelindex); } - ent->frame = new->frame; + animation->frame = new->frame; if (forcelink || new->colormap != old->colormap || new->skinnum != old->skinnum) { old->skinnum = new->skinnum; - ent->skinnum = new->skinnum; + renderer->skinnum = new->skinnum; old->colormap = new->colormap; if (new->colormap && (new->colormap <= MAX_CLIENTS) && cl.players[new->colormap - 1].name && cl.players[new->colormap - 1].name->value[0] && new->modelindex == cl_playerindex) { player_info_t *player = &cl.players[new->colormap - 1]; - ent->skin = mod_funcs->Skin_SetSkin (ent->skin, new->colormap, - player->skinname->value); - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, - new->colormap); + renderer->skin + = mod_funcs->Skin_SetSkin (renderer->skin, new->colormap, + player->skinname->value); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + new->colormap); } else { - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, 0); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + 0); } } - ent->scale = new->scale / 16.0; - VectorCopy (ent_colormod[new->colormod], ent->colormod); - ent->colormod[3] = new->alpha / 255.0; + VectorCopy (ent_colormod[new->colormod], renderer->colormod); + renderer->colormod[3] = new->alpha / 255.0; - ent->min_light = 0; - ent->fullbright = 0; + renderer->min_light = 0; + renderer->fullbright = 0; if (new->modelindex == cl_playerindex) { - ent->min_light = min (cl.fbskins, cl_fb_players->value); - if (ent->min_light >= 1.0) - ent->fullbright = 1; + renderer->min_light = min (cl.fbskins, cl_fb_players->value); + if (renderer->min_light >= 1.0) { + renderer->fullbright = 1; + } } + ent->old_origin = Transform_GetWorldPosition (ent->transform); if (forcelink) { - ent->pose1 = ent->pose2 = -1; - VectorCopy (new->origin, ent->origin); - if (!(ent->model->flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles, true); + animation->pose1 = animation->pose2 = -1; + CL_TransformEntity (ent, new->scale / 16, new->angles, + new->origin); if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + } + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } - VectorCopy (ent->origin, ent->old_origin); } else { + vec4f_t delta = new->origin - old->origin; f = frac; - VectorCopy (ent->origin, ent->old_origin); - VectorSubtract (new->origin, old->origin, delta); // If the delta is large, assume a teleport and don't lerp if (fabs (delta[0]) > 100 || fabs (delta[1] > 100) || fabs (delta[2]) > 100) { // assume a teleportation, not a motion - VectorCopy (new->origin, ent->origin); - if (!(ent->model->flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles, true); - ent->pose1 = ent->pose2 = -1; + CL_TransformEntity (ent, new->scale / 16, new->angles, + new->origin); + animation->pose1 = animation->pose2 = -1; } else { vec3_t angles, d; + vec4f_t origin = old->origin + f * delta; // interpolate the origin and angles - VectorMultAdd (old->origin, f, delta, ent->origin); - if (!(ent->model->flags & EF_ROTATE)) { + if (!(renderer->model->flags & EF_ROTATE)) { VectorSubtract (new->angles, old->angles, d); for (j = 0; j < 3; j++) { if (d[j] > 180) @@ -362,37 +241,42 @@ CL_LinkPacketEntities (void) d[j] += 360; } VectorMultAdd (old->angles, f, d, angles); - CL_TransformEntity (ent, angles, false); } + CL_TransformEntity (ent, new->scale / 16.0, angles, origin); } if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) { - if (!VectorCompare (ent->origin, ent->old_origin)) { + if (ent->visibility.efrag) { + vec4f_t org + = Transform_GetWorldPosition (ent->transform); + if (!VectorCompare (org, ent->old_origin)) {//FIXME r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } else { - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } } - if (!ent->efrag) - r_funcs->R_AddEfrags (ent); + if (!ent->visibility.efrag) { + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + } // rotate binary objects locally - if (ent->model->flags & EF_ROTATE) { + if (renderer->model->flags & EF_ROTATE) { vec3_t angles; angles[PITCH] = 0; angles[YAW] = anglemod (100 * cl.time); angles[ROLL] = 0; - CL_TransformEntity (ent, angles, false); + CL_TransformEntity (ent, new->scale / 16.0, angles, new->origin); } //CL_EntityEffects (i, ent, new); - //CL_NewDlight (i, ent->origin, new->effects, 0, 0); - if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) - VectorCopy (ent->origin, old->origin); - if (ent->model->flags & ~EF_ROTATE) - CL_ModelEffects (ent, -new->number, new->glow_color); + //CL_NewDlight (i, ent->origin, new->effects, 0, 0, cl.time); + vec4f_t org = Transform_GetWorldPosition (ent->transform); + if (VectorDistance_fast (old->origin, org) > (256 * 256)) + old->origin = org; + if (renderer->model->flags & ~EF_ROTATE) { + CL_ModelEffects (ent, -new->number, new->glow_color, cl.time); + } } } @@ -413,36 +297,40 @@ CL_AddFlagModels (entity_t *ent, int team, int key) }; float f; entity_t *fent; - vec_t *v_forward, *v_left; - vec3_t ang; - - if (cl_flagindex == -1) - return; - - f = 14.0; - if (ent->frame >= 29 && ent->frame <= 40) { - f = flag_offsets[ent->frame - 29]; - } else if (ent->frame >= 103 && ent->frame <= 118) { - if (ent->frame <= 106) // 103-104 nailattack - f = 20.0; // 105-106 light - else // 107-112 rocketattack - f = 21.0; // 112-118 shotattack - } fent = &cl_flag_ents[key]; - fent->model = cl.model_precache[cl_flagindex]; - fent->skinnum = team; - v_forward = ent->transform + 0; - v_left = ent->transform + 4; + if (cl_flagindex == -1) { + fent->active = 0; + return; + } - VectorMultAdd (ent->origin, -f, v_forward, fent->origin); - VectorMultAdd (fent->origin, -22, v_left, fent->origin); - fent->origin[2] -= 16.0; + fent->active = 1; + f = 14.0; + if (ent->animation.frame >= 29 && ent->animation.frame <= 40) { + f = flag_offsets[ent->animation.frame - 29]; + } else if (ent->animation.frame >= 103 && ent->animation.frame <= 118) { + if (ent->animation.frame <= 106) { // 103-104 nailattack + f = 20.0; // 105-106 light + } else { // 107-112 rocketattack + f = 21.0; // 112-118 shotattack + } + } - VectorCopy (ent->angles, ang); - ang[2] -= 45.0; - CL_TransformEntity (fent, ang, false); + vec4f_t position = { 22, -f, -16, 1}; + + if (!Transform_GetParent (fent->transform)) { + vec4f_t scale = { 1, 1, 1, 1 }; + // -45 degree roll (x is forward) + vec4f_t rotation = { -0.382683432, 0, 0, 0.923879533 }; + Transform_SetParent (fent->transform, ent->transform); + Transform_SetLocalTransform (fent->transform, scale, rotation, + position); + } else { + Transform_SetLocalPosition (fent->transform, position); + } + fent->renderer.model = cl.model_precache[cl_flagindex]; + fent->renderer.skinnum = team; r_funcs->R_EnqueueEntity (fent);//FIXME should use efrag (needs smarter // handling //in the player code) @@ -458,14 +346,15 @@ static void CL_LinkPlayers (void) { double playertime; - int msec, oldphysent, i, j; + int msec, oldphysent, j; entity_t *ent; frame_t *frame; player_info_t *info; player_state_t exact; player_state_t *state; qboolean clientplayer; - vec3_t org, ang = {0, 0, 0}; + vec3_t ang = {0, 0, 0}; + vec4f_t org; playertime = realtime - cls.latency + 0.02; if (playertime > realtime) @@ -476,7 +365,7 @@ CL_LinkPlayers (void) for (j = 0, info = cl.players, state = frame->playerstate; j < MAX_CLIENTS; j++, info++, state++) { ent = &cl_player_ents[j]; - if (ent->efrag) + if (ent->visibility.efrag) r_funcs->R_RemoveEfrags (ent); if (state->messagenum != cl.parsecount) continue; // not present this frame @@ -486,11 +375,11 @@ CL_LinkPlayers (void) // spawn light flashes, even ones coming from invisible objects if (j == cl.playernum) { - VectorCopy (cl.simorg, org); + org = cl.viewstate.origin; r_data->player_entity = &cl_player_ents[j]; clientplayer = true; } else { - VectorCopy (state->pls.origin, org); + org = state->pls.es.origin; clientplayer = false; } if (info->chat && info->chat->value[0] != '0') { @@ -500,77 +389,84 @@ CL_LinkPlayers (void) dl->die = cl.time + 0.1; QuatSet (0.0, 1.0, 0.0, 1.0, dl->color); } else { - CL_NewDlight (j + 1, org, state->pls.effects, state->pls.glow_size, - state->pls.glow_color); + CL_NewDlight (j + 1, org, state->pls.es.effects, + state->pls.es.glow_size, state->pls.es.glow_color, + cl.time); } // Draw player? if (!Cam_DrawPlayer (j)) continue; - if (!state->pls.modelindex) + if (!state->pls.es.modelindex) continue; // Hack hack hack if (cl_deadbodyfilter->int_val - && state->pls.modelindex == cl_playerindex - && ((i = state->pls.frame) == 49 || i == 60 || i == 69 || i == 84 - || i == 93 || i == 102)) + && state->pls.es.modelindex == cl_playerindex + && is_dead_body (&state->pls.es)) continue; // predict only half the move to minimize overruns msec = 500 * (playertime - state->state_time); if (msec <= 0 || (!cl_predict_players->int_val) || cls.demoplayback2) { - VectorCopy (state->pls.origin, ent->origin); + Sys_Printf("a\n"); + exact.pls.es.origin = state->pls.es.origin; } else { // predict players movement state->pls.cmd.msec = msec = min (msec, 255); oldphysent = pmove.numphysent; CL_SetSolidPlayers (j); + exact.pls.es.origin[3] = 1;//FIXME should be done by prediction CL_PredictUsercmd (state, &exact, &state->pls.cmd, clientplayer); pmove.numphysent = oldphysent; - VectorCopy (exact.pls.origin, ent->origin); } // angles if (j == cl.playernum) { - ang[PITCH] = -cl.viewangles[PITCH] / 3.0; - ang[YAW] = cl.viewangles[YAW]; + ang[PITCH] = -cl.viewstate.angles[PITCH] / 3.0; + ang[YAW] = cl.viewstate.angles[YAW]; } else { ang[PITCH] = -state->viewangles[PITCH] / 3.0; ang[YAW] = state->viewangles[YAW]; } - ang[ROLL] = V_CalcRoll (ang, state->pls.velocity) * 4.0; + ang[ROLL] = V_CalcRoll (ang, state->pls.es.velocity) * 4.0; - ent->model = cl.model_precache[state->pls.modelindex]; - ent->frame = state->pls.frame; - ent->skinnum = state->pls.skinnum; + if (ent->renderer.model + != cl.model_precache[state->pls.es.modelindex]) { + ent->renderer.model = cl.model_precache[state->pls.es.modelindex]; + ent->animation.nolerp = 1; + } + ent->animation.frame = state->pls.es.frame; + ent->renderer.skinnum = state->pls.es.skinnum; - CL_TransformEntity (ent, ang, false); + //FIXME scale + CL_TransformEntity (ent, 1, ang, exact.pls.es.origin); - ent->min_light = 0; - ent->fullbright = 0; + ent->renderer.min_light = 0; + ent->renderer.fullbright = 0; - if (state->pls.modelindex == cl_playerindex) { //XXX + if (state->pls.es.modelindex == cl_playerindex) { //XXX // use custom skin - ent->skin = info->skin; + ent->renderer.skin = info->skin; - ent->min_light = min (cl.fbskins, cl_fb_players->value); + ent->renderer.min_light = min (cl.fbskins, cl_fb_players->value); - if (ent->min_light >= 1.0) - ent->fullbright = 1; + if (ent->renderer.min_light >= 1.0) { + ent->renderer.fullbright = 1; + } } else { // FIXME no team colors on nonstandard player models - ent->skin = 0; + ent->renderer.skin = 0; } // stuff entity in map - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); - if (state->pls.effects & EF_FLAG1) + if (state->pls.es.effects & EF_FLAG1) CL_AddFlagModels (ent, 0, j); - else if (state->pls.effects & EF_FLAG2) + else if (state->pls.es.effects & EF_FLAG2) CL_AddFlagModels (ent, 1, j); } } @@ -590,39 +486,15 @@ CL_EmitEntities (void) if (!cl.validsequence) return; + TEntContext_t tentCtx = { + cl.viewstate.origin, cl.worldmodel, cl.viewentity + }; + CL_LinkPlayers (); CL_LinkPacketEntities (); - CL_UpdateTEnts (); + CL_UpdateTEnts (cl.time, &tentCtx); if (cl_draw_locs->int_val) { - //FIXME custom ent rendering code would be nice - dlight_t *dl; - location_t *nearloc; - vec3_t trueloc; - int i; - - nearloc = locs_find (cl.simorg); - if (nearloc) { - dl = r_funcs->R_AllocDlight (4096); - if (dl) { - VectorCopy (nearloc->loc, dl->origin); - dl->radius = 200; - dl->die = r_data->realtime + 0.1; - dl->color[0] = 0; - dl->color[1] = 1; - dl->color[2] = 0; - dl->color[3] = 0.7; - } - VectorCopy (nearloc->loc, trueloc); - r_funcs->particles->R_Particle_New (pt_smokecloud, part_tex_smoke, - trueloc, 2.0, - vec3_origin, r_data->realtime + 9.0, 254, - 0.25 + qfrandom (0.125), 0.0); - for (i = 0; i < 15; i++) - r_funcs->particles->R_Particle_NewRandom (pt_fallfade, - part_tex_dot, trueloc, 12, - 0.7, 96, r_data->realtime + 5.0, - 104 + (rand () & 7), 1.0, 0.0); - } + locs_draw (cl.viewstate.origin); } } diff --git a/qw/source/cl_http.c b/qw/source/cl_http.c index 38bd9f204..b13986cf2 100644 --- a/qw/source/cl_http.c +++ b/qw/source/cl_http.c @@ -38,9 +38,9 @@ #include "QF/dstring.h" #include "QF/sys.h" -#include "cl_http.h" -#include "cl_parse.h" -#include "client.h" +#include "qw/include/cl_http.h" +#include "qw/include/cl_parse.h" +#include "qw/include/client.h" static int curl_borked; static CURL *easy_handle; @@ -129,7 +129,7 @@ CL_HTTP_Reset (void) #else -#include "cl_http.h" +#include "qw/include/cl_http.h" void CL_HTTP_Init (void) {} void CL_HTTP_Shutdown (void) {} diff --git a/qw/source/cl_input.c b/qw/source/cl_input.c index e80ea4714..770e16358 100644 --- a/qw/source/cl_input.c +++ b/qw/source/cl_input.c @@ -45,17 +45,19 @@ #include "QF/teamplay.h" #include "QF/va.h" +#include "compat.h" + +#include "client/view.h" + #include "qw/msg_ucmd.h" -#include "chase.h" -#include "cl_cam.h" -#include "cl_demo.h" -#include "cl_input.h" -#include "cl_parse.h" -#include "client.h" -#include "compat.h" -#include "host.h" -#include "clview.h" +#include "qw/include/chase.h" +#include "qw/include/cl_cam.h" +#include "qw/include/cl_demo.h" +#include "qw/include/cl_input.h" +#include "qw/include/cl_parse.h" +#include "qw/include/client.h" +#include "qw/include/host.h" cvar_t *cl_nodelta; cvar_t *cl_maxnetfps; @@ -87,8 +89,9 @@ int in_impulse; static void -KeyPress (kbutton_t *b) +KeyPress (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -117,8 +120,9 @@ KeyPress (kbutton_t *b) } static void -KeyRelease (kbutton_t *b) +KeyRelease (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -151,25 +155,7 @@ KeyRelease (kbutton_t *b) } static void -IN_KLookPress (void) -{ - KeyPress (&in_klook); -} - -static void -IN_KLookRelease (void) -{ - KeyRelease (&in_klook); -} - -static void -IN_MLookPress (void) -{ - KeyPress (&in_mlook); -} - -static void -IN_MLookRelease (void) +IN_MLookRelease (void *data) { KeyRelease (&in_mlook); if (!freelook && lookspring->int_val) @@ -177,187 +163,7 @@ IN_MLookRelease (void) } static void -IN_UpPress (void) -{ - KeyPress (&in_up); -} - -static void -IN_UpRelease (void) -{ - KeyRelease (&in_up); -} - -static void -IN_DownPress (void) -{ - KeyPress (&in_down); -} - -static void -IN_DownRelease (void) -{ - KeyRelease (&in_down); -} - -static void -IN_LeftPress (void) -{ - KeyPress (&in_left); -} - -static void -IN_LeftRelease (void) -{ - KeyRelease (&in_left); -} - -static void -IN_RightPress (void) -{ - KeyPress (&in_right); -} - -static void -IN_RightRelease (void) -{ - KeyRelease (&in_right); -} - -static void -IN_ForwardPress (void) -{ - KeyPress (&in_forward); -} - -static void -IN_ForwardRelease (void) -{ - KeyRelease (&in_forward); -} - -static void -IN_BackPress (void) -{ - KeyPress (&in_back); -} - -static void -IN_BackRelease (void) -{ - KeyRelease (&in_back); -} - -static void -IN_LookupPress (void) -{ - KeyPress (&in_lookup); -} - -static void -IN_LookupRelease (void) -{ - KeyRelease (&in_lookup); -} - -static void -IN_LookdownPress (void) -{ - KeyPress (&in_lookdown); -} - -static void -IN_LookdownRelease (void) -{ - KeyRelease (&in_lookdown); -} - -static void -IN_MoveleftPress (void) -{ - KeyPress (&in_moveleft); -} - -static void -IN_MoveleftRelease (void) -{ - KeyRelease (&in_moveleft); -} - -static void -IN_MoverightPress (void) -{ - KeyPress (&in_moveright); -} - -static void -IN_MoverightRelease (void) -{ - KeyRelease (&in_moveright); -} - -static void -IN_SpeedPress (void) -{ - KeyPress (&in_speed); -} - -static void -IN_SpeedRelease (void) -{ - KeyRelease (&in_speed); -} - -static void -IN_StrafePress (void) -{ - KeyPress (&in_strafe); -} - -static void -IN_StrafeRelease (void) -{ - KeyRelease (&in_strafe); -} - -static void -IN_AttackPress (void) -{ - KeyPress (&in_attack); -} - -static void -IN_AttackRelease (void) -{ - KeyRelease (&in_attack); -} - -static void -IN_UsePress (void) -{ - KeyPress (&in_use); -} - -static void -IN_UseRelease (void) -{ - KeyRelease (&in_use); -} - -static void -IN_JumpPress (void) -{ - KeyPress (&in_jump); -} - -static void -IN_JumpRelease (void) -{ - KeyRelease (&in_jump); -} - -static void -IN_Impulse (void) +IN_Impulse (void *data) { in_impulse = atoi (Cmd_Argv (1)); if (Cmd_Argc () <= 2) @@ -452,35 +258,35 @@ CL_AdjustAngles (void) yawspeed *= host_frametime; if (!(in_strafe.state & 1)) { - cl.viewangles[YAW] -= yawspeed * CL_KeyState (&in_right); - cl.viewangles[YAW] += yawspeed * CL_KeyState (&in_left); - cl.viewangles[YAW] = anglemod (cl.viewangles[YAW]); + cl.viewstate.angles[YAW] -= yawspeed * CL_KeyState (&in_right); + cl.viewstate.angles[YAW] += yawspeed * CL_KeyState (&in_left); + cl.viewstate.angles[YAW] = anglemod (cl.viewstate.angles[YAW]); } if (in_klook.state & 1) { V_StopPitchDrift (); - cl.viewangles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); - cl.viewangles[PITCH] += pitchspeed * CL_KeyState (&in_back); + cl.viewstate.angles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); + cl.viewstate.angles[PITCH] += pitchspeed * CL_KeyState (&in_back); } up = CL_KeyState (&in_lookup); down = CL_KeyState (&in_lookdown); - cl.viewangles[PITCH] -= pitchspeed * up; - cl.viewangles[PITCH] += pitchspeed * down; + cl.viewstate.angles[PITCH] -= pitchspeed * up; + cl.viewstate.angles[PITCH] += pitchspeed * down; if (up || down) V_StopPitchDrift (); // FIXME: Need to clean up view angle limits - if (cl.viewangles[PITCH] > 80) - cl.viewangles[PITCH] = 80; - if (cl.viewangles[PITCH] < -70) - cl.viewangles[PITCH] = -70; + if (cl.viewstate.angles[PITCH] > 80) + cl.viewstate.angles[PITCH] = 80; + if (cl.viewstate.angles[PITCH] < -70) + cl.viewstate.angles[PITCH] = -70; - if (cl.viewangles[ROLL] > 50) - cl.viewangles[ROLL] = 50; - if (cl.viewangles[ROLL] < -50) - cl.viewangles[ROLL] = -50; + if (cl.viewstate.angles[ROLL] > 50) + cl.viewstate.angles[ROLL] = 50; + if (cl.viewstate.angles[ROLL] < -50) + cl.viewstate.angles[ROLL] = -50; } /* @@ -491,11 +297,15 @@ CL_AdjustAngles (void) void CL_BaseMove (usercmd_t *cmd) { + if (cls.state != ca_active) { + return; + } + CL_AdjustAngles (); memset (cmd, 0, sizeof (*cmd)); - VectorCopy (cl.viewangles, cmd->angles); + VectorCopy (cl.viewstate.angles, cmd->angles); if (in_strafe.state & 1) { cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); @@ -528,12 +338,13 @@ CL_BaseMove (usercmd_t *cmd) IN_Move (); // adjust for chase camera angles + /*FIXME:chase figure out just what this does and get it working if (cl.chase && (chase_active->int_val == 2 || chase_active->int_val == 3)) { vec3_t forward, right, up, f, r; vec3_t dir = {0, 0, 0}; - dir[1] = r_data->refdef->viewangles[1] - cl.viewangles[1]; + dir[1] = r_data->refdef->viewangles[1] - cl.viewstate.angles[1]; AngleVectors (dir, forward, right, up); VectorScale (forward, cmd->forwardmove, f); VectorScale (right, cmd->sidemove, r); @@ -544,16 +355,18 @@ CL_BaseMove (usercmd_t *cmd) viewdelta.position[2] = f[0] + r[0]; viewdelta.position[0] = (f[1] + r[1]) * -1; } + */ cmd->forwardmove += viewdelta.position[2] * m_forward->value; cmd->sidemove += viewdelta.position[0] * m_side->value; cmd->upmove += viewdelta.position[1]; - cl.viewangles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; - cl.viewangles[YAW] += viewdelta.angles[YAW] * m_yaw->value; - cl.viewangles[ROLL] += viewdelta.angles[ROLL]; + cl.viewstate.angles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; + cl.viewstate.angles[YAW] += viewdelta.angles[YAW] * m_yaw->value; + cl.viewstate.angles[ROLL] += viewdelta.angles[ROLL]; if (freelook && !(in_strafe.state & 1)) { - cl.viewangles[PITCH] = bound (-70, cl.viewangles[PITCH], 80); + cl.viewstate.angles[PITCH] + = bound (-70, cl.viewstate.angles[PITCH], 80); } } @@ -605,7 +418,7 @@ CL_FinishMove (usercmd_t *cmd) } cmd->msec = ms; - VectorCopy (cl.viewangles, cmd->angles); + VectorCopy (cl.viewstate.angles, cmd->angles); cmd->impulse = in_impulse; in_impulse = 0; @@ -763,78 +576,88 @@ CL_SendCmd (void) void CL_Input_Init (void) { - Cmd_AddCommand ("+moveup", IN_UpPress, "When active the player is " - "swimming up in a liquid"); - Cmd_AddCommand ("-moveup", IN_UpRelease, "When active the player is not " - "swimming up in a liquid"); - Cmd_AddCommand ("+movedown", IN_DownPress, "When active the player is " - "swimming down in a liquid"); - Cmd_AddCommand ("-movedown", IN_DownRelease, "When active the player is " - "not swimming down in a liquid"); - Cmd_AddCommand ("+left", IN_LeftPress, "When active the player is turning " - "left"); - Cmd_AddCommand ("-left", IN_LeftRelease, "When active the player is not " - "turning left"); - Cmd_AddCommand ("+right", IN_RightPress, "When active the player is " - "turning right"); - Cmd_AddCommand ("-right", IN_RightRelease, "When active the player is not " - "turning right"); - Cmd_AddCommand ("+forward", IN_ForwardPress, "When active the player is " - "moving forward"); - Cmd_AddCommand ("-forward", IN_ForwardRelease, "When active the player is " - "not moving forward"); - Cmd_AddCommand ("+back", IN_BackPress, "When active the player is moving " - "backwards"); - Cmd_AddCommand ("-back", IN_BackRelease, "When active the player is not " - "moving backwards"); - Cmd_AddCommand ("+lookup", IN_LookupPress, "When active the player's view " - "is looking up"); - Cmd_AddCommand ("-lookup", IN_LookupRelease, "When active the player's " - "view is not looking up"); - Cmd_AddCommand ("+lookdown", IN_LookdownPress, "When active the player's " - "view is looking down"); - Cmd_AddCommand ("-lookdown", IN_LookdownRelease, "When active the " - "player's view is not looking up"); - Cmd_AddCommand ("+strafe", IN_StrafePress, "When active, +left and +right " - "function like +moveleft and +moveright"); - Cmd_AddCommand ("-strafe", IN_StrafeRelease, "When active, +left and " - "+right stop functioning like +moveleft and +moveright"); - Cmd_AddCommand ("+moveleft", IN_MoveleftPress, "When active the player is " - "strafing left"); - Cmd_AddCommand ("-moveleft", IN_MoveleftRelease, "When active the player " - "is not strafing left"); - Cmd_AddCommand ("+moveright", IN_MoverightPress, "When active the player " - "is strafing right"); - Cmd_AddCommand ("-moveright", IN_MoverightRelease, "When active the " - "player is not strafing right"); - Cmd_AddCommand ("+speed", IN_SpeedPress, "When active the player is " - "running"); - Cmd_AddCommand ("-speed", IN_SpeedRelease, "When active the player is not " - "running"); - Cmd_AddCommand ("+attack", IN_AttackPress, "When active player is " - "firing/using current weapon"); - Cmd_AddCommand ("-attack", IN_AttackRelease, "When active player is not " - "firing/using current weapon"); - Cmd_AddCommand ("+use", IN_UsePress, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("-use", IN_UseRelease, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("+jump", IN_JumpPress, "When active the player is " - "jumping"); - Cmd_AddCommand ("-jump", IN_JumpRelease, "When active the player is not " - "jumping"); - Cmd_AddCommand ("impulse", IN_Impulse, "Call a game function or QuakeC " - "function."); - Cmd_AddCommand ("+klook", IN_KLookPress, "When active, +forward and +back " - "perform +lookup and +lookdown"); - Cmd_AddCommand ("-klook", IN_KLookRelease, "When active, +forward and " - "+back don't perform +lookup and +lookdown"); - Cmd_AddCommand ("+mlook", IN_MLookPress, "When active moving the mouse or " - "joystick forwards and backwards performs +lookup and " - "+lookdown"); - Cmd_AddCommand ("-mlook", IN_MLookRelease, "When active moving the mouse " - "or joystick forwards and backwards doesn't perform " - "+lookup and +lookdown"); + Cmd_AddDataCommand ("+moveup", KeyPress, &in_up, + "When active the player is swimming up in a liquid"); + Cmd_AddDataCommand ("-moveup", KeyRelease, &in_up, + "When active the player is not swimming up in a " + "liquid"); + Cmd_AddDataCommand ("+movedown", KeyPress, &in_down, + "When active the player is swimming down in a liquid"); + Cmd_AddDataCommand ("-movedown", KeyRelease, &in_down, + "When active the player is not swimming down in a " + "liquid"); + Cmd_AddDataCommand ("+left", KeyPress, &in_left, + "When active the player is turning left"); + Cmd_AddDataCommand ("-left", KeyRelease, &in_left, + "When active the player is not turning left"); + Cmd_AddDataCommand ("+right", KeyPress, &in_right, + "When active the player is turning right"); + Cmd_AddDataCommand ("-right", KeyRelease, &in_right, + "When active the player is not turning right"); + Cmd_AddDataCommand ("+forward", KeyPress, &in_forward, + "When active the player is moving forward"); + Cmd_AddDataCommand ("-forward", KeyRelease, &in_forward, + "When active the player is not moving forward"); + Cmd_AddDataCommand ("+back", KeyPress, &in_back, + "When active the player is moving backwards"); + Cmd_AddDataCommand ("-back", KeyRelease, &in_back, + "When active the player is not moving backwards"); + Cmd_AddDataCommand ("+lookup", KeyPress, &in_lookup, + "When active the player's view is looking up"); + Cmd_AddDataCommand ("-lookup", KeyRelease, &in_lookup, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+lookdown", KeyPress, &in_lookdown, + "When active the player's view is looking down"); + Cmd_AddDataCommand ("-lookdown", KeyRelease, &in_lookdown, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+strafe", KeyPress, &in_strafe, + "When active, +left and +right function like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("-strafe", KeyRelease, &in_strafe, + "When active, +left and +right stop functioning like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("+moveleft", KeyPress, &in_moveleft, + "When active the player is strafing left"); + Cmd_AddDataCommand ("-moveleft", KeyRelease, &in_moveleft, + "When active the player is not strafing left"); + Cmd_AddDataCommand ("+moveright", KeyPress, &in_moveright, + "When active the player is strafing right"); + Cmd_AddDataCommand ("-moveright", KeyRelease, &in_moveright, + "When active the player is not strafing right"); + Cmd_AddDataCommand ("+speed", KeyPress, &in_speed, + "When active the player is running"); + Cmd_AddDataCommand ("-speed", KeyRelease, &in_speed, + "When active the player is not running"); + Cmd_AddDataCommand ("+attack", KeyPress, &in_attack, + "When active player is firing/using current weapon"); + Cmd_AddDataCommand ("-attack", KeyRelease, &in_attack, + "When active player is not firing/using current " + "weapon"); + Cmd_AddDataCommand ("+use", KeyPress, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("-use", KeyRelease, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("+jump", KeyPress, &in_jump, + "When active the player is jumping"); + Cmd_AddDataCommand ("-jump", KeyRelease, &in_jump, + "When active the player is not jumping"); + Cmd_AddDataCommand ("impulse", IN_Impulse, 0, + "Call a game function or QuakeC function."); + Cmd_AddDataCommand ("+klook", KeyPress, &in_klook, + "When active, +forward and +back perform +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-klook", KeyRelease, &in_klook, + "When active, +forward and +back don't perform " + "+lookup and +lookdown"); + Cmd_AddDataCommand ("+mlook", KeyPress, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards performs +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-mlook", IN_MLookRelease, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards doesn't perform +lookup and +lookdown"); } void diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 09fb1aec2..4bc686d4d 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -91,28 +91,31 @@ #include "QF/plugin/console.h" -#include "qw/bothdefs.h" #include "buildnum.h" -#include "cl_cam.h" -#include "cl_chat.h" -#include "cl_demo.h" -#include "cl_ents.h" -#include "cl_http.h" -#include "cl_input.h" -#include "cl_main.h" -#include "cl_parse.h" -#include "cl_pred.h" -#include "cl_skin.h" -#include "cl_slist.h" -#include "cl_tent.h" -#include "client.h" #include "compat.h" -#include "game.h" -#include "host.h" -#include "netchan.h" -#include "qw/pmove.h" #include "sbar.h" -#include "clview.h" + +#include "client/temp_entities.h" +#include "client/view.h" + +#include "qw/bothdefs.h" +#include "qw/pmove.h" + +#include "qw/include/cl_cam.h" +#include "qw/include/cl_chat.h" +#include "qw/include/cl_demo.h" +#include "qw/include/cl_ents.h" +#include "qw/include/cl_http.h" +#include "qw/include/cl_input.h" +#include "qw/include/cl_main.h" +#include "qw/include/cl_parse.h" +#include "qw/include/cl_pred.h" +#include "qw/include/cl_skin.h" +#include "qw/include/cl_slist.h" +#include "qw/include/client.h" +#include "qw/include/game.h" +#include "qw/include/host.h" +#include "netchan.h" CLIENT_PLUGIN_PROTOS static plugin_list_t client_plugin_list[] = { @@ -319,7 +322,7 @@ CL_CheckForResend (void) connect_time = realtime + t2 - t1; // for retransmit requests - VID_SetCaption (va ("Connecting to %s", cls.servername->str)); + VID_SetCaption (va (0, "Connecting to %s", cls.servername->str)); Sys_Printf ("Connecting to %s...\n", cls.servername->str); Netchan_SendPacket (strlen (getchallenge), (void *) getchallenge, cls.server_addr); @@ -395,7 +398,10 @@ CL_ClearState (void) // wipe the entire cl structure if (cl.serverinfo) Info_Destroy (cl.serverinfo); + if (cl.players) + free (cl.players); memset (&cl, 0, sizeof (cl)); + cl.players = calloc (MAX_CLIENTS, sizeof (player_info_t)); r_data->force_fullscreen = 0; cl.maxclients = MAX_CLIENTS; @@ -412,8 +418,7 @@ CL_ClearState (void) CL_Init_Entity (&cl.viewent); Sys_MaskPrintf (SYS_DEV, "Clearing memory\n"); - if (viddef.flush_caches) - viddef.flush_caches (); + VID_ClearMemory (); Mod_ClearAll (); if (host_hunklevel) // FIXME: check this... Hunk_FreeToLowMark (host_hunklevel); @@ -784,7 +789,7 @@ CL_NextDemo (void) } } - Cbuf_InsertText (cl_cbuf, va ("playdemo %s\n", cls.demos[cls.demonum])); + Cbuf_InsertText (cl_cbuf, va (0, "playdemo %s\n", cls.demos[cls.demonum])); cls.demonum++; } @@ -1088,7 +1093,7 @@ CL_Download_f (void) cls.downloadtype = dl_single; MSG_WriteByte (&cls.netchan.message, clc_stringcmd); - SZ_Print (&cls.netchan.message, va ("download %s\n", Cmd_Argv (1))); + SZ_Print (&cls.netchan.message, va (0, "download %s\n", Cmd_Argv (1))); } else { Sys_Printf ("error downloading %s: %s\n", Cmd_Argv (1), strerror (errno)); @@ -1098,7 +1103,7 @@ CL_Download_f (void) static void Force_CenterView_f (void) { - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; } static void @@ -1107,12 +1112,12 @@ CL_PRotate_f (void) if ((cl.fpd & FPD_LIMIT_PITCH) || Cmd_Argc() < 2) return; - cl.viewangles[PITCH] += atoi (Cmd_Argv (1)); + cl.viewstate.angles[PITCH] += atoi (Cmd_Argv (1)); - if (cl.viewangles[PITCH] < -70) - cl.viewangles[PITCH] = -70; - else if (cl.viewangles[PITCH] > 80) - cl.viewangles[PITCH] = 80; + if (cl.viewstate.angles[PITCH] < -70) + cl.viewstate.angles[PITCH] = -70; + else if (cl.viewstate.angles[PITCH] > 80) + cl.viewstate.angles[PITCH] = 80; } static void @@ -1121,8 +1126,8 @@ CL_Rotate_f (void) if ((cl.fpd & FPD_LIMIT_YAW) || Cmd_Argc() < 2) return; - cl.viewangles[YAW] += atoi (Cmd_Argv (1)); - cl.viewangles[YAW] = anglemod (cl.viewangles[YAW]); + cl.viewstate.angles[YAW] += atoi (Cmd_Argv (1)); + cl.viewstate.angles[YAW] = anglemod (cl.viewstate.angles[YAW]); } void @@ -1219,6 +1224,7 @@ CL_Init (void) cls.downloadname = dstring_newstr (); cls.downloadurl = dstring_newstr (); cl.serverinfo = Info_ParseString ("", MAX_INFO_STRING, 0); + cl.players = calloc (MAX_CLIENTS, sizeof (player_info_t)); // register our commands Cmd_AddCommand ("version", CL_Version_f, "Report version information"); @@ -1514,7 +1520,7 @@ Host_WriteConfiguration (void) QFile *f; if (host_initialized && cl_writecfg->int_val) { - char *path = va ("%s/config.cfg", qfs_gamedir->dir.def); + char *path = va (0, "%s/config.cfg", qfs_gamedir->dir.def); f = QFS_WOpen (path, 0); if (!f) { @@ -1603,6 +1609,8 @@ Host_Frame (float time) oldrealtime = realtime; host_frametime = min (host_frametime, 0.2); + cl.viewstate.frametime = host_frametime; + con_frametime = con_realtime - oldcon_realtime; oldcon_realtime = con_realtime; @@ -1629,8 +1637,8 @@ Host_Frame (float time) oldself = &cl.frames[(cls.netchan.outgoing_sequence - 1) & UPDATE_MASK].playerstate[cl.playernum]; self->messagenum = cl.parsecount; - VectorCopy (oldself->pls.origin, self->pls.origin); - VectorCopy (oldself->pls.velocity, self->pls.velocity); + VectorCopy (oldself->pls.es.origin, self->pls.es.origin); + VectorCopy (oldself->pls.es.velocity, self->pls.es.velocity); VectorCopy (oldself->viewangles, self->viewangles); CL_ParseClientdata (); @@ -1699,7 +1707,7 @@ Host_Frame (float time) if (cls.demo_capture) { tex_t *tex = r_funcs->SCR_CaptureBGR (); - WritePNGqfs (va ("%s/qfmv%06d.png", qfs_gamedir->dir.shots, + WritePNGqfs (va (0, "%s/qfmv%06d.png", qfs_gamedir->dir.shots, cls.demo_capture++), tex->data, tex->width, tex->height); free (tex); @@ -1755,7 +1763,7 @@ CL_Init_Memory (void) Sys_Error ("Only %4.1f megs of memory reported, can't execute game", mem_size / (float) 0x100000); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); @@ -1781,7 +1789,7 @@ CL_Autoexec (int phase) Cbuf_AddText (cl_cbuf, "exec autoexec.cfg\n"); } - Cbuf_AddText (cl_cbuf, va ("cmd_warncmd %d\n", cmd_warncmd_val)); + Cbuf_AddText (cl_cbuf, va (0, "cmd_warncmd %d\n", cmd_warncmd_val)); } void @@ -1804,12 +1812,10 @@ Host_Init (void) Netchan_Init_Cvars (); - PR_Init_Cvars (); + PR_Init_Cvars (); // FIXME location CL_Init_Cvars (); - PR_Init (); - CL_Chat_Init (); CL_Cmd_Init (); @@ -1869,7 +1875,7 @@ Host_Init (void) } void -Host_Shutdown (void) +Host_Shutdown (void *data) { static qboolean isdown = false; @@ -1883,10 +1889,5 @@ Host_Shutdown (void) Host_WriteConfiguration (); - CDAudio_Shutdown (); CL_HTTP_Shutdown (); - NET_Shutdown (); - S_Shutdown (); - IN_Shutdown (); - VID_Shutdown (); } diff --git a/qw/source/cl_ngraph.c b/qw/source/cl_ngraph.c index 2503c8ee4..21891f471 100644 --- a/qw/source/cl_ngraph.c +++ b/qw/source/cl_ngraph.c @@ -41,8 +41,9 @@ #include "QF/screen.h" #include "compat.h" -#include "cl_parse.h" -#include "client.h" + +#include "qw/include/cl_parse.h" +#include "qw/include/client.h" #include "sbar.h" cvar_t *r_netgraph; diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index a271c1197..a1e8474ca 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -52,7 +52,7 @@ #include "QF/idparse.h" #include "QF/msg.h" #include "QF/progs.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/quakeio.h" #include "QF/screen.h" #include "QF/skin.h" @@ -61,24 +61,28 @@ #include "QF/teamplay.h" #include "QF/va.h" -#include "qw/bothdefs.h" -#include "cl_cam.h" -#include "cl_chat.h" -#include "cl_ents.h" -#include "cl_http.h" -#include "cl_input.h" -#include "cl_main.h" -#include "cl_parse.h" -#include "cl_skin.h" -#include "cl_tent.h" -#include "client.h" #include "compat.h" -#include "host.h" -#include "map_cfg.h" +#include "sbar.h" + +#include "client/effects.h" +#include "client/temp_entities.h" +#include "client/view.h" + +#include "qw/bothdefs.h" #include "qw/pmove.h" #include "qw/protocol.h" -#include "sbar.h" -#include "clview.h" + +#include "qw/include/cl_cam.h" +#include "qw/include/cl_chat.h" +#include "qw/include/cl_ents.h" +#include "qw/include/cl_http.h" +#include "qw/include/cl_input.h" +#include "qw/include/cl_main.h" +#include "qw/include/cl_parse.h" +#include "qw/include/cl_skin.h" +#include "qw/include/client.h" +#include "qw/include/host.h" +#include "qw/include/map_cfg.h" const char *svc_strings[] = { "svc_bad", @@ -159,30 +163,43 @@ int oldparsecountmod; int parsecountmod; double parsecounttime; -int cl_spikeindex, cl_playerindex, cl_flagindex; +int cl_playerindex, cl_flagindex; int cl_h_playerindex, cl_gib1index, cl_gib2index, cl_gib3index; int packet_latency[NET_TIMINGS]; extern cvar_t *hud_scoreboard_uid; -entity_t *cl_static_entities; -static entity_t **cl_static_tail; +entitystateset_t cl_static_entities = DARRAY_STATIC_INIT (32); static void CL_LoadSky (void) { plitem_t *item; const char *name = 0; + static const char *sky_keys[] = { + "sky", // Q2/DarkPlaces + "skyname", // old QF + "qlsky", // QuakeLives + 0 + }; - if (!cl.worldspawn) { - r_funcs->R_LoadSkys (0); - return; + // R_LoadSkys does the right thing with null pointers. + if (cl.serverinfo) { + name = Info_ValueForKey (cl.serverinfo, "sky"); } - if ((item = PL_ObjectForKey (cl.worldspawn, "sky")) // Q2/DarkPlaces - || (item = PL_ObjectForKey (cl.worldspawn, "skyname")) // old QF - || (item = PL_ObjectForKey (cl.worldspawn, "qlsky"))) /* QuakeLives */ { - name = PL_String (item); + + if (!name) { + if (!cl.worldspawn) { + r_funcs->R_LoadSkys (0); + return; + } + for (const char **key = sky_keys; *key; key++) { + if ((item = PL_ObjectForKey (cl.worldspawn, *key))) { + name = PL_String (item); + break; + } + } } r_funcs->R_LoadSkys (name); } @@ -263,7 +280,7 @@ CL_CheckOrDownloadFile (const char *filename) MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va ("download \"%s\"", cls.downloadname->str)); + va (0, "download \"%s\"", cls.downloadname->str)); cls.downloadnumber++; @@ -286,7 +303,7 @@ map_ent (const char *mapname) edicts = ED_Parse (&edpr, buf); free (buf); } else { - edicts = ED_Parse (&edpr, cl.model_precache[1]->entities); + edicts = ED_Parse (&edpr, cl.model_precache[1]->brush.entities); } free (name); return edicts; @@ -295,15 +312,14 @@ map_ent (const char *mapname) static void CL_NewMap (const char *mapname) { - cl_static_entities = 0; - cl_static_tail = &cl_static_entities; + cl_static_entities.size = 0; r_funcs->R_NewMap (cl.worldmodel, cl.model_precache, cl.nummodels); Team_NewMap (); Con_NewMap (); Hunk_Check (); // make sure nothing is hurt Sbar_CenterPrint (0); - if (cl.model_precache[1] && cl.model_precache[1]->entities) { + if (cl.model_precache[1] && cl.model_precache[1]->brush.entities) { cl.edicts = map_ent (mapname); if (cl.edicts) { cl.worldspawn = PL_ObjectAtIndex (cl.edicts, 0); @@ -371,12 +387,13 @@ Model_NextDownload (void) aliashdr_t *ahdr = cl.model_precache[i]->aliashdr; if (!ahdr) ahdr = Cache_Get (&cl.model_precache[i]->cache); - Info_SetValueForKey (cls.userinfo, info_key, va ("%d", ahdr->crc), + Info_SetValueForKey (cls.userinfo, info_key, va (0, "%d", + ahdr->crc), 0); if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); - SZ_Print (&cls.netchan.message, va ("setinfo %s %d", info_key, - ahdr->crc)); + SZ_Print (&cls.netchan.message, va (0, "setinfo %s %d", + info_key, ahdr->crc)); } if (!cl.model_precache[i]->aliashdr) Cache_Release (&cl.model_precache[i]->cache); @@ -400,8 +417,8 @@ Model_NextDownload (void) if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (prespawn_name, cl.servercount, - cl.worldmodel->checksum2)); + va (0, prespawn_name, cl.servercount, + cl.worldmodel->brush.checksum2)); } } @@ -421,7 +438,7 @@ Sound_NextDownload (void) for (; cl.sound_name[cls.downloadnumber][0]; cls.downloadnumber++) { s = cl.sound_name[cls.downloadnumber]; - if (!CL_CheckOrDownloadFile (va ("sound/%s", s))) + if (!CL_CheckOrDownloadFile (va (0, "sound/%s", s))) return; // started a download } @@ -434,14 +451,13 @@ Sound_NextDownload (void) // done with sounds, request models now memset (cl.model_precache, 0, sizeof (cl.model_precache)); cl_playerindex = -1; - cl_spikeindex = -1; cl_flagindex = -1; cl_h_playerindex = -1; cl_gib1index = cl_gib2index = cl_gib3index = -1; if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (modellist_name, cl.servercount, 0)); + va (0, modellist_name, cl.servercount, 0)); } } @@ -470,7 +486,7 @@ void CL_FinishDownload (void) { Qclose (cls.download); - VID_SetCaption (va ("Connecting to %s", cls.servername->str)); + VID_SetCaption (va (0, "Connecting to %s", cls.servername->str)); // rename the temp file to it's final name if (strcmp (cls.downloadtempname->str, cls.downloadname->str)) { @@ -660,8 +676,8 @@ CL_ParseDownload (void) if (percent != 100) { // request next block if (percent != cls.downloadpercent) - VID_SetCaption (va ("Downloading %s %d%%", cls.downloadname->str, - percent)); + VID_SetCaption (va (0, "Downloading %s %d%%", + cls.downloadname->str, percent)); cls.downloadpercent = percent; MSG_WriteByte (&cls.netchan.message, clc_stringcmd); @@ -840,7 +856,7 @@ CL_ParseServerData (void) if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (soundlist_name, cl.servercount, 0)); + va (0, soundlist_name, cl.servercount, 0)); } // now waiting for downloads, etc @@ -876,7 +892,7 @@ CL_ParseSoundlist (void) if (n && !cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (soundlist_name, cl.servercount, n)); + va (0, soundlist_name, cl.servercount, n)); return; } @@ -903,9 +919,7 @@ CL_ParseModellist (void) Host_Error ("Server sent too many model_precache"); strcpy (cl.model_name[cl.nummodels], str); - if (!strcmp (cl.model_name[cl.nummodels], "progs/spike.mdl")) - cl_spikeindex = cl.nummodels; - else if (!strcmp (cl.model_name[cl.nummodels], "progs/player.mdl")) + if (!strcmp (cl.model_name[cl.nummodels], "progs/player.mdl")) cl_playerindex = cl.nummodels; else if (!strcmp (cl.model_name[cl.nummodels], "progs/flag.mdl")) cl_flagindex = cl.nummodels; @@ -927,7 +941,7 @@ CL_ParseModellist (void) if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (modellist_name, cl.servercount, n)); + va (0, modellist_name, cl.servercount, n)); } return; } @@ -945,7 +959,8 @@ CL_ParseBaseline (entity_state_t *es) es->colormap = MSG_ReadByte (net_message); es->skinnum = MSG_ReadByte (net_message); - MSG_ReadCoordAngleV (net_message, es->origin, es->angles); + MSG_ReadCoordAngleV (net_message, &es->origin[0], es->angles);//FIXME + es->origin[3] = 1; // LordHavoc: set up baseline to for new effects (alpha, colormod, etc) es->colormod = 255; @@ -972,18 +987,16 @@ CL_ParseStatic (void) ent = r_funcs->R_AllocEntity (); CL_Init_Entity (ent); - *cl_static_tail = ent; - cl_static_tail = &ent->unext; + DARRAY_APPEND (&cl_static_entities, es); // copy it to the current state - ent->model = cl.model_precache[es.modelindex]; - ent->frame = es.frame; - ent->skinnum = es.skinnum; + ent->renderer.model = cl.model_precache[es.modelindex]; + ent->animation.frame = es.frame; + ent->renderer.skinnum = es.skinnum; - VectorCopy (es.origin, ent->origin); - CL_TransformEntity (ent, es.angles, true); + CL_TransformEntity (ent, es.scale / 16.0, es.angles, es.origin); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } static void @@ -1093,7 +1106,8 @@ CL_ProcessUserInfo (int slot, player_info_t *player) while (!(player->name = Info_Key (player->userinfo, "name"))) { if (player->userid) Info_SetValueForKey (player->userinfo, "name", - va ("user-%i [exploit]", player->userid), 1); + va (0, "user-%i [exploit]", + player->userid), 1); else Info_SetValueForKey (player->userinfo, "name", "", 1); } @@ -1246,7 +1260,8 @@ CL_SetStat (int stat, int value) break; case STAT_HEALTH: if (cl_player_health_e->func) - GIB_Event_Callback (cl_player_health_e, 1, va ("%i", value)); + GIB_Event_Callback (cl_player_health_e, 1, + va (0, "%i", value)); if (value <= 0) Team_Dead (); break; @@ -1255,12 +1270,14 @@ CL_SetStat (int stat, int value) } static void -CL_MuzzleFlash (void) +CL_ParseMuzzleFlash (void) { - dlight_t *dl; + //FIXME this should just enable the effect on the relevant entity and + //then automatic entity updates take care of the rest int i; player_state_t *pl; - vec3_t fv, rv, uv; + vec3_t f, r, u; + vec4f_t position = { 0, 0, 0, 1}, fv = {}; i = MSG_ReadShort (net_message); @@ -1269,23 +1286,14 @@ CL_MuzzleFlash (void) pl = &cl.frames[parsecountmod].playerstate[i - 1]; - dl = r_funcs->R_AllocDlight (i); - if (!dl) - return; - if (i - 1 == cl.playernum) - AngleVectors (cl.viewangles, fv, rv, uv); + AngleVectors (cl.viewstate.angles, f, r, u); else - AngleVectors (pl->viewangles, fv, rv, uv); + AngleVectors (pl->viewangles, f, r, u); - VectorMultAdd (pl->pls.origin, 18, fv, dl->origin); - dl->radius = 200 + (rand () & 31); - dl->die = cl.time + 0.1; - dl->minlight = 32; - dl->color[0] = 0.2; - dl->color[1] = 0.1; - dl->color[2] = 0.05; - dl->color[3] = 0.7; + VectorCopy (f, fv); + VectorCopy (pl->pls.es.origin, position); + CL_MuzzleFlash (position, fv, 0, i, cl.time); } #define SHOWNET(x) \ @@ -1300,6 +1308,9 @@ CL_ParseServerMessage (void) int cmd = 0, i, j; const char *str; static dstring_t *stuffbuf; + TEntContext_t tentCtx = { + cl.viewstate.origin, cl.worldmodel, cl.viewentity + }; received_framecount = host_framecount; cl.last_servermessage = realtime; @@ -1329,7 +1340,7 @@ CL_ParseServerMessage (void) break; // end of message } - SHOWNET (va ("%s(%d)", svc_strings[cmd], cmd)); + SHOWNET (va (0, "%s(%d)", svc_strings[cmd], cmd)); // other commands switch (cmd) { @@ -1418,7 +1429,7 @@ CL_ParseServerMessage (void) case svc_setangle: { - vec_t *dest = cl.viewangles; + vec_t *dest = cl.viewstate.angles; vec3_t dummy; if (cls.demoplayback2) { @@ -1502,7 +1513,7 @@ CL_ParseServerMessage (void) break; case svc_temp_entity: - CL_ParseTEnt (); + CL_ParseTEnt_qw (net_message, cl.time, &tentCtx); break; case svc_setpause: @@ -1544,16 +1555,17 @@ CL_ParseServerMessage (void) cl.completed_time = realtime; r_data->vid->recalc_refdef = true; // go to full screen Sys_MaskPrintf (SYS_DEV, "intermission simorg: "); - MSG_ReadCoordV (net_message, cl.simorg); - for (i = 0; i < 3; i++) - Sys_MaskPrintf (SYS_DEV, "%f ", cl.simorg[i]); + MSG_ReadCoordV (net_message, &cl.viewstate.origin[0]);//FIXME + cl.viewstate.origin[3] = 1; + Sys_MaskPrintf (SYS_DEV, VEC4F_FMT, + VEC4_EXP (cl.viewstate.origin)); Sys_MaskPrintf (SYS_DEV, "\nintermission simangles: "); - MSG_ReadAngleV (net_message, cl.simangles); - cl.simangles[ROLL] = 0; // FIXME @@@ - for (i = 0; i < 3; i++) - Sys_MaskPrintf (SYS_DEV, "%f ", cl.simangles[i]); + MSG_ReadAngleV (net_message, cl.viewstate.angles); + cl.viewstate.angles[ROLL] = 0; // FIXME @@@ + Sys_MaskPrintf (SYS_DEV, "%f %f %f", + VectorExpand (cl.viewstate.angles)); Sys_MaskPrintf (SYS_DEV, "\n"); - VectorZero (cl.simvel); + cl.viewstate.velocity = (vec4f_t) { }; // automatic fraglogging (by elmex) // XXX: Should this _really_ called here? @@ -1586,11 +1598,17 @@ CL_ParseServerMessage (void) // svc_cutscene (same value as svc_smallkick) case svc_smallkick: - cl.punchangle[PITCH] = -2; + cl.viewstate.punchangle = (vec4f_t) { + // -2 degrees pitch + 0, -0.0174524064, 0, 0.999847695 + }; break; case svc_bigkick: - cl.punchangle[PITCH] = -4; + cl.viewstate.punchangle = (vec4f_t) { + // -4 degrees pitch + 0, -0.0348994967, 0, 0.999390827 + }; break; case svc_updateping: @@ -1618,7 +1636,7 @@ CL_ParseServerMessage (void) break; case svc_muzzleflash: - CL_MuzzleFlash (); + CL_ParseMuzzleFlash (); break; case svc_updateuserinfo: @@ -1634,7 +1652,7 @@ CL_ParseServerMessage (void) break; case svc_nails: - CL_ParseProjectiles (false); + CL_ParseProjectiles (net_message, false, &tentCtx); break; case svc_chokecount: // some preceding packets were choked @@ -1685,7 +1703,7 @@ CL_ParseServerMessage (void) break; case svc_nails2: // FIXME from qwex - CL_ParseProjectiles (true); + CL_ParseProjectiles (net_message, true, &tentCtx); break; } } diff --git a/qw/source/cl_pred.c b/qw/source/cl_pred.c index 6b110e46c..40f9f1459 100644 --- a/qw/source/cl_pred.c +++ b/qw/source/cl_pred.c @@ -34,11 +34,12 @@ #include "QF/cvar.h" #include "QF/keys.h" -#include "qw/bothdefs.h" #include "compat.h" -#include "cl_ents.h" -#include "cl_pred.h" -#include "client.h" + +#include "qw/bothdefs.h" +#include "qw/include/cl_ents.h" +#include "qw/include/cl_pred.h" +#include "qw/include/client.h" #include "qw/pmove.h" cvar_t *cl_predict; @@ -46,14 +47,14 @@ cvar_t *cl_pushlatency; void -CL_PredictUsercmd (player_state_t * from, player_state_t * to, usercmd_t *u, +CL_PredictUsercmd (player_state_t *from, player_state_t *to, usercmd_t *u, qboolean clientplayer) { if (!clientplayer) { - if (VectorIsZero (from->pls.velocity)) { - VectorCopy (from->pls.origin, to->pls.origin); + if (VectorIsZero (from->pls.es.velocity)) { + VectorCopy (from->pls.es.origin, to->pls.es.origin); VectorCopy (u->angles, to->viewangles); - VectorCopy (from->pls.velocity, to->pls.velocity); + VectorCopy (from->pls.es.velocity, to->pls.es.velocity); return; } } @@ -71,9 +72,9 @@ CL_PredictUsercmd (player_state_t * from, player_state_t * to, usercmd_t *u, return; } - VectorCopy (from->pls.origin, pmove.origin); + VectorCopy (from->pls.es.origin, pmove.origin); VectorCopy (u->angles, pmove.angles); - VectorCopy (from->pls.velocity, pmove.velocity); + VectorCopy (from->pls.es.velocity, pmove.velocity); pmove.oldbuttons = from->oldbuttons; pmove.oldonground = from->oldonground; @@ -91,11 +92,11 @@ CL_PredictUsercmd (player_state_t * from, player_state_t * to, usercmd_t *u, to->waterjumptime = pmove.waterjumptime; to->oldbuttons = pmove.oldbuttons; // Tonik to->oldonground = pmove.oldonground; - VectorCopy (pmove.origin, to->pls.origin); + VectorCopy (pmove.origin, to->pls.es.origin); VectorCopy (pmove.angles, to->viewangles); - VectorCopy (pmove.velocity, to->pls.velocity); + VectorCopy (pmove.velocity, to->pls.es.velocity); to->onground = onground; - to->pls.weaponframe = from->pls.weaponframe; + to->pls.es.weaponframe = from->pls.es.weaponframe; } void @@ -104,6 +105,8 @@ CL_PredictMove (void) float f; int oldphysent, i; frame_t *from, *to = NULL; + entity_state_t *fromes; + entity_state_t *toes; if (cl_pushlatency->value > 0) Cvar_Set (cl_pushlatency, "0"); @@ -112,7 +115,7 @@ CL_PredictMove (void) return; // assume on ground unless prediction says different - cl.onground = 0; + cl.viewstate.onground = 0; cl.time = realtime - cls.latency - cl_pushlatency->value * 0.001; if (cl.time > realtime) @@ -129,15 +132,16 @@ CL_PredictMove (void) UPDATE_BACKUP - 1) return; - VectorCopy (cl.viewangles, cl.simangles); - cl.simangles[ROLL] = 0; // FIXME @@@ + //VectorCopy (cl.viewstate.angles, cl.viewstate.angles); + cl.viewstate.angles[ROLL] = 0; // FIXME @@@ // this is the last frame received from the server from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; + fromes = &from->playerstate[cl.playernum].pls.es; if (!cl_predict->int_val) { - VectorCopy (from->playerstate[cl.playernum].pls.velocity, cl.simvel); - VectorCopy (from->playerstate[cl.playernum].pls.origin, cl.simorg); + cl.viewstate.velocity = fromes->velocity; + cl.viewstate.origin = fromes->origin; return; } @@ -153,7 +157,7 @@ CL_PredictMove (void) CL_PredictUsercmd (&from->playerstate[cl.playernum], &to->playerstate[cl.playernum], &to->cmd, true); - cl.onground = onground; + cl.viewstate.onground = onground; if (to->senttime >= cl.time) break; from = to; @@ -164,6 +168,7 @@ CL_PredictMove (void) if (i == UPDATE_BACKUP - 1 || !to) return; // net hasn't deliver packets in a // long time... + toes = &to->playerstate[cl.playernum].pls.es; // now interpolate some fraction of the final frame if (to->senttime == from->senttime) @@ -174,22 +179,14 @@ CL_PredictMove (void) } for (i = 0; i < 3; i++) - if (fabs (from->playerstate[cl.playernum].pls.origin[i] - - to->playerstate[cl.playernum].pls.origin[i]) > 128) { + if (fabs (fromes->origin[i] - toes->origin[i]) > 128) { // teleported, so don't lerp - VectorCopy (to->playerstate[cl.playernum].pls.velocity, cl.simvel); - VectorCopy (to->playerstate[cl.playernum].pls.origin, cl.simorg); + cl.viewstate.velocity = toes->velocity; + cl.viewstate.origin = toes->origin; return; } - for (i = 0; i < 3; i++) { - cl.simorg[i] = from->playerstate[cl.playernum].pls.origin[i] + - f * (to->playerstate[cl.playernum].pls.origin[i] - - from->playerstate[cl.playernum].pls.origin[i]); - cl.simvel[i] = from->playerstate[cl.playernum].pls.velocity[i] + - f * (to->playerstate[cl.playernum].pls.velocity[i] - - from->playerstate[cl.playernum].pls.velocity[i]); - } + cl.viewstate.origin = fromes->origin + f * (toes->origin - fromes->origin); } void diff --git a/qw/source/cl_rss.c b/qw/source/cl_rss.c index 447e25dcc..bb4cbd993 100644 --- a/qw/source/cl_rss.c +++ b/qw/source/cl_rss.c @@ -42,8 +42,8 @@ #include "QF/pcx.h" #include "QF/sys.h" -#include "cl_parse.h" -#include "client.h" +#include "qw/include/cl_parse.h" +#include "qw/include/client.h" void CL_RSShot_f (void) diff --git a/qw/source/cl_screen.c b/qw/source/cl_screen.c index adf20f7e4..12cfb8441 100644 --- a/qw/source/cl_screen.c +++ b/qw/source/cl_screen.c @@ -44,10 +44,12 @@ #include "QF/pcx.h" #include "QF/screen.h" -#include "client.h" -#include "clview.h" #include "sbar.h" +#include "client/view.h" + +#include "qw/include/client.h" + static qpic_t *scr_net; static void @@ -85,7 +87,9 @@ SCR_CShift (void) int contents = CONTENTS_EMPTY; if (cls.state == ca_active && cl.worldmodel) { - leaf = Mod_PointInLeaf (r_data->refdef->vieworg, cl.worldmodel); + //FIXME + leaf = Mod_PointInLeaf (&r_data->refdef->viewposition[0], + cl.worldmodel); contents = leaf->contents; } V_SetContentsColor (contents); @@ -146,5 +150,5 @@ CL_UpdateScreen (double realtime) scr_funcs_normal[3] = r_funcs->SCR_DrawPause; V_PrepBlend (); - r_funcs->SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); + SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); } diff --git a/qw/source/cl_skin.c b/qw/source/cl_skin.c index d533a58d3..491d12652 100644 --- a/qw/source/cl_skin.c +++ b/qw/source/cl_skin.c @@ -43,11 +43,12 @@ #include "QF/sys.h" #include "QF/va.h" -#include "cl_parse.h" -#include "cl_skin.h" -#include "client.h" #include "compat.h" -#include "host.h" + +#include "qw/include/cl_parse.h" +#include "qw/include/cl_skin.h" +#include "qw/include/client.h" +#include "qw/include/host.h" cvar_t *noskins; //XXX FIXME cvar_t *skin; @@ -77,7 +78,8 @@ Skin_NextDownload (void) //XXX Skin_Find (sc); if (noskins->int_val) //XXX FIXME continue; - //XXX if (!CL_CheckOrDownloadFile (va ("skins/%s.pcx", sc->skin->name))) + //XXX if (!CL_CheckOrDownloadFile (va (0, "skins/%s.pcx", + // sc->skin->name))) //XXX return; // started a download } @@ -98,7 +100,7 @@ Skin_NextDownload (void) // get next signon phase MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va ("begin %i", cl.servercount)); + va (0, "begin %i", cl.servercount)); Cache_Report (); // print remaining memory } CL_SetState (ca_active); diff --git a/qw/source/cl_slist.c b/qw/source/cl_slist.c index 569b711ce..ded6445c8 100644 --- a/qw/source/cl_slist.c +++ b/qw/source/cl_slist.c @@ -68,9 +68,9 @@ #include "QF/va.h" #include "qw/bothdefs.h" -#include "cl_main.h" -#include "cl_slist.h" -#include "client.h" +#include "qw/include/cl_main.h" +#include "qw/include/cl_slist.h" +#include "qw/include/client.h" typedef struct server_entry_s { char *server; @@ -119,7 +119,6 @@ SL_Add (server_entry_t *start, const char *ip, const char *desc) { server_entry_t *p; - p = start; if (!start) { // Nothing at beginning of list, // create it start = calloc (1, sizeof (server_entry_t)); @@ -315,7 +314,7 @@ SL_Shutdown (void) SL_Del_All (all_slist); } -static char * +static __attribute__((pure)) char * gettokstart (char *str, int req, char delim) { char *start = str; @@ -341,14 +340,14 @@ gettokstart (char *str, int req, char delim) return start; } -static int +static __attribute__((pure)) int gettoklen (char *str, int req, char delim) { char *start = 0; int len = 0; start = gettokstart (str, req, delim); - if (start == '\0') { + if (*start == '\0') { return 0; } while (*start != delim && *start != '\0') { @@ -576,7 +575,7 @@ MSL_ParseServerList (const char *msl_data) unsigned int msl_ptr; for (msl_ptr = 0; msl_ptr < strlen (msl_data); msl_ptr = msl_ptr + 6) { - slist = SL_Add (slist, va ("%i.%i.%i.%i:%i", + slist = SL_Add (slist, va (0, "%i.%i.%i.%i:%i", (byte) msl_data[msl_ptr], (byte) msl_data[msl_ptr+1], (byte) msl_data[msl_ptr+2], diff --git a/qw/source/cl_sys_sdl.c b/qw/source/cl_sys_sdl.c index 75f7c0024..c3b620ca8 100644 --- a/qw/source/cl_sys_sdl.c +++ b/qw/source/cl_sys_sdl.c @@ -50,19 +50,16 @@ # include #endif -#ifndef _WIN32 -# include -#endif - #include #include #include "QF/qargs.h" #include "QF/sys.h" -#include "host.h" #include "netchan.h" +#include "qw/include/host.h" + #ifdef _WIN32 # include "winquake.h" #endif @@ -93,7 +90,7 @@ startup (void) } static void -shutdown_f (void) +shutdown_f (void *data) { #ifndef _WIN32 // change stdin to blocking @@ -122,9 +119,9 @@ SDL_main (int argc, char *argv[]) if (!COM_CheckParm ("-noconinput")) fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) | O_NONBLOCK); #endif - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (Net_LogStop); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (Net_LogStop, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/qw/source/cl_sys_unix.c b/qw/source/cl_sys_unix.c index 05aedf9ff..d0ef58225 100644 --- a/qw/source/cl_sys_unix.c +++ b/qw/source/cl_sys_unix.c @@ -48,11 +48,12 @@ #include "QF/qargs.h" #include "QF/sys.h" -#include "host.h" #include "netchan.h" +#include "qw/include/host.h" + static void -shutdown_f (void) +shutdown_f (void *data) { // change stdin to blocking fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK); @@ -73,9 +74,9 @@ main (int argc, const char **argv) if (!COM_CheckParm ("-noconinput")) fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) | O_NONBLOCK); - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (Net_LogStop); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (Net_LogStop, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/qw/source/cl_sys_win.c b/qw/source/cl_sys_win.c index 44d7c8afb..6fe2fbe06 100644 --- a/qw/source/cl_sys_win.c +++ b/qw/source/cl_sys_win.c @@ -34,8 +34,8 @@ #include "QF/screen.h" #include "QF/sys.h" -#include "client.h" -#include "host.h" +#include "qw/include/client.h" +#include "qw/include/host.h" #define MAXIMUM_WIN_MEMORY 0x1000000 #define MINIMUM_WIN_MEMORY 0x0c00000 @@ -93,7 +93,7 @@ startup (void) } static void -shutdown_f (void) +shutdown_f (void *data) { if (tevent) CloseHandle (tevent); @@ -181,9 +181,9 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, if (!tevent) Sys_Error ("Couldn't create event"); - Sys_RegisterShutdown (Host_Shutdown); - Sys_RegisterShutdown (Net_LogStop); - Sys_RegisterShutdown (shutdown_f); + Sys_RegisterShutdown (Host_Shutdown, 0); + Sys_RegisterShutdown (Net_LogStop, 0); + Sys_RegisterShutdown (shutdown_f, 0); Host_Init (); diff --git a/qw/source/cl_tent.c b/qw/source/cl_tent.c deleted file mode 100644 index c401defa2..000000000 --- a/qw/source/cl_tent.c +++ /dev/null @@ -1,665 +0,0 @@ -/* - cl_tent.c - - client side temporary entities - - Copyright (C) 1996-1997 Id Software, Inc. - - 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: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#include -#include - -#include "QF/console.h" -#include "QF/model.h" -#include "QF/msg.h" -#include "QF/sound.h" -#include "QF/sys.h" - -#include "cl_ents.h" -#include "cl_main.h" -#include "cl_parse.h" -#include "cl_tent.h" -#include "client.h" -#include "compat.h" - -typedef struct tent_s { - struct tent_s *next; - entity_t ent; -} tent_t; - -#define TEMP_BATCH 64 -static tent_t *temp_entities = 0; - -typedef struct { - int entity; - struct model_s *model; - float endtime; - vec3_t start, end; - tent_t *tents; - int seed; -} beam_t; - -#define BEAM_SEED_INTERVAL 72 -#define BEAM_SEED_PRIME 3191 - -typedef struct { - float start; - tent_t *tent; -} explosion_t; - -typedef struct tent_obj_s { - struct tent_obj_s *next; - union { - beam_t beam; - explosion_t ex; - } to; -} tent_obj_t; - -static tent_obj_t *tent_objects; -static tent_obj_t *cl_beams; -static tent_obj_t *cl_explosions; -static tent_t *cl_projectiles; - -static sfx_t *cl_sfx_wizhit; -static sfx_t *cl_sfx_knighthit; -static sfx_t *cl_sfx_tink1; -static sfx_t *cl_sfx_ric1; -static sfx_t *cl_sfx_ric2; -static sfx_t *cl_sfx_ric3; -static sfx_t *cl_sfx_r_exp3; - -static model_t *cl_mod_beam; -static model_t *cl_mod_bolt; -static model_t *cl_mod_bolt2; -static model_t *cl_mod_bolt3; -static model_t *cl_spr_explod; - -static void -CL_TEnts_Precache (int phase) -{ - if (!phase) - return; - cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); - cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); - cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); - cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); - cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); - cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); - cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); - - cl_mod_bolt = Mod_ForName ("progs/bolt.mdl", true); - cl_mod_bolt2 = Mod_ForName ("progs/bolt2.mdl", true); - cl_mod_bolt3 = Mod_ForName ("progs/bolt3.mdl", true); - cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - cl_mod_beam = Mod_ForName ("progs/beam.mdl", false); - if (!cl_mod_beam) - cl_mod_beam = cl_mod_bolt; -} - -void -CL_TEnts_Init (void) -{ - QFS_GamedirCallback (CL_TEnts_Precache); - CL_TEnts_Precache (1); -} - -void -CL_Init_Entity (entity_t *ent) -{ - memset (ent, 0, sizeof (*ent)); - - ent->skin = 0; - QuatSet (1.0, 1.0, 1.0, 1.0, ent->colormod); - ent->scale = 1.0; - ent->pose1 = ent->pose2 = -1; -} - -static tent_t * -new_temp_entity (void) -{ - tent_t *tent; - if (!temp_entities) { - int i; - - temp_entities = malloc (TEMP_BATCH * sizeof (tent_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) { - temp_entities[i].next = &temp_entities[i + 1]; - } - temp_entities[i].next = 0; - } - tent = temp_entities; - temp_entities = tent->next; - tent->next = 0; - CL_Init_Entity (&tent->ent); - return tent; -} - -static void -free_temp_entities (tent_t *tents) -{ - tent_t **t = &tents; - - while (*t) - t = &(*t)->next; - *t = temp_entities; - temp_entities = tents; -} - -static tent_obj_t * -new_tent_object (void) -{ - tent_obj_t *tobj; - if (!tent_objects) { - int i; - - tent_objects = malloc (TEMP_BATCH * sizeof (tent_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) - tent_objects[i].next = &tent_objects[i + 1]; - tent_objects[i].next = 0; - } - tobj = tent_objects; - tent_objects = tobj->next; - tobj->next = 0; - return tobj; -} - -static void -free_tent_objects (tent_obj_t *tobjs) -{ - tent_obj_t **t = &tobjs; - - while (*t) - t = &(*t)->next; - *t = tent_objects; - tent_objects = tobjs; -} - -void -CL_ClearTEnts (void) -{ - tent_t *t; - tent_obj_t *to; - - for (to = cl_beams; to; to = to->next) { - for (t = to->to.beam.tents; t; t = t->next) - t->ent.efrag = 0; - free_temp_entities (to->to.beam.tents); - } - free_tent_objects (cl_beams); - cl_beams = 0; - - for (to = cl_explosions; to; to = to->next) { - for (t = to->to.ex.tent; t; t = t->next) - t->ent.efrag = 0; - free_temp_entities (to->to.ex.tent); - } - free_tent_objects (cl_explosions); - cl_explosions = 0; -} - -static inline void -beam_clear (beam_t *b) -{ - if (b->tents) { - tent_t *t; - - for (t = b->tents; t; t = t->next) { - r_funcs->R_RemoveEfrags (&t->ent); - t->ent.efrag = 0; - } - free_temp_entities (b->tents); - b->tents = 0; - } -} - -static inline void -beam_setup (beam_t *b, qboolean transform) -{ - tent_t *tent; - float forward, pitch, yaw, d; - int ent_count; - vec3_t dist, org, ang; - unsigned seed; - - // calculate pitch and yaw - VectorSubtract (b->end, b->start, dist); - - if (dist[1] == 0 && dist[0] == 0) { - yaw = 0; - if (dist[2] > 0) - pitch = 90; - else - pitch = 270; - } else { - yaw = (int) (atan2 (dist[1], dist[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - - forward = sqrt (dist[0] * dist[0] + dist[1] * dist[1]); - pitch = (int) (atan2 (dist[2], forward) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - - // add new entities for the lightning - VectorCopy (b->start, org); - d = VectorNormalize (dist); - VectorScale (dist, 30, dist); - ent_count = ceil (d / 30); - d = 0; - - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % - BEAM_SEED_INTERVAL); - - ang[ROLL] = 0; - while (ent_count--) { - tent = new_temp_entity (); - tent->next = b->tents; - b->tents = tent; - - VectorMultAdd (org, d, dist, tent->ent.origin); - d += 1.0; - tent->ent.model = b->model; - ang[PITCH] = pitch; - ang[YAW] = yaw; - if (transform) { - seed = seed * BEAM_SEED_PRIME; - ang[ROLL] = seed % 360; - CL_TransformEntity (&tent->ent, ang, true); - } - VectorCopy (ang, tent->ent.angles); - r_funcs->R_AddEfrags (&tent->ent); - } -} - -static void -CL_ParseBeam (model_t *m) -{ - tent_obj_t *to; - beam_t *b; - int ent; - vec3_t start, end; - - ent = MSG_ReadShort (net_message); - - MSG_ReadCoordV (net_message, start); - MSG_ReadCoordV (net_message, end); - - to = 0; - if (ent) { - for (to = cl_beams; to; to = to->next) - if (to->to.beam.entity == ent) - break; - } - if (!to) { - to = new_tent_object (); - to->next = cl_beams; - cl_beams = to; - to->to.beam.tents = 0; - to->to.beam.entity = ent; - } - b = &to->to.beam; - - beam_clear (b); - b->model = m; - b->endtime = cl.time + 0.2; - b->seed = rand (); - VectorCopy (end, b->end); - if (b->entity != cl.viewentity) { - // this will be done in CL_UpdateBeams - VectorCopy (start, b->start); - beam_setup (b, true); - } -} - -void -CL_ParseTEnt (void) -{ - byte type; - dlight_t *dl; - tent_obj_t *to; - explosion_t *ex; - int colorStart, colorLength; - int cnt = -1; - vec3_t pos; - sfx_t *spike_sound[] = { - cl_sfx_ric3, cl_sfx_ric3, cl_sfx_ric2, cl_sfx_ric1, - }; - - type = MSG_ReadByte (net_message); - switch (type) { - case TE_WIZSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_WizSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); - break; - - case TE_KNIGHTSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_KnightSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); - break; - - case TE_SPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } - break; - - case TE_SUPERSPIKE: // super spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SuperSpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } - break; - - case TE_EXPLOSION: // rocket explosion - // particles - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_ParticleExplosion (pos); - - // light - dl = r_funcs->R_AllocDlight (0); - if (dl) { - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - QuatSet (0.86, 0.31, 0.24, 0.7, dl->color); - } - - // sound - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - - // sprite - to = new_tent_object (); - to->next = cl_explosions; - cl_explosions = to; - ex = &to->to.ex; - ex->tent = new_temp_entity (); - - VectorCopy (pos, ex->tent->ent.origin); - ex->start = cl.time; - //FIXME need better model management - if (!cl_spr_explod->cache.data) - cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - ex->tent->ent.model = cl_spr_explod; - CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true); - break; - - case TE_TAREXPLOSION: // tarbaby explosion - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_BlobExplosion (pos); - - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - break; - - case TE_LIGHTNING1: // lightning bolts - CL_ParseBeam (cl_mod_bolt); - break; - - case TE_LIGHTNING2: // lightning bolts - CL_ParseBeam (cl_mod_bolt2); - break; - - case TE_LIGHTNING3: // lightning bolts - CL_ParseBeam (cl_mod_bolt3); - break; - - // PGM 01/21/97 - case TE_BEAM: // grappling hook beam - CL_ParseBeam (cl_mod_beam); - break; - // PGM 01/21/97 - - case TE_LAVASPLASH: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_LavaSplash (pos); - break; - - case TE_TELEPORT: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_TeleportSplash (pos); - break; - - case TE_EXPLOSION2: // color mapped explosion - MSG_ReadCoordV (net_message, pos); - colorStart = MSG_ReadByte (net_message); - colorLength = MSG_ReadByte (net_message); - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - r_funcs->particles->R_ParticleExplosion2 (pos, colorStart, - colorLength); - dl = r_funcs->R_AllocDlight (0); - if (!dl) - break; - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - colorStart = (colorStart + (rand () % colorLength)) * 3; - VectorScale (&r_data->vid->palette[colorStart], 1.0 / 255.0, - dl->color); - dl->color[3] = 0.7; - break; - - case TE_GUNSHOT: // bullet hitting wall - cnt = MSG_ReadByte (net_message) * 20; - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_GunshotEffect (pos, cnt); - break; - - case TE_BLOOD: // bullet hitting body - cnt = MSG_ReadByte (net_message) * 20; - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_BloodPuffEffect (pos, cnt); - break; - - case TE_LIGHTNINGBLOOD: // lightning hitting body - MSG_ReadCoordV (net_message, pos); - - // light - dl = r_funcs->R_AllocDlight (0); - if (dl) { - VectorCopy (pos, dl->origin); - dl->radius = 150; - dl->die = cl.time + 0.1; - dl->decay = 200; - QuatSet (0.25, 0.40, 0.65, 1, dl->color); - } - - r_funcs->particles->R_LightningBloodEffect (pos); - break; - - default: - Sys_Error ("CL_ParseTEnt: bad type %d", type); - } -} - -static void -CL_UpdateBeams (void) -{ - tent_obj_t **to; - beam_t *b; - unsigned seed; - tent_t *t; - - // update lightning - for (to = &cl_beams; *to; ) { - b = &(*to)->to.beam; - if (!b->endtime) - continue; - if (!b->model || b->endtime < cl.time) { - tent_obj_t *_to; - b->endtime = 0; - beam_clear (b); - _to = *to; - *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; - continue; - } - to = &(*to)->next; - - // if coming from the player, update the start position - if (b->entity == cl.viewentity) { - beam_clear (b); - VectorCopy (cl.simorg, b->start); - beam_setup (b, false); - } - - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % - BEAM_SEED_INTERVAL); - - // add new entities for the lightning - for (t = b->tents; t; t = t->next) { - seed = seed * BEAM_SEED_PRIME; - t->ent.angles[ROLL] = seed % 360; - CL_TransformEntity (&t->ent, t->ent.angles, true); - } - } -} - -static void -CL_UpdateExplosions (void) -{ - int f; - tent_obj_t **to; - explosion_t *ex; - entity_t *ent; - - for (to = &cl_explosions; *to; ) { - ex = &(*to)->to.ex; - ent = &ex->tent->ent; - f = 10 * (cl.time - ex->start); - if (f >= ent->model->numframes) { - tent_obj_t *_to; - r_funcs->R_RemoveEfrags (ent); - ent->efrag = 0; - free_temp_entities (ex->tent); - _to = *to; - *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; - continue; - } - to = &(*to)->next; - - ent->frame = f; - if (!ent->efrag) - r_funcs->R_AddEfrags (ent); - } -} - -void -CL_UpdateTEnts (void) -{ - CL_UpdateBeams (); - CL_UpdateExplosions (); -} - -void -CL_ClearProjectiles (void) -{ - tent_t *tent; - - for (tent = cl_projectiles; tent; tent = tent->next) { - r_funcs->R_RemoveEfrags (&tent->ent); - tent->ent.efrag = 0; - } - free_temp_entities (cl_projectiles); - cl_projectiles = 0; -} - -/* - Nails are passed as efficient temporary entities -*/ -void -CL_ParseProjectiles (qboolean nail2) -{ - tent_t *tent; - tent_t *head = 0, **tail = &head; - byte bits[6]; - int i, c, j, num; - entity_t *pr; - - c = MSG_ReadByte (net_message); - - for (i = 0; i < c; i++) { - if (nail2) - num = MSG_ReadByte (net_message); - else - num = 0; - (void) num; //FIXME - - for (j = 0; j < 6; j++) - bits[j] = MSG_ReadByte (net_message); - - tent = new_temp_entity (); - *tail = tent; - tail = &tent->next; - - pr = &tent->ent; - pr->model = cl.model_precache[cl_spikeindex]; - pr->skin = 0; - pr->origin[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; - pr->origin[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; - pr->origin[2] = ((bits[3] + ((bits[4] & 15) << 8)) << 1) - 4096; - pr->angles[0] = (bits[4] >> 4) * (360.0 / 16.0); - pr->angles[1] = bits[5] * (360.0 / 256.0); - pr->angles[2] = 0; - CL_TransformEntity (&tent->ent, tent->ent.angles, true); - - r_funcs->R_AddEfrags (&tent->ent); - } - - *tail = cl_projectiles; - cl_projectiles = head; -} diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 09633388b..0da8c09cc 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -33,15 +33,18 @@ #include "QF/msg.h" #include "QF/screen.h" -#include "qw/bothdefs.h" -#include "chase.h" -#include "cl_cam.h" -#include "cl_ents.h" -#include "cl_main.h" -#include "client.h" +#include "QF/simd/vec4f.h" + #include "compat.h" -#include "host.h" -#include "clview.h" + +#include "qw/bothdefs.h" + +#include "qw/include/chase.h" +#include "qw/include/cl_cam.h" +#include "qw/include/cl_ents.h" +#include "qw/include/cl_main.h" +#include "qw/include/client.h" +#include "qw/include/host.h" /* The view is allowed to move slightly from it's true position for bobbing, @@ -79,8 +82,9 @@ cvar_t *v_idlescale; float v_dmg_time, v_dmg_roll, v_dmg_pitch; -frame_t *view_frame; -player_state_t *view_message; +vec4f_t v_idle_yaw; +vec4f_t v_idle_roll; +vec4f_t v_idle_pitch; cshift_t cshift_empty = { {130, 80, 50}, 0}; cshift_t cshift_water = { {130, 80, 50}, 128}; @@ -91,7 +95,7 @@ cshift_t cshift_bonus = { {215, 186, 60}, 50}; #define sqr(x) ((x) * (x)) float -V_CalcRoll (const vec3_t angles, const vec3_t velocity) +V_CalcRoll (const vec3_t angles, vec4f_t velocity) { float side, sign, value; vec3_t forward, right, up; @@ -114,7 +118,7 @@ V_CalcRoll (const vec3_t angles, const vec3_t velocity) static float V_CalcBob (void) { - vec_t *velocity = cl.simvel; + vec4f_t velocity = cl.viewstate.velocity; float cycle; static double bobtime; static float bob; @@ -122,10 +126,10 @@ V_CalcBob (void) if (cl.spectator) return 0; - if (cl.onground == -1) + if (cl.viewstate.onground == -1) return bob; // just use old value - bobtime += host_frametime; + bobtime += cl.viewstate.frametime; cycle = bobtime - (int) (bobtime / cl_bobcycle->value) * cl_bobcycle->value; cycle /= cl_bobcycle->value; @@ -136,8 +140,8 @@ V_CalcBob (void) // bob is proportional to velocity in the xy plane // (don't count Z, or jumping messes it up) - - bob = sqrt (sqr (velocity[0]) + sqr (velocity[1])) * cl_bob->value; + velocity[2] = 0; + bob = sqrt (dotf (velocity, velocity)[0]) * cl_bob->value; bob = bob * 0.3 + bob * 0.7 * sin (cycle * M_PI); if (bob > 4) bob = 4; @@ -184,10 +188,9 @@ static void V_DriftPitch (void) { float delta, move; - int frameno = (cls.netchan.outgoing_sequence - 1) & UPDATE_MASK; - usercmd_t *cmd = &cl.frames[frameno].cmd; + float forwardmove = cl.viewstate.movecmd[0]; - if (view_message->onground == -1 || cls.demoplayback) { + if (noclip_anglehack || cl.viewstate.onground == -1 || cls.demoplayback) { cl.driftmove = 0; cl.pitchvel = 0; return; @@ -195,10 +198,10 @@ V_DriftPitch (void) // don't count small mouse motion if (cl.nodrift) { - if (fabs (cmd->forwardmove) < cl_forwardspeed->value) + if (fabs (forwardmove) < cl_forwardspeed->value) cl.driftmove = 0; else - cl.driftmove += host_frametime; + cl.driftmove += cl.viewstate.frametime; if (cl.driftmove > v_centermove->value) { V_StartPitchDrift (); @@ -206,28 +209,28 @@ V_DriftPitch (void) return; } - delta = cl.idealpitch - cl.viewangles[PITCH]; + delta = cl.idealpitch - cl.viewstate.angles[PITCH]; if (!delta) { cl.pitchvel = 0; return; } - move = host_frametime * cl.pitchvel; - cl.pitchvel += host_frametime * v_centerspeed->value; + move = cl.viewstate.frametime * cl.pitchvel; + cl.pitchvel += cl.viewstate.frametime * v_centerspeed->value; if (delta > 0) { if (move > delta) { cl.pitchvel = 0; move = delta; } - cl.viewangles[PITCH] += move; + cl.viewstate.angles[PITCH] += move; } else if (delta < 0) { if (move > -delta) { cl.pitchvel = 0; move = -delta; } - cl.viewangles[PITCH] -= move; + cl.viewstate.angles[PITCH] -= move; } } @@ -238,8 +241,8 @@ V_ParseDamage (void) { float count, side; int armor, blood; - vec_t *origin = cl.simorg; - vec_t *angles = cl.simangles; + vec4f_t origin = cl.viewstate.origin; + vec_t *angles = cl.viewstate.angles; vec3_t from, forward, right, up; armor = MSG_ReadByte (net_message); @@ -395,7 +398,7 @@ V_CalcPowerupCshift (void) LordHavoc made this a real, true alpha blend. Cleaned it up a bit, but otherwise this is his code. --KB */ -void +static void V_CalcBlend (void) { float a2, a3; @@ -483,73 +486,41 @@ V_PrepBlend (void) /* VIEW RENDERING */ -static float -angledelta (float a) -{ - a = anglemod (a); - if (a > 180) - a -= 360; - return a; -} - static void CalcGunAngle (void) { - float yaw, pitch, move; - static float oldpitch = 0, oldyaw = 0; - - yaw = r_data->refdef->viewangles[YAW]; - pitch = -r_data->refdef->viewangles[PITCH]; - - yaw = angledelta (yaw - r_data->refdef->viewangles[YAW]) * 0.4; - yaw = bound (-10, yaw, 10); - pitch = angledelta (-pitch - r_data->refdef->viewangles[PITCH]) * 0.4; - pitch = bound (-10, pitch, 10); - - move = host_frametime * 20; - if (yaw > oldyaw) { - if (oldyaw + move < yaw) - yaw = oldyaw + move; - } else { - if (oldyaw - move > yaw) - yaw = oldyaw - move; - } - - if (pitch > oldpitch) { - if (oldpitch + move < pitch) - pitch = oldpitch + move; - } else { - if (oldpitch - move > pitch) - pitch = oldpitch - move; - } - - oldyaw = yaw; - oldpitch = pitch; - - cl.viewent.angles[YAW] = r_data->refdef->viewangles[YAW] + yaw; - cl.viewent.angles[PITCH] = -(r_data->refdef->viewangles[PITCH] + pitch); + vec4f_t rotation = r_data->refdef->viewrotation; + //FIXME make child of camera + Transform_SetWorldRotation (cl.viewent.transform, rotation); } static void V_BoundOffsets (void) { - vec_t *origin = cl.simorg; + vec4f_t offset = r_data->refdef->viewposition + - cl.viewstate.origin; // absolutely bound refresh reletive to entity clipping hull // so the view can never be inside a solid wall - if (r_data->refdef->vieworg[0] < origin[0] - 14) - r_data->refdef->vieworg[0] = origin[0] - 14; - else if (r_data->refdef->vieworg[0] > origin[0] + 14) - r_data->refdef->vieworg[0] = origin[0] + 14; - if (r_data->refdef->vieworg[1] < origin[1] - 14) - r_data->refdef->vieworg[1] = origin[1] - 14; - else if (r_data->refdef->vieworg[1] > origin[1] + 14) - r_data->refdef->vieworg[1] = origin[1] + 14; - if (r_data->refdef->vieworg[2] < origin[2] - 22) - r_data->refdef->vieworg[2] = origin[2] - 22; - else if (r_data->refdef->vieworg[2] > origin[2] + 30) - r_data->refdef->vieworg[2] = origin[2] + 30; + offset[0] = bound (-14, offset[0], 14); + offset[1] = bound (-14, offset[1], 14); + offset[2] = bound (-22, offset[2], 30); + r_data->refdef->viewposition = cl.viewstate.origin + offset; +} + +static vec4f_t +idle_quat (vec4f_t axis, cvar_t *cycle, cvar_t *level) +{ + vec4f_t identity = { 0, 0, 0, 1 }; + if (!level || !cycle) { + return identity; + } + float scale = sin (cl.time * cycle->value); + float ang = scale * level->value * v_idlescale->value; + float c = cos (ang); + float s = sin (ang); + return axis * s + identity * c; } /* @@ -560,19 +531,21 @@ V_BoundOffsets (void) static void V_AddIdle (void) { - r_data->refdef->viewangles[ROLL] += v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - r_data->refdef->viewangles[PITCH] += v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - r_data->refdef->viewangles[YAW] += v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + vec4f_t roll = idle_quat ((vec4f_t) { 1, 0, 0, 0}, + v_iroll_cycle, v_iroll_level); + vec4f_t pitch = idle_quat ((vec4f_t) { 0, 1, 0, 0}, + v_ipitch_cycle, v_ipitch_level); + vec4f_t yaw = idle_quat ((vec4f_t) { 0, 0, 1, 0}, + v_iyaw_cycle, v_iyaw_level); + vec4f_t rot = normalf (qmulf (yaw, qmulf (pitch, roll))); - cl.viewent.angles[ROLL] -= v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - cl.viewent.angles[PITCH] -= v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - cl.viewent.angles[YAW] -= v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + // rotate the view + r_data->refdef->viewrotation = qmulf (rot, r_data->refdef->viewrotation); + + // counter-rotate the weapon + rot = qmulf (qconjf (rot), + Transform_GetWorldRotation (cl.viewent.transform)); + Transform_SetWorldRotation (cl.viewent.transform, rot); } /* @@ -583,23 +556,25 @@ V_AddIdle (void) static void V_CalcViewRoll (void) { - float side; - vec_t *angles = cl.simangles; - vec_t *velocity = cl.simvel; + vec_t *angles = cl.viewstate.angles; + vec4f_t velocity = cl.viewstate.velocity; + vec3_t ang = { }; - side = V_CalcRoll (angles, velocity); - r_data->refdef->viewangles[ROLL] += side; + ang[ROLL] = V_CalcRoll (angles, velocity); if (v_dmg_time > 0) { - r_data->refdef->viewangles[ROLL] += - v_dmg_time / v_kicktime->value * v_dmg_roll; - r_data->refdef->viewangles[PITCH] += - v_dmg_time / v_kicktime->value * v_dmg_pitch; - v_dmg_time -= host_frametime; + ang[ROLL] += v_dmg_time / v_kicktime->value * v_dmg_roll; + ang[PITCH] += v_dmg_time / v_kicktime->value * v_dmg_pitch; + v_dmg_time -= cl.viewstate.frametime; } - if (view_message->pls.flags & PF_DEAD) // PF_GIB will also set PF_DEAD - r_data->refdef->viewangles[ROLL] = 80; // dead view angle + if (cl.viewstate.flags & VF_DEAD) { // VF_GIB will also set VF_DEAD + ang[ROLL] = 80; // dead view angle + } + + vec4f_t rot; + AngleQuat (ang, &rot[0]);//FIXME + r_data->refdef->viewrotation = qmulf (r_data->refdef->viewrotation, rot); } static void @@ -607,15 +582,13 @@ V_CalcIntermissionRefdef (void) { entity_t *view; float old; - vec_t *origin = cl.simorg; - vec_t *angles = cl.simangles; // view is the weapon model (visible only from inside body) view = &cl.viewent; - VectorCopy (origin, r_data->refdef->vieworg); - VectorCopy (angles, r_data->refdef->viewangles); - view->model = NULL; + r_data->refdef->viewposition = cl.viewstate.origin; + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME + view->renderer.model = NULL; // always idle in intermission old = v_idlescale->value; @@ -631,112 +604,122 @@ V_CalcRefdef (void) entity_t *view = &cl.viewent; float bob; static float oldz = 0; - int i; - vec3_t forward, right, up; - vec_t *origin = cl.simorg; - vec_t *viewangles = cl.simangles; + vec4f_t forward = {}, right = {}, up = {}; + vec4f_t origin = cl.viewstate.origin; + vec_t *viewangles = cl.viewstate.angles; V_DriftPitch (); bob = V_CalcBob (); // refresh position - VectorCopy (origin, r_data->refdef->vieworg); - r_data->refdef->vieworg[2] += cl.viewheight + bob; + r_data->refdef->viewposition = origin; + r_data->refdef->viewposition[2] += cl.viewheight + bob; // never let it sit exactly on a node line, because a water plane can // disappear when viewed with the eye exactly on it. // server protocol specifies to only 1/8 pixel, so add 1/16 in each axis - r_data->refdef->vieworg[0] += 1.0 / 16; - r_data->refdef->vieworg[1] += 1.0 / 16; - r_data->refdef->vieworg[2] += 1.0 / 16; + r_data->refdef->viewposition += (vec4f_t) { 1.0/16, 1.0/16, 1.0/16, 0}; - VectorCopy (viewangles, r_data->refdef->viewangles); + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME V_CalcViewRoll (); V_AddIdle (); // offsets - AngleVectors (viewangles, forward, right, up); + //FIXME semi-duplicates AngleQuat (also, vec3_t vs vec4f_t) + AngleVectors (viewangles, &forward[0], &right[0], &up[0]); // don't allow cheats in multiplayer // FIXME check for dead if (cl.maxclients == 1) { - for (i = 0; i < 3; i++) { - r_data->refdef->vieworg[i] += scr_ofsx->value * forward[i] + - scr_ofsy->value * right[i] + - scr_ofsz->value * up[i]; - } + r_data->refdef->viewposition += scr_ofsx->value * forward + + scr_ofsy->value * right + + scr_ofsz->value * up; } V_BoundOffsets (); // set up gun position - VectorCopy (viewangles, view->angles); - CalcGunAngle (); - VectorCopy (origin, view->origin); - view->origin[2] += cl.viewheight; - - for (i = 0; i < 3; i++) { - view->origin[i] += forward[i] * bob * 0.4; -// view->origin[i] += right[i] * bob * 0.4; -// view->origin[i] += up[i] * bob * 0.8; - } - view->origin[2] += bob; + origin += (vec4f_t) { 0, 0, cl.viewheight, 0 }; + origin += forward * bob * 0.4f + (vec4f_t) { 0, 0, bob, 0 }; // fudge position around to keep amount of weapon visible // roughly equal with different FOV - if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) + if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) { ; - else if (r_data->scr_viewsize->int_val == 110) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 100) - view->origin[2] += 2; - else if (r_data->scr_viewsize->int_val == 90) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 80) - view->origin[2] += 0.5; + } else if (r_data->scr_viewsize->int_val == 110) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 100) { + origin += (vec4f_t) { 0, 0, 2, 0}; + } else if (r_data->scr_viewsize->int_val == 90) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 80) { + origin += (vec4f_t) { 0, 0, 0.5, 0}; + } - if (view_message->pls.flags & (PF_GIB | PF_DEAD)) - view->model = NULL; - else - view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; - view->frame = view_message->pls.weaponframe; - view->skin = 0; + if (cl.viewstate.flags & (VF_GIB | VF_DEAD)) { + view->renderer.model = NULL; + } else { + view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; + } + view->animation.frame = cl.viewstate.weaponframe; + view->renderer.skin = 0; // set up the refresh position - VectorAdd (r_data->refdef->viewangles, cl.punchangle, - r_data->refdef->viewangles); + r_data->refdef->viewrotation = qmulf (cl.viewstate.punchangle, + r_data->refdef->viewrotation); // smooth out stair step ups - if ((cl.onground != -1) && (origin[2] - oldz > 0)) { + if ((cl.viewstate.onground != -1) && (origin[2] - oldz > 0)) { float steptime; - steptime = host_frametime; + steptime = cl.viewstate.frametime; oldz += steptime * 80; if (oldz > origin[2]) oldz = origin[2]; if (origin[2] - oldz > 12) oldz = origin[2] - 12; - r_data->refdef->vieworg[2] += oldz - origin[2]; - view->origin[2] += oldz - origin[2]; - } else + r_data->refdef->viewposition[2] += oldz - origin[2]; + origin[2] += oldz - origin[2]; + } else { oldz = origin[2]; + } + { + // FIXME sort out the alias model specific negation + vec3_t ang = {-viewangles[0], viewangles[1], viewangles[2]}; + CL_TransformEntity (view, 1, ang, origin); + } - if (cl.chase && chase_active->int_val) + if (cl.chase && chase_active->int_val) { Chase_Update (); - - CL_TransformEntity (view, view->angles, true); + } } static void DropPunchAngle (void) { - cl.punchangle[PITCH] -= 10 * host_frametime; - if (cl.punchangle[PITCH] < 0) - cl.punchangle[PITCH] = 0; + vec4f_t punch = cl.viewstate.punchangle; + float ps = magnitude3f (punch)[0]; + if (ps < 1e-3) { + // < 0.2 degree rotation, not worth worrying about + //ensure the quaternion is normalized + cl.viewstate.punchangle = (vec4f_t) { 0, 0, 0, 1 }; + return; + } + float pc = punch[3]; + float ds = 0.0871557427 * cl.viewstate.frametime; + float dc = sqrt (1 - ds * ds); + float s = ps * dc - pc * ds; + float c = pc * dc + ps * ds; + if (s <= 0 || c >= 1) { + cl.viewstate.punchangle = (vec4f_t) { 0, 0, 0, 1 }; + } else { + punch *= s / ps; + punch[3] = c; + } } /* @@ -748,17 +731,17 @@ DropPunchAngle (void) void V_RenderView (void) { - if (cls.state != ca_active) + if (cls.state != ca_active) { + r_data->refdef->viewposition = (vec4f_t) { 0, 0, 0, 1 }; + r_data->refdef->viewrotation = (vec4f_t) { 0, 0, 0, 1 }; return; + } - view_frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; - view_message = &view_frame->playerstate[cl.playernum]; - - if (view_message->pls.flags & PF_GIB) + if (cl.viewstate.flags & VF_GIB) { cl.viewheight = 8; // gib view height - else if (view_message->pls.flags & PF_DEAD) + } else if (cl.viewstate.flags & VF_DEAD) { cl.viewheight = -16; // corpse view height - else { + } else { cl.viewheight = DEFAULT_VIEWHEIGHT; // view height if (cl.stdver) cl.viewheight = cl.stats[STAT_VIEWHEIGHT]; diff --git a/qw/source/crudefile.c b/qw/source/crudefile.c index 58426ad4d..a02bc81bc 100644 --- a/qw/source/crudefile.c +++ b/qw/source/crudefile.c @@ -50,7 +50,8 @@ #include "QF/zone.h" #include "compat.h" -#include "crudefile.h" + +#include "qw/include/crudefile.h" int cf_maxsize; // max combined file size (eg quota) int cf_cursize; // current combined file size @@ -149,7 +150,7 @@ CF_BuildQuota (void) cf_cursize = 0; while ((i = readdir (dir))) { - cf_cursize += CF_GetFileSize (va ("%s/%s", path->str, i->d_name)); + cf_cursize += CF_GetFileSize (va (0, "%s/%s", path->str, i->d_name)); } closedir (dir); } diff --git a/qw/source/game.c b/qw/source/game.c index ac69d83ea..df180b306 100644 --- a/qw/source/game.c +++ b/qw/source/game.c @@ -43,8 +43,8 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "game.h" -#include "server.h" +#include "qw/include/game.h" +#include "qw/include/server.h" cvar_t *registered; int static_registered = 1; // only for startup check, then set diff --git a/qw/source/map_cfg.c b/qw/source/map_cfg.c index 10b4a5cd5..296bad56b 100644 --- a/qw/source/map_cfg.c +++ b/qw/source/map_cfg.c @@ -44,7 +44,7 @@ #include "QF/idparse.h" #include "QF/quakefs.h" -#include "map_cfg.h" +#include "qw/include/map_cfg.h" void map_cfg (const char *mapname, int all) diff --git a/qw/source/net_packetlog.c b/qw/source/net_packetlog.c index 87edf8e45..3d2c58dc8 100644 --- a/qw/source/net_packetlog.c +++ b/qw/source/net_packetlog.c @@ -54,9 +54,10 @@ #include "QF/va.h" #include "compat.h" + #include "netchan.h" #include "qw/protocol.h" -#include "server.h" +#include "qw/include/server.h" cvar_t *net_packetlog; cvar_t *net_loglevel; @@ -177,7 +178,7 @@ Net_LogStart (const char *fname) } void -Net_LogStop (void) +Net_LogStop (void *data) { if (Net_PacketLog) Qclose (Net_PacketLog); @@ -635,7 +636,7 @@ Parse_Server_Packet (int has_sequence) break; case svc_playerinfo: Net_LogPrintf ("\n\tPlayer: %d", MSG_ReadByte (&packet)); - mask2 = mask1 = MSG_ReadShort (&packet); + mask1 = MSG_ReadShort (&packet); Net_LogPrintf (" Mask1: %d", mask1); #if 1 Net_LogPrintf (" Origin:"); @@ -954,7 +955,7 @@ Net_PacketLog_f (cvar_t *var) if (var->int_val) { Net_LogStart ("qfpacket.log"); } else { - Net_LogStop (); + Net_LogStop (0); } } diff --git a/qw/source/pmove.c b/qw/source/pmove.c index 31702c2f3..358409bc5 100644 --- a/qw/source/pmove.c +++ b/qw/source/pmove.c @@ -34,8 +34,9 @@ #include "QF/qtypes.h" #include "QF/sys.h" -#include "client.h" #include "compat.h" + +#include "qw/include/client.h" #include "qw/pmove.h" cvar_t *no_pogo_stick; @@ -737,7 +738,7 @@ SpectatorMove (void) // friction speed = DotProduct (pmove.velocity, pmove.velocity); if (speed < 1) { - VectorZero (pmove.velocity) + VectorZero (pmove.velocity); } else { speed = sqrt (speed); drop = 0; diff --git a/qw/source/pmovetst.c b/qw/source/pmovetst.c index da23aef9d..b79e860e0 100644 --- a/qw/source/pmovetst.c +++ b/qw/source/pmovetst.c @@ -41,6 +41,7 @@ #include "QF/sys.h" #include "compat.h" + #include "qw/pmove.h" #include "world.h" @@ -135,7 +136,7 @@ PM_PointContents (const vec3_t p) hull_t *hull; plane_t *plane; - hull = &pmove.physents[0].model->hulls[0]; + hull = &pmove.physents[0].model->brush.hulls[0]; num = hull->firstclipnode; @@ -173,7 +174,7 @@ PM_TestPlayerPosition (const vec3_t pos) pe = &pmove.physents[i]; // get the clipping hull if (pe->model) - hull = &pmove.physents[i].model->hulls[1]; + hull = &pmove.physents[i].model->brush.hulls[1]; else { VectorSubtract (pe->mins, player_maxs, mins); VectorSubtract (pe->maxs, player_mins, maxs); @@ -234,7 +235,7 @@ PM_PlayerMove (const vec3_t start, const vec3_t end) } else { check_box = 1; if (pe->model) { - hull = &pe->model->hulls[1]; + hull = &pe->model->brush.hulls[1]; VectorSubtract (pe->model->mins, player_maxs, mins); VectorSubtract (pe->model->maxs, player_mins, maxs); } else { diff --git a/qw/source/sbar.c b/qw/source/sbar.c index 7234c7f51..4a517887e 100644 --- a/qw/source/sbar.c +++ b/qw/source/sbar.c @@ -54,11 +54,12 @@ #include "QF/plugin/console.h" -#include "qw/bothdefs.h" -#include "cl_cam.h" -#include "cl_parse.h" -#include "client.h" #include "compat.h" + +#include "qw/bothdefs.h" +#include "qw/include/cl_cam.h" +#include "qw/include/cl_parse.h" +#include "qw/include/client.h" #include "sbar.h" int sb_updates; // if >= vid.numpages, no update needed @@ -476,7 +477,7 @@ draw_solo (view_t *view) static inline void draw_smallnum (view_t *view, int x, int y, int n, int packed, int colored) { - char num[4]; + char num[12]; packed = packed != 0; // ensure 0 or 1 @@ -1107,7 +1108,7 @@ Sbar_LogFrags (void) if (t) Qwrite (file, t, strlen (t)); - Qprintf (file, "%s\n%s %s\n", cls.servername->str, cl.worldmodel->name, + Qprintf (file, "%s\n%s %s\n", cls.servername->str, cl.worldmodel->path, cl.levelname); // scores @@ -1604,7 +1605,7 @@ draw_net (view_t *view) int ping = cl.players[cl.playernum].ping; ping = bound (0, ping, 999); - draw_string (view, 0, 0, va ("%3d ms ", ping)); + draw_string (view, 0, 0, va (0, "%3d ms ", ping)); } if (hud_ping->int_val && hud_pl->int_val) @@ -1614,7 +1615,7 @@ draw_net (view_t *view) int lost = CL_CalcNet (); lost = bound (0, lost, 999); - draw_string (view, 56, 0, va ("%3d pl", lost)); + draw_string (view, 56, 0, va (0, "%3d pl", lost)); } } @@ -1949,8 +1950,8 @@ Sbar_Init (void) Key_KeydestCallback (sbar_keydest_callback); for (i = 0; i < 10; i++) { - sb_nums[0][i] = r_funcs->Draw_PicFromWad (va ("num_%i", i)); - sb_nums[1][i] = r_funcs->Draw_PicFromWad (va ("anum_%i", i)); + sb_nums[0][i] = r_funcs->Draw_PicFromWad (va (0, "num_%i", i)); + sb_nums[1][i] = r_funcs->Draw_PicFromWad (va (0, "anum_%i", i)); } sb_nums[0][10] = r_funcs->Draw_PicFromWad ("num_minus"); @@ -1976,19 +1977,26 @@ Sbar_Init (void) sb_weapons[1][6] = r_funcs->Draw_PicFromWad ("inv2_lightng"); for (i = 0; i < 5; i++) { - sb_weapons[2 + i][0] = r_funcs->Draw_PicFromWad (va ("inva%i_shotgun", + sb_weapons[2 + i][0] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_shotgun", i + 1)); - sb_weapons[2 + i][1] = r_funcs->Draw_PicFromWad (va ("inva%i_sshotgun", + sb_weapons[2 + i][1] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_sshotgun", i + 1)); - sb_weapons[2 + i][2] = r_funcs->Draw_PicFromWad (va ("inva%i_nailgun", + sb_weapons[2 + i][2] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_nailgun", i + 1)); - sb_weapons[2 + i][3] = r_funcs->Draw_PicFromWad (va ("inva%i_snailgun", + sb_weapons[2 + i][3] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_snailgun", i + 1)); - sb_weapons[2 + i][4] = r_funcs->Draw_PicFromWad (va ("inva%i_rlaunch", + sb_weapons[2 + i][4] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_rlaunch", i + 1)); - sb_weapons[2 + i][5] = r_funcs->Draw_PicFromWad (va ("inva%i_srlaunch", + sb_weapons[2 + i][5] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_srlaunch", i + 1)); - sb_weapons[2 + i][6] = r_funcs->Draw_PicFromWad (va ("inva%i_lightng", + sb_weapons[2 + i][6] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_lightng", i + 1)); } diff --git a/qw/source/sv_ccmds.c b/qw/source/sv_ccmds.c index aa359c576..22604df69 100644 --- a/qw/source/sv_ccmds.c +++ b/qw/source/sv_ccmds.c @@ -49,13 +49,14 @@ #include "QF/sys.h" #include "QF/va.h" -#include "qw/bothdefs.h" #include "compat.h" -#include "server.h" -#include "sv_demo.h" -#include "sv_progs.h" -#include "sv_qtv.h" -#include "sv_recorder.h" + +#include "qw/bothdefs.h" +#include "qw/include/server.h" +#include "qw/include/sv_demo.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_qtv.h" +#include "qw/include/sv_recorder.h" qboolean sv_allow_cheats; @@ -223,7 +224,7 @@ SV_Restart_f (void) net_message->message->data); } Sys_Printf ("Shutting down: server restart, shell must relaunch server\n"); - SV_Shutdown (); + SV_Shutdown (0); // Error code 2 on exit, indication shell must restart the server exit (2); } @@ -249,7 +250,7 @@ SV_Fraglogfile_f (void) } name = dstring_new (); if (!QFS_NextFilename (name, - va ("%s/frag_", qfs_gamedir->dir.def), ".log")) { + va (0, "%s/frag_", qfs_gamedir->dir.def), ".log")) { SV_Printf ("Can't open any logfiles.\n"); sv_fraglogfile = NULL; } else { @@ -395,29 +396,29 @@ nice_time (float time) #if 0 //FIXME ditch or cvar? if (t < 60) { - return va ("%ds", t); + return va (0, "%ds", t); } else if (t < 600) { - return va ("%dm%02ds", t / 60, t % 60); + return va (0, "%dm%02ds", t / 60, t % 60); } else if (t < 3600) { - return va ("%dm", t / 60); + return va (0, "%dm", t / 60); } else if (t < 36000) { t /= 60; - return va ("%dh%02dm", t / 60, t % 60); + return va (0, "%dh%02dm", t / 60, t % 60); } else if (t < 86400) { - return va ("%dh", t / 3600); + return va (0, "%dh", t / 3600); } else { t /= 3600; - return va ("%dd%02dh", t / 24, t % 24); + return va (0, "%dd%02dh", t / 24, t % 24); } #endif if (t < 60) { - return va ("%ds", t); + return va (0, "%ds", t); } else if (t < 3600) { - return va ("%dm%02ds", t / 60, t % 60); + return va (0, "%dm%02ds", t / 60, t % 60); } else if (t < 86400) { - return va ("%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); + return va (0, "%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); } else { - return va ("%dd%02dh%02dm%02ds", + return va (0, "%dd%02dh%02dm%02ds", t / 86400, (t / 3600) % 24, (t / 60) % 60, t % 60); } } @@ -741,15 +742,15 @@ SV_Ban_f (void) if (argc > argr) { reason = Cmd_Args (argr); SV_BroadcastPrintf (PRINT_HIGH, "Admin Banned user %s %s: %s\n", - cl->name, mins ? va ("for %.1f minutes", mins) + cl->name, mins ? va (0, "for %.1f minutes", mins) : "permanently", reason); } else { SV_BroadcastPrintf (PRINT_HIGH, "Admin Banned user %s %s\n", - cl->name, mins ? va ("for %.1f minutes", mins) + cl->name, mins ? va (0, "for %.1f minutes", mins) : "permanently"); } SV_DropClient (cl); - Cmd_ExecuteString (va ("addip %s %f", + Cmd_ExecuteString (va (0, "addip %s %f", NET_BaseAdrToString (cl->netchan.remote_address), mins), src_command); } @@ -811,7 +812,7 @@ SV_ConSay (const char *prefix, client_t *client) dbuf = SVR_WriteBegin (dem_all, 0, strlen (text->str) + 7); MSG_WriteByte (dbuf, svc_print); MSG_WriteByte (dbuf, PRINT_HIGH); - MSG_WriteString (dbuf, va ("%s\n", text->str)); + MSG_WriteString (dbuf, va (0, "%s\n", text->str)); MSG_WriteByte (dbuf, svc_print); MSG_WriteByte (dbuf, PRINT_CHAT); MSG_WriteString (dbuf, ""); @@ -950,6 +951,7 @@ SV_SetLocalinfo (const char *key, const char *value) P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue); P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value); + sv_pr_state.pr_argc = 3; PR_ExecuteProgram (&sv_pr_state, sv_funcs.LocalinfoChanged); PR_PopFrame (&sv_pr_state); } @@ -1134,7 +1136,7 @@ SV_Snap (int uid) cl->uploadfn = dstring_new (); if (!QFS_NextFilename (cl->uploadfn, - va ("%s/snap/%d-", qfs_gamedir->dir.def, uid), + va (0, "%s/snap/%d-", qfs_gamedir->dir.def, uid), ".pcx")) { SV_Printf ("Snap: Couldn't create a file, clean some out.\n"); dstring_delete (cl->uploadfn); diff --git a/qw/source/sv_demo.c b/qw/source/sv_demo.c index 65b6d397c..1018ecb6c 100644 --- a/qw/source/sv_demo.c +++ b/qw/source/sv_demo.c @@ -47,11 +47,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "QF/va.h" #include "compat.h" + #include "qw/pmove.h" -#include "server.h" -#include "sv_demo.h" -#include "sv_progs.h" -#include "sv_recorder.h" +#include "qw/include/server.h" +#include "qw/include/sv_demo.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_recorder.h" static QFile *demo_file; static byte *demo_mfile; @@ -190,7 +191,7 @@ SV_Stop (int reason) sv_redirected = RD_NONE; // onrecord script is called always // from the console - Cmd_TokenizeString (va ("script %s \"%s\" \"%s\" \"%s\" %s", + Cmd_TokenizeString (va (0, "script %s \"%s\" \"%s\" \"%s\" %s", sv_onrecordfinish->string, demo.path->str, serverdemo->string, path, p != NULL ? p + 1 : "")); @@ -453,7 +454,7 @@ SV_Record (char *name) // send server info string MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("fullserverinfo \"%s\"\n", + MSG_WriteString (&buf, va (0, "fullserverinfo \"%s\"\n", Info_MakeString (svs.info, 0))); // flush packet @@ -523,7 +524,7 @@ SV_Record (char *name) } MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("cmd spawn %i 0\n", svs.spawncount)); + MSG_WriteString (&buf, va (0, "cmd spawn %i 0\n", svs.spawncount)); if (buf.cursize) { SV_WriteRecordDemoMessage (&buf); @@ -575,7 +576,7 @@ SV_Record (char *name) // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("skins\n")); + MSG_WriteString (&buf, va (0, "skins\n")); SV_WriteRecordDemoMessage (&buf); @@ -773,7 +774,7 @@ Demo_Init (void) if (p < com_argc - 1) size = atoi (com_argv[p + 1]) * 1024; else - Sys_Error ("Memory_Init: you must specify a size in KB after " + Sys_Error ("Demo_Init: you must specify a size in KB after " "-democache"); } @@ -796,7 +797,7 @@ Demo_Init (void) sv_demoPings = Cvar_Get ("sv_demoPings", "3", CVAR_NONE, 0, "FIXME"); sv_demoNoVis = Cvar_Get ("sv_demoNoVis", "1", CVAR_NONE, 0, "FIXME"); sv_demoUseCache = Cvar_Get ("sv_demoUseCache", "0", CVAR_NONE, 0, "FIXME"); - sv_demoCacheSize = Cvar_Get ("sv_demoCacheSize", va ("%d", size / 1024), + sv_demoCacheSize = Cvar_Get ("sv_demoCacheSize", va (0, "%d", size / 1024), CVAR_ROM, 0, "FIXME"); sv_demoMaxSize = Cvar_Get ("sv_demoMaxSize", "20480", CVAR_NONE, 0, "FIXME"); diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index bb0b2b1b3..5538de54b 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -39,11 +39,12 @@ #include "QF/msg.h" #include "QF/sys.h" +#include "compat.h" + #include "qw/msg_ucmd.h" -#include "compat.h" -#include "server.h" -#include "sv_progs.h" +#include "qw/include/server.h" +#include "qw/include/sv_progs.h" /* @@ -53,7 +54,7 @@ when the bob crosses a waterline. */ -byte fatpvs[MAX_MAP_LEAFS / 8]; +byte fatpvs[MAP_PVS_BYTES]; int fatbytes; @@ -98,9 +99,9 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node) static byte * SV_FatPVS (vec3_t org) { - fatbytes = (sv.worldmodel->numleafs + 31) >> 3; + fatbytes = (sv.worldmodel->brush.numleafs + 31) >> 3; memset (fatpvs, 0, fatbytes); - SV_AddToFatPVS (org, sv.worldmodel->nodes); + SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); return fatpvs; } @@ -399,7 +400,7 @@ write_demoplayer (delta_t *delta, plent_state_t *from, plent_state_t *to, int flags; int j; - flags = to->flags >> 1; // convert PF_(GIB|DEAD) to DF_(GIB|DEAD) + flags = to->es.flags >> 1; // convert PF_(GIB|DEAD) to DF_(GIB|DEAD) flags &= DF_GIB | DF_DEAD; // PF_MSEC and PF_COMMAND aren't wanted if (full) { flags |= DF_ORIGIN | (DF_ORIGIN << 1) | (DF_ORIGIN << 2) @@ -407,55 +408,55 @@ write_demoplayer (delta_t *delta, plent_state_t *from, plent_state_t *to, | DF_EFFECTS | DF_SKINNUM | DF_WEAPONFRAME | DF_MODEL; } else { for (j = 0; j < 3; j++) - if (from->origin[j] != to->origin[j]) + if (from->es.origin[j] != to->es.origin[j]) flags |= DF_ORIGIN << j; for (j = 0; j < 3; j++) if (from->cmd.angles[j] != to->cmd.angles[j]) flags |= DF_ANGLES << j; - if (from->modelindex != to->modelindex) + if (from->es.modelindex != to->es.modelindex) flags |= DF_MODEL; - if ((from->effects & 0xff) != (to->effects & 0xff)) + if ((from->es.effects & 0xff) != (to->es.effects & 0xff)) flags |= DF_EFFECTS; - if (from->skinnum != to->skinnum) + if (from->es.skinnum != to->es.skinnum) flags |= DF_SKINNUM; - if (from->weaponframe != to->weaponframe) + if (from->es.weaponframe != to->es.weaponframe) flags |= DF_WEAPONFRAME; } MSG_WriteByte (msg, svc_playerinfo); - MSG_WriteByte (msg, to->number); + MSG_WriteByte (msg, to->es.number); MSG_WriteShort (msg, flags); - MSG_WriteByte (msg, to->frame); + MSG_WriteByte (msg, to->es.frame); for (j = 0; j < 3; j++) if (flags & (DF_ORIGIN << j)) - MSG_WriteCoord (msg, to->origin[j]); + MSG_WriteCoord (msg, to->es.origin[j]); for (j = 0; j < 3; j++) if (flags & (DF_ANGLES << j)) MSG_WriteAngle16 (msg, to->cmd.angles[j]); if (flags & DF_MODEL) - MSG_WriteByte (msg, to->modelindex); + MSG_WriteByte (msg, to->es.modelindex); if (flags & DF_SKINNUM) - MSG_WriteByte (msg, to->skinnum); + MSG_WriteByte (msg, to->es.skinnum); if (flags & DF_EFFECTS) - MSG_WriteByte (msg, to->effects); + MSG_WriteByte (msg, to->es.effects); if (flags & DF_WEAPONFRAME) - MSG_WriteByte (msg, to->weaponframe); + MSG_WriteByte (msg, to->es.weaponframe); } static void write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, sizebuf_t *msg, int mask, int full) { - int flags = to->flags; + int flags = to->es.flags; int qf_bits = 0; int i; int ds = delta->delta_sequence & 0x7f; @@ -471,30 +472,30 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, ds = -1; } else { for (i = 0; i < 3; i++) - if (from->velocity[i] != to->velocity[i]) + if (from->es.velocity[i] != to->es.velocity[i]) flags |= PF_VELOCITY1 << i; - if (from->modelindex != to->modelindex) + if (from->es.modelindex != to->es.modelindex) flags |= PF_MODEL; - if (from->skinnum != to->skinnum) + if (from->es.skinnum != to->es.skinnum) flags |= PF_SKINNUM; - if ((from->effects & 0xff) != (to->effects &0xff)) + if ((from->es.effects & 0xff) != (to->es.effects &0xff)) flags |= PF_EFFECTS; - if (from->weaponframe != to->weaponframe) + if (from->es.weaponframe != to->es.weaponframe) flags |= PF_WEAPONFRAME; - if (from->alpha != to->alpha) + if (from->es.alpha != to->es.alpha) qf_bits |= PF_ALPHA; - if (from->scale != to->scale) + if (from->es.scale != to->es.scale) qf_bits |= PF_SCALE; - if ((from->effects & 0xff00) != (to->effects & 0xff00)) + if ((from->es.effects & 0xff00) != (to->es.effects & 0xff00)) qf_bits |= PF_EFFECTS2; - if (from->glow_size != to->glow_size) + if (from->es.glow_size != to->es.glow_size) qf_bits |= PF_GLOWSIZE; - if (from->glow_color != to->glow_color) + if (from->es.glow_color != to->es.glow_color) qf_bits |= PF_GLOWCOLOR; - if (from->colormod != to->colormod) + if (from->es.colormod != to->es.colormod) qf_bits |= PF_COLORMOD; - if ((from->frame & 0xff00) != (to->frame & 0xff00)) + if ((from->es.frame & 0xff00) != (to->es.frame & 0xff00)) qf_bits |= PF_FRAME2; if (qf_bits) flags |= PF_QF; @@ -505,12 +506,12 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, MSG_WriteByte (msg, svc_playerinfo); if (delta->type == dt_tp_qtv) MSG_WriteByte (msg, ds); - MSG_WriteByte (msg, to->number); + MSG_WriteByte (msg, to->es.number); MSG_WriteShort (msg, flags); - MSG_WriteCoordV (msg, to->origin); + MSG_WriteCoordV (msg, &to->es.origin[0]);//FIXME - MSG_WriteByte (msg, to->frame); + MSG_WriteByte (msg, to->es.frame); if (flags & PF_MSEC) MSG_WriteByte (msg, to->msec); @@ -518,32 +519,32 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, MSG_WriteDeltaUsercmd (msg, &from->cmd, &to->cmd); for (i = 0; i < 3; i++) if (flags & (PF_VELOCITY1 << i)) - MSG_WriteShort (msg, to->velocity[i]); + MSG_WriteShort (msg, to->es.velocity[i]); if (flags & PF_MODEL) - MSG_WriteByte (msg, to->modelindex); + MSG_WriteByte (msg, to->es.modelindex); if (flags & PF_SKINNUM) - MSG_WriteByte (msg, to->skinnum); + MSG_WriteByte (msg, to->es.skinnum); if (flags & PF_EFFECTS) - MSG_WriteByte (msg, to->effects); + MSG_WriteByte (msg, to->es.effects); if (flags & PF_WEAPONFRAME) - MSG_WriteByte (msg, to->weaponframe); + MSG_WriteByte (msg, to->es.weaponframe); if (flags & PF_QF) { MSG_WriteByte (msg, qf_bits); if (qf_bits & PF_ALPHA) - MSG_WriteByte (msg, to->alpha); + MSG_WriteByte (msg, to->es.alpha); if (qf_bits & PF_SCALE) - MSG_WriteByte (msg, to->scale); + MSG_WriteByte (msg, to->es.scale); if (qf_bits & PF_EFFECTS2) - MSG_WriteByte (msg, to->effects >> 8); + MSG_WriteByte (msg, to->es.effects >> 8); if (qf_bits & PF_GLOWSIZE) - MSG_WriteByte (msg, to->glow_size); + MSG_WriteByte (msg, to->es.glow_size); if (qf_bits & PF_GLOWCOLOR) - MSG_WriteByte (msg, to->glow_color); + MSG_WriteByte (msg, to->es.glow_color); if (qf_bits & PF_COLORMOD) - MSG_WriteByte (msg, to->colormod); + MSG_WriteByte (msg, to->es.colormod); if (qf_bits & PF_FRAME2) - MSG_WriteByte (msg, to->frame); + MSG_WriteByte (msg, to->es.frame); } } @@ -565,20 +566,19 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) void (*write) (delta_t *, plent_state_t *, plent_state_t *, sizebuf_t *, int, int); - if (!null_player_state.alpha) { - null_player_state.alpha = 255; - null_player_state.scale = 16; - null_player_state.glow_size = 0; - null_player_state.glow_color = 254; - null_player_state.colormod = 255; + if (!null_player_state.es.alpha) { + null_player_state.es.alpha = 255; + null_player_state.es.scale = 16; + null_player_state.es.glow_size = 0; + null_player_state.es.glow_color = 254; + null_player_state.es.colormod = 255; } - null_player_state.modelindex = 0; + null_player_state.es.modelindex = 0; if (delta->client) { clent = delta->client->edict; spec_track = delta->client->spec_track; - stdver = delta->client->stdver; - null_player_state.modelindex = sv_playermodel; + null_player_state.es.modelindex = sv_playermodel; full = 0; // normal qw clients don't get real deltas on players } @@ -625,9 +625,9 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) state = &pack->players[pack->num_players]; pack->num_players++; - state->number = j; - state->flags = 0; - VectorCopy (SVvector (ent, origin), state->origin); + state->es.number = j; + state->es.flags = 0; + VectorCopy (SVvector (ent, origin), state->es.origin); state->msec = min (255, 1000 * (sv.time - cl->localtime)); @@ -639,44 +639,44 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) state->cmd.angles[0] = 0; } - VectorCopy (SVvector (ent, velocity), state->velocity); - state->modelindex = SVfloat (ent, modelindex); - state->frame = SVfloat (ent, frame); - state->skinnum = SVfloat (ent, skin); - state->effects = SVfloat (ent, effects); - state->weaponframe = SVfloat (ent, weaponframe); + VectorCopy (SVvector (ent, velocity), state->es.velocity); + state->es.modelindex = SVfloat (ent, modelindex); + state->es.frame = SVfloat (ent, frame); + state->es.skinnum = SVfloat (ent, skin); + state->es.effects = SVfloat (ent, effects); + state->es.weaponframe = SVfloat (ent, weaponframe); if (SVfloat (ent, health) <= 0) - state->flags |= PF_DEAD; + state->es.flags |= PF_DEAD; if (SVvector (ent, mins)[2] != -24) - state->flags |= PF_GIB; - state->flags |= PF_MSEC | PF_COMMAND; + state->es.flags |= PF_GIB; + state->es.flags |= PF_MSEC | PF_COMMAND; - state->alpha = 255; - state->scale = 16; - state->glow_size = 0; - state->glow_color = 254; - state->colormod = 255; + state->es.alpha = 255; + state->es.scale = 16; + state->es.glow_size = 0; + state->es.glow_color = 254; + state->es.colormod = 255; if (sv_fields.alpha != -1 && SVfloat (ent, alpha)) { float alpha = SVfloat (ent, alpha); - state->alpha = bound (0, alpha, 1) * 255.0; + state->es.alpha = bound (0, alpha, 1) * 255.0; } if (sv_fields.scale != -1 && SVfloat (ent, scale)) { float scale = SVfloat (ent, scale); - state->scale = bound (0, scale, 15.9375) * 16; + state->es.scale = bound (0, scale, 15.9375) * 16; } if (sv_fields.glow_size != -1 && SVfloat (ent, glow_size)) { int glow_size = SVfloat (ent, glow_size); - state->glow_size = bound (-1024, glow_size, 1016) >> 3; + state->es.glow_size = bound (-1024, glow_size, 1016) >> 3; } if (sv_fields.glow_color != -1 && SVfloat (ent, glow_color)) - state->glow_color = SVfloat (ent, glow_color); + state->es.glow_color = SVfloat (ent, glow_color); if (sv_fields.colormod != -1 && !VectorIsZero (SVvector (ent, colormod))) { float *colormod= SVvector (ent, colormod); - state->colormod = ((int) (bound (0, colormod[0], 1) * 7) << 5) | - ((int) (bound (0, colormod[1], 1) * 7) << 2) | - (int) (bound (0, colormod[2], 1) * 3); + state->es.colormod = ((int) (bound (0, colormod[0], 1) * 7) << 5) | + ((int) (bound (0, colormod[1], 1) * 7) << 2) | + (int) (bound (0, colormod[2], 1) * 3); } if (cl->spectator) { @@ -693,10 +693,10 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) if (from_pack && from_pack->players) { while (k < from_pack->num_players - && from_pack->players[k].number < state->number) + && from_pack->players[k].es.number < state->es.number) k++; if (k < from_pack->num_players - && from_pack->players[k].number == state->number) { + && from_pack->players[k].es.number == state->es.number) { write (delta, &from_pack->players[k], state, msg, mask, full); continue; } @@ -738,7 +738,7 @@ calc_pvs (delta_t *delta) if (pvs == NULL) { pvs = SV_FatPVS (org); } else { - SV_AddToFatPVS (org, sv.worldmodel->nodes); + SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); } } } diff --git a/qw/source/sv_gib.c b/qw/source/sv_gib.c index 7600805d2..3e4d5421c 100644 --- a/qw/source/sv_gib.c +++ b/qw/source/sv_gib.c @@ -39,8 +39,8 @@ #include "QF/info.h" #include "QF/gib.h" -#include "server.h" -#include "client.h" +#include "qw/include/server.h" +#include "qw/include/client.h" gib_event_t *sv_chat_e; gib_event_t *sv_client_connect_e; diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index b9dbb0aec..6fbd6cbc7 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -44,12 +44,13 @@ #include "QF/va.h" #include "compat.h" -#include "crudefile.h" -#include "map_cfg.h" + +#include "qw/include/crudefile.h" +#include "qw/include/map_cfg.h" #include "qw/pmove.h" -#include "server.h" -#include "sv_progs.h" -#include "sv_gib.h" +#include "qw/include/server.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_gib.h" #include "world.h" info_t *localinfo; // local game info @@ -166,8 +167,8 @@ SV_CreateBaseline (void) MSG_WriteByte (&sv.signon, SVdata (svent)->state.colormap); MSG_WriteByte (&sv.signon, SVdata (svent)->state.skinnum); - MSG_WriteCoordAngleV (&sv.signon, SVdata (svent)->state.origin, - SVdata (svent)->state.angles); + MSG_WriteCoordAngleV (&sv.signon, &SVdata (svent)->state.origin[0], + SVdata (svent)->state.angles);//FIXME } } @@ -228,7 +229,7 @@ SV_CalcPHS (void) SV_Printf ("Building PHS...\n"); - num = sv.worldmodel->numleafs; + num = sv.worldmodel->brush.numleafs; rowwords = (num + 31) >> 5; rowbytes = rowwords * 4; @@ -236,7 +237,8 @@ SV_CalcPHS (void) scan = sv.pvs; vcount = 0; for (i = 0; i < num; i++, scan += rowbytes) { - memcpy (scan, Mod_LeafPVS (sv.worldmodel->leafs + i, sv.worldmodel), + memcpy (scan, Mod_LeafPVS (sv.worldmodel->brush.leafs + i, + sv.worldmodel), rowbytes); if (i == 0) continue; @@ -341,6 +343,9 @@ SV_SpawnServer (const char *server) so_buffers = sv.signon_buffers; so_sizes = sv.signon_buffer_size; + if (sv.name) { + free (sv.name); + } memset (&sv, 0, sizeof (sv)); sv.recorders = recorders; @@ -363,14 +368,14 @@ SV_SpawnServer (const char *server) SV_NextSignon (); - strcpy (sv.name, server); + sv.name = strdup(server); // load progs to get entity field count which determines how big each // edict is SV_LoadProgs (); SV_FreeAllEdictLeafs (); SV_SetupUserCommands (); - Info_SetValueForStarKey (svs.info, "*progs", va ("%i", sv_pr_state.crc), + Info_SetValueForStarKey (svs.info, "*progs", va (0, "%i", sv_pr_state.crc), !sv_highchars->int_val); // leave slots at start for only clients @@ -384,7 +389,6 @@ SV_SpawnServer (const char *server) sv.time = 1.0; - strncpy (sv.name, server, sizeof (sv.name)); snprintf (sv.modelname, sizeof (sv.modelname), "maps/%s.bsp", server); map_cfg (sv.modelname, 0); sv.worldmodel = Mod_ForName (sv.modelname, true); @@ -399,7 +403,7 @@ SV_SpawnServer (const char *server) sv.model_precache[0] = sv_pr_state.pr_strings; sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; - for (i = 1; i < sv.worldmodel->numsubmodels; i++) { + for (i = 1; i < sv.worldmodel->brush.numsubmodels; i++) { sv.model_precache[1 + i] = localmodels[i]; sv.models[i + 1] = Mod_ForName (localmodels[i], false); } @@ -417,7 +421,7 @@ SV_SpawnServer (const char *server) ent = EDICT_NUM (&sv_pr_state, 0); ent->free = false; - SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->name); + SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->path); SVfloat (ent, modelindex) = 1; // world model SVfloat (ent, solid) = SOLID_BSP; SVfloat (ent, movetype) = MOVETYPE_PUSH; @@ -434,13 +438,13 @@ SV_SpawnServer (const char *server) // load and spawn all other entities *sv_globals.time = sv.time; - ent_file = QFS_VOpenFile (va ("maps/%s.ent", server), 0, + ent_file = QFS_VOpenFile (va (0, "maps/%s.ent", server), 0, sv.worldmodel->vpath); if ((buf = QFS_LoadFile (ent_file, 0))) { ED_LoadFromFile (&sv_pr_state, (char *) buf); free (buf); } else { - ED_LoadFromFile (&sv_pr_state, sv.worldmodel->entities); + ED_LoadFromFile (&sv_pr_state, sv.worldmodel->brush.entities); } // look up some model indexes for specialized message compression diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 42a313aa6..d91a24832 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -77,19 +77,20 @@ #include "QF/plugin/console.h" -#include "qw/bothdefs.h" #include "buildnum.h" #include "compat.h" -#include "crudefile.h" -#include "game.h" #include "netchan.h" + +#include "qw/bothdefs.h" +#include "qw/include/crudefile.h" +#include "qw/include/game.h" #include "qw/pmove.h" -#include "server.h" -#include "sv_demo.h" -#include "sv_progs.h" -#include "sv_gib.h" -#include "sv_qtv.h" -#include "sv_recorder.h" +#include "qw/include/server.h" +#include "qw/include/sv_demo.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_gib.h" +#include "qw/include/sv_qtv.h" +#include "qw/include/sv_recorder.h" SERVER_PLUGIN_PROTOS static plugin_list_t server_plugin_list[] = { @@ -237,7 +238,7 @@ Master_Shutdown (void) Quake calls this before calling Sys_Quit or Sys_Error */ void -SV_Shutdown (void) +SV_Shutdown (void *data) { Master_Shutdown (); if (sv_fraglogfile) { @@ -246,9 +247,6 @@ SV_Shutdown (void) } if (sv.recording_demo) SV_Stop (0); - - NET_Shutdown (); - Con_Shutdown (); } /* @@ -257,7 +255,7 @@ SV_Shutdown (void) Sends a datagram to all the clients informing them of the server crash, then exits */ -static void +static __attribute__((format(printf, 1, 0))) void SV_Error (const char *error, va_list argptr) { static qboolean inerror = false; @@ -370,7 +368,7 @@ SV_DropClient (client_t *drop) // Trigger GIB event if (sv_client_disconnect_e->func) GIB_Event_Callback (sv_client_disconnect_e, 1, - va ("%u", drop->userid)); + va (0, "%u", drop->userid)); } int @@ -1206,7 +1204,7 @@ SV_MaskIPTrim (byte *ip, int mask) } // assumes b has already been masked -static inline qboolean +static inline __attribute__((pure)) qboolean SV_MaskIPCompare (byte *a, byte *b, int mask) { int i; @@ -1430,7 +1428,7 @@ SV_AddIP_f (void) // FIXME: this should boot any matching clients for (i = 0; i < MAX_CLIENTS; i++) { client_t *cl = &svs.clients[i]; - char text[1024]; + const char *text; const char *typestr; char timestr[1024]; @@ -1461,9 +1459,9 @@ SV_AddIP_f (void) bantime / 60); else strncpy (timestr, "permanently", sizeof (timestr)); - snprintf (text, sizeof (text), "You are %s %s\n%s", - typestr, timestr, type == ft_ban ? "" : - "\nReconnecting won't help..."); + text = va (0, "You are %s %s\n%s", + typestr, timestr, type == ft_ban ? "" : + "\nReconnecting won't help..."); MSG_ReliableWrite_Begin (&cl->backbuf, svc_centerprint, strlen (text) + 2); MSG_ReliableWrite_String (&cl->backbuf, text); @@ -1886,7 +1884,7 @@ SV_CheckVars (void) Info_SetValueForKey (svs.info, "needpass", "", !sv_highchars->int_val); else - Info_SetValueForKey (svs.info, "needpass", va ("%i", v), + Info_SetValueForKey (svs.info, "needpass", va (0, "%i", v), !sv_highchars->int_val); } @@ -2472,7 +2470,7 @@ SV_Init_Memory (void) Sys_Error ("Only %4.1f megs of memory reported, can't execute game", mem_size / (float) 0x100000); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); @@ -2486,7 +2484,7 @@ SV_Init (void) sv_cbuf = Cbuf_New (&id_interp); sv_args = Cbuf_ArgsNew (); - Sys_RegisterShutdown (SV_Shutdown); + Sys_RegisterShutdown (SV_Shutdown, 0); Sys_Init (); GIB_Init (true); @@ -2523,8 +2521,6 @@ SV_Init (void) Mod_Init_Cvars (); Netchan_Init_Cvars (); Pmove_Init_Cvars (); - SV_Progs_Init_Cvars (); - PR_Init_Cvars (); // and now reprocess the cmdline's sets for overrides Cmd_StuffCmds (sv_cbuf); @@ -2534,7 +2530,6 @@ SV_Init (void) Game_Init (); - PR_Init (); SV_Progs_Init (); Mod_Init (); diff --git a/qw/source/sv_move.c b/qw/source/sv_move.c index 013e4d48e..75b4f8e01 100644 --- a/qw/source/sv_move.c +++ b/qw/source/sv_move.c @@ -28,8 +28,8 @@ # include "config.h" #endif -#include "server.h" -#include "sv_progs.h" +#include "qw/include/server.h" +#include "qw/include/sv_progs.h" #include "world.h" #define STEPSIZE 18 diff --git a/qw/source/sv_phys.c b/qw/source/sv_phys.c index e2d08e814..9c627f9e9 100644 --- a/qw/source/sv_phys.c +++ b/qw/source/sv_phys.c @@ -31,8 +31,8 @@ #include "QF/cvar.h" #include "QF/sys.h" -#include "server.h" -#include "sv_progs.h" +#include "qw/include/server.h" +#include "qw/include/sv_progs.h" #include "world.h" /* diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index 4f832e5a2..b30664a76 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -46,11 +46,12 @@ #include "QF/va.h" #include "compat.h" -#include "crudefile.h" -#include "server.h" -#include "sv_gib.h" -#include "sv_progs.h" -#include "sv_recorder.h" + +#include "qw/include/crudefile.h" +#include "qw/include/server.h" +#include "qw/include/sv_gib.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_recorder.h" #include "world.h" /* BUILT-IN FUNCTIONS */ @@ -459,7 +460,7 @@ PF_checkpos (progs_t *pr) { } -byte checkpvs[MAX_MAP_LEAFS / 8]; +byte checkpvs[MAP_PVS_BYTES]; static int PF_newcheckclient (progs_t *pr, int check) @@ -505,7 +506,7 @@ PF_newcheckclient (progs_t *pr, int check) VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org); leaf = Mod_PointInLeaf (org, sv.worldmodel); pvs = Mod_LeafPVS (leaf, sv.worldmodel); - memcpy (checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3); + memcpy (checkpvs, pvs, (sv.worldmodel->brush.numleafs + 7) >> 3); return i; } @@ -550,7 +551,7 @@ PF_checkclient (progs_t *pr) self = PROG_TO_EDICT (pr, *sv_globals.self); VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view); leaf = Mod_PointInLeaf (view, sv.worldmodel); - l = (leaf - sv.worldmodel->leafs) - 1; + l = (leaf - sv.worldmodel->brush.leafs) - 1; if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) { c_notvis++; RETURN_EDICT (pr, sv.edicts); @@ -1061,7 +1062,7 @@ PF_changeyaw (progs_t *pr) #define MSG_INIT 3 // write to the init string #define MSG_MULTICAST 4 // for multicast () -static sizebuf_t * +static __attribute__((pure)) sizebuf_t * WriteDest (progs_t *pr) { int dest; @@ -1094,7 +1095,7 @@ WriteDest (progs_t *pr) return NULL; } -static client_t * +static __attribute__((pure)) client_t * Write_GetClient (progs_t *pr) { edict_t *ent; @@ -1410,7 +1411,7 @@ PF_changelevel (progs_t *pr) last_spawncount = svs.spawncount; s = P_GSTRING (pr, 0); - Cbuf_AddText (sv_cbuf, va ("map %s\n", s)); + Cbuf_AddText (sv_cbuf, va (0, "map %s\n", s)); } /* @@ -1459,13 +1460,13 @@ PF_logfrag (progs_t *pr) snprintf(buf, sizeof(buf), "%d", u2); - GIB_Event_Callback (sv_frag_e, 4, type1, va ("%d", u1), type2, buf); + GIB_Event_Callback (sv_frag_e, 4, type1, va (0, "%d", u1), type2, buf); } if (e1 < 1 || e1 > MAX_CLIENTS || e2 < 1 || e2 > MAX_CLIENTS) return; - s = va ("\\%s\\%s\\\n", svs.clients[e1 - 1].name, + s = va (0, "\\%s\\%s\\\n", svs.clients[e1 - 1].name, svs.clients[e2 - 1].name); SZ_Print (&svs.log[svs.logsequence & 1], s); @@ -1510,7 +1511,7 @@ PF_infokey (progs_t *pr) else if (!strcmp (key, "ping")) { int ping = SV_CalcPing (&svs.clients[e1 - 1]); - value = va ("%d", ping); + value = va (0, "%d", ping); } else value = Info_ValueForKey (svs.clients[e1 - 1].userinfo, key); } else @@ -1861,7 +1862,7 @@ PF_SV_FreeClient (progs_t *pr) cl->state = cs_free; //if (sv_client_disconnect_e->func) - // GIB_Event_Callback (sv_client_disconnect_e, 2, va ("%u", cl->userid), + // GIB_Event_Callback (sv_client_disconnect_e, 2, va (0, "%u", cl->userid), // "server"); } diff --git a/qw/source/sv_pr_cpqw.c b/qw/source/sv_pr_cpqw.c index 594f66219..e2ac3ffd2 100644 --- a/qw/source/sv_pr_cpqw.c +++ b/qw/source/sv_pr_cpqw.c @@ -39,9 +39,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "QF/quakefs.h" #include "QF/sys.h" -#include "server.h" -#include "sv_pr_cpqw.h" -#include "sv_progs.h" +#include "qw/include/server.h" +#include "qw/include/sv_pr_cpqw.h" +#include "qw/include/sv_progs.h" #include "world.h" static struct { @@ -818,10 +818,11 @@ cpqw_user_cmd (void) PR_PushFrame (pr); P_FLOAT (pr, 0) = argc; - for (i = 1; i < argc; i++) + for (i = 1; i < argc + 1; i++) P_STRING (pr, i) = PR_SetTempString (pr, Cmd_Argv (i - 1)); - for (; i < 7; i++) + for (; i < 8; i++) P_STRING (pr, i) = 0; + pr->pr_argc = 8; PR_ExecuteProgram (pr, cpqw_funcs.ClientCommand); PR_PopFrame (pr); return (int) R_FLOAT (pr); diff --git a/qw/source/sv_pr_qwe.c b/qw/source/sv_pr_qwe.c index 0c844abd8..ea4d533f4 100644 --- a/qw/source/sv_pr_qwe.c +++ b/qw/source/sv_pr_qwe.c @@ -50,10 +50,10 @@ #include "QF/sys.h" #include "QF/va.h" -#include "server.h" -#include "sv_pr_qwe.h" -#include "sv_progs.h" -#include "sv_recorder.h" +#include "qw/include/server.h" +#include "qw/include/sv_pr_qwe.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_recorder.h" typedef struct { func_t timeofday; @@ -353,6 +353,7 @@ PF_calltimeofday (progs_t *pr) P_FLOAT (pr, 5) = (float) date.year; P_STRING (pr, 6) = PR_SetReturnString (pr, date.str); + pr->pr_argc = 7; PR_ExecuteProgram (pr, (func_t) (f - sv_pr_state.pr_functions)); PR_PopFrame (&sv_pr_state); } @@ -450,7 +451,7 @@ PF_log (progs_t *pr) char *text; QFile *file; - name = va ("%s/%s.log", qfs_gamedir->dir.def, P_GSTRING (pr, 0)); + name = va (0, "%s/%s.log", qfs_gamedir->dir.def, P_GSTRING (pr, 0)); file = QFS_Open (name, "a"); text = PF_VarString (pr, 2); @@ -551,7 +552,7 @@ static int qwe_load_finish (progs_t *pr) { edict_t *ent; - ddef_t *targetname; + pr_def_t *targetname; targetname = PR_FindField (pr, "targetname"); ent = EDICT_NUM (pr, 0); diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index e11805c17..0081466ad 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -42,10 +42,11 @@ #include "QF/sys.h" #include "compat.h" -#include "server.h" -#include "sv_progs.h" -#include "sv_pr_cpqw.h" -#include "sv_pr_qwe.h" + +#include "qw/include/server.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_pr_cpqw.h" +#include "qw/include/sv_pr_qwe.h" #include "world.h" progs_t sv_pr_state; @@ -53,6 +54,7 @@ sv_globals_t sv_globals; sv_funcs_t sv_funcs; sv_fields_t sv_fields; +edict_t sv_edicts[MAX_EDICTS]; sv_data_t sv_data[MAX_EDICTS]; cvar_t *r_skyname; @@ -92,16 +94,16 @@ static void free_edict (progs_t *pr, edict_t *ent) { if (sv_old_entity_free->int_val) { - ent->v[sv_fields.model].entity_var = 0; - ent->v[sv_fields.takedamage].float_var = 0; - ent->v[sv_fields.modelindex].float_var = 0; - ent->v[sv_fields.colormap].float_var = 0; - ent->v[sv_fields.skin].float_var = 0; - ent->v[sv_fields.frame].float_var = 0; - ent->v[sv_fields.nextthink].float_var = -1; - ent->v[sv_fields.solid].float_var = 0; - memset (ent->v[sv_fields.origin].vector_var, 0, 3*sizeof (float)); - memset (ent->v[sv_fields.angles].vector_var, 0, 3*sizeof (float)); + E_fld (ent, sv_fields.model).entity_var = 0; + E_fld (ent, sv_fields.takedamage).float_var = 0; + E_fld (ent, sv_fields.modelindex).float_var = 0; + E_fld (ent, sv_fields.colormap).float_var = 0; + E_fld (ent, sv_fields.skin).float_var = 0; + E_fld (ent, sv_fields.frame).float_var = 0; + E_fld (ent, sv_fields.nextthink).float_var = -1; + E_fld (ent, sv_fields.solid).float_var = 0; + memset (&E_fld (ent, sv_fields.origin).vector_var, 0, 3*sizeof (float)); + memset (&E_fld (ent, sv_fields.angles).vector_var, 0, 3*sizeof (float)); } else { ED_ClearEdict (pr, ent, 0); } @@ -371,6 +373,9 @@ set_address (sv_def_t *def, void *address) case ev_quat: *(float **)def->field = (float *) address; break; + case ev_double: + *(double **)def->field = (double *) address; + break; case ev_string: case ev_entity: case ev_field: @@ -386,7 +391,7 @@ set_address (sv_def_t *def, void *address) static int resolve_globals (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -432,7 +437,7 @@ resolve_functions (progs_t *pr, sv_def_t *def, int mode) static int resolve_fields (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -481,12 +486,32 @@ resolve (progs_t *pr) return ret; } +static int +sv_init_edicts (progs_t *pr) +{ + int i; + + memset (sv_edicts, 0, sizeof (sv_edicts)); + memset (sv_data, 0, sizeof (sv_data)); + + // init the data field of the edicts + for (i = 0; i < MAX_EDICTS; i++) { + edict_t *ent = EDICT_NUM (&sv_pr_state, i); + ent->pr = &sv_pr_state; + ent->entnum = i; + ent->edict = EDICT_TO_PROG (&sv_pr_state, ent); + ent->edata = &sv_data[i]; + SVdata (ent)->edict = ent; + } + + return 1; +} + void SV_LoadProgs (void) { const char *progs_name = "qwprogs.dat"; const char *range; - int i; if (strequal (sv_progs_ext->string, "qf")) { sv_range = PR_RANGE_QF; @@ -521,27 +546,22 @@ SV_LoadProgs (void) if (*sv_progs->string) progs_name = sv_progs->string; - PR_LoadProgs (&sv_pr_state, progs_name, MAX_EDICTS, - sv_progs_zone->int_val * 1024); + sv_pr_state.max_edicts = MAX_EDICTS; + sv_pr_state.zone_size = sv_progs_zone->int_val * 1024; + sv.edicts = sv_edicts; + + PR_LoadProgs (&sv_pr_state, progs_name); if (!sv_pr_state.progs) Sys_Error ("SV_LoadProgs: couldn't load %s", progs_name); - - memset (sv_data, 0, sizeof (sv_data)); - - // init the data field of the edicts - for (i = 0; i < MAX_EDICTS; i++) { - edict_t *ent = EDICT_NUM (&sv_pr_state, i); - ent->entnum = i; - ent->edata = &sv_data[i]; - SVdata (ent)->edict = ent; - } } void SV_Progs_Init (void) { + SV_Progs_Init_Cvars (); + pr_gametype = "quakeworld"; - sv_pr_state.edicts = &sv.edicts; + sv_pr_state.pr_edicts = &sv.edicts; sv_pr_state.num_edicts = &sv.num_edicts; sv_pr_state.reserved_edicts = &reserved_edicts; sv_pr_state.unlink = SV_UnlinkEdict; @@ -552,6 +572,9 @@ SV_Progs_Init (void) sv_pr_state.bi_map = bi_map; sv_pr_state.resolve = resolve; + PR_AddLoadFunc (&sv_pr_state, sv_init_edicts); + PR_Init (&sv_pr_state); + SV_PR_Cmds_Init (); SV_PR_QWE_Init (&sv_pr_state); SV_PR_CPQW_Init (&sv_pr_state); @@ -571,6 +594,8 @@ SV_Progs_Init (void) void SV_Progs_Init_Cvars (void) { + PR_Init_Cvars (); + r_skyname = Cvar_Get ("r_skyname", "", CVAR_NONE, NULL, "Default name of skybox if none given by map"); sv_progs = Cvar_Get ("sv_progs", "", CVAR_NONE, NULL, diff --git a/qw/source/sv_qtv.c b/qw/source/sv_qtv.c index a36b1c3cc..366c2d687 100644 --- a/qw/source/sv_qtv.c +++ b/qw/source/sv_qtv.c @@ -48,9 +48,10 @@ #include "QF/va.h" #include "compat.h" -#include "server.h" -#include "sv_qtv.h" -#include "sv_recorder.h" + +#include "qw/include/server.h" +#include "qw/include/sv_qtv.h" +#include "qw/include/sv_recorder.h" typedef struct { netchan_t netchan; @@ -193,9 +194,9 @@ qtv_prespawn_f (sv_qtv_t *proxy) buf = 0; if (buf == sv.num_signon_buffers - 1) - command = va ("cmd spawn %i 0\n", svs.spawncount); + command = va (0, "cmd spawn %i 0\n", svs.spawncount); else - command = va ("cmd prespawn %i %i\n", svs.spawncount, buf + 1); + command = va (0, "cmd prespawn %i %i\n", svs.spawncount, buf + 1); size = (3 + sv.signon_buffer_size[buf]) + (1 + strlen (command) + 1); msg = MSG_ReliableCheckBlock (&proxy->backbuf, size); @@ -533,7 +534,7 @@ SV_qtvChanging (void) int i, len; const char *msg; - msg = va ("%cchanging", qtv_stringcmd); + msg = va (0, "%cchanging", qtv_stringcmd); len = strlen (msg) + 1; for (i = 0; i < MAX_PROXIES; i++) { proxy = proxies + i; @@ -554,7 +555,7 @@ SV_qtvReconnect (void) int i, len; const char *msg; - msg = va ("%creconnect", qtv_stringcmd); + msg = va (0, "%creconnect", qtv_stringcmd); len = strlen (msg) + 1; for (i = 0; i < MAX_PROXIES; i++) { proxy = proxies + i; diff --git a/qw/source/sv_recorder.c b/qw/source/sv_recorder.c index 562fd94d3..d2555862e 100644 --- a/qw/source/sv_recorder.c +++ b/qw/source/sv_recorder.c @@ -49,10 +49,10 @@ #include "QF/sys.h" #include "qw/bothdefs.h" -#include "server.h" -#include "sv_demo.h" -#include "sv_progs.h" -#include "sv_recorder.h" +#include "qw/include/server.h" +#include "qw/include/sv_demo.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_recorder.h" typedef struct dbuffer_s { byte *data; diff --git a/qw/source/sv_sbar.c b/qw/source/sv_sbar.c index a76729789..12aa9115a 100644 --- a/qw/source/sv_sbar.c +++ b/qw/source/sv_sbar.c @@ -37,9 +37,10 @@ #include "QF/plugin/console.h" -#include "server.h" #include "sv_console.h" -#include "sv_recorder.h" + +#include "qw/include/server.h" +#include "qw/include/sv_recorder.h" static void draw_cpu (view_t *view) @@ -54,7 +55,7 @@ draw_cpu (view_t *view) cpu = (svs.stats.latched_active + svs.stats.latched_idle); cpu = 100 * svs.stats.latched_active / cpu; - cpu_str = va ("[CPU: %3d%%]", (int) cpu); + cpu_str = va (0, "[CPU: %3d%%]", (int) cpu); for (s = cpu_str, d = sb->text + view->xrel; *s; s++) *d++ = *s; if (cpu > 70.0) { @@ -73,7 +74,7 @@ draw_rec (view_t *view) const char *s; char *d; - str = va ("[REC: %d]", SVR_NumRecorders ()); + str = va (0, "[REC: %d]", SVR_NumRecorders ()); for (s = str, d = sb->text + view->xrel; *s; s++) *d++ = *s; } diff --git a/qw/source/sv_send.c b/qw/source/sv_send.c index 58fb00bef..0948e6f18 100644 --- a/qw/source/sv_send.c +++ b/qw/source/sv_send.c @@ -46,11 +46,12 @@ #include "QF/sound.h" // FIXME: DEFAULT_SOUND_PACKET_* #include "QF/sys.h" -#include "qw/bothdefs.h" #include "compat.h" -#include "server.h" -#include "sv_progs.h" -#include "sv_recorder.h" + +#include "qw/bothdefs.h" +#include "qw/include/server.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_recorder.h" #define CHAN_AUTO 0 #define CHAN_WEAPON 1 @@ -148,6 +149,20 @@ SV_EndRedirect (void) } #define MAXPRINTMSG 4096 +static int +find_userid (const char *name) +{ + int i; + + for (i = 0; i < MAX_CLIENTS; i++) { + if (!svs.clients[i].state) + continue; + if (!strcmp (svs.clients[i].name, name)) { + return svs.clients[i].userid; + } + } + return 0; +} /* SV_Printf @@ -158,10 +173,11 @@ SV_EndRedirect (void) void SV_Print (const char *fmt, va_list args) { + static dstring_t *premsg; + static dstring_t *msg; + static dstring_t *msg2; static int pending = 0; // partial line being printed - char premsg[MAXPRINTMSG]; - unsigned char msg[MAXPRINTMSG]; - char msg2[MAXPRINTMSG]; + char msg3[MAXPRINTMSG]; time_t mytime = 0; @@ -169,50 +185,42 @@ SV_Print (const char *fmt, va_list args) qboolean timestamps = false; char *in; - unsigned char *out; - vsnprintf (premsg, sizeof (premsg), fmt, args); - in = premsg; - out = msg; + if (!premsg) { + premsg = dstring_newstr (); + msg = dstring_new (); + msg2 = dstring_new (); + } + dstring_clearstr (msg); - if (!*premsg) + dvsprintf (premsg, fmt, args); + in = premsg->str; + + if (!*premsg->str) return; // expand FFnickFF to nick do { - switch ((byte) *in) { - case 0xFF: { - char *end = strchr (in + 1, 0xFF); - int userid = 0; - int len; - int i; - - if (!end) - end = in + strlen (in); - *end = '\0'; - for (i = 0; i < MAX_CLIENTS; i++) { - if (!svs.clients[i].state) - continue; - if (!strcmp (svs.clients[i].name, in + 1)) { - userid = svs.clients[i].userid; - break; - } - } - len = snprintf ((char *) out, sizeof (msg) - (out - msg), - "%s <%d>", in + 1, userid); - out += len; - in = end + 1; - break; + char *beg = strchr (in, 0xFF); + if (beg) { + char *name = beg + 1; + char *end = strchr (name, 0xFF); + if (!end) { + end = beg + strlen (name); } - default: - *out++ = *in++; + *end = 0; + dstring_appendsubstr (msg, in, beg - in); + dasprintf (msg, "%s <%d>", name, find_userid (name)); + in = end + 1; + } else { + dstring_appendstr (msg, in); + break; } - } while (sizeof (msg) - (out - msg) > 0 && *in); - *out = '\0'; + } while (*in); if (sv_redirected) { // Add to redirected message - dstring_appendstr (&outputbuf, (char *) msg); + dstring_appendstr (&outputbuf, msg->str); } - if (*msg && !con_printf_no_log) { + if (*msg->str && !con_printf_no_log) { // We want to output to console and maybe logfile if (sv_timestamps && sv_timefmt && sv_timefmt->string && sv_timestamps->int_val && !pending) @@ -223,17 +231,17 @@ SV_Print (const char *fmt, va_list args) local = localtime (&mytime); strftime (msg3, sizeof (msg3), sv_timefmt->string, local); - snprintf (msg2, sizeof (msg2), "%s%s", msg3, msg); + dsprintf (msg2, "%s%s", msg3, msg->str); } else { - snprintf (msg2, sizeof (msg2), "%s", msg); + dsprintf (msg2, "%s", msg->str); } - if (msg2[strlen (msg2) - 1] != '\n') { + if (msg2->str[strlen (msg2->str) - 1] != '\n') { pending = 1; } else { pending = 0; } - Con_Printf ("%s", msg2); // also echo to debugging console + Con_Printf ("%s", msg2->str); // also echo to debugging console } } @@ -289,12 +297,13 @@ SV_Multicast (const vec3_t origin, int to) int leafnum, j; mleaf_t *leaf; qboolean reliable; + mod_brush_t *brush = &sv.worldmodel->brush; leaf = Mod_PointInLeaf (origin, sv.worldmodel); if (!leaf) leafnum = 0; else - leafnum = leaf - sv.worldmodel->leafs; + leafnum = leaf - sv.worldmodel->brush.leafs; reliable = false; @@ -308,13 +317,13 @@ SV_Multicast (const vec3_t origin, int to) case MULTICAST_PHS_R: reliable = true; // intentional fallthrough case MULTICAST_PHS: - mask = sv.phs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5); + mask = sv.phs + leafnum * 4 * ((brush->numleafs + 31) >> 5); break; case MULTICAST_PVS_R: reliable = true; // intentional fallthrough case MULTICAST_PVS: - mask = sv.pvs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5); + mask = sv.pvs + leafnum * 4 * ((brush->numleafs + 31) >> 5); break; default: @@ -339,7 +348,7 @@ SV_Multicast (const vec3_t origin, int to) sv.worldmodel); if (leaf) { // -1 is because pvs rows are 1 based, not 0 based like leafs - leafnum = leaf - sv.worldmodel->leafs - 1; + leafnum = leaf - brush->leafs - 1; if (!(mask[leafnum >> 3] & (1 << (leafnum & 7)))) { // SV_Printf ("supressed multicast\n"); continue; diff --git a/qw/source/sv_sys_unix.c b/qw/source/sv_sys_unix.c index 315fb02ff..cb7aabbdd 100644 --- a/qw/source/sv_sys_unix.c +++ b/qw/source/sv_sys_unix.c @@ -43,7 +43,7 @@ #include "QF/qargs.h" #include "QF/sys.h" -#include "server.h" +#include "qw/include/server.h" #ifdef NeXT # include @@ -122,7 +122,7 @@ main (int argc, const char **argv) SV_Init (); - Sys_RegisterShutdown (Net_LogStop); + Sys_RegisterShutdown (Net_LogStop, 0); // run one frame immediately for first heartbeat SV_Frame (0.1); @@ -138,8 +138,7 @@ main (int argc, const char **argv) SV_Frame (time); - // extrasleep is just a way to generate a fucked up connection on - // purpose + // extrasleep is just a way to generate a bad connection on purpose if (sys_extrasleep->int_val) usleep (sys_extrasleep->int_val); } diff --git a/qw/source/sv_sys_win.c b/qw/source/sv_sys_win.c index 4397f5d92..20fbdfb4e 100644 --- a/qw/source/sv_sys_win.c +++ b/qw/source/sv_sys_win.c @@ -36,7 +36,7 @@ #include "QF/qargs.h" #include "QF/sys.h" -#include "server.h" +#include "qw/include/server.h" qboolean WinNT; server_static_t svs; @@ -93,7 +93,7 @@ main (int argc, const char **argv) if (WinNT) Cvar_Set (sys_sleep, "0"); - Sys_RegisterShutdown (Net_LogStop); + Sys_RegisterShutdown (Net_LogStop, 0); // run one frame immediately for first heartbeat SV_Frame (0.1); diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 5398eff6c..5b3c9f14f 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -53,16 +53,17 @@ #include "QF/sys.h" #include "QF/va.h" +#include "compat.h" + #include "qw/msg_ucmd.h" #include "qw/msg_ucmd.h" #include "qw/bothdefs.h" -#include "compat.h" #include "qw/pmove.h" -#include "server.h" -#include "sv_gib.h" -#include "sv_progs.h" -#include "sv_recorder.h" +#include "qw/include/server.h" +#include "qw/include/sv_gib.h" +#include "qw/include/sv_progs.h" +#include "qw/include/sv_recorder.h" #include "world.h" typedef struct ucmd_s { @@ -140,7 +141,7 @@ SV_WriteWorldVars (netchan_t *netchan) // send server info string MSG_WriteByte (&netchan->message, svc_stufftext); MSG_WriteString (&netchan->message, - va ("fullserverinfo \"%s\"\n", + va (0, "fullserverinfo \"%s\"\n", Info_MakeString (svs.info, 0))); } @@ -193,7 +194,7 @@ SV_New_f (void *unused) // Trigger GIB connection event if (sv_client_connect_e->func) GIB_Event_Callback (sv_client_connect_e, 1, - va ("%u", host_client->userid)); + va (0, "%u", host_client->userid)); } void @@ -334,14 +335,15 @@ SV_PreSpawn_f (void *unused) // Sys_MaskPrintf (SYS_DEV, , "Client check = %d\n", check); - if (sv_mapcheck->int_val && check != sv.worldmodel->checksum && - check != sv.worldmodel->checksum2) { + if (sv_mapcheck->int_val && check != sv.worldmodel->brush.checksum && + check != sv.worldmodel->brush.checksum2) { SV_ClientPrintf (1, host_client, PRINT_HIGH, "Map model file does " "not match (%s), %i != %i/%i.\n" "You may need a new version of the map, or the " "proper install files.\n", - sv.modelname, check, sv.worldmodel->checksum, - sv.worldmodel->checksum2); + sv.modelname, check, + sv.worldmodel->brush.checksum, + sv.worldmodel->brush.checksum2); SV_DropClient (host_client); return; } @@ -350,9 +352,9 @@ SV_PreSpawn_f (void *unused) host_client->prespawned = true; if (buf == sv.num_signon_buffers - 1) - command = va ("cmd spawn %i 0\n", svs.spawncount); + command = va (0, "cmd spawn %i 0\n", svs.spawncount); else - command = va ("cmd prespawn %i %i\n", svs.spawncount, buf + 1); + command = va (0, "cmd prespawn %i %i\n", svs.spawncount, buf + 1); size = sv.signon_buffer_size[buf] + 1 + strlen (command) + 1; @@ -376,7 +378,7 @@ SV_Spawn (client_t *client) // set up the edict ent = client->edict; - memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); + memset (&E_fld (ent, 0), 0, sv_pr_state.progs->entityfields * 4); SVfloat (ent, colormap) = NUM_FOR_EDICT (&sv_pr_state, ent); SVfloat (ent, team) = 0; // FIXME SVstring (ent, netname) = PR_SetString (&sv_pr_state, client->name); @@ -604,7 +606,7 @@ SV_Begin_f (void *unused) // Trigger GIB events if (sv_client_spawn_e->func) - GIB_Event_Callback (sv_client_spawn_e, 1, va ("%u", + GIB_Event_Callback (sv_client_spawn_e, 1, va (0, "%u", host_client->userid)); } @@ -786,7 +788,7 @@ SV_BeginDownload_f (void *unused) MSG_ReliableWrite_Short (&host_client->backbuf, DL_HTTP); MSG_ReliableWrite_Byte (&host_client->backbuf, 0); MSG_ReliableWrite_String (&host_client->backbuf, - va ("%s/%s", sv_http_url_base->string, + va (0, "%s/%s", sv_http_url_base->string, ren ? qfs_foundfile.realname : name)); MSG_ReliableWrite_String (&host_client->backbuf, ren ? qfs_foundfile.realname : ""); @@ -913,7 +915,7 @@ SV_Say (qboolean team) dsprintf (text, fmt, host_client->name); if (sv_chat_e->func) - GIB_Event_Callback (sv_chat_e, 2, va ("%i", host_client->userid), p, + GIB_Event_Callback (sv_chat_e, 2, va (0, "%i", host_client->userid), p, type); dstring_appendstr (text, p); @@ -1200,7 +1202,7 @@ SV_SetUserinfo (client_t *client, const char *key, const char *value) // trigger a GIB event if (sv_setinfo_e->func) - GIB_Event_Callback (sv_setinfo_e, 4, va("%d", client->userid), + GIB_Event_Callback (sv_setinfo_e, 4, va (0, "%d", client->userid), key, oldvalue, value); if (sv_funcs.UserInfoChanged) { @@ -1211,6 +1213,7 @@ SV_SetUserinfo (client_t *client, const char *key, const char *value) P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue); P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value); + sv_pr_state.pr_argc = 3; PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoChanged); PR_PopFrame (&sv_pr_state); send_changes = !R_FLOAT (&sv_pr_state); @@ -1261,6 +1264,7 @@ SV_SetInfo_f (void *unused) PR_RESET_PARAMS (&sv_pr_state); P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, value); + sv_pr_state.pr_argc = 2; PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoCallback); PR_PopFrame (&sv_pr_state); if (R_FLOAT (&sv_pr_state)) @@ -2007,7 +2011,7 @@ static builtin_t builtins[] = { void SV_UserInit (void) { - ucmd_table = Hash_NewTable (251, ucmds_getkey, ucmds_free, 0); + ucmd_table = Hash_NewTable (251, ucmds_getkey, ucmds_free, 0, 0); Hash_SetHashCompare (ucmd_table, ucmd_get_hash, ucmd_compare); PR_RegisterBuiltins (&sv_pr_state, builtins); cl_rollspeed = Cvar_Get ("cl_rollspeed", "200", CVAR_NONE, NULL, diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index 513fdd4f7..c3e2a0424 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -43,20 +43,22 @@ #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/gib.h" -#include "QF/locs.h" #include "QF/model.h" #include "QF/va.h" #include "QF/skin.h" #include "QF/sys.h" #include "QF/teamplay.h" -#include "qw/bothdefs.h" -#include "cl_input.h" -#include "client.h" #include "compat.h" +#include "client/locs.h" + +#include "qw/bothdefs.h" +#include "qw/include/cl_input.h" +#include "qw/include/client.h" + static qboolean died = false, recorded_location = false; -static vec3_t death_location, last_recorded_location; +static vec4f_t death_location, last_recorded_location; cvar_t *cl_deadbodyfilter; cvar_t *cl_gibfilter; @@ -117,13 +119,12 @@ Team_BestWeaponImpulse (void) in_impulse = best; } - -const char * -Team_ParseSay (const char *s) +//FIXME slow use of dstring +const char * +Team_ParseSay (dstring_t *buf, const char *s) { - char chr, t2[128], t3[128]; + char chr, t2[128], t3[2]; const char *t1; - static char buf[1024]; size_t i, bracket; static location_t *location = NULL; @@ -157,7 +158,6 @@ Team_ParseSay (const char *s) case 'S': bracket = 0; t1 = skin->string; - t1 = "FIXME"; break; case 'd': bracket = 0; @@ -165,7 +165,7 @@ Team_ParseSay (const char *s) location = locs_find (death_location); if (location) { recorded_location = true; - VectorCopy (death_location, last_recorded_location); + last_recorded_location = death_location; t1 = location->name; break; } @@ -184,10 +184,10 @@ Team_ParseSay (const char *s) case 'l': location: bracket = 0; - location = locs_find (cl.simorg); + location = locs_find (cl.viewstate.origin); if (location) { recorded_location = true; - VectorCopy (cl.simorg, last_recorded_location); + last_recorded_location = cl.viewstate.origin; t1 = location->name; } else snprintf (t2, sizeof (t2), "Unknown!"); @@ -213,8 +213,9 @@ Team_ParseSay (const char *s) snprintf (t2, sizeof (t2), "%sa:%i", t3, cl.stats[STAT_ARMOR]); - } else + } else { snprintf (t2, sizeof (t2), "%i", cl.stats[STAT_ARMOR]); + } break; case 'A': bracket = 0; @@ -254,36 +255,31 @@ Team_ParseSay (const char *s) t1 = t2; } - if (bracket) - buf[i++] = 0x90; // '[' - - if (t1) { - int len; - - len = strlen (t1); - if (i + len >= sizeof (buf)) - continue; // No more space in buffer, icky. - strncpy (buf + i, t1, len); - i += len; + if (bracket) { + dstring_appendstr (buf, "\x90"); // '[' } - if (bracket) - buf[i++] = 0x91; // ']' + if (t1) { + dstring_appendstr (buf, t1); + } + + if (bracket) { + dstring_appendstr (buf, "\x91"); // ']' + } continue; } - buf[i++] = *s++; + dstring_appendsubstr (buf, s++, 1); } - buf[i] = 0; - return buf; + return buf->str; } void Team_Dead (void) { died = true; - VectorCopy (cl.simorg, death_location); + death_location = cl.viewstate.origin; } void @@ -293,8 +289,8 @@ Team_NewMap (void) died = false; recorded_location = false; - mapname = strdup (cl.worldmodel->name); - t2 = malloc (sizeof (cl.worldmodel->name)); + mapname = strdup (cl.worldmodel->path); + t2 = malloc (sizeof (cl.worldmodel->path)); if (!mapname || !t2) Sys_Error ("Can't duplicate mapname!"); map_to_loc (mapname,t2); @@ -350,10 +346,10 @@ locs_loc (void) } if (Cmd_Argc () >= 3) desc = Cmd_Args (2); - mapname = malloc (sizeof (cl.worldmodel->name)); + mapname = malloc (sizeof (cl.worldmodel->path)); if (!mapname) Sys_Error ("Can't duplicate mapname!"); - map_to_loc (cl.worldmodel->name, mapname); + map_to_loc (cl.worldmodel->path, mapname); snprintf (locfile, sizeof (locfile), "%s/%s", qfs_gamedir->dir.def, mapname); free (mapname); @@ -374,7 +370,7 @@ locs_loc (void) if (strcasecmp (Cmd_Argv (1), "add") == 0) { if (Cmd_Argc () >= 3) - locs_mark (cl.simorg, desc); + locs_mark (cl.viewstate.origin, desc); else Sys_Printf ("loc add :marks the current location " "with the description and records the information " @@ -383,7 +379,7 @@ locs_loc (void) if (strcasecmp (Cmd_Argv (1), "rename") == 0) { if (Cmd_Argc () >= 3) - locs_edit (cl.simorg, desc); + locs_edit (cl.viewstate.origin, desc); else Sys_Printf ("loc rename :changes the description of " "the nearest location marker\n"); @@ -391,14 +387,14 @@ locs_loc (void) if (strcasecmp (Cmd_Argv (1),"delete") == 0) { if (Cmd_Argc () == 2) - locs_del (cl.simorg); + locs_del (cl.viewstate.origin); else Sys_Printf ("loc delete :removes nearest location marker\n"); } if (strcasecmp (Cmd_Argv (1),"move") == 0) { if (Cmd_Argc () == 2) - locs_edit (cl.simorg, NULL); + locs_edit (cl.viewstate.origin, NULL); else Sys_Printf ("loc move :moves the nearest location marker to your " "current location\n"); @@ -413,7 +409,7 @@ Locs_Loc_Get (void) if (GIB_Argc () != 1) GIB_USAGE (""); else { - location = locs_find (cl.simorg); + location = locs_find (cl.viewstate.origin); GIB_Return (location ? location->name : "unknown"); } } @@ -429,7 +425,7 @@ Locs_Init (void) static const char * Team_F_Version (char *args) { - return va ("say %s", PACKAGE_STRING); + return va (0, "say %s", PACKAGE_STRING); } static const char * @@ -451,7 +447,7 @@ Team_F_Skins (char *args) if (l == 0) { //XXXtotalfb = Skin_FbPercent (0); totalfb = 0; - return va ("say Player models have %f%% brightness\n" + return va (0, "say Player models have %f%% brightness\n" "say Average percent fullbright for all loaded skins is " "%d.%d%%", allfb * 100, totalfb / 10, totalfb % 10); } @@ -460,8 +456,8 @@ Team_F_Skins (char *args) totalfb = 0; if (totalfb >= 0) - return va ("say \"Skin %s is %d.%d%% fullbright\"", args, totalfb / 10, - totalfb % 10); + return va (0, "say \"Skin %s is %d.%d%% fullbright\"", + args, totalfb / 10, totalfb % 10); else return ("say \"Skin not currently loaded.\""); } @@ -480,7 +476,6 @@ Team_ParseChat (const char *string) if (!cl_freply->value) return; - s = strchr (string, ':'); if (!(s = strchr (string, ':'))) return; s++; diff --git a/qw/source/world.c b/qw/source/world.c index ac5dd641b..393daaf6f 100644 --- a/qw/source/world.c +++ b/qw/source/world.c @@ -43,8 +43,9 @@ #include "QF/sys.h" #include "compat.h" -#include "server.h" -#include "sv_progs.h" + +#include "qw/include/server.h" +#include "qw/include/sv_progs.h" #include "world.h" #define always_inline inline __attribute__((__always_inline__)) @@ -244,7 +245,7 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, PR_GetString (&sv_pr_state, SVstring (ent, classname))); - hull_list = model->hull_list; + hull_list = model->brush.hull_list; } if (hull_list) { // decide which clipping hull to use, based on the size @@ -424,7 +425,7 @@ SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) leaf = (mleaf_t *) node; edict_leaf = alloc_edict_leaf (); - edict_leaf->leafnum = leaf - sv.worldmodel->leafs - 1; + edict_leaf->leafnum = leaf - sv.worldmodel->brush.leafs - 1; edict_leaf->next = SVdata (ent)->leafs; SVdata (ent)->leafs = edict_leaf; return; @@ -496,7 +497,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) // link to PVS leafs free_edict_leafs (&SVdata (ent)->leafs); if (SVfloat (ent, modelindex)) - SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); + SV_FindTouchedLeafs (ent, sv.worldmodel->brush.nodes); if (SVfloat (ent, solid) == SOLID_NOT) return; @@ -559,7 +560,7 @@ SV_PointContents (const vec3_t p) { int cont; - cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + cont = SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) cont = CONTENTS_WATER; return cont; @@ -568,7 +569,7 @@ SV_PointContents (const vec3_t p) int SV_TruePointContents (const vec3_t p) { - return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + return SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); } /* @@ -677,7 +678,7 @@ SV_ClipMoveToEntity (edict_t *touched, const vec3_t start, return trace; } -static always_inline int +static always_inline __attribute__((pure)) int ctl_pretest_everything (edict_t *touch, moveclip_t *clip) { if (touch->free) @@ -705,7 +706,7 @@ ctl_pretest_triggers (edict_t *touch, moveclip_t *clip) return 1; } -static always_inline int +static always_inline __attribute__((pure)) int ctl_pretest_other (edict_t *touch, moveclip_t *clip) { if (SVfloat (touch, solid) == SOLID_NOT) @@ -990,7 +991,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin) vec3_t boxmins, boxmaxs, offset; // check world first - hull = &sv.worldmodel->hulls[1]; + hull = &sv.worldmodel->brush.hulls[1]; if (SV_HullPointContents (hull, hull->firstclipnode, origin) != CONTENTS_EMPTY) return sv.edicts; diff --git a/ruamoko/Makefile.am b/ruamoko/Makefile.am deleted file mode 100644 index 779fc1439..000000000 --- a/ruamoko/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -SUBDIRS= include lib game gui cl_menu scheme - -doc: Doxyfile - doxygen - -clean-local: - -rm -fr doxygen diff --git a/ruamoko/Makemodule.am b/ruamoko/Makemodule.am new file mode 100644 index 000000000..202fbffb6 --- /dev/null +++ b/ruamoko/Makemodule.am @@ -0,0 +1,10 @@ +ruamoko_libdir = $(datarootdir)/qfcc/lib +ruamoko_lib_LIBRARIES = + +include ruamoko/include/Makemodule.am +include ruamoko/lib/Makemodule.am +include ruamoko/game/Makemodule.am +include ruamoko/gui/Makemodule.am +include ruamoko/cl_menu/Makemodule.am +include ruamoko/scheme/Makemodule.am +include ruamoko/qwaq/Makemodule.am diff --git a/ruamoko/cl_menu/CvarRangeView.r b/ruamoko/cl_menu/CvarRangeView.r index f32d37b6d..b9980ca0a 100644 --- a/ruamoko/cl_menu/CvarRangeView.r +++ b/ruamoko/cl_menu/CvarRangeView.r @@ -1,5 +1,6 @@ #include "key.h" #include "sound.h" +#include "legacy_string.h" #include "string.h" #include "gui/Text.h" diff --git a/ruamoko/cl_menu/HUD.r b/ruamoko/cl_menu/HUD.r index 48bfc916f..b0ff525b2 100644 --- a/ruamoko/cl_menu/HUD.r +++ b/ruamoko/cl_menu/HUD.r @@ -166,7 +166,7 @@ int HUDHandleClass; if (looping) currentFrame = 0; else { - nextFrameTime = 0.0; + nextFrameTime = 0.0f; currentFrame = 0; return; } @@ -201,7 +201,7 @@ int HUDHandleClass; - (void) stop { - nextFrameTime = 0.0; + nextFrameTime = 0.0f; currentFrame = 0; } diff --git a/ruamoko/cl_menu/Makefile.am b/ruamoko/cl_menu/Makefile.am deleted file mode 100644 index 55c21a857..000000000 --- a/ruamoko/cl_menu/Makefile.am +++ /dev/null @@ -1,49 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -pkgdatadir=@sharepath@/QF - -QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Wall -Werror -Wno-integer-divide --no-default-paths -QCPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/ruamoko/include -I$(top_srcdir)/ruamoko/include -I$(top_builddir)/include -I$(top_srcdir)/include -GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi -GZ=@progs_gz@ -# BSD make can't handle $(shell foo) directives, and GNU make can't handle |= -# so we have to bite the bullet and pass this to the shell every time. -STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` - -menu_data=menu.dat$(GZ) menu.sym$(GZ) menu.plist - -data=$(menu_data) - -pkgdata_DATA= $(data) -EXTRA_DATA= $(menu_data) - -menu_src= \ - client_menu.r controls_o.r options.r options_util.r servlist.r \ - Frame.r menu.r HUD.r plistmenu.r ../lib/debug.r \ - \ - CrosshairCvar.r CrosshairView.r CvarColor.r CvarColorView.r \ - CvarObject.r CvarRange.r CvarRangeView.r CvarString.r CvarStringView.r \ - CvarToggle.r CvarToggleView.r \ - MenuGroup.r MouseToggle.r ProxyView.r RunToggle.r SubMenu.r - -SUFFIXES=.qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< -menu_obj=$(menu_src:.r=.qfo) - -menu.dat$(GZ): $(menu_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a ../gui/libgui.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o menu.dat $(menu_obj) ../gui/libgui.a ../lib/libcsqc.a ../lib/libr.a - $(GZIP) -menu.sym$(GZ): menu.dat$(GZ) - -EXTRA_DIST= $(menu_src) \ - CrosshairCvar.h CrosshairView.h CvarColor.h CvarColorView.h CvarObject.h \ - CvarRange.h CvarRangeView.h CvarString.h CvarStringView.h \ - CvarToggle.h CvarToggleView.h Frame.h HUD.h \ - MenuGroup.h MouseToggle.h ProxyView.h RunToggle.h SubMenu.h client_menu.h \ - controls_o.h menu.h options.h options_util.h plistmenu.h servlist.h \ - menu.plist -CLEANFILES= *.dat *.sym *.gz *.qfo diff --git a/ruamoko/cl_menu/Makemodule.am b/ruamoko/cl_menu/Makemodule.am new file mode 100644 index 000000000..c6c57aa7a --- /dev/null +++ b/ruamoko/cl_menu/Makemodule.am @@ -0,0 +1,77 @@ +ruamoko_cl_menu_libexec=ruamoko/cl_menu/menu.dat$(EXEEXT) +ruamoko_cl_menu_data=ruamoko/cl_menu/menu.plist ruamoko/cl_menu/menu.sym + +ruamoko_cl_menudir = @sharepath@/QF +ruamoko_cl_menu_DATA = $(ruamoko_cl_menu_data) +ruamoko_cl_menu_PROGRAMS = $(ruamoko_cl_menu_libexec) +EXTRA_PROGRAMS += $(ruamoko_cl_menu_libexec) + +ruamoko_menu_src= \ + ruamoko/cl_menu/client_menu.r \ + ruamoko/cl_menu/controls_o.r \ + ruamoko/cl_menu/options.r \ + ruamoko/cl_menu/options_util.r \ + ruamoko/cl_menu/servlist.r \ + ruamoko/cl_menu/Frame.r \ + ruamoko/cl_menu/HUD.r \ + ruamoko/cl_menu/menu.r \ + ruamoko/cl_menu/plistmenu.r \ + ruamoko/cl_menu/CrosshairCvar.r \ + ruamoko/cl_menu/CrosshairView.r \ + ruamoko/cl_menu/CvarColor.r \ + ruamoko/cl_menu/CvarColorView.r \ + ruamoko/cl_menu/CvarObject.r \ + ruamoko/cl_menu/CvarRange.r \ + ruamoko/cl_menu/CvarRangeView.r \ + ruamoko/cl_menu/CvarString.r \ + ruamoko/cl_menu/CvarStringView.r \ + ruamoko/cl_menu/CvarToggle.r \ + ruamoko/cl_menu/CvarToggleView.r \ + ruamoko/cl_menu/MenuGroup.r \ + ruamoko/cl_menu/MouseToggle.r \ + ruamoko/cl_menu/ProxyView.r \ + ruamoko/cl_menu/RunToggle.r \ + ruamoko/cl_menu/SubMenu.r + +ruamoko_cl_menu_menu_dat_SOURCES=$(ruamoko_menu_src) +ruamoko_menu_obj=$(ruamoko_cl_menu_menu_dat_SOURCES:.r=.o) +ruamoko_menu_dep=$(call qcautodep,$(ruamoko_cl_menu_menu_dat_SOURCES)) +ruamoko/cl_menu/menu.dat$(EXEEXT): $(ruamoko_menu_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a ruamoko/gui/libgui.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_menu_obj) -Lruamoko/gui -lgui -lcsqc -lr +include $(ruamoko_menu_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_menu_dep) + +ruamoko/cl_menu/menu.sym: ruamoko/cl_menu/menu.dat + +EXTRA_DIST += \ + ruamoko/cl_menu/CrosshairCvar.h \ + ruamoko/cl_menu/CrosshairView.h \ + ruamoko/cl_menu/CvarColor.h \ + ruamoko/cl_menu/CvarColorView.h \ + ruamoko/cl_menu/CvarObject.h \ + ruamoko/cl_menu/CvarRange.h \ + ruamoko/cl_menu/CvarRangeView.h \ + ruamoko/cl_menu/CvarString.h \ + ruamoko/cl_menu/CvarStringView.h \ + ruamoko/cl_menu/CvarToggle.h \ + ruamoko/cl_menu/CvarToggleView.h \ + ruamoko/cl_menu/Frame.h \ + ruamoko/cl_menu/HUD.h \ + ruamoko/cl_menu/MenuGroup.h \ + ruamoko/cl_menu/MouseToggle.h \ + ruamoko/cl_menu/ProxyView.h \ + ruamoko/cl_menu/RunToggle.h \ + ruamoko/cl_menu/SubMenu.h \ + ruamoko/cl_menu/client_menu.h \ + ruamoko/cl_menu/controls_o.h \ + ruamoko/cl_menu/menu.h \ + ruamoko/cl_menu/options.h \ + ruamoko/cl_menu/options_util.h \ + ruamoko/cl_menu/plistmenu.h \ + ruamoko/cl_menu/servlist.h \ + ruamoko/cl_menu/menu.plist + +CLEANFILES += \ + ruamoko/cl_menu/*.dat \ + ruamoko/cl_menu/*.sym +DISTCLEANFILES += $(ruamoko_menu_dep) diff --git a/ruamoko/cl_menu/client_menu.r b/ruamoko/cl_menu/client_menu.r index 769ad9cae..dc4cd487e 100644 --- a/ruamoko/cl_menu/client_menu.r +++ b/ruamoko/cl_menu/client_menu.r @@ -1,6 +1,5 @@ #include "AutoreleasePool.h" #include "menu.h" -#include "file.h" #include "cmd.h" #include "gib.h" #include "draw.h" @@ -10,6 +9,7 @@ #include "options.h" #include "servlist.h" #include "system.h" +#include "qfs.h" #include "debug.h" #include "HUD.h" #include "client_menu.h" @@ -137,17 +137,18 @@ void (int quick) scan_saves = local QFile f; local string line; local int max = MAX_SAVEGAMES; - if (quick) + string basename = "s"; + if (quick) { max = MAX_QUICK; + basename = "quick"; + } for (i = 0; i < max; i++) { if (!filenames[i]) filenames[i] = str_new (); loadable[i] = 0; - if (quick) { - f = File_Open (sprintf ("quick%i.sav", i + 1), "rz"); - } else { - f = File_Open (sprintf ("s%i.sav", i), "rz"); - } + string path = sprintf ("%s%i.sav", basename, i); + //dprint(path + "\n"); + f = QFS_OpenFile (path); if (!f) { str_copy (filenames[i], "--- UNUSED SLOT ---"); continue; diff --git a/ruamoko/cl_menu/controls_o.r b/ruamoko/cl_menu/controls_o.r index 5c389d88e..3ae1b60c2 100644 --- a/ruamoko/cl_menu/controls_o.r +++ b/ruamoko/cl_menu/controls_o.r @@ -30,6 +30,7 @@ #include "draw.h" #include "system.h" #include "debug.h" +#include "legacy_string.h" #include "string.h" #include "key.h" #include "options_util.h" diff --git a/ruamoko/cl_menu/options.r b/ruamoko/cl_menu/options.r index e0529c23e..a228b1062 100644 --- a/ruamoko/cl_menu/options.r +++ b/ruamoko/cl_menu/options.r @@ -130,7 +130,7 @@ MENU_video_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"video_options"]); - video_options = ret.pointer_val; + video_options = (Group *) ret.pointer_val; } Menu_End (); @@ -177,7 +177,7 @@ MENU_audio_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"audio_options"]); - audio_options = ret.pointer_val; + audio_options = (Group *) ret.pointer_val; } Menu_End (); @@ -224,7 +224,7 @@ MENU_control_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"control_options"]); - control_options = ret.pointer_val; + control_options = (Group *) ret.pointer_val; } MENU_control_binding (); //FIXME how to hook in the bindings menu? @@ -275,7 +275,7 @@ MENU_feature_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"feature_options"]); - feature_options = ret.pointer_val; + feature_options = (Group *) ret.pointer_val; } Menu_End (); @@ -361,7 +361,7 @@ MENU_player_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"player_options"]); - player_options = ret.pointer_val; + player_options = (Group *) ret.pointer_val; } Menu_End (); @@ -426,7 +426,7 @@ MENU_network_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"network_options"]); - network_options = ret.pointer_val; + network_options = (Group *) ret.pointer_val; } Menu_End (); diff --git a/ruamoko/cl_menu/plistmenu.r b/ruamoko/cl_menu/plistmenu.r index 04d4355b7..f94e6bdfc 100644 --- a/ruamoko/cl_menu/plistmenu.r +++ b/ruamoko/cl_menu/plistmenu.r @@ -25,6 +25,7 @@ */ #include "debug.h" +#include "legacy_string.h" #include "string.h" #include "qfs.h" @@ -58,6 +59,7 @@ class_from_plist (PLDictionary *pldict) return ret; } obj = [class alloc]; + params[0].pointer_val = obj; messages = (PLArray*) [pldict getObjectForKey:"Messages"]; message_count = [messages count]; @@ -65,9 +67,10 @@ class_from_plist (PLDictionary *pldict) msg = (PLArray*) [messages getObjectAtIndex:i]; selname = [(PLString*) [msg getObjectAtIndex:0] string]; sel = sel_get_uid (selname); - va_list.count = [msg count] - 1; - for (j = 0; j < va_list.count; j++) { - paramstr = [(PLString*) [msg getObjectAtIndex:j + 1] string]; + params[1].pointer_val = sel; + va_list.count = [msg count] + 1; + for (j = 2; j < va_list.count; j++) { + paramstr = [(PLString*) [msg getObjectAtIndex:j - 1] string]; switch (str_mid (paramstr, 0, 1)) { case "\"": va_list.list[j].string_val = str_mid (paramstr, 1, -1); @@ -78,7 +81,7 @@ class_from_plist (PLDictionary *pldict) break; case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": - if (str_str (paramstr, ".")) + if (str_str (paramstr, ".") >= 0) va_list.list[j].float_val = stof (paramstr); else va_list.list[j].integer_val = stoi (paramstr); @@ -103,7 +106,7 @@ array_from_plist (PLArray *plarray) count = [plarray count]; for (i = 0; i < count; i++) { ret = object_from_plist ([plarray getObjectAtIndex:i]); - [array addObject: ret.pointer_val]; + [array addObject: (id) ret.pointer_val]; } ret.pointer_val = array; return ret; @@ -142,7 +145,7 @@ string_from_plist (PLString *plstring) local @param ret; local string str = [plstring string]; - ret.quaternion_val = nil; //FIXME should be ret = nil; + ret = nil; if (str_mid (str, 0, 1) == "[") return rect_from_plist (plstring); diff --git a/ruamoko/game/Axe.r b/ruamoko/game/Axe.r index 06c4ca083..7e3c49745 100644 --- a/ruamoko/game/Axe.r +++ b/ruamoko/game/Axe.r @@ -14,7 +14,7 @@ - (id) init { [super init]; - damage = (deathmatch > 3) ? 75.0 : 20.0; + damage = (deathmatch > 3) ? 75.0f : 20.0f; return self; } @@ -32,7 +32,7 @@ source = s.origin + '0 0 16'; traceline (source, source + v_forward * 64, NO, s); - if (trace_fraction == 1.0) + if (trace_fraction == 1.0f) return; org = trace_endpos - v_forward * 4; diff --git a/ruamoko/game/Makefile.am b/ruamoko/game/Makefile.am deleted file mode 100644 index e1ff2fbf2..000000000 --- a/ruamoko/game/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -#FIXME should qf data be installed somewhere other than id1 that gets -#searched after everything else? -pkgdatadir=@sharepath@/id1 - -QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/ruamoko/include -I$(top_srcdir)/ruamoko/include -GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi -GZ=@progs_gz@ -# BSD make can't handle $(shell foo) directives, and GNU make can't handle |= -# so we have to bite the bullet and pass this to the shell every time. -STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` - -data=game.dat$(GZ) - -noinst_DATA= $(data) -EXTRA_DATA= game.dat - -game_src= Axe.r GameEntity.r World.r tempent.r - -SUFFIXES=.qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< - -game_obj=$(game_src:.r=.qfo) -game.dat$(GZ): $(game_obj) ../lib/libr.a ../lib/libqw.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o game.dat $(game_obj) ../lib/libr.a ../lib/libqw.a ../lib/libr.a - $(GZIP) - -EXTRA_DIST= $(game_src) Axe.h GameEntity.h tempent.h Weapon.h World.h -CLEANFILES= *.dat *.sym *.gz *.qfo diff --git a/ruamoko/game/Makemodule.am b/ruamoko/game/Makemodule.am new file mode 100644 index 000000000..576867c27 --- /dev/null +++ b/ruamoko/game/Makemodule.am @@ -0,0 +1,27 @@ +ruamoko_game_libexec=ruamoko/game/game.dat$(EXEEXT) + +noinst_PROGRAMS += $(ruamoko_game_libexec) +EXTRA_PROGRAMS += $(ruamoko_game_libexec) + +ruamoko_game_src= ruamoko/game/Axe.r ruamoko/game/GameEntity.r ruamoko/game/World.r ruamoko/game/tempent.r + +ruamoko_game_game_dat_SOURCES=$(ruamoko_game_src) +ruamoko_game_obj=$(ruamoko_game_game_dat_SOURCES:.r=.o) +ruamoko_game_dep=$(call qcautodep,$(ruamoko_game_game_dat_SOURCES)) +ruamoko/game/game.dat$(EXEEXT): $(ruamoko_game_obj) $(QFCC_DEP) ruamoko/lib/libr.a ruamoko/lib/libqw.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_game_obj) -lqw -lr +include $(ruamoko_game_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_game_dep) + +ruamoko/game/game.sym: ruamoko/game/game.dat + +EXTRA_DIST += $(ruamoko_game_src) \ + ruamoko/game/Axe.h \ + ruamoko/game/GameEntity.h \ + ruamoko/game/tempent.h \ + ruamoko/game/Weapon.h \ + ruamoko/game/World.h +CLEANFILES += \ + ruamoko/game/*.dat \ + ruamoko/game/*.sym +DISTCLEANFILES += $(ruamoko_game_dep) diff --git a/ruamoko/gui/Group.r b/ruamoko/gui/Group.r index 4bcccadf1..56b7303c7 100644 --- a/ruamoko/gui/Group.r +++ b/ruamoko/gui/Group.r @@ -1,6 +1,6 @@ -#include "gui/Group.h" -#include "gui/Point.h" -#include "Array.h" +#include +#include +#include @implementation Group diff --git a/ruamoko/gui/InputLine.r b/ruamoko/gui/InputLine.r index 781e56b78..e4fb8df8a 100644 --- a/ruamoko/gui/InputLine.r +++ b/ruamoko/gui/InputLine.r @@ -1,6 +1,6 @@ -#include "draw.h" -#include "gui/InputLine.h" -#include "gui/Rect.h" +#include +#include +#include inputline_t InputLine_Create (int lines, int size, int prompt) = #0; void InputLine_SetPos (inputline_t il, int x, int y) = #0; diff --git a/ruamoko/gui/Makefile.am b/ruamoko/gui/Makefile.am deleted file mode 100644 index e4866e856..000000000 --- a/ruamoko/gui/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -pkglibdir=$(datarootdir)/qfcc/lib - -QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) -PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) -RANLIB=touch - -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include - -gui_libs=libgui.a -libs=$(gui_libs) - -pkglib_LIBRARIES= $(libs) -EXTRA_LIBRARIES= $(gui_libs) - -SUFFIXES= .qfo .r .qc -.r.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< - -libgui_a_SOURCES= \ - Group.r InputLine.r Pic.r Point.r Rect.r Size.r Slider.r Text.r View.r -libgui_a_AR= $(PAK) -cf - -CLEANFILES= *.qfo *.o diff --git a/ruamoko/gui/Makemodule.am b/ruamoko/gui/Makemodule.am new file mode 100644 index 000000000..ee25d5111 --- /dev/null +++ b/ruamoko/gui/Makemodule.am @@ -0,0 +1,25 @@ +ruamoko_gui_gui_libs=ruamoko/gui/libgui.a + +ruamoko_lib_LIBRARIES += $(ruamoko_gui_gui_libs) +EXTRA_LIBRARIES += $(ruamoko_gui_gui_libs) + +ruamoko_gui_libgui_a_SOURCES= \ + ruamoko/gui/Group.r \ + ruamoko/gui/InputLine.r \ + ruamoko/gui/Pic.r \ + ruamoko/gui/Point.r \ + ruamoko/gui/Rect.r \ + ruamoko/gui/Size.r \ + ruamoko/gui/Slider.r \ + ruamoko/gui/Text.r \ + ruamoko/gui/View.r +ruamoko_gui_libgui_a_dep=$(call qcautodep,$(ruamoko_gui_libgui_a_SOURCES)) +ruamoko_gui_libgui_a_AR= $(PAK) -cf +EXTRA_ruamoko_gui_libgui_a_DEPENDENCIES=pak +include $(ruamoko_gui_libgui_a_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_gui_libgui_a_dep) + +CLEANFILES += \ + ruamoko/gui/*.dat \ + ruamoko/gui/*.sym +DISTCLEANFILES += $(ruamoko_gui_libgui_a_dep) diff --git a/ruamoko/gui/Pic.r b/ruamoko/gui/Pic.r index 89cf93950..748393cc5 100644 --- a/ruamoko/gui/Pic.r +++ b/ruamoko/gui/Pic.r @@ -1,6 +1,6 @@ -#include "draw.h" -#include "string.h" -#include "gui/Pic.h" +#include +#include +#include @implementation Pic -(id)init diff --git a/ruamoko/gui/Point.r b/ruamoko/gui/Point.r index c25c72000..91163087b 100644 --- a/ruamoko/gui/Point.r +++ b/ruamoko/gui/Point.r @@ -1,4 +1,4 @@ -#include "gui/Point.h" +#include Point makePoint (int x, int y) { diff --git a/ruamoko/gui/Rect.r b/ruamoko/gui/Rect.r index be1c69384..a7280cea3 100644 --- a/ruamoko/gui/Rect.r +++ b/ruamoko/gui/Rect.r @@ -1,7 +1,7 @@ -#include "Object.h" -#include "gui/Point.h" -#include "gui/Size.h" -#include "gui/Rect.h" +#include +#include +#include +#include Rect makeRect (int x, int y, int w, int h) { diff --git a/ruamoko/gui/Size.r b/ruamoko/gui/Size.r index d4565a33f..da1bf04a9 100644 --- a/ruamoko/gui/Size.r +++ b/ruamoko/gui/Size.r @@ -1,4 +1,4 @@ -#include "gui/Size.h" +#include Size makeSize (int width, int height) { diff --git a/ruamoko/gui/Slider.r b/ruamoko/gui/Slider.r index d43cdcf21..275a64de4 100644 --- a/ruamoko/gui/Slider.r +++ b/ruamoko/gui/Slider.r @@ -1,7 +1,7 @@ -#include "draw.h" +#include -#include "gui/Slider.h" -#include "gui/Rect.h" +#include +#include @implementation Slider diff --git a/ruamoko/gui/Text.r b/ruamoko/gui/Text.r index 731f661ce..6011273d8 100644 --- a/ruamoko/gui/Text.r +++ b/ruamoko/gui/Text.r @@ -1,6 +1,6 @@ -#include "gui/Text.h" -#include "string.h" -#include "draw.h" +#include +#include +#include @implementation Text - (id) init diff --git a/ruamoko/gui/View.r b/ruamoko/gui/View.r index 2accc4fe7..a83ebeb33 100644 --- a/ruamoko/gui/View.r +++ b/ruamoko/gui/View.r @@ -1,7 +1,7 @@ -#include "gui/Size.h" -#include "gui/Point.h" -#include "gui/Rect.h" -#include "gui/View.h" +#include +#include +#include +#include @implementation View diff --git a/ruamoko/include/Array.h b/ruamoko/include/Array.h index 8a9f91f36..cfc95f595 100644 --- a/ruamoko/include/Array.h +++ b/ruamoko/include/Array.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_Array_h #define __ruamoko_Array_h -#include "Object.h" -#include "runtime.h" +#include +#include /** The Array class is a general ordered collection class. @@ -271,7 +271,16 @@ Iteratively sends #performSelector:withObject: to each contained object. */ - (void) makeObjectsPerformSelector: (SEL)selector - withObject: (id)arg; + withObject: (void *)arg; +//\} + +/** + Iteratively sends #performSelector:withObject:withObject: to each + contained object. +*/ +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)arg + withObject: (void *)arg2; //\} @end diff --git a/ruamoko/include/AutoreleasePool.h b/ruamoko/include/AutoreleasePool.h index a02600c9e..c8202e0f0 100644 --- a/ruamoko/include/AutoreleasePool.h +++ b/ruamoko/include/AutoreleasePool.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_AutoreleasePool_h #define __ruamoko_AutoreleasePool_h -#include "Object.h" +#include @class Array; diff --git a/ruamoko/include/Entity.h b/ruamoko/include/Entity.h index 85f304efb..8ff0f568c 100644 --- a/ruamoko/include/Entity.h +++ b/ruamoko/include/Entity.h @@ -30,7 +30,7 @@ #ifndef __ruamoko_Entity_h #define __ruamoko_Entity_h -#include "Object.h" +#include @interface Entity: Object { diff --git a/ruamoko/include/Makefile.am b/ruamoko/include/Makefile.am deleted file mode 100644 index d978b3a70..000000000 --- a/ruamoko/include/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -AUTOMAKE_OPTIONS= foreign -pkgincludedir= $(datarootdir)/qfcc/include -nobase_pkginclude_HEADERS= \ - crudefile.h debug.h entities.h infokey.h math.h message.h nq_message.h \ - physics.h msgbuf.h qfile.h qfs.h qw_message.h qw_physics.h qw_sys.h \ - server.h sound.h script.h string.h sv_sound.h system.h \ - \ - draw.h key.h \ - \ - cbuf.h cmd.h cvar.h file.h gib.h hash.h plist.h runtime.h \ - Object.h Protocol.h \ - AutoreleasePool.h Array.h Entity.h PropertyList.h Set.h \ - \ - gui/Group.h gui/InputLine.h gui/Pic.h gui/Point.h gui/Rect.h gui/Size.h \ - gui/Slider.h gui/Text.h gui/View.h diff --git a/ruamoko/include/Makemodule.am b/ruamoko/include/Makemodule.am new file mode 100644 index 000000000..d53289e72 --- /dev/null +++ b/ruamoko/include/Makemodule.am @@ -0,0 +1,56 @@ +ruamoko_include = \ + ruamoko/include/crudefile.h \ + ruamoko/include/debug.h \ + ruamoko/include/entities.h \ + ruamoko/include/infokey.h \ + ruamoko/include/math.h \ + ruamoko/include/message.h \ + ruamoko/include/nq_message.h \ + ruamoko/include/physics.h \ + ruamoko/include/msgbuf.h \ + ruamoko/include/qfile.h \ + ruamoko/include/qfs.h \ + ruamoko/include/qw_message.h \ + ruamoko/include/qw_physics.h \ + ruamoko/include/qw_sys.h \ + ruamoko/include/server.h \ + ruamoko/include/sound.h \ + ruamoko/include/script.h \ + ruamoko/include/string.h \ + ruamoko/include/sv_sound.h \ + ruamoko/include/system.h \ + ruamoko/include/types.h \ + ruamoko/include/legacy_string.h \ + ruamoko/include/draw.h \ + ruamoko/include/key.h \ + ruamoko/include/cbuf.h \ + ruamoko/include/cmd.h \ + ruamoko/include/cvar.h \ + ruamoko/include/gib.h \ + ruamoko/include/hash.h \ + ruamoko/include/plist.h \ + ruamoko/include/runtime.h \ + ruamoko/include/Object.h \ + ruamoko/include/Protocol.h \ + ruamoko/include/AutoreleasePool.h \ + ruamoko/include/Array.h \ + ruamoko/include/Entity.h \ + ruamoko/include/PropertyList.h \ + ruamoko/include/Set.h + +ruamoko_gui_include = \ + ruamoko/include/gui/Group.h \ + ruamoko/include/gui/InputLine.h \ + ruamoko/include/gui/Pic.h \ + ruamoko/include/gui/Point.h \ + ruamoko/include/gui/Rect.h \ + ruamoko/include/gui/Size.h \ + ruamoko/include/gui/Slider.h \ + ruamoko/include/gui/Text.h \ + ruamoko/include/gui/View.h + +ruamoko_includedir = $(datarootdir)/qfcc/include +ruamoko_gui_includedir = $(datarootdir)/qfcc/include/gui + +ruamoko_include_HEADERS = $(ruamoko_include) +ruamoko_gui_include_HEADERS = $(ruamoko_gui_include) diff --git a/ruamoko/include/Object.h b/ruamoko/include/Object.h index 23623ef06..981977651 100644 --- a/ruamoko/include/Object.h +++ b/ruamoko/include/Object.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_Object_h #define __ruamoko_Object_h -#include "runtime.h" +#include @class Protocol; @@ -20,10 +20,14 @@ - (id) performSelector: (SEL)aSelector; - (id) performSelector: (SEL)aSelector - withObject: (id)anObject; + withObject: (void *)anObject; - (id) performSelector: (SEL)aSelector - withObject: (id)anObject - withObject: (id)anotherObject; + withObject: (void *)anObject + withObject: (void *)anotherObject; +// void return does not touch the actual return value (effectively retval) +// so if the target returns a value, and the forwarding method simply returns +// (and is void), the vallue will get out to the caller +- (void) performv: (SEL) sel : (@va_list) args; - (BOOL) respondsToSelector: (SEL)aSelector; - (BOOL) conformsToProtocol: (Protocol *)aProtocol; diff --git a/ruamoko/include/PropertyList.h b/ruamoko/include/PropertyList.h index 0f255cdfe..d2494a94a 100644 --- a/ruamoko/include/PropertyList.h +++ b/ruamoko/include/PropertyList.h @@ -1,10 +1,32 @@ #ifndef __ruamoko_PropertyList_h #define __ruamoko_PropertyList_h -#include "plist.h" -#include "Object.h" +#include +#include -@interface PLItem: Object +@class PLItem; + +@protocol PLDictionary +- (int) count; +- (int) numKeys; +- (PLItem *) getObjectForKey:(string) key; +- (PLItem *) allKeys; +- addKey:(string) key value:(PLItem *) value; +@end + +@protocol PLArray +- (int) count; +- (int) numObjects; +- (PLItem *) getObjectAtIndex:(int) index; +- addObject:(PLItem *) object; +- insertObject:(PLItem *) object atIndex:(int) index; +@end + +@protocol PLString +- (string) string; +@end + +@interface PLItem: Object { plitem_t item; int own; @@ -20,36 +42,23 @@ - initWithOwnItem:(plitem_t) item; - (string) write; - (pltype_t) type; +- (int) line; @end -@interface PLDictionary: PLItem +@interface PLDictionary: PLItem + (PLDictionary *) new; - -- (int) count; -- (int) numKeys; -- (PLItem *) getObjectForKey:(string) key; -- (PLItem *) allKeys; -- addKey:(string) key value:(PLItem *) value; @end -@interface PLArray: PLItem +@interface PLArray: PLItem + (PLArray *) new; - -- (int) count; -- (int) numObjects; -- (PLItem *) getObjectAtIndex:(int) index; -- addObject:(PLItem *) object; -- insertObject:(PLItem *) object atIndex:(int) index; @end @interface PLData: PLItem + (PLData *) new:(void*) data size:(int) len; @end -@interface PLString: PLItem +@interface PLString: PLItem + (PLString *) new:(string) str; - -- (string) string; @end #endif//__ruamoko_PropertyList_h diff --git a/ruamoko/include/Protocol.h b/ruamoko/include/Protocol.h index 2894ee4fa..3d377ab75 100644 --- a/ruamoko/include/Protocol.h +++ b/ruamoko/include/Protocol.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_Protocol_h #define __ruamoko_Protocol_h -#include "Object.h" +#include struct obj_method_description { string name; diff --git a/ruamoko/include/draw.h b/ruamoko/include/draw.h index df4a1470f..ae868ff36 100644 --- a/ruamoko/include/draw.h +++ b/ruamoko/include/draw.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_draw_h #define __ruamoko_draw_h -#include "Object.h" +#include struct _qpic_t { int width; diff --git a/ruamoko/include/file.h b/ruamoko/include/file.h deleted file mode 100644 index f1c3a580b..000000000 --- a/ruamoko/include/file.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __ruamoko_file_h -#define __ruamoko_file_h - -#include "qfile.h" - -@extern QFile File_Open (string path, string mode); - -#endif//__ruamoko_file_h diff --git a/ruamoko/include/gui/Group.h b/ruamoko/include/gui/Group.h index b9ea99386..ccd4baa65 100644 --- a/ruamoko/include/gui/Group.h +++ b/ruamoko/include/gui/Group.h @@ -1,10 +1,10 @@ #ifndef __ruamoko_gui_Group_h #define __ruamoko_gui_Group_h -#include "View.h" +#include /** \addtogroup gui */ -//@{ +///@{ @class Array; @@ -41,6 +41,6 @@ - (id) addViews: (Array*)viewlist; @end -//@} +///@} #endif//__ruamoko_gui_Group_h diff --git a/ruamoko/include/gui/InputLine.h b/ruamoko/include/gui/InputLine.h index 692562a08..c0b14cfb4 100644 --- a/ruamoko/include/gui/InputLine.h +++ b/ruamoko/include/gui/InputLine.h @@ -1,14 +1,14 @@ #ifndef __ruamoko_gui_InputLine_h #define __ruamoko_gui_InputLine_h -#include "View.h" +#include /** \defgroup inputline Low level intputline interface. \ingroup gui Interface functions to the engine implementation. */ -//@{ +///@{ /** Opaque handle to an inputline. @@ -118,10 +118,10 @@ typedef void (il_enterfunc)(string, void*); \return The current text of the intputline. */ @extern string InputLine_GetText (inputline_t il); -//@} +///@} /** \addtogroup gui */ -//@{ +///@{ /** Class representation of the low-level inputline objects. */ @@ -252,6 +252,6 @@ typedef void (il_enterfunc)(string, void*); - (string) text; @end -//@} +///@} #endif //__ruamoko_gui_InputLine_h diff --git a/ruamoko/include/gui/Pic.h b/ruamoko/include/gui/Pic.h index f19e8b6e4..9bfe29fbc 100644 --- a/ruamoko/include/gui/Pic.h +++ b/ruamoko/include/gui/Pic.h @@ -1,10 +1,10 @@ #ifndef __ruamoko_gui_Pic_h #define __ruamoko_gui_Pic_h -#include "gui/View.h" +#include /** \addtogroup gui */ -//@{ +///@{ @interface Pic : View { @@ -18,6 +18,6 @@ -(void)draw; @end -//@} +///@} #endif//__ruamoko_gui_Pic_h diff --git a/ruamoko/include/gui/Point.h b/ruamoko/include/gui/Point.h index 4ac36391a..9de4d7f5e 100644 --- a/ruamoko/include/gui/Point.h +++ b/ruamoko/include/gui/Point.h @@ -2,7 +2,7 @@ #define __ruamoko_gui_Point_h /** \addtogroup gui */ -//@{ +///@{ struct Point { int x; @@ -15,6 +15,6 @@ typedef struct Point Point; @extern Point addPoint (Point a, Point b); @extern Point subtractPoint (Point a, Point b); -//@} +///@} #endif //__ruamoko_gui_Point_h diff --git a/ruamoko/include/gui/Rect.h b/ruamoko/include/gui/Rect.h index 145815d66..d1432f460 100644 --- a/ruamoko/include/gui/Rect.h +++ b/ruamoko/include/gui/Rect.h @@ -1,11 +1,11 @@ #ifndef __ruamoko_gui_Rect_h #define __ruamoko_gui_Rect_h -#include "gui/Point.h" -#include "gui/Size.h" +#include +#include /** \addtogroup gui */ -//@{ +///@{ struct Rect { Point origin; @@ -30,6 +30,6 @@ typedef struct Rect Rect; - (Rect) offsetBySize: (Size)aSize; #endif -//@} +///@} #endif //__ruamoko_gui_Rect_h diff --git a/ruamoko/include/gui/Size.h b/ruamoko/include/gui/Size.h index 0f6b387a3..dd48c6259 100644 --- a/ruamoko/include/gui/Size.h +++ b/ruamoko/include/gui/Size.h @@ -2,7 +2,7 @@ #define __ruamoko_gui_Size_h /** \addtogroup gui */ -//@{ +///@{ struct Size { int width; @@ -15,6 +15,6 @@ typedef struct Size Size; @extern Size addSize (Size a, Size b); @extern Size subtractSize (Size a, Size b); -//@} +///@} #endif //__ruamoko_gui_Size_h diff --git a/ruamoko/include/gui/Slider.h b/ruamoko/include/gui/Slider.h index 13a68f492..99840af7e 100644 --- a/ruamoko/include/gui/Slider.h +++ b/ruamoko/include/gui/Slider.h @@ -1,10 +1,10 @@ #ifndef __ruamoko_gui_Slider_h #define __ruamoko_gui_Slider_h -#include "View.h" +#include /** \addtogroup gui */ -//@{ +///@{ @interface Slider: View { @@ -19,6 +19,6 @@ @end -//@} +///@} #endif //__ruamoko_gui_Slider_h diff --git a/ruamoko/include/gui/Text.h b/ruamoko/include/gui/Text.h index d9c6a1311..ef389bf9c 100644 --- a/ruamoko/include/gui/Text.h +++ b/ruamoko/include/gui/Text.h @@ -1,10 +1,10 @@ #ifndef __ruamoko_gui_Text_h #define __ruamoko_gui_Text_h -#include "View.h" +#include /** \addtogroup gui */ -//@{ +///@{ @interface Text: View { @@ -18,6 +18,6 @@ - (void) draw; @end -//@} +///@} #endif //__ruamoko_gui_Text_h diff --git a/ruamoko/include/gui/View.h b/ruamoko/include/gui/View.h index a84f05e06..3cb51ee67 100644 --- a/ruamoko/include/gui/View.h +++ b/ruamoko/include/gui/View.h @@ -1,14 +1,14 @@ #ifndef __ruamoko_gui_View_h #define __ruamoko_gui_View_h -#include "Object.h" -#include "gui/Rect.h" +#include +#include /** \defgroup gui GUI goo for gooey chewing */ /** \addtogroup gui */ -//@{ +///@{ /** The View class. */ @@ -34,6 +34,6 @@ - (int) keyEvent:(int)key unicode:(int)unicode down:(int)down; @end -//@} +///@} #endif //__ruamoko_gui_View_h diff --git a/ruamoko/include/hash.h b/ruamoko/include/hash.h index 8c07169aa..2d0aa80fc 100644 --- a/ruamoko/include/hash.h +++ b/ruamoko/include/hash.h @@ -1,24 +1,24 @@ #ifndef __ruamoko_hash_h #define __ruamoko_hash_h -typedef struct _hashtab_t *hashtab_t; +typedef struct _hashtab_t hashtab_t; -@extern hashtab_t Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud); -@extern void Hash_SetHashCompare (hashtab_t tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)); -@extern void Hash_DelTable (hashtab_t tab); -@extern void Hash_FlushTable (hashtab_t tab); -@extern int Hash_Add (hashtab_t tab, void *ele); -@extern int Hash_AddElement (hashtab_t tab, void *ele); -@extern void *Hash_Find (hashtab_t tab, string key); -@extern void *Hash_FindElement (hashtab_t tab, void *ele); -@extern void **Hash_FindList (hashtab_t tab, string key); -@extern void **Hash_FindElementList (hashtab_t tab, void *ele); -@extern void *Hash_Del (hashtab_t tab, string key); -@extern void *Hash_DelElement (hashtab_t tab, void *ele); -@extern void Hash_Free (hashtab_t tab, void *ele); +@extern hashtab_t *Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud); +@extern void Hash_SetHashCompare (hashtab_t *tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)); +@extern void Hash_DelTable (hashtab_t *tab); +@extern void Hash_FlushTable (hashtab_t *tab); +@extern int Hash_Add (hashtab_t *tab, void *ele); +@extern int Hash_AddElement (hashtab_t *tab, void *ele); +@extern void *Hash_Find (hashtab_t *tab, string key); +@extern void *Hash_FindElement (hashtab_t *tab, void *ele); +@extern void **Hash_FindList (hashtab_t *tab, string key); +@extern void **Hash_FindElementList (hashtab_t *tab, void *ele); +@extern void *Hash_Del (hashtab_t *tab, string key); +@extern void *Hash_DelElement (hashtab_t *tab, void *ele); +@extern void Hash_Free (hashtab_t *tab, void *ele); @extern int Hash_String (string str); @extern int Hash_Buffer (void *buf, int len); -@extern void **Hash_GetList (hashtab_t tab); -@extern void Hash_Stats (hashtab_t tab); +@extern void **Hash_GetList (hashtab_t *tab); +@extern void Hash_Stats (hashtab_t *tab); #endif // __ruamoko_hash_h diff --git a/ruamoko/include/key.h b/ruamoko/include/key.h index bc7d04801..f3355b3d2 100644 --- a/ruamoko/include/key.h +++ b/ruamoko/include/key.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_key_h #define __ruamoko_key_h -#include "QF/keys.h" +#include @extern int Key_keydown (int keynum); @extern string Key_SetBinding (string imt, int keynum, string binding); diff --git a/ruamoko/include/legacy_string.h b/ruamoko/include/legacy_string.h new file mode 100644 index 000000000..34e47817a --- /dev/null +++ b/ruamoko/include/legacy_string.h @@ -0,0 +1,12 @@ +#ifndef __ruamoko_legacy_string_h +#define __ruamoko_legacy_string_h + +@extern string ftos (float f); +@extern string vtos (vector v); +@extern float stof (string s); +@extern float charcount (string goal, string s); +@extern string itos (int i); +@extern int stoi (string s); +@extern vector stov (string s); + +#endif//__ruamoko_legacy_string_h diff --git a/ruamoko/include/math.h b/ruamoko/include/math.h index fad67a9de..d6ad33342 100644 --- a/ruamoko/include/math.h +++ b/ruamoko/include/math.h @@ -60,17 +60,20 @@ /** Returns \a f, rounded down to the next lower integer */ -@extern float floor (float f); +@extern @overload float floor (float f); +@extern @overload double floor (double f); /** Returns \a f, rounded up to the next highest integer */ -@extern float ceil (float f); +@extern @overload float ceil (float f); +@extern @overload double ceil (double f); /** Returns the absolute value of \a f */ -@extern float fabs (float f); +@extern @overload float fabs (float f); +@extern @overload double fabs (double f); //\} ///\name Exponentials and Logarithms @@ -78,32 +81,38 @@ /** Returns the natural log of \a x. */ -@extern float log (float x); +@extern @overload float log (float x); +@extern @overload double log (double x); /** Returns the base-2 log of \a x. */ -@extern float log2 (float x); +@extern @overload float log2 (float x); +@extern @overload double log2 (double x); /** Returns the base-10 log of \a x. */ -@extern float log10 (float x); +@extern @overload float log10 (float x); +@extern @overload double log10 (double x); /** Returns \a x to the \a y power */ -@extern float pow (float x, float y); +@extern @overload float pow (float x, float y); +@extern @overload double pow (double x, double y); /** Returns the square root of \a x */ -@extern float sqrt (float x); +@extern @overload float sqrt (float x); +@extern @overload double sqrt (double x); /** Returns the cube root of \a x */ -@extern float cbrt (float x); +@extern @overload float cbrt (float x); +@extern @overload double cbrt (double x); //\} ///\name Trigonometric functions @@ -112,40 +121,52 @@ /** Returns the sine of \a x. */ -@extern float sin (float x); +@extern @overload float sin (float x); +@extern @overload double sin (double x); /** Returns the cosine of \a x. */ -@extern float cos (float x); +@extern @overload float cos (float x); +@extern @overload double cos (double x); /** Returns the tangent of \a x. */ -@extern float tan (float x); +@extern @overload float tan (float x); +@extern @overload double tan (double x); /** Returns the arcsine of \a x. */ -@extern float asin (float x); +@extern @overload float asin (float x); +@extern @overload double asin (double x); /** Returns the arccosine of \a x. */ -@extern float acos (float x); +@extern @overload float acos (float x); +@extern @overload double acos (double x); /** Returns the arctangent of \a x. */ -@extern float atan (float x); -@extern float atan2 (float y, float x); +@extern @overload float atan (float x); +@extern @overload double atan (double x); + +/** + Returns the arctangent of \a y / \a x preserving the quadrant. +*/ +@extern @overload float atan2 (float y, float x); +@extern @overload double atan2 (double y, double x); /** Returns the length of the hypotenuse of a right triangle with sides \a x and \a y. That is, this function returns sqrt (\a x*\a x + \a y*\a y). */ -@extern float hypot (float x, float y); +@extern @overload float hypot (float x, float y); +@extern @overload double hypot (double x, double y); //\} ///\name Hyperbolic functions @@ -153,32 +174,38 @@ /** Returns the hyperbolic sine of \a x */ -@extern float sinh (float x); +@extern @overload float sinh (float x); +@extern @overload double sinh (double x); /** Returns the hyperbolic cosine of \a x */ -@extern float cosh (float x); +@extern @overload float cosh (float x); +@extern @overload double cosh (double x); /** Returns the hyperbolic tangent of \a x */ -@extern float tanh (float x); +@extern @overload float tanh (float x); +@extern @overload double tanh (double x); /** Returns the area hyperbolic sine of \a x */ -@extern float asinh (float x); +@extern @overload float asinh (float x); +@extern @overload double asinh (double x); /** Returns the area hyperbolic cosine of \a x */ -@extern float acosh (float x); +@extern @overload float acosh (float x); +@extern @overload double acosh (double x); /** Returns the area hyperbolic tangent of \a x */ -@extern float atanh (float x); +@extern @overload float atanh (float x); +@extern @overload double atanh (double x); //\} ///\name Vector Functions diff --git a/ruamoko/include/msgbuf.h b/ruamoko/include/msgbuf.h index d26ba4de9..172d7338a 100644 --- a/ruamoko/include/msgbuf.h +++ b/ruamoko/include/msgbuf.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_msgbuf_h #define __ruamoko_msgbuf_h -#include "qfile.h" +#include struct msgbuf_s; typedef struct msgbuf_s msgbuf_t; diff --git a/ruamoko/include/plist.h b/ruamoko/include/plist.h index 949419ea9..bfaa25516 100644 --- a/ruamoko/include/plist.h +++ b/ruamoko/include/plist.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_plist_h #define __ruamoko_plist_h -#include "qfile.h" +#include typedef struct plitem_s *plitem_t; typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types @@ -10,6 +10,7 @@ typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible t @extern plitem_t PL_GetPropertyList (string str); @extern string PL_WritePropertyList (plitem_t pl); @extern pltype_t PL_Type (plitem_t str); +@extern int PL_Line (plitem_t str); @extern string PL_String (plitem_t str); @extern plitem_t PL_ObjectForKey (plitem_t item, string key); @extern plitem_t PL_RemoveObjectForKey (plitem_t item, string key); diff --git a/ruamoko/include/qfs.h b/ruamoko/include/qfs.h index 484a020c0..379e29ad2 100644 --- a/ruamoko/include/qfs.h +++ b/ruamoko/include/qfs.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_qfs_h #define __ruamoko_qfs_h -#include "qfile.h" +#include struct _qfslist_t { int count; @@ -17,5 +17,6 @@ typedef struct _qfslist_t *QFSlist; @extern int QFS_WriteFile (string filename, void *buf, int count); @extern QFSlist QFS_Filelist (string path, string ext, int strip); @extern void QFS_FilelistFree (QFSlist list); +@extern string QFS_GetDirectory (void); #endif//__ruamoko_qfs_h diff --git a/ruamoko/include/qw_message.h b/ruamoko/include/qw_message.h index 5bd7efb0d..60c8587d1 100644 --- a/ruamoko/include/qw_message.h +++ b/ruamoko/include/qw_message.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_qw_message_h #define __ruamoko_qw_message_h -#include "message.h" +#include @extern void multicast (vector where, float set); diff --git a/ruamoko/include/runtime.h b/ruamoko/include/runtime.h index bbcd793ed..276d270fb 100644 --- a/ruamoko/include/runtime.h +++ b/ruamoko/include/runtime.h @@ -38,6 +38,8 @@ typedef enum { YES ///< a true value } BOOL; +@extern void __obj_forward(id obj, SEL sel, ...); +@extern BOOL __obj_responds_to(id obj, SEL sel); @extern void obj_error (id object, int code, string fmt, ...); @extern void obj_verror (id object, int code, string fmt, @va_list args); //obj_error_handler obj_set_error_handler (objc_error_handler func); @@ -98,6 +100,10 @@ typedef enum { @extern void *PR_FindGlobal (string name); //FIXME where? +// copies the list in src to a temporary buffer that will be freed when the +// calling function returns, and places the pointer to the buffer into the +// returned va_list. The count is copies as-is. +@extern @va_list va_copy(@va_list src); #endif //__ruamoko_runtime_h_ /** \} diff --git a/ruamoko/include/string.h b/ruamoko/include/string.h index c4136e2fc..3d978cfd5 100644 --- a/ruamoko/include/string.h +++ b/ruamoko/include/string.h @@ -1,23 +1,23 @@ #ifndef __ruamoko_string_h #define __ruamoko_string_h -@extern string ftos (float f); -@extern string vtos (vector v); -@extern float stof (string s); -@extern float strlen (string s); -@extern float charcount (string goal, string s); +@extern int strlen (string s); @extern string sprintf (string fmt, ...); -@extern string itos (int i); -@extern int stoi (string s); -@extern vector stov (string s); - +@extern string vsprintf (string fmt, @va_list args); @extern string str_new (void); -@extern string str_free (string str); +@extern void str_free (string str); +@extern string str_hold (string str); +@extern int str_valid (string str); +@extern int str_mutable (string str); @extern string str_copy (string dst, string src); @extern string str_cat (string dst, string src); @extern string str_clear (string str); @extern @overload string str_mid (string str, int start); @extern @overload string str_mid (string str, int start, int len); -@extern string str_str (string haystack, string needle); +int str_str (string haystack, string needle); +@extern int str_char (string str, int ind); +string str_quote (string str); +string str_lower (string str); +string str_upper (string str); #endif//__ruamoko_string_h diff --git a/ruamoko/include/types.h b/ruamoko/include/types.h new file mode 100644 index 000000000..c2f157e76 --- /dev/null +++ b/ruamoko/include/types.h @@ -0,0 +1,96 @@ +#ifndef __types_h +#define __types_h + +typedef enum { + ev_void, + ev_string, + ev_float, + ev_vector, + ev_entity, + ev_field, + ev_func, + ev_pointer, // end of v6 types + ev_quat, + ev_integer, + ev_uinteger, + ev_short, // value is embedded in the opcode + ev_double, + + ev_invalid, // invalid type. used for instruction checking + ev_type_count // not a type, gives number of types +} etype_t; + +typedef enum { + ty_basic, ///< VM type (float, int, pointer, field, etc) + ty_struct, + ty_union, + ty_enum, + ty_array, + ty_class, + ty_alias, +} ty_meta_e; + +typedef struct qfot_alias_s { + etype_t type; + struct qfot_type_s *aux_type; + struct qfot_type_s *full_type; + string name; +} qfot_alias_t; + +typedef struct qfot_fldptr_s { + etype_t type; + struct qfot_type_s *aux_type; +} qfot_fldptr_t; + +typedef struct qfot_func_s { + etype_t type; + struct qfot_type_s *return_type; + int num_params; + struct qfot_type_s *param_types[1]; +} qfot_func_t; + +typedef struct qfot_var_s { + struct qfot_type_s *type; + string name; + int offset; // value for enum, 0 for union +} qfot_var_t; + +typedef struct qfot_struct_s { + string tag; + int num_fields; + qfot_var_t fields[1]; +} qfot_struct_t; + +typedef struct qfot_array_s { + struct qfot_type_s *type; + int base; + int size; +} qfot_array_t; + +typedef struct qfot_type_s { + ty_meta_e meta; + int size; + string encoding; + union { + etype_t type; + qfot_fldptr_t fldptr; + qfot_func_t func; + qfot_struct_t strct; + qfot_array_t array; + string class; + qfot_alias_t alias; + }; +} qfot_type_t; + +// the minimum size of a type encoding +#define TYPESIZE 4 + +typedef struct qfot_type_encodings_s { + qfot_type_t *types; + int size; +} qfot_type_encodings_t; + +@extern string ty_meta_name[7]; +@extern string pr_type_name[ev_type_count]; + +#endif diff --git a/ruamoko/lib/Array+Private.r b/ruamoko/lib/Array+Private.r index 167404e5c..2cdea39cf 100644 --- a/ruamoko/lib/Array+Private.r +++ b/ruamoko/lib/Array+Private.r @@ -20,14 +20,14 @@ local unsigned i = count; local unsigned tmp; - do { - if (_objs[--i] == anObject) { + while (i-- > 0) { + if (_objs[i] == anObject) { for (tmp = i; tmp < count - 1; tmp++) { _objs[tmp] = _objs[tmp + 1]; } count--; } - } while (i); + } } @end diff --git a/ruamoko/lib/Array.r b/ruamoko/lib/Array.r index 4673c31d8..5fbaa9e56 100644 --- a/ruamoko/lib/Array.r +++ b/ruamoko/lib/Array.r @@ -1,7 +1,7 @@ -#include "math.h" +#include -#include "Array.h" -#include "runtime.h" +#include +#include #define STANDARD_CAPACITY 16 #define ARRAY_MAX_GRANULARITY 100 @@ -162,7 +162,7 @@ - (id) objectAtIndex: (unsigned)index { if (index >= count) // FIXME: need exceptions - [self error: "-replaceObjectAtIndex:withObject: index out of range"]; + [self error: "-objectAtIndex:withObject: index out of range"]; return _objs[index]; } @@ -261,7 +261,7 @@ { local unsigned i; - if (index >= count) // FIXME: need exceptions + if (index > count) // FIXME: need exceptions [self error: "-insertObject:atIndex: index out of range"]; if (count == capacity) { // at capacity, expand @@ -401,7 +401,7 @@ } - (void) makeObjectsPerformSelector: (SEL)selector - withObject: (id)anObject + withObject: (void *)anObject { local int i; @@ -410,6 +410,19 @@ } } +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + withObject: (void *)anotherObject +{ + local int i; + + for (i = 0; i < [self count]; i++) { + [[self objectAtIndex: i] performSelector: selector + withObject: anObject + withObject: anotherObject]; + } +} + - (void) dealloc { local unsigned i; diff --git a/ruamoko/lib/AutoreleasePool.r b/ruamoko/lib/AutoreleasePool.r index 6d8077cfc..b4aadd36f 100644 --- a/ruamoko/lib/AutoreleasePool.r +++ b/ruamoko/lib/AutoreleasePool.r @@ -1,7 +1,6 @@ -#include "AutoreleasePool.h" -#include "Array+Private.h" +#include -#include "Array.h" +#include #include "Array+Private.h" @static Array *poolStack; diff --git a/ruamoko/lib/Entity.r b/ruamoko/lib/Entity.r index 5cc1f4f11..e2ea25000 100644 --- a/ruamoko/lib/Entity.r +++ b/ruamoko/lib/Entity.r @@ -1,15 +1,15 @@ -#include "Entity.h" +#include -#include "debug.h" -#include "entities.h" -#include "plist.h" -#include "script.h" -#include "string.h" +#include +#include +#include +#include +#include typedef void () void_function; int PR_SetField (entity ent, string field, string value) = #0; -function PR_FindFunction (string func) = #0; +@function PR_FindFunction (string func) = #0; @static void ParseEntities (string ent_data); @@ -66,7 +66,7 @@ function PR_FindFunction (string func) = #0; local int count; local string field, value; local plitem_t keys; - local function func; + local @function func; local Entity *e; classname = PL_String (PL_ObjectForKey (dict, "classname")); diff --git a/ruamoko/lib/Makefile.am b/ruamoko/lib/Makefile.am deleted file mode 100644 index 53a20875b..000000000 --- a/ruamoko/lib/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -pkglibdir=$(datarootdir)/qfcc/lib - -QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QCFLAGS=-qq -O -g -Wall -Wno-integer-divide -Werror --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) -PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) -RANLIB=touch - -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include - -noinst_HEADERS= \ - Array+Private.h - -ruamoko_libs=libr.a libqw.a libnq.a libcsqc.a -libs=$(ruamoko_libs) - -pkglib_LIBRARIES= $(libs) -EXTRA_LIBRARIES= $(ruamoko_libs) - -SUFFIXES= .o .r .qc -.r.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< -.qc.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< - -libr_a_SOURCES=\ - cbuf.r cmd.r cvar.r file.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ - sound.r string.r math.r \ - Object.r Protocol.r \ - AutoreleasePool.r Array.r Array+Private.r Entity.r PropertyList.r Set.r -libr_a_AR=$(PAK) -cf - -libqw_a_SOURCES=\ - crudefile.r debug.r entities.r infokey.r math.r message.r \ - physics.r qw_message.r qw_physics.r qw_sys.r \ - server.r sv_sound.r system.r -libqw_a_AR=$(PAK) -cf - -libnq_a_SOURCES=\ - crudefile.r debug.r entities.r infokey.r math.r message.r \ - nq_message.r physics.r server.r sv_sound.r system.r -libnq_a_AR=$(PAK) -cf - -libcsqc_a_SOURCES= \ - debug.r draw.r gib.r key.r system.r -libcsqc_a_AR= $(PAK) -cf - -CLEANFILES= *.qfo *.o diff --git a/ruamoko/lib/Makemodule.am b/ruamoko/lib/Makemodule.am new file mode 100644 index 000000000..0d189f6b7 --- /dev/null +++ b/ruamoko/lib/Makemodule.am @@ -0,0 +1,87 @@ +ruamoko_libs=ruamoko/lib/libr.a ruamoko/lib/libqw.a ruamoko/lib/libnq.a ruamoko/lib/libcsqc.a + +ruamoko_lib_LIBRARIES += $(ruamoko_libs) +EXTRA_LIBRARIES += $(ruamoko_libs) + +noinst_HEADERS += \ + ruamoko/lib/Array+Private.h + +ruamoko_lib_libr_a_SOURCES=\ + ruamoko/lib/cbuf.r \ + ruamoko/lib/cmd.r \ + ruamoko/lib/cvar.r \ + ruamoko/lib/hash.r \ + ruamoko/lib/msgbuf.r \ + ruamoko/lib/plist.r \ + ruamoko/lib/qfile.r \ + ruamoko/lib/qfs.r \ + ruamoko/lib/script.r \ + ruamoko/lib/sound.r \ + ruamoko/lib/string.r \ + ruamoko/lib/math.r \ + ruamoko/lib/types.r \ + ruamoko/lib/va_list.r \ + ruamoko/lib/obj_forward.r \ + ruamoko/lib/Object.r \ + ruamoko/lib/Protocol.r \ + ruamoko/lib/AutoreleasePool.r \ + ruamoko/lib/Array.r \ + ruamoko/lib/Array+Private.r \ + ruamoko/lib/Entity.r \ + ruamoko/lib/PropertyList.r \ + ruamoko/lib/Set.r +ruamoko_lib_libr_a_dep=$(call qcautodep,$(ruamoko_lib_libr_a_SOURCES)) +ruamoko_lib_libr_a_AR=$(PAK) -cf +EXTRA_ruamoko_lib_libr_a_DEPENDENCIES=pak +include $(ruamoko_lib_libr_a_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_lib_libr_a_dep) + +ruamoko_lib_common_src=ruamoko/lib/debug.r ruamoko/lib/system.r ruamoko/lib/legacy_string.r +ruamoko_lib_server_src= \ + ruamoko/lib/crudefile.r ruamoko/lib/entities.r ruamoko/lib/infokey.r ruamoko/lib/message.r \ + ruamoko/lib/physics.r ruamoko/lib/server.r ruamoko/lib/sv_sound.r +ruamoko_lib_libqw_a_src= \ + ruamoko/lib/qw_message.r ruamoko/lib/qw_physics.r ruamoko/lib/qw_sys.r +ruamoko_lib_libnq_a_src= \ + ruamoko/lib/nq_message.r +ruamoko_lib_libcsqc_a_src= ruamoko/lib/draw.r ruamoko/lib/gib.r ruamoko/lib/key.r + +ruamoko_lib_common_dep=$(call qcautodep,$(ruamoko_lib_common_src)) +include $(ruamoko_lib_common_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_lib_common_dep) + +ruamoko_lib_server_dep=$(call qcautodep,$(ruamoko_lib_server_src)) +include $(ruamoko_lib_server_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_lib_server_dep) + +ruamoko_lib_libqw_a_SOURCES=$(ruamoko_lib_libqw_a_src) $(ruamoko_lib_common_src) $(ruamoko_lib_server_src) ruamoko/lib/math.r +ruamoko_lib_libqw_a_dep=$(call qcautodep,$(ruamoko_lib_libqw_a_src)) +ruamoko_lib_libqw_a_AR=$(PAK) -cf +EXTRA_ruamoko_lib_libqw_a_DEPENDENCIES=pak +include $(ruamoko_lib_libqw_a_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_lib_libqw_a_dep) + +ruamoko_lib_libnq_a_SOURCES=$(ruamoko_lib_libnq_a_src) $(ruamoko_lib_common_src) $(ruamoko_lib_server_src) ruamoko/lib/math.r +ruamoko_lib_libnq_a_dep=$(call qcautodep,$(ruamoko_lib_libnq_a_src)) +ruamoko_lib_libnq_a_AR=$(PAK) -cf +EXTRA_ruamoko_lib_libnq_a_DEPENDENCIES=pak +include $(ruamoko_lib_libnq_a_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_lib_libnq_a_dep) + +ruamoko_lib_libcsqc_a_SOURCES=$(ruamoko_lib_libcsqc_a_src) $(ruamoko_lib_common_src) +ruamoko_lib_libcsqc_a_dep=$(call qcautodep,$(ruamoko_lib_libcsqc_a_src)) +ruamoko_lib_libcsqc_a_AR= $(PAK) -cf +EXTRA_ruamoko_lib_libcsqc_a_DEPENDENCIES=pak +include $(ruamoko_lib_libcsqc_a_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_lib_libcsqc_a_dep) + +CLEANFILES += \ + ruamoko/lib/*.dat \ + ruamoko/lib/*.sym +DISTCLEANFILES += \ + $(ruamoko_lib_libr_a_dep) \ + $(ruamoko_lib_common_dep) \ + $(ruamoko_lib_server_dep) \ + $(ruamoko_lib_libqw_a_dep) \ + $(ruamoko_lib_libnq_a_dep) \ + $(ruamoko_lib_libcsqc_a_dep) diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index a6b0e9d85..6c7e0e6f4 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -1,9 +1,15 @@ -#include "Object.h" -#include "AutoreleasePool.h" +#include +#include + +static void link__obj_forward (void) +{ + __obj_forward (nil, nil); +} void *PR_FindGlobal (string name) = #0; //FIXME where? void __obj_exec_class (struct obj_module *msg) = #0; +BOOL __obj_responds_to(id obj, SEL sel) = #0; void (id object, int code, string fmt, ...) obj_error = #0; void (id object, int code, string fmt, @va_list args) obj_verror = #0; //obj_error_handler (objc_error_handler func) obj_set_error_handler = #0; @@ -247,7 +253,7 @@ BOOL (id object) object_is_meta_class = #0; return msg (self, aSelector); } -- (id) performSelector: (SEL)aSelector withObject: (id)anObject +- (id) performSelector: (SEL)aSelector withObject: (void *)anObject { local IMP msg = nil; // FIXME teach qfcc about noreturn @@ -260,8 +266,8 @@ BOOL (id object) object_is_meta_class = #0; } - (id) performSelector: (SEL)aSelector - withObject: (id)anObject - withObject: (id)anotherObject + withObject: (void *)anObject + withObject: (void *)anotherObject { local IMP msg; @@ -274,6 +280,11 @@ BOOL (id object) object_is_meta_class = #0; return msg (self, aSelector, anObject, anotherObject); } +- (void) performv: (SEL) sel : (@va_list) args +{ + obj_msg_sendv (self, sel, args); +} + - (void) doesNotRecognizeSelector: (SEL)aSelector { [self error: "%s does not recognize %s", diff --git a/ruamoko/lib/PropertyList.r b/ruamoko/lib/PropertyList.r index 0bcfa9850..c6df13070 100644 --- a/ruamoko/lib/PropertyList.r +++ b/ruamoko/lib/PropertyList.r @@ -1,4 +1,4 @@ -#include "PropertyList.h" +#include @implementation PLItem @@ -94,6 +94,86 @@ return PL_Type (item); } +- (int) line +{ + return PL_Line (item); +} + +- (int) count +{ + if ([self class] == [PLDictionary class]) { + return PL_D_NumKeys (item); + } else { + return PL_A_NumObjects (item); + } +} + +- (int) numKeys +{ + return PL_D_NumKeys (item); +} + +- (PLItem *) getObjectForKey:(string) key +{ + return [[PLItem itemClass: PL_ObjectForKey (item, key)] autorelease]; +} + +- (PLItem *) allKeys +{ + return [[PLItem itemClass: PL_D_AllKeys (item)] autorelease]; +} + +- addKey:(string) key value:(PLItem *) value +{ + if (!value.own) { + obj_error (self, 0, "add of unowned key/value to PLDictionary"); + return self; + } + PL_D_AddObject (item, key, value.item); + value.own = 0; + [value release]; + return self; +} + +- (int) numObjects +{ + return PL_A_NumObjects (item); +} + +- (PLItem *) getObjectAtIndex:(int) index +{ + return [[PLItem itemClass: PL_ObjectAtIndex (item, index)] autorelease]; +} + +- addObject:(PLItem *) object +{ + if (!object.own) { + obj_error (self, 0, "add of unowned object to PLArray"); + return self; + } + PL_A_AddObject (item, object.item); + object.own = 0; + [object release]; + return self; +} + +- insertObject:(PLItem *) object atIndex:(int) index +{ + if (!object.own) { + obj_error (self, 0, "add of unowned object to PLArray"); + return self; + } + PL_A_InsertObjectAtIndex (item, object.item, index); + object.own = 0; + [object release]; + return self; +} + +- (string) string +{ + return PL_String (item); +} + @end diff --git a/ruamoko/lib/Protocol.r b/ruamoko/lib/Protocol.r index 715ca30a7..8893d13bb 100644 --- a/ruamoko/lib/Protocol.r +++ b/ruamoko/lib/Protocol.r @@ -1,4 +1,4 @@ -#include "Protocol.h" +#include struct obj_protocol_list { struct obj_protocol_list *next; diff --git a/ruamoko/lib/Set.r b/ruamoko/lib/Set.r index 10cf6397d..9e215ec51 100644 --- a/ruamoko/lib/Set.r +++ b/ruamoko/lib/Set.r @@ -1,4 +1,4 @@ -#include "Set.h" +#include void set_del_iter (set_iter_t *set_iter) = #0; set_t *set_new (void) = #0; @@ -27,6 +27,15 @@ string set_as_string (set_t *set) = #0; @implementation SetIterator: Object +- initWithIterator: (set_iter_t *) iter +{ + if (!(self = [super init])) { + return nil; + } + self.iter = iter; + return self; +} + - (SetIterator *) next { if ((iter = set_next (iter))) @@ -84,8 +93,7 @@ string set_as_string (set_t *set) = #0; if (!iter) return nil; - iterator = [[SetIterator alloc] init]; - iterator.iter = iter; + iterator = [[SetIterator alloc] initWithIterator: iter]; return iterator; } diff --git a/ruamoko/lib/cbuf.r b/ruamoko/lib/cbuf.r index 496585fd5..f22498f3c 100644 --- a/ruamoko/lib/cbuf.r +++ b/ruamoko/lib/cbuf.r @@ -1,4 +1,4 @@ -#include "cbuf.h" +#include void (string text) Cbuf_AddText = #0; void (string text) Cbuf_InsertText = #0; diff --git a/ruamoko/lib/cmd.r b/ruamoko/lib/cmd.r index 2ecb6d100..ba86632f8 100644 --- a/ruamoko/lib/cmd.r +++ b/ruamoko/lib/cmd.r @@ -1,4 +1,4 @@ -#include "cmd.h" +#include void (string name, void () func) Cmd_AddCommand = #0; int () Cmd_Argc = #0; diff --git a/ruamoko/lib/crudefile.r b/ruamoko/lib/crudefile.r index c8d4b9e27..2987af452 100644 --- a/ruamoko/lib/crudefile.r +++ b/ruamoko/lib/crudefile.r @@ -1,4 +1,4 @@ -#include "crudefile.h" +#include float (string path, string mode) cfopen = #0x000f0000 + 103; void (float desc) cfclose = #0x000f0000 + 104; diff --git a/ruamoko/lib/cvar.r b/ruamoko/lib/cvar.r index 168c38e18..be12b212e 100644 --- a/ruamoko/lib/cvar.r +++ b/ruamoko/lib/cvar.r @@ -1,4 +1,4 @@ -#include "cvar.h" +#include float (string s) cvar = #45; void (string var, string val) cvar_set = #72; diff --git a/ruamoko/lib/debug.r b/ruamoko/lib/debug.r index 844c88eff..7cf9c8895 100644 --- a/ruamoko/lib/debug.r +++ b/ruamoko/lib/debug.r @@ -1,4 +1,4 @@ -#include "debug.h" +#include void abort (void) = #6; void coredump (void) = #28; diff --git a/ruamoko/lib/draw.r b/ruamoko/lib/draw.r index 741857bf5..5aef3ab75 100644 --- a/ruamoko/lib/draw.r +++ b/ruamoko/lib/draw.r @@ -1,4 +1,4 @@ -#include "draw.h" +#include void Draw_FreePic (qpic_t pic) = #0; qpic_t Draw_MakePic (int width, int heiight, string data) = #0; diff --git a/ruamoko/lib/entities.r b/ruamoko/lib/entities.r index f55bd91a7..f49cc9a53 100644 --- a/ruamoko/lib/entities.r +++ b/ruamoko/lib/entities.r @@ -1,4 +1,4 @@ -#include "entities.h" +#include void setmodel (entity e, string m) = #3; void setorigin (entity e, vector o) = #2; diff --git a/ruamoko/lib/file.r b/ruamoko/lib/file.r deleted file mode 100644 index 02494d317..000000000 --- a/ruamoko/lib/file.r +++ /dev/null @@ -1,3 +0,0 @@ -#include "file.h" - -QFile (string path, string mode) File_Open = #0; diff --git a/ruamoko/lib/gib.r b/ruamoko/lib/gib.r index c3fead7b1..26baacd2f 100644 --- a/ruamoko/lib/gib.r +++ b/ruamoko/lib/gib.r @@ -1,4 +1,4 @@ -#include "gib.h" +#include void GIB_Builtin_Add (string name, void func (int argc, string *argv)) = #0; int (string value) GIB_Return = #0; diff --git a/ruamoko/lib/hash.r b/ruamoko/lib/hash.r index 24844bfc2..120d140f9 100644 --- a/ruamoko/lib/hash.r +++ b/ruamoko/lib/hash.r @@ -1,19 +1,19 @@ -#include "hash.h" +#include -hashtab_t Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud) = #0; -void Hash_SetHashCompare (hashtab_t tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)) = #0; -void Hash_DelTable (hashtab_t tab) = #0; -void Hash_FlushTable (hashtab_t tab) = #0; -int Hash_Add (hashtab_t tab, void *ele) = #0; -int Hash_AddElement (hashtab_t tab, void *ele) = #0; -void *Hash_Find (hashtab_t tab, string key) = #0; -void *Hash_FindElement (hashtab_t tab, void *ele) = #0; -void **Hash_FindList (hashtab_t tab, string key) = #0; -void **Hash_FindElementList (hashtab_t tab, void *ele) = #0; -void *Hash_Del (hashtab_t tab, string key) = #0; -void *Hash_DelElement (hashtab_t tab, void *ele) = #0; -void Hash_Free (hashtab_t tab, void *ele) = #0; +hashtab_t *Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud) = #0; +void Hash_SetHashCompare (hashtab_t *tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)) = #0; +void Hash_DelTable (hashtab_t *tab) = #0; +void Hash_FlushTable (hashtab_t *tab) = #0; +int Hash_Add (hashtab_t *tab, void *ele) = #0; +int Hash_AddElement (hashtab_t *tab, void *ele) = #0; +void *Hash_Find (hashtab_t *tab, string key) = #0; +void *Hash_FindElement (hashtab_t *tab, void *ele) = #0; +void **Hash_FindList (hashtab_t *tab, string key) = #0; +void **Hash_FindElementList (hashtab_t *tab, void *ele) = #0; +void *Hash_Del (hashtab_t *tab, string key) = #0; +void *Hash_DelElement (hashtab_t *tab, void *ele) = #0; +void Hash_Free (hashtab_t *tab, void *ele) = #0; int Hash_String (string str) = #0; int Hash_Buffer (void *buf, int len) = #0; -void **Hash_GetList (hashtab_t tab) = #0; -void Hash_Stats (hashtab_t tab) = #0; +void **Hash_GetList (hashtab_t *tab) = #0; +void Hash_Stats (hashtab_t *tab) = #0; diff --git a/ruamoko/lib/infokey.r b/ruamoko/lib/infokey.r index d0049a4fd..a2913df18 100644 --- a/ruamoko/lib/infokey.r +++ b/ruamoko/lib/infokey.r @@ -1,4 +1,4 @@ -#include "infokey.h" +#include string (entity e, string key) infokey = #80; void (entity ent, string key, string value) setinfokey = #0x000f0000 + 102; diff --git a/ruamoko/lib/key.r b/ruamoko/lib/key.r index 19662f138..4b8c1a09a 100644 --- a/ruamoko/lib/key.r +++ b/ruamoko/lib/key.r @@ -1,4 +1,4 @@ -#include "key.h" +#include int Key_keydown (int keynum) = #0; string (string imt, int keynum, string binding) Key_SetBinding = #0; diff --git a/ruamoko/lib/legacy_string.r b/ruamoko/lib/legacy_string.r new file mode 100644 index 000000000..258a33ade --- /dev/null +++ b/ruamoko/lib/legacy_string.r @@ -0,0 +1,9 @@ +#include + +string (float f) ftos = #26; +string (vector v) vtos = #27; +float (string s) stof = #81; +float (string goal, string s) charcount = #0x000f0000 + 101; +string (int i) itos = #0x000f0000 + 112; +int (string s) stoi = #0x000f0000 + 113; +vector (string s) stov = #0x000f0000 + 114; diff --git a/ruamoko/lib/math.r b/ruamoko/lib/math.r index 8d0c51342..47624527a 100644 --- a/ruamoko/lib/math.r +++ b/ruamoko/lib/math.r @@ -1,4 +1,4 @@ -#include "math.h" +#include vector v_forward, v_up, v_right; @@ -34,3 +34,27 @@ float (float x) atanh = #0; float (float x) sqrt = #0; float (float x) cbrt = #0; float (float x, float y) hypot = #0; + +double (double v) floor = #0; +double (double v) ceil = #0; +double (double f) fabs = #0; +double (double x) sin = #0; +double (double x) cos = #0; +double (double x) tan = #0; +double (double x) asin = #0; +double (double x) acos = #0; +double (double x) atan = #0; +double (double y, double x) atan2 = #0; +double (double x) log = #0; +double (double x) log2 = #0; +double (double x) log10 = #0; +double (double x, double y) pow = #0; +double (double x) sinh = #0; +double (double x) cosh = #0; +double (double x) tanh = #0; +double (double x) asinh = #0; +double (double x) acosh = #0; +double (double x) atanh = #0; +double (double x) sqrt = #0; +double (double x) cbrt = #0; +double (double x, double y) hypot = #0; diff --git a/ruamoko/lib/message.r b/ruamoko/lib/message.r index 3136cd678..4ddb31571 100644 --- a/ruamoko/lib/message.r +++ b/ruamoko/lib/message.r @@ -1,4 +1,4 @@ -#include "message.h" +#include void (...) bprint = #23; void (entity client, string s) sprint = #24; diff --git a/ruamoko/lib/msgbuf.r b/ruamoko/lib/msgbuf.r index c1352a43e..1bd4e09b1 100644 --- a/ruamoko/lib/msgbuf.r +++ b/ruamoko/lib/msgbuf.r @@ -1,4 +1,4 @@ -#include "msgbuf.h" +#include msgbuf_t *MsgBuf_New (int size) = #0; void MsgBuf_Delete (msgbuf_t *msgbuf) = #0; diff --git a/ruamoko/lib/nq_message.r b/ruamoko/lib/nq_message.r index 14c06827a..223d1c604 100644 --- a/ruamoko/lib/nq_message.r +++ b/ruamoko/lib/nq_message.r @@ -1,3 +1,3 @@ -#include "nq_message.h" +#include void (vector o, vector d, float color, float count) particle = #48; diff --git a/ruamoko/lib/obj_forward.r b/ruamoko/lib/obj_forward.r new file mode 100644 index 000000000..60ad819b5 --- /dev/null +++ b/ruamoko/lib/obj_forward.r @@ -0,0 +1,3 @@ +// __obj_foward is the only thing in this file so it can be readily replaced +// at link time +void __obj_forward(id object, SEL sel, ...) = #0; diff --git a/ruamoko/lib/physics.r b/ruamoko/lib/physics.r index ca19e052f..b42585d00 100644 --- a/ruamoko/lib/physics.r +++ b/ruamoko/lib/physics.r @@ -1,4 +1,4 @@ -#include "physics.h" +#include float trace_allsolid; float trace_startsolid; diff --git a/ruamoko/lib/plist.r b/ruamoko/lib/plist.r index 4b01c653b..34f0ce6c1 100644 --- a/ruamoko/lib/plist.r +++ b/ruamoko/lib/plist.r @@ -1,9 +1,10 @@ -#include "plist.h" +#include plitem_t PL_GetFromFile (QFile file) = #0; plitem_t PL_GetPropertyList (string str) = #0; string PL_WritePropertyList (plitem_t pl) = #0; pltype_t PL_Type (plitem_t str) = #0; +int PL_Line (plitem_t str) = #0; string PL_String (plitem_t str) = #0; plitem_t PL_ObjectForKey (plitem_t item, string key) = #0; plitem_t PL_RemoveObjectForKey (plitem_t item, string key) = #0; diff --git a/ruamoko/lib/qfile.r b/ruamoko/lib/qfile.r index 072d72a1c..487beb5c5 100644 --- a/ruamoko/lib/qfile.r +++ b/ruamoko/lib/qfile.r @@ -1,4 +1,4 @@ -#include "qfile.h" +#include int Qrename (string old, string new) = #0; int Qremove (string path) = #0; diff --git a/ruamoko/lib/qfs.r b/ruamoko/lib/qfs.r index e1d374fc4..d467b09ce 100644 --- a/ruamoko/lib/qfs.r +++ b/ruamoko/lib/qfs.r @@ -1,4 +1,4 @@ -#include "qfs.h" +#include QFile QFS_Open (string path, string mode) = #0; QFile QFS_WOpen (string path, int zip) = #0; @@ -8,3 +8,4 @@ QFile QFS_OpenFile (string filename) = #0; int QFS_WriteFile (string filename, void *buf, int count) = #0; QFSlist QFS_Filelist (string path, string ext, int strip) = #0; void QFS_FilelistFree (QFSlist list) = #0; +string QFS_GetDirectory (void) = #0; diff --git a/ruamoko/lib/qw_message.r b/ruamoko/lib/qw_message.r index fcc714c37..218db52cd 100644 --- a/ruamoko/lib/qw_message.r +++ b/ruamoko/lib/qw_message.r @@ -1,3 +1,3 @@ -#include "qw_message.h" +#include void (vector where, float set) multicast = #82; diff --git a/ruamoko/lib/qw_physics.r b/ruamoko/lib/qw_physics.r index 431e97e63..0ff633569 100644 --- a/ruamoko/lib/qw_physics.r +++ b/ruamoko/lib/qw_physics.r @@ -1,4 +1,4 @@ -#include "qw_physics.h" +#include entity (entity ent) testentitypos = #0x000f0000 + 92; void (vector start, vector mins, vector maxs, vector end, float type, entity passent) checkmove = #0x000f0000 + 98; diff --git a/ruamoko/lib/qw_sys.r b/ruamoko/lib/qw_sys.r index 8d8643576..529f42947 100644 --- a/ruamoko/lib/qw_sys.r +++ b/ruamoko/lib/qw_sys.r @@ -1,3 +1,3 @@ -#include "qw_sys.h" +#include void (entity killer, entity killee) logfrag = #79; diff --git a/ruamoko/lib/script.r b/ruamoko/lib/script.r index 74c120075..e72c4b72a 100644 --- a/ruamoko/lib/script.r +++ b/ruamoko/lib/script.r @@ -1,4 +1,4 @@ -#include "script.h" +#include script_t Script_New (void) = #0; void Script_Delete (script_t script) = #0; diff --git a/ruamoko/lib/server.r b/ruamoko/lib/server.r index 42bd99eb5..b65c3ac7d 100644 --- a/ruamoko/lib/server.r +++ b/ruamoko/lib/server.r @@ -1,4 +1,4 @@ -#include "server.h" +#include void (string s) precache_sound = #19; void (string s) precache_model = #20; diff --git a/ruamoko/lib/sound.r b/ruamoko/lib/sound.r index 863800c81..000ef7047 100644 --- a/ruamoko/lib/sound.r +++ b/ruamoko/lib/sound.r @@ -1,3 +1,3 @@ -#include "sound.h" +#include void (string sound) S_LocalSound = #0; diff --git a/ruamoko/lib/string.r b/ruamoko/lib/string.r index f7eda6b48..5169296a0 100644 --- a/ruamoko/lib/string.r +++ b/ruamoko/lib/string.r @@ -1,20 +1,20 @@ -#include "string.h" - -string (float f) ftos = #26; -string (vector v) vtos = #27; -float (string s) stof = #81; -float (string s) strlen = #0x000f0000 + 100; -float (string goal, string s) charcount = #0x000f0000 + 101; -string (string fmt, ...) sprintf = #0x000f0000 + 109; -string (int i) itos = #0x000f0000 + 112; -int (string s) stoi = #0x000f0000 + 113; -vector (string s) stov = #0x000f0000 + 114; +#include +int (string s) strlen = #0; +string (string fmt, ...) sprintf = #0; +string vsprintf (string fmt, @va_list args) = #0; string (void) str_new = #0; -string (string str) str_free = #0; +void (string str) str_free = #0; +string str_hold (string str) = #0; +int str_valid (string str) = #0; +int str_mutable (string str) = #0; string (string dst, string src) str_copy = #0; string (string dst, string src) str_cat = #0; string (string str) str_clear = #0; string (string str, int start) str_mid = #0; string (string str, int start, int len) str_mid = #0; -string (string haystack, string needle) str_str = #0; +int str_str (string haystack, string needle) = #0; +int str_char (string str, int ind) = #0; +string str_quote (string str) = #0; +string str_lower (string str) = #0; +string str_upper (string str) = #0; diff --git a/ruamoko/lib/sv_sound.r b/ruamoko/lib/sv_sound.r index 7880c6b1b..cd4b4f43e 100644 --- a/ruamoko/lib/sv_sound.r +++ b/ruamoko/lib/sv_sound.r @@ -1,4 +1,4 @@ -#include "sound.h" +#include void (entity e, float chan, string samp, float vol, float atten) sound = #8; void (vector pos, string samp, float vol, float atten) ambientsound = #74; diff --git a/ruamoko/lib/system.r b/ruamoko/lib/system.r index 1a387f890..753a41d99 100644 --- a/ruamoko/lib/system.r +++ b/ruamoko/lib/system.r @@ -1,4 +1,4 @@ -#include "system.h" +#include float time; diff --git a/ruamoko/lib/types.r b/ruamoko/lib/types.r new file mode 100644 index 000000000..aa1f65a02 --- /dev/null +++ b/ruamoko/lib/types.r @@ -0,0 +1,29 @@ +#include +#include + +string ty_meta_name[7] = { + "basic", + "struct", + "union", + "enum", + "array", + "class", + "alias", +}; + +string pr_type_name[ev_type_count] = { + "void", + "string", + "float", + "vector", + "entity", + "field", + "function", + "pointer", + "quaternion", + "integer", + "uinteger", + "short", + "double" + "invalid", +}; diff --git a/ruamoko/lib/va_list.r b/ruamoko/lib/va_list.r new file mode 100644 index 000000000..399e05933 --- /dev/null +++ b/ruamoko/lib/va_list.r @@ -0,0 +1,3 @@ +#include + +@va_list va_copy(@va_list src) = #0; diff --git a/tools/qwaq/.gdbinit b/ruamoko/qwaq/.gdbinit similarity index 100% rename from tools/qwaq/.gdbinit rename to ruamoko/qwaq/.gdbinit diff --git a/ruamoko/qwaq/Makemodule.am b/ruamoko/qwaq/Makemodule.am new file mode 100644 index 000000000..781db5c76 --- /dev/null +++ b/ruamoko/qwaq/Makemodule.am @@ -0,0 +1,150 @@ +QWAQ_LIBS=@QWAQ_LIBS@ +QWAQ_DEPS=@QWAQ_DEPS@ +QWAQ_INCS=@QWAQ_INCS@ + +noinst_PROGRAMS += @QWAQ_TARGETS@ ruamoko/qwaq/qwaq-app.dat$(EXEEXT) ruamoko/qwaq/gcd.dat$(EXEEXT) + +qwaq_app_dat_src= \ + ruamoko/qwaq/qwaq-app.r \ + ruamoko/qwaq/debugger/views/basicview.r \ + ruamoko/qwaq/debugger/views/defview.r \ + ruamoko/qwaq/debugger/views/doubleview.r \ + ruamoko/qwaq/debugger/views/entityview.r \ + ruamoko/qwaq/debugger/views/fieldview.r \ + ruamoko/qwaq/debugger/views/floatview.r \ + ruamoko/qwaq/debugger/views/funcview.r \ + ruamoko/qwaq/debugger/views/intview.r \ + ruamoko/qwaq/debugger/views/nameview.r \ + ruamoko/qwaq/debugger/views/pointerview.r\ + ruamoko/qwaq/debugger/views/quatview.r \ + ruamoko/qwaq/debugger/views/stringview.r \ + ruamoko/qwaq/debugger/views/uintview.r \ + ruamoko/qwaq/debugger/views/vectorview.r \ + ruamoko/qwaq/debugger/views/voidview.r \ + ruamoko/qwaq/debugger/debug.r \ + ruamoko/qwaq/debugger/debugger.r \ + ruamoko/qwaq/debugger/localsdata.r \ + ruamoko/qwaq/debugger/typeencodings.r \ + ruamoko/qwaq/editor/editbuffer.r \ + ruamoko/qwaq/editor/editor.r \ + ruamoko/qwaq/ui/button.r \ + ruamoko/qwaq/ui/draw.r \ + ruamoko/qwaq/ui/garray.r \ + ruamoko/qwaq/ui/group.r \ + ruamoko/qwaq/ui/listener.r \ + ruamoko/qwaq/ui/proxyview.r \ + ruamoko/qwaq/ui/rect.r \ + ruamoko/qwaq/ui/scrollbar.r \ + ruamoko/qwaq/ui/tableview.r \ + ruamoko/qwaq/ui/textcontext.r \ + ruamoko/qwaq/ui/titlebar.r \ + ruamoko/qwaq/ui/view.r \ + ruamoko/qwaq/ui/window.r \ + $e + +#FIXME this coupling is horrible +qwaq_curses_libs= \ + libs/video/targets/libvid_common.la \ + libs/console/libQFconsole.la \ + libs/gib/libQFgib.la + +ruamoko_qwaq_qwaq_curses_SOURCES= \ + ruamoko/qwaq/builtins/main.c \ + ruamoko/qwaq/builtins/curses.c \ + ruamoko/qwaq/builtins/debug.c \ + ruamoko/qwaq/builtins/editbuffer.c \ + ruamoko/qwaq/builtins/input.c \ + $e + +ruamoko_qwaq_qwaq_curses_LDADD= $(qwaq_curses_libs) $(QWAQ_LIBS) \ + $(PANEL_LIBS) $(CURSES_LIBS) $(PTHREAD_LDFLAGS) $(DL_LIBS) +ruamoko_qwaq_qwaq_curses_LDFLAGS= +ruamoko_qwaq_qwaq_curses_DEPENDENCIES= $(qwaq_curses_libs) $(QWAQ_DEPS) + +qwaq_cl_plugin_libs= \ + @client_static_plugin_libs@ + +qwaq_client_libs= \ + $(top_builddir)/libs/entity/libQFentity.la \ + $(top_builddir)/libs/console/libQFconsole.la \ + $(top_builddir)/libs/video/targets/libQFjs.la \ + $(top_builddir)/libs/audio/libQFcd.la \ + $(top_builddir)/libs/audio/libQFsound.la \ + $(top_builddir)/libs/image/libQFimage.la + +qwaq_x11_libs= \ + $(qwaq_cl_plugin_libs) \ + $(top_builddir)/libs/video/renderer/libQFrenderer.la \ + $(top_builddir)/libs/models/libQFmodels.la \ + $(top_builddir)/libs/video/targets/libQFx11.la \ + $(qwaq_client_libs) \ + $(top_builddir)/libs/gib/libQFgib.la +ruamoko_qwaq_qwaq_x11_SOURCES=ruamoko/qwaq/builtins/qwaq.c ruamoko/qwaq/builtins/qwaq-bi.c +ruamoko_qwaq_qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \ + $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ + $(X_EXTRA_LIBS) $(X_SHM_LIB) $(DL_LIBS) +ruamoko_qwaq_qwaq_x11_LDFLAGS= +ruamoko_qwaq_qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) + +ruamoko_qwaq_qwaq_app_dat_SOURCES=$(qwaq_app_dat_src) +ruamoko_qwaq_qwaq_app_obj=$(ruamoko_qwaq_qwaq_app_dat_SOURCES:.r=.o) +ruamoko_qwaq_qwaq_app_dep=$(call qcautodep,$(ruamoko_qwaq_qwaq_app_dat_SOURCES:.o=.Qo)) +ruamoko/qwaq/qwaq-app.dat$(EXEEXT): $(ruamoko_qwaq_qwaq_app_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_qwaq_app_obj) -lcsqc -lr +include $(ruamoko_qwaq_qwaq_app_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_qwaq_qwaq_app_dep) + +ruamoko_qwaq_gcd_dat_SOURCES=ruamoko/qwaq/gcd.r +ruamoko_qwaq_gcd_obj=$(ruamoko_qwaq_gcd_dat_SOURCES:.r=.o) +ruamoko_qwaq_gcd_dep=$(call qcautodep,$(ruamoko_qwaq_gcd_dat_SOURCES:.o=.Qo)) +ruamoko/qwaq/gcd.dat$(EXEEXT): $(ruamoko_qwaq_gcd_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_gcd_obj) -lcsqc -lr +include $(ruamoko_qwaq_gcd_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_qwaq_gcd_dep) + +EXTRA_PROGRAMS += ruamoko/qwaq/qwaq-curses ruamoko/qwaq/qwaq-x11 +EXTRA_DIST += \ + $(qwaq_dat_src) \ + ruamoko/qwaq/debugger/debug.h \ + ruamoko/qwaq/debugger/debugger.h \ + ruamoko/qwaq/debugger/localsdata.h \ + ruamoko/qwaq/debugger/typeencodings.h \ + ruamoko/qwaq/debugger/views/basicview.h \ + ruamoko/qwaq/debugger/views/defview.h \ + ruamoko/qwaq/debugger/views/doubleview.h \ + ruamoko/qwaq/debugger/views/entityview.h \ + ruamoko/qwaq/debugger/views/fieldview.h \ + ruamoko/qwaq/debugger/views/floatview.h \ + ruamoko/qwaq/debugger/views/funcview.h \ + ruamoko/qwaq/debugger/views/intview.h \ + ruamoko/qwaq/debugger/views/nameview.h \ + ruamoko/qwaq/debugger/views/pointerview.h \ + ruamoko/qwaq/debugger/views/quatview.h \ + ruamoko/qwaq/debugger/views/stringview.h \ + ruamoko/qwaq/debugger/views/uintview.h \ + ruamoko/qwaq/debugger/views/vectorview.h \ + ruamoko/qwaq/debugger/views/voidview.h \ + ruamoko/qwaq/editor/editbuffer.h \ + ruamoko/qwaq/editor/editor.h \ + ruamoko/qwaq/qwaq-app.h \ + ruamoko/qwaq/qwaq.h \ + ruamoko/qwaq/ui/button.h \ + ruamoko/qwaq/ui/color.h \ + ruamoko/qwaq/ui/curses.h \ + ruamoko/qwaq/ui/draw.h \ + ruamoko/qwaq/ui/event.h \ + ruamoko/qwaq/ui/garray.h \ + ruamoko/qwaq/ui/group.h \ + ruamoko/qwaq/ui/listener.h \ + ruamoko/qwaq/ui/proxyview.h \ + ruamoko/qwaq/ui/rect.h \ + ruamoko/qwaq/ui/scrollbar.h \ + ruamoko/qwaq/ui/tableview.h \ + ruamoko/qwaq/ui/textcontext.h \ + ruamoko/qwaq/ui/titlebar.h \ + ruamoko/qwaq/ui/view.h \ + ruamoko/qwaq/ui/window.h +CLEANFILES += \ + ruamoko/qwaq/qwaq-curses.log \ + ruamoko/qwaq/*.dat \ + ruamoko/qwaq/*.sym diff --git a/tools/qwaq/builtins.c b/ruamoko/qwaq/builtins/builtins.c similarity index 99% rename from tools/qwaq/builtins.c rename to ruamoko/qwaq/builtins/builtins.c index 3976dc330..9f575617c 100644 --- a/tools/qwaq/builtins.c +++ b/ruamoko/qwaq/builtins/builtins.c @@ -42,7 +42,7 @@ #include #include -#include "qwaq.h" +#include "ruamoko/qwaq/qwaq.h" static void bi_print (progs_t *pr) diff --git a/ruamoko/qwaq/builtins/curses.c b/ruamoko/qwaq/builtins/curses.c new file mode 100644 index 000000000..cf4f1ebe3 --- /dev/null +++ b/ruamoko/qwaq/builtins/curses.c @@ -0,0 +1,2046 @@ +/* + curses.c + + Ruamoko ncurses wrapper using threading + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/03/01 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "QF/dstring.h" +#include "QF/progs.h" +#include "QF/ringbuffer.h" +#include "QF/sys.h" + +#include "ruamoko/qwaq/qwaq.h" +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/ui/rect.h" +#include "ruamoko/qwaq/ui/textcontext.h" + +#define always_inline inline __attribute__((__always_inline__)) +#define CMD_SIZE(x) sizeof(x)/sizeof(x[0]) + +typedef enum qwaq_commands_e { + qwaq_cmd_syncprint, + qwaq_cmd_newwin, + qwaq_cmd_delwin, + qwaq_cmd_getwrect, + qwaq_cmd_new_panel, + qwaq_cmd_del_panel, + qwaq_cmd_hide_panel, + qwaq_cmd_show_panel, + qwaq_cmd_top_panel, + qwaq_cmd_bottom_panel, + qwaq_cmd_move_panel, + qwaq_cmd_panel_window, + qwaq_cmd_replace_panel, + qwaq_cmd_update_panels, + qwaq_cmd_doupdate, + qwaq_cmd_mvwaddstr, + qwaq_cmd_waddstr, + qwaq_cmd_mvwaddch, + qwaq_cmd_waddch, + qwaq_cmd_wrefresh, + qwaq_cmd_init_pair, + qwaq_cmd_wbkgd, + qwaq_cmd_werase, + qwaq_cmd_scrollok, + qwaq_cmd_move, + qwaq_cmd_curs_set, + qwaq_cmd_wborder, + qwaq_cmd_mvwblit_line, + qwaq_cmd_wresize, + qwaq_cmd_resizeterm, + qwaq_cmd_mvwhline, + qwaq_cmd_mvwvline, +} qwaq_commands; + +static const char *qwaq_command_names[]= { + "syncprint", + "newwin", + "delwin", + "getwrect", + "new_panel", + "del_panel", + "hide_panel", + "show_panel", + "top_panel", + "bottom_panel", + "move_panel", + "panel_window", + "replace_panel", + "update_panels", + "doupdate", + "mvwaddstr", + "waddstr", + "mvwaddch", + "waddch", + "wrefresh", + "init_pair", + "wbkgd", + "werase", + "scrollok", + "move", + "curs_set", + "wborder", + "mvwblit_line", + "wresize", + "resizeterm", + "mvwhline", + "mvwvline", +}; + +static window_t * +window_new (qwaq_resources_t *res) +{ + return PR_RESNEW (res->window_map); +} + +static void +window_free (qwaq_resources_t *res, window_t *win) +{ + PR_RESFREE (res->window_map, win); +} + +static void +window_reset (qwaq_resources_t *res) +{ + PR_RESRESET (res->window_map); +} + +static inline window_t * +window_get (qwaq_resources_t *res, unsigned index) +{ + return PR_RESGET(res->window_map, index); +} + +static inline int __attribute__((pure)) +window_index (qwaq_resources_t *res, window_t *win) +{ + return PR_RESINDEX (res->window_map, win); +} + +static always_inline window_t * __attribute__((pure)) +get_window (qwaq_resources_t *res, const char *name, int handle) +{ + if (handle == 1) { + return &res->stdscr; + } + + window_t *window = window_get (res, handle); + + if (!window || !window->win) { + PR_RunError (res->pr, "invalid window %d passed to %s", + handle, name + 5); + } + return window; +} + +static panel_t * +panel_new (qwaq_resources_t *res) +{ + return PR_RESNEW (res->panel_map); +} + +static void +panel_free (qwaq_resources_t *res, panel_t *win) +{ + PR_RESFREE (res->panel_map, win); +} + +static void +panel_reset (qwaq_resources_t *res) +{ + PR_RESRESET (res->panel_map); +} + +static inline panel_t * +panel_get (qwaq_resources_t *res, unsigned index) +{ + return PR_RESGET(res->panel_map, index); +} + +static inline int __attribute__((pure)) +panel_index (qwaq_resources_t *res, panel_t *win) +{ + return PR_RESINDEX (res->panel_map, win); +} + +static always_inline panel_t * __attribute__((pure)) +get_panel (qwaq_resources_t *res, const char *name, int handle) +{ + panel_t *panel = panel_get (res, handle); + + if (!panel || !panel->panel) { + PR_RunError (res->pr, "invalid panel passed to %s", name + 3); + } + return panel; +} + +static int +acquire_string (qwaq_resources_t *res) +{ + int string_id = -1; + + pthread_mutex_lock (&res->string_id_cond.mut); + while (RB_DATA_AVAILABLE (res->string_ids) < 1) { + pthread_cond_wait (&res->string_id_cond.rcond, + &res->string_id_cond.mut); + } + RB_READ_DATA (res->string_ids, &string_id, 1); + pthread_cond_broadcast (&res->string_id_cond.wcond); + pthread_mutex_unlock (&res->string_id_cond.mut); + return string_id; +} + +static void +release_string (qwaq_resources_t *res, int string_id) +{ + pthread_mutex_lock (&res->string_id_cond.mut); + while (RB_SPACE_AVAILABLE (res->string_ids) < 1) { + pthread_cond_wait (&res->string_id_cond.wcond, + &res->string_id_cond.mut); + } + RB_WRITE_DATA (res->string_ids, &string_id, 1); + pthread_cond_broadcast (&res->string_id_cond.rcond); + pthread_mutex_unlock (&res->string_id_cond.mut); +} + +static void +qwaq_submit_command (qwaq_resources_t *res, const int *cmd) +{ + unsigned len = cmd[1]; + + pthread_mutex_lock (&res->command_cond.mut); + while (RB_SPACE_AVAILABLE (res->command_queue) < len) { + pthread_cond_wait (&res->command_cond.wcond, + &res->command_cond.mut); + } + RB_WRITE_DATA (res->command_queue, cmd, len); + pthread_cond_broadcast (&res->command_cond.rcond); + pthread_mutex_unlock (&res->command_cond.mut); +} + +static void +qwaq_submit_result (qwaq_resources_t *res, const int *result, unsigned len) +{ + pthread_mutex_lock (&res->results_cond.mut); + while (RB_SPACE_AVAILABLE (res->results) < len) { + pthread_cond_wait (&res->results_cond.wcond, + &res->results_cond.mut); + } + RB_WRITE_DATA (res->results, result, len); + pthread_cond_broadcast (&res->results_cond.rcond); + pthread_mutex_unlock (&res->results_cond.mut); +} + +static void +qwaq_wait_result (qwaq_resources_t *res, int *result, int cmd, unsigned len) +{ + pthread_mutex_lock (&res->results_cond.mut); + while (RB_DATA_AVAILABLE (res->results) < len + || *RB_PEEK_DATA (res->results, 0) != cmd) { + pthread_cond_wait (&res->results_cond.rcond, + &res->results_cond.mut); + } + RB_READ_DATA (res->results, result, len); + pthread_cond_broadcast (&res->results_cond.wcond); + pthread_mutex_unlock (&res->results_cond.mut); +} + +static void +cmd_syncprint (qwaq_resources_t *res) +{ + int string_id = *RB_PEEK_DATA (res->command_queue, 2); + + Sys_Printf ("%s\n", res->strings[string_id].str); + release_string (res, string_id); +} + +static void +cmd_newwin (qwaq_resources_t *res) +{ + int xpos = *RB_PEEK_DATA (res->command_queue, 2); + int ypos = *RB_PEEK_DATA (res->command_queue, 3); + int xlen = *RB_PEEK_DATA (res->command_queue, 4); + int ylen = *RB_PEEK_DATA (res->command_queue, 5); + + window_t *window = window_new (res); + window->win = newwin (ylen, xlen, ypos, xpos); + keypad (window->win, FALSE); // do it ourselves + + int window_id = window_index (res, window); + int cmd_result[] = { qwaq_cmd_newwin, window_id }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_delwin (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + delwin (window->win); + window_free (res, window); +} + +static void +cmd_getwrect (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int xpos, ypos; + int xlen, ylen; + + window_t *window = get_window (res, __FUNCTION__, window_id); + getparyx (window->win, ypos, xpos); + if (xpos == -1 && ypos ==-1) { + getbegyx (window->win, ypos, xpos); + } + getmaxyx (window->win, ylen, xlen); + + int cmd_result[] = { qwaq_cmd_getwrect, xpos, ypos, xlen, ylen }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_new_panel (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + panel_t *panel = panel_new (res); + panel->panel = new_panel (window->win); + panel->window_id = window_id; + + int panel_id = panel_index (res, panel); + int cmd_result[] = { qwaq_cmd_new_panel, panel_id }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_del_panel (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + del_panel (panel->panel); + panel_free (res, panel); +} + +static void +cmd_hide_panel (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + hide_panel (panel->panel); +} + +static void +cmd_show_panel (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + show_panel (panel->panel); +} + +static void +cmd_top_panel (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + top_panel (panel->panel); +} + +static void +cmd_bottom_panel (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + bottom_panel (panel->panel); +} + +static void +cmd_move_panel (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + move_panel (panel->panel, y, x); +} + +static void +cmd_panel_window (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + + int window_id = panel->window_id; + int cmd_result[] = { qwaq_cmd_panel_window, window_id, }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_replace_panel (qwaq_resources_t *res) +{ + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + int window_id = *RB_PEEK_DATA (res->command_queue, 3); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + window_t *window = get_window (res, __FUNCTION__, window_id); + + replace_panel (panel->panel, window->win); +} + +static void +cmd_update_panels (qwaq_resources_t *res) +{ + update_panels (); +} + +static void +cmd_doupdate (qwaq_resources_t *res) +{ + doupdate (); +} + +static void +cmd_mvwaddstr (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int string_id = *RB_PEEK_DATA (res->command_queue, 5); + + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwaddstr (window->win, y, x, res->strings[string_id].str); + release_string (res, string_id); +} + +static void +cmd_waddstr (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int string_id = *RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + waddstr (window->win, res->strings[string_id].str); + release_string (res, string_id); +} + +static void +cmd_mvwaddch (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int ch = *RB_PEEK_DATA (res->command_queue, 5); + + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwaddch (window->win, y, x, ch); +} + +static void +cmd_waddch (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int ch = *RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + waddch (window->win, ch); +} + +static void +cmd_wrefresh (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wrefresh (window->win); +} + +static void +cmd_init_pair (qwaq_resources_t *res) +{ + int pair = *RB_PEEK_DATA (res->command_queue, 2); + int f = *RB_PEEK_DATA (res->command_queue, 3); + int b = *RB_PEEK_DATA (res->command_queue, 4); + + init_pair (pair, f, b); +} + +static void +cmd_wbkgd (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int ch = *RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wbkgd (window->win, ch); +} + +static void +cmd_werase (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + werase (window->win); +} + +static void +cmd_scrollok (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int flag = *RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + scrollok (window->win, flag); +} + +static void +cmd_move (qwaq_resources_t *res) +{ + int x = *RB_PEEK_DATA (res->command_queue, 2); + int y = *RB_PEEK_DATA (res->command_queue, 3); + + move (y, x); +} + +static void +cmd_curs_set (qwaq_resources_t *res) +{ + int visibility = *RB_PEEK_DATA (res->command_queue, 2); + + curs_set (visibility); +} + +static void +cmd_wborder (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int ls = *RB_PEEK_DATA (res->command_queue, 3); + int rs = *RB_PEEK_DATA (res->command_queue, 4); + int ts = *RB_PEEK_DATA (res->command_queue, 5); + int bs = *RB_PEEK_DATA (res->command_queue, 6); + int tl = *RB_PEEK_DATA (res->command_queue, 7); + int tr = *RB_PEEK_DATA (res->command_queue, 8); + int bl = *RB_PEEK_DATA (res->command_queue, 9); + int br = *RB_PEEK_DATA (res->command_queue, 10); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wborder (window->win, ls, rs, ts, bs, tl, tr, bl, br); +} + +static void +cmd_mvwblit_line (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int chs_id = *RB_PEEK_DATA (res->command_queue, 5); + int len = *RB_PEEK_DATA (res->command_queue, 6); + int *chs = (int *) res->strings[chs_id].str; + int save_x; + int save_y; + + window_t *window = get_window (res, __FUNCTION__, window_id); + getyx (window->win, save_y, save_x); + for (int i = 0; i < len; i++) { + if (chs[i] & 0xff) { + mvwaddch (window->win, y, x + i, chs[i]); + } + } + wmove (window->win, save_y, save_x); + release_string (res, chs_id); +} + +static void +cmd_wresize (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int width = *RB_PEEK_DATA (res->command_queue, 3); + int height = *RB_PEEK_DATA (res->command_queue, 4); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wresize (window->win, height, width); +} + +static void +cmd_resizeterm (qwaq_resources_t *res) +{ + int width = *RB_PEEK_DATA (res->command_queue, 2); + int height = *RB_PEEK_DATA (res->command_queue, 3); + + resizeterm (height, width); +} + +static void +cmd_mvwhline (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int ch = *RB_PEEK_DATA (res->command_queue, 5); + int n = *RB_PEEK_DATA (res->command_queue, 6); + + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwhline (window->win, y, x, ch, n); +} + +static void +cmd_mvwvline (qwaq_resources_t *res) +{ + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int ch = *RB_PEEK_DATA (res->command_queue, 5); + int n = *RB_PEEK_DATA (res->command_queue, 6); + + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwvline (window->win, y, x, ch, n); +} + +static void +dump_command (qwaq_resources_t *res, int len) +{ + if (0) { + qwaq_commands cmd = *RB_PEEK_DATA (res->command_queue, 0); + Sys_Printf ("%s[%d]", qwaq_command_names[cmd], len); + if (cmd == qwaq_cmd_syncprint) { + Sys_Printf (" "); + } else { + for (int i = 2; i < len; i++) { + Sys_Printf (" %d", *RB_PEEK_DATA (res->command_queue, i)); + } + Sys_Printf ("\n"); + } + } +} + +void +qwaq_init_timeout (struct timespec *timeout, long time) +{ + #define SEC 1000000000L + struct timeval now; + gettimeofday(&now, 0); + timeout->tv_sec = now.tv_sec; + timeout->tv_nsec = now.tv_usec * 1000L + time; + if (timeout->tv_nsec >= SEC) { + timeout->tv_sec += timeout->tv_nsec / SEC; + timeout->tv_nsec %= SEC; + } +} + +static void +process_commands (qwaq_resources_t *res) +{ + struct timespec timeout; + int avail; + int len; + int ret = 0; + + pthread_mutex_lock (&res->command_cond.mut); + qwaq_init_timeout (&timeout, 20 * 1000000); + while (RB_DATA_AVAILABLE (res->command_queue) < 2 && ret == 0) { + ret = pthread_cond_timedwait (&res->command_cond.rcond, + &res->command_cond.mut, &timeout); + } + // The mutex is unlocked at the top of the loop and locked again + // (for broadcast) at the bottom, then finally unlocked after the loop. + // It should be only the data availability check that's not threadsafe + // as the mutex is not released until after the data has been written to + // the buffer. + while ((avail = RB_DATA_AVAILABLE (res->command_queue)) >= 2 + && avail >= (len = *RB_PEEK_DATA (res->command_queue, 1))) { + pthread_mutex_unlock (&res->command_cond.mut); + dump_command (res, len); + qwaq_commands cmd = *RB_PEEK_DATA (res->command_queue, 0); + switch (cmd) { + case qwaq_cmd_syncprint: + cmd_syncprint (res); + break; + case qwaq_cmd_newwin: + cmd_newwin (res); + break; + case qwaq_cmd_delwin: + cmd_delwin (res); + break; + case qwaq_cmd_getwrect: + cmd_getwrect (res); + break; + case qwaq_cmd_new_panel: + cmd_new_panel (res); + break; + case qwaq_cmd_del_panel: + cmd_del_panel (res); + break; + case qwaq_cmd_hide_panel: + cmd_hide_panel (res); + break; + case qwaq_cmd_show_panel: + cmd_show_panel (res); + break; + case qwaq_cmd_top_panel: + cmd_top_panel (res); + break; + case qwaq_cmd_bottom_panel: + cmd_bottom_panel (res); + break; + case qwaq_cmd_move_panel: + cmd_move_panel (res); + break; + case qwaq_cmd_panel_window: + cmd_panel_window (res); + break; + case qwaq_cmd_replace_panel: + cmd_replace_panel (res); + break; + case qwaq_cmd_update_panels: + cmd_update_panels (res); + break; + case qwaq_cmd_doupdate: + cmd_doupdate (res); + break; + case qwaq_cmd_mvwaddstr: + cmd_mvwaddstr (res); + break; + case qwaq_cmd_waddstr: + cmd_waddstr (res); + break; + case qwaq_cmd_mvwaddch: + cmd_mvwaddch (res); + break; + case qwaq_cmd_waddch: + cmd_waddch (res); + break; + case qwaq_cmd_wrefresh: + cmd_wrefresh (res); + break; + case qwaq_cmd_init_pair: + cmd_init_pair (res); + break; + case qwaq_cmd_wbkgd: + cmd_wbkgd (res); + break; + case qwaq_cmd_werase: + cmd_werase (res); + break; + case qwaq_cmd_scrollok: + cmd_scrollok (res); + break; + case qwaq_cmd_move: + cmd_move (res); + break; + case qwaq_cmd_curs_set: + cmd_curs_set (res); + break; + case qwaq_cmd_wborder: + cmd_wborder (res); + break; + case qwaq_cmd_mvwblit_line: + cmd_mvwblit_line (res); + break; + case qwaq_cmd_wresize: + cmd_wresize (res); + break; + case qwaq_cmd_resizeterm: + cmd_resizeterm (res); + break; + case qwaq_cmd_mvwhline: + cmd_mvwhline (res); + break; + case qwaq_cmd_mvwvline: + cmd_mvwvline (res); + break; + } + pthread_mutex_lock (&res->command_cond.mut); + RB_RELEASE (res->command_queue, len); + pthread_cond_broadcast (&res->command_cond.wcond); + // unlocked at top of top if there's more data, otherwise just after + // the loop + } + pthread_mutex_unlock (&res->command_cond.mut); +} + +static int +get_event (qwaq_resources_t *res, qwaq_event_t *event) +{ + struct timespec timeout; + int ret = 0; + int was_event = 0; + + pthread_mutex_lock (&res->event_cond.mut); + qwaq_init_timeout (&timeout, 20 * 1000000); + while (RB_DATA_AVAILABLE (res->event_queue) < 1 && ret == 0) { + ret = pthread_cond_timedwait (&res->event_cond.rcond, + &res->event_cond.mut, &timeout); + } + if (event) { + if (ret == 0) { + RB_READ_DATA (res->event_queue, event, 1); + was_event = 1; + } else if (res->button_state) { + event->what = qe_mouseauto; + event->when = Sys_DoubleTime (); + event->mouse.buttons = res->button_state; + event->mouse.x = res->mouse_x; + event->mouse.y = res->mouse_y; + } else { + event->what = qe_none; + } + } + pthread_cond_broadcast (&res->event_cond.wcond); + pthread_mutex_unlock (&res->event_cond.mut); + return was_event; +} + +static int need_endwin; +static void +bi_shutdown (void *_pr) +{ + __auto_type pr = (progs_t *) _pr; + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (need_endwin) { + qwaq_input_shutdown (res); + endwin (); + } +} + +static void +bi_syncprintf (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + const char *fmt = P_GSTRING (pr, 0); + int count = pr->pr_argc - 1; + pr_type_t **args = pr->pr_params + 1; + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { qwaq_cmd_syncprint, 0, string_id }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "mvwaddstr", fmt, count, args); + + qwaq_submit_command (res, command); +} + +static void +bi_newwin (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int xpos = P_INT (pr, 0); + int ypos = P_INT (pr, 1); + int xlen = P_INT (pr, 2); + int ylen = P_INT (pr, 3); + int command[] = { + qwaq_cmd_newwin, 0, + xpos, ypos, xlen, ylen, + }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_newwin, CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; +} + +static void +bi_delwin (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_delwin, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + +static void +qwaq_getwrect (progs_t *pr, int window_id) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_getwrect, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[5]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_getwrect, + CMD_SIZE (cmd_result)); + // return xpos, ypos, xlen, ylen + (&R_INT (pr))[0] = cmd_result[1]; + (&R_INT (pr))[1] = cmd_result[2]; + (&R_INT (pr))[2] = cmd_result[3]; + (&R_INT (pr))[3] = cmd_result[4]; + } +} +static void +bi_getwrect (progs_t *pr) +{ + qwaq_getwrect (pr, P_INT (pr, 0)); +} + +static void +bi_new_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_new_panel, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_new_panel, + CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; + } +} + +static void +panel_command (progs_t *pr, qwaq_commands cmd) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { cmd, 0, panel_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + +static void +bi_del_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_del_panel); +} + +static void +bi_hide_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_hide_panel); +} + +static void +bi_show_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_show_panel); +} + +static void +bi_top_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_top_panel); +} + +static void +bi_bottom_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_bottom_panel); +} + +static void +bi_move_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { qwaq_cmd_move_panel, 0, panel_id, x, y, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + +static void +bi_panel_window (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { qwaq_cmd_panel_window, 0, panel_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_panel_window, + CMD_SIZE (cmd_result)); + (&R_INT (pr))[0] = cmd_result[1]; + } +} + +static void +bi_replace_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + int window_id = P_INT (pr, 1); + + if (get_panel (res, __FUNCTION__, panel_id) + && get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_replace_panel, 0, + panel_id, window_id}; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + +static void +qwaq_update_panels (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_update_panels, 0, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_update_panels (progs_t *pr) +{ + qwaq_update_panels (pr); +} + +static void +qwaq_doupdate (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_doupdate, 0, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_doupdate (progs_t *pr) +{ + qwaq_doupdate (pr); +} + +static void +qwaq_waddstr (progs_t *pr, int window_id, const char *str) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_copystr (print_buffer, str); + qwaq_submit_command (res, command); + } +} +static void +bi_waddstr (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *str = P_GSTRING (pr, 1); + + qwaq_waddstr (pr, window_id, str); +} + +static void +qwaq_wresize (progs_t *pr, int window_id, int width, int height) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { + qwaq_cmd_wresize, 0, + window_id, width, height + }; + + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_wresize (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int width = P_INT (pr, 1); + int height = P_INT (pr, 2); + + qwaq_wresize (pr, window_id, width, height); +} + +static void +qwaq_resizeterm (progs_t *pr, int width, int height) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_resizeterm, 0, width, height }; + + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_resizeterm (progs_t *pr) +{ + int width = P_INT (pr, 0); + int height = P_INT (pr, 1); + + qwaq_resizeterm (pr, width, height); +} + +static void +qwaq_mvwhline (progs_t *pr, int window_id, int x, int y, int ch, int n) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { + qwaq_cmd_mvwhline, 0, + window_id, x, y, ch, n + }; + + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_mvwhline (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int ch = P_INT (pr, 3); + int n = P_INT (pr, 4); + + qwaq_mvwhline (pr, window_id, x, y, ch, n); +} + +static void +qwaq_mvwvline (progs_t *pr, int window_id, int x, int y, int ch, int n) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { + qwaq_cmd_mvwvline, 0, + window_id, x, y, ch, n + }; + + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_mvwvline (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int ch = P_INT (pr, 3); + int n = P_INT (pr, 4); + + qwaq_mvwvline (pr, window_id, x, y, ch, n); +} + +static void +qwaq_mvwaddstr (progs_t *pr, int window_id, int x, int y, const char *str) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_copystr (print_buffer, str); + qwaq_submit_command (res, command); + } +} +static void +bi_mvwaddstr (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *str = P_GSTRING (pr, 3); + + qwaq_mvwaddstr (pr, window_id, x, y, str); +} + +static void +qwaq_mvwprintf (progs_t *pr, int window_id, int x, int y, const char *fmt, + int count, pr_type_t **args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "mvwaddstr", fmt, count, args); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + qwaq_mvwprintf (pr, window_id, x, y, fmt, count, args); +} + +static void +qwaq_wprintf (progs_t *pr, int window_id, const char *fmt, + int count, pr_type_t **args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, count, args); + + qwaq_submit_command (res, command); + } +} +static void +bi_wprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *fmt = P_GSTRING (pr, 1); + int count = pr->pr_argc - 2; + pr_type_t **args = pr->pr_params + 2; + + qwaq_wprintf (pr, window_id, fmt, count, args); +} + +static void +qwaq_wvprintf (progs_t *pr, int window_id, const char *fmt, pr_va_list_t *args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, args->count, list); + + qwaq_submit_command (res, command); + } +} +static void +bi_wvprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *fmt = P_GSTRING (pr, 1); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 2); + + qwaq_wvprintf (pr, window_id, fmt, args); +} + +static void +qwaq_waddch (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_waddch, 0, window_id, ch }; + + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_waddch (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 0); + + qwaq_waddch (pr, window_id, ch); +} + +static void +qwaq_mvwvprintf (progs_t *pr, int window_id, int x, int y, + const char *fmt, pr_va_list_t *args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, args->count, list); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwvprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *fmt = P_GSTRING (pr, 2); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 3); + + qwaq_mvwvprintf (pr, window_id, x, y, fmt, args); +} + +static void +qwaq_mvwaddch (progs_t *pr, int window_id, int x, int y, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { + qwaq_cmd_mvwaddch, 0, + window_id, x, y, ch + }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_mvwaddch (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int ch = P_INT (pr, 3); + + qwaq_mvwaddch (pr, window_id, x, y, ch); +} + +static void +qwaq_wrefresh (progs_t *pr, int window_id) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wrefresh, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_wrefresh (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + + qwaq_wrefresh (pr, window_id); +} + +static void +bi_get_event (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + qwaq_event_t *event = &G_STRUCT (pr, qwaq_event_t, P_INT (pr, 0)); + + R_INT (pr) = get_event (res, event); +} + +static void +bi_max_colors (progs_t *pr) +{ + R_INT (pr) = COLORS; +} + +static void +bi_max_color_pairs (progs_t *pr) +{ + R_INT (pr) = COLOR_PAIRS; +} + +static void +qwaq_init_pair (progs_t *pr, int pair, int f, int b) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_init_pair, 0, pair, f, b, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_init_pair (progs_t *pr) +{ + int pair = P_INT (pr, 0); + int f = P_INT (pr, 1); + int b = P_INT (pr, 2); + + qwaq_init_pair (pr, pair, f, b); +} + +static void +qwaq_wbkgd (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wbkgd, 0, window_id, ch, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_wbkgd (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 1); + + qwaq_wbkgd (pr, window_id, ch); +} + +static void +qwaq_werase (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_werase, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_werase (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 1); + + qwaq_werase (pr, window_id, ch); +} + +static void +qwaq_scrollok (progs_t *pr, int window_id, int flag) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_scrollok, 0, window_id, flag, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_scrollok (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int flag = P_INT (pr, 1); + + qwaq_scrollok (pr, window_id, flag); +} + +static const char qwaq_acs_char_map[] = "lmkjtuvwqxnos`afg~,+.-hi0pryz{|}"; +static void +qwaq_acs_char (progs_t *pr, unsigned acs) +{ + if (acs < 256) { + R_INT (pr) = NCURSES_ACS(acs); + } else if (acs - 256 < sizeof (qwaq_acs_char_map)) { + R_INT (pr) = NCURSES_ACS(qwaq_acs_char_map[acs - 256]); + } else { + R_INT (pr) = 0; + } +} +static void +bi_acs_char (progs_t *pr) +{ + int acs = P_INT (pr, 0); + + qwaq_acs_char (pr, acs); +} + +static void +qwaq_move (progs_t *pr, int x, int y) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_move, 0, x, y, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_move (progs_t *pr) +{ + int x = P_INT (pr, 0); + int y = P_INT (pr, 1); + + qwaq_move (pr, x, y); +} + +static void +qwaq_curs_set (progs_t *pr, int visibility) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_curs_set, 0, visibility, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_curs_set (progs_t *pr) +{ + int visibility = P_INT (pr, 0); + + qwaq_curs_set (pr, visibility); +} + +static void +qwaq_wborder (progs_t *pr, int window_id, + box_sides_t sides, box_corners_t corns) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wborder, 0, window_id, + sides.ls, sides.rs, sides.ts, sides.bs, + corns.tl, corns.tr, corns.bl, corns.br, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_wborder (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + __auto_type sides = P_PACKED (pr, box_sides_t, 1); + __auto_type corns = P_PACKED (pr, box_corners_t, 2); + + qwaq_wborder (pr, window_id, sides, corns); +} + +static void +qwaq__mvwblit_line (progs_t *pr, int window_id, int x, int y, + int *chs, int len) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int chs_id = acquire_string (res); + dstring_t *chs_buf = res->strings + chs_id; + int command[] = { qwaq_cmd_mvwblit_line, 0, window_id, + x, y, chs_id, len,}; + + command[1] = CMD_SIZE(command); + + chs_buf->size = len * sizeof (int); + dstring_adjust (chs_buf); + memcpy (chs_buf->str, chs, len * sizeof (int)); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwblit_line (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int *chs = (int *) P_GPOINTER (pr, 3); + int len = P_INT (pr, 4); + qwaq__mvwblit_line (pr, window_id, x, y, chs, len); +} + +static void * +qwaq_curses_thread (qwaq_thread_t *thread) +{ + qwaq_resources_t *res = thread->data; + + while (1) { + process_commands (res); + qwaq_process_input (res); + } + thread->return_code = 0; + return thread; +} + +static void +bi_initialize (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + initscr (); + need_endwin = 1; + res->initialized = 1; + start_color (); + raw (); + keypad (stdscr, FALSE); // do it ourselves + noecho (); + nonl (); + nodelay (stdscr, TRUE); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); + qwaq_input_init (res); + refresh(); + + res->stdscr.win = stdscr; + + create_thread (qwaq_curses_thread, res); +} + +static void +bi_c_TextContext__is_initialized (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + R_INT (pr) = res->initialized; +} + +static void +bi_c_TextContext__max_colors (progs_t *pr) +{ + bi_max_colors (pr); +} + +static void +bi_c_TextContext__max_color_pairs (progs_t *pr) +{ + bi_max_color_pairs (pr); +} + +static void +bi_c_TextContext__init_pair_ (progs_t *pr) +{ + int pair = P_INT (pr, 2); + int f = P_INT (pr, 3); + int b = P_INT (pr, 4); + + qwaq_init_pair (pr, pair, f, b); +} + +static void +bi_c_TextContext__acs_char_ (progs_t *pr) +{ + int acs = P_INT (pr, 2); + + qwaq_acs_char (pr, acs); +} + +static void +bi_c_TextContext__move_ (progs_t *pr) +{ + Point *pos = &P_PACKED (pr, Point, 2); + + qwaq_move (pr, pos->x, pos->y); +} + +static void +bi_c_TextContext__curs_set_ (progs_t *pr) +{ + int visibility = P_INT (pr, 2); + + qwaq_curs_set (pr, visibility); +} + +static void +bi_c_TextContext__doupdate (progs_t *pr) +{ + bi_doupdate (pr); +} + +static void +bi_i_TextContext__mvprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + qwaq_mvwprintf (pr, window_id, pos->x, pos->y, fmt, count, args); +} + +static void +bi_i_TextContext__printf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *fmt = P_GSTRING (pr, 2); + int count = pr->pr_argc - 3; + pr_type_t **args = pr->pr_params + 3; + + qwaq_wprintf (pr, window_id, fmt, count, args); +} + +static void +bi_i_TextContext__vprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *fmt = P_GSTRING (pr, 2); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 3); + + qwaq_wvprintf (pr, window_id, fmt, args); +} + +static void +bi_i_TextContext__addch_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int ch = P_INT (pr, 2); + + qwaq_waddch (pr, window_id, ch); +} + +static void +bi_i_TextContext__addstr_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *str = P_GSTRING (pr, 2); + + qwaq_waddstr (pr, window_id, str); +} + +static void +bi_i_TextContext__mvvprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *fmt = P_GSTRING (pr, 3); + __auto_type args = &P_PACKED (pr, pr_va_list_t, 4); + + qwaq_mvwvprintf (pr, window_id, pos->x, pos->y, fmt, args); +} + +static void +bi_i_TextContext__resizeTo_ (progs_t *pr) +{ + __auto_type self = &P_STRUCT (pr, qwaq_textcontext_t, 0); + int window_id = self->window; + + self->size = P_PACKED (pr, Extent, 2); + qwaq_wresize (pr, window_id, self->size.width, self->size.height); + if (window_id == 1) { + qwaq_wbkgd (pr, window_id, self->background); + } +} + +static void +bi_c_TextContext__refresh (progs_t *pr) +{ + qwaq_update_panels (pr); + qwaq_doupdate (pr); +} + +static void +bi_i_TextContext__refresh (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + + //qwaq_wrefresh (pr, window_id); + qwaq_update_panels (pr); + if (window_id == 1) { + qwaq_doupdate (pr); + } +} + +static void +bi_i_TextContext__mvaddch_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + int ch = P_INT (pr, 3); + + qwaq_mvwaddch (pr, window_id, pos->x, pos->y, ch); +} + +static void +bi_i_TextContext__mvaddstr_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *str = P_GSTRING (pr, 3); + + qwaq_mvwaddstr (pr, window_id, pos->x, pos->y, str); +} + +static void +bi_i_TextContext__bkgd_ (progs_t *pr) +{ + __auto_type self = &P_STRUCT (pr, qwaq_textcontext_t, 0); + int window_id = self->window; + int ch = P_INT (pr, 2); + + self->background = ch; + qwaq_wbkgd (pr, window_id, ch); +} + +static void +bi_i_TextContext__clear (progs_t *pr) +{ + __auto_type self = &P_STRUCT (pr, qwaq_textcontext_t, 0); + int window_id = self->window; + int ch = self->background; + + qwaq_werase (pr, window_id, ch); +} + +static void +bi_i_TextContext__scrollok_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int flag = P_INT (pr, 2); + + qwaq_scrollok (pr, window_id, flag); +} + +static void +bi_i_TextContext__border_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + __auto_type sides = P_PACKED (pr, box_sides_t, 2); + __auto_type corns = P_PACKED (pr, box_corners_t, 3); + + qwaq_wborder (pr, window_id, sides, corns); +} + +static void +bi_i_TextContext__mvhline_ (progs_t *pr) +{ + __auto_type self = &P_STRUCT (pr, qwaq_textcontext_t, 0); + int window_id = self->window; + __auto_type pos = &P_PACKED (pr, Point, 2); + int ch = P_INT (pr, 3); + int n = P_INT (pr, 4); + + qwaq_mvwhline (pr, window_id, pos->x, pos->y, ch, n); +} + +static void +bi_i_TextContext__mvvline_ (progs_t *pr) +{ + __auto_type self = &P_STRUCT (pr, qwaq_textcontext_t, 0); + int window_id = self->window; + __auto_type pos = &P_PACKED (pr, Point, 2); + int ch = P_INT (pr, 3); + int n = P_INT (pr, 4); + + qwaq_mvwvline (pr, window_id, pos->x, pos->y, ch, n); +} + +static void +bi_qwaq_clear (progs_t *pr, void *data) +{ + __auto_type res = (qwaq_resources_t *) data; + + if (res->initialized) { + qwaq_input_shutdown (res); + endwin (); + } + need_endwin = 0; + window_reset (res); + panel_reset (res); +} + +static builtin_t builtins[] = { + {"initialize", bi_initialize, -1}, + {"syncprintf", bi_syncprintf, -1}, + {"create_window", bi_newwin, -1}, + {"destroy_window", bi_delwin, -1}, + {"getwrect", bi_getwrect, -1}, + {"create_panel", bi_new_panel, -1}, + {"destroy_panel", bi_del_panel, -1}, + {"hide_panel", bi_hide_panel, -1}, + {"show_panel", bi_show_panel, -1}, + {"top_panel", bi_top_panel, -1}, + {"bottom_panel", bi_bottom_panel, -1}, + {"move_panel", bi_move_panel, -1}, + {"panel_window", bi_panel_window, -1}, + {"replace_panel", bi_replace_panel, -1}, + {"update_panels", bi_update_panels, -1}, + {"doupdate", bi_doupdate, -1}, + {"mvwprintf", bi_mvwprintf, -1}, + {"wprintf", bi_wprintf, -1}, + {"wvprintf", bi_wvprintf, -1}, + {"mvwvprintf", bi_mvwvprintf, -1}, + {"mvwaddch", bi_mvwaddch, -1}, + {"waddch", bi_waddch, -1}, + {"mvwaddstr", bi_mvwaddstr, -1}, + {"waddstr", bi_waddstr, -1}, + {"wrefresh", bi_wrefresh, -1}, + {"get_event", bi_get_event, -1}, + {"max_colors", bi_max_colors, -1}, + {"max_color_pairs", bi_max_color_pairs, -1}, + {"init_pair", bi_init_pair, -1}, + {"wbkgd", bi_wbkgd, -1}, + {"werase", bi_werase, -1}, + {"scrollok", bi_scrollok, -1}, + {"acs_char", bi_acs_char, -1}, + {"move", bi_move, -1}, + {"curs_set", bi_curs_set, -1}, + {"wborder", bi_wborder, -1}, + {"mvwblit_line", bi_mvwblit_line, -1}, + {"wresize", bi_wresize, -1}, + {"resizeterm", bi_resizeterm, -1}, + {"mvwhline", bi_mvwhline, -1}, + {"mvwvline", bi_mvwvline, -1}, + + {"_c_TextContext__is_initialized", bi_c_TextContext__is_initialized, -1}, + {"_c_TextContext__max_colors", bi_c_TextContext__max_colors, -1}, + {"_c_TextContext__max_color_pairs", bi_c_TextContext__max_color_pairs, -1}, + {"_c_TextContext__init_pair_", bi_c_TextContext__init_pair_, -1}, + {"_c_TextContext__acs_char_", bi_c_TextContext__acs_char_, -1}, + {"_c_TextContext__move_", bi_c_TextContext__move_, -1}, + {"_c_TextContext__curs_set_", bi_c_TextContext__curs_set_, -1}, + {"_c_TextContext__doupdate", bi_c_TextContext__doupdate, -1}, + {"_i_TextContext__mvprintf_", bi_i_TextContext__mvprintf_, -1}, + {"_i_TextContext__printf_", bi_i_TextContext__printf_, -1}, + {"_i_TextContext__vprintf_", bi_i_TextContext__vprintf_, -1}, + {"_i_TextContext__addch_", bi_i_TextContext__addch_, -1}, + {"_i_TextContext__addstr_", bi_i_TextContext__addstr_, -1}, + {"_i_TextContext__mvvprintf_", bi_i_TextContext__mvvprintf_, -1}, + {"_i_TextContext__resizeTo_", bi_i_TextContext__resizeTo_, -1}, + {"_c_TextContext__refresh", bi_c_TextContext__refresh, -1}, + {"_i_TextContext__refresh", bi_i_TextContext__refresh, -1}, + {"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1}, + {"_i_TextContext__mvaddstr_", bi_i_TextContext__mvaddstr_, -1}, + {"_i_TextContext__bkgd_", bi_i_TextContext__bkgd_, -1}, + {"_i_TextContext__clear", bi_i_TextContext__clear, -1}, + {"_i_TextContext__scrollok_", bi_i_TextContext__scrollok_, -1}, + {"_i_TextContext__border_", bi_i_TextContext__border_, -1}, + {"_i_TextContext__mvhline_", bi_i_TextContext__mvhline_, -1}, + {"_i_TextContext__mvvline_", bi_i_TextContext__mvvline_, -1}, + + {0} +}; + +static FILE *logfile; + +static __attribute__((format(printf, 1, 0))) void +qwaq_print (const char *fmt, va_list args) +{ + vfprintf (logfile, fmt, args); + fflush (logfile); +} + +void +qwaq_init_cond (rwcond_t *cond) +{ + pthread_cond_init (&cond->rcond, 0); + pthread_cond_init (&cond->wcond, 0); + pthread_mutex_init (&cond->mut, 0); +} + +void +BI_Init (progs_t *pr) +{ + qwaq_resources_t *res = calloc (sizeof (*res), 1); + res->pr = pr; + + for (int i = 0; i < STRING_ID_QUEUE_SIZE - 1; i++) { + RB_WRITE_DATA (res->string_ids, &i, 1); + res->strings[i].mem = &dstring_default_mem; + } + res->escbuff.mem = &dstring_default_mem; + // ensure the backing buffer exists + dstring_clearstr (&res->escbuff); + + qwaq_init_cond (&res->event_cond); + qwaq_init_cond (&res->command_cond); + qwaq_init_cond (&res->results_cond); + qwaq_init_cond (&res->string_id_cond); + + PR_Resources_Register (pr, "qwaq", res, bi_qwaq_clear); + PR_RegisterBuiltins (pr, builtins); + Sys_RegisterShutdown (bi_shutdown, pr); + logfile = fopen ("qwaq-curses.log", "wt"); + Sys_SetStdPrintf (qwaq_print); +} diff --git a/ruamoko/qwaq/builtins/debug.c b/ruamoko/qwaq/builtins/debug.c new file mode 100644 index 000000000..a8c56f280 --- /dev/null +++ b/ruamoko/qwaq/builtins/debug.c @@ -0,0 +1,667 @@ +/* + debug.c + + Debugging support + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/03/24 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/keys.h" +#include "QF/quakefs.h" +#include "QF/sys.h" + +#include "ruamoko/qwaq/qwaq.h" +#include "ruamoko/qwaq/ui/event.h" +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/debugger/debug.h" + +typedef struct qwaq_target_s { + progs_t *pr; + struct qwaq_debug_s *debugger; + int handle; + prdebug_t event; + void *param; + rwcond_t run_cond; + int run_command; +} qwaq_target_t; + +typedef struct qwaq_debug_s { + progs_t *pr; + qwaq_resources_t *qwaq; // to communicate with the debugger thread + PR_RESMAP (qwaq_target_t) targets; +} qwaq_debug_t; + +#define always_inline inline __attribute__((__always_inline__)) + +static qwaq_target_t * +target_new (qwaq_debug_t *debug) +{ + return PR_RESNEW (debug->targets); +} + +static void +target_free (qwaq_debug_t *debug, qwaq_target_t *target) +{ + PR_RESFREE (debug->targets, target); +} + +static void +target_reset (qwaq_debug_t *debug) +{ + PR_RESRESET (debug->targets); +} + +static inline qwaq_target_t * +target_get (qwaq_debug_t *debug, unsigned index) +{ + return PR_RESGET (debug->targets, index); +} + +static inline int __attribute__((pure)) +target_index (qwaq_debug_t *debug, qwaq_target_t *target) +{ + return PR_RESINDEX (debug->targets, target); +} + +static always_inline qwaq_target_t * __attribute__((pure)) +get_target (qwaq_debug_t *debug, const char *name, int handle) +{ + qwaq_target_t *target = target_get (debug, handle); + + if (!target || !target->debugger) { + PR_RunError (debug->pr, "invalid target passed to %s", name + 4); + } + return target; +} + +static void +qwaq_debug_handler (prdebug_t debug_event, void *param, void *data) +{ + __auto_type target = (qwaq_target_t *) data; + qwaq_debug_t *debug = target->debugger; + qwaq_event_t event = {}; + int ret; + + target->event = debug_event; + target->param = param; + event.what = qe_debug_event; + event.message.pointer_val = target->handle; + + while ((ret = qwaq_add_event (debug->qwaq, &event)) == ETIMEDOUT) { + // spin + } + if (ret == EINVAL) { + Sys_Error ("event queue broke"); + } + pthread_mutex_lock (&target->run_cond.mut); + while (!target->run_command) { + pthread_cond_wait (&target->run_cond.rcond, &target->run_cond.mut); + } + target->run_command = 0; + pthread_mutex_unlock (&target->run_cond.mut); + if (debug_event == prd_runerror || debug_event == prd_error) { + pthread_exit (param); + } +} + +//FIXME need a better way to get this from one thread to the others +pthread_cond_t debug_data_cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t debug_data_mutex = PTHREAD_MUTEX_INITIALIZER; +static qwaq_debug_t *qwaq_debug_data; + +static int +qwaq_debug_load (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + + pthread_mutex_lock (&debug_data_mutex); + qwaq_debug_data = debug; // FIXME ? see decl + pthread_cond_broadcast (&debug_data_cond); + pthread_mutex_unlock (&debug_data_mutex); + + return 1; +} + +static void +qwaq_debug_clear (progs_t *pr, void *data) +{ + __auto_type debug = (qwaq_debug_t *) data; + target_reset (debug); +} + +static void +qwaq_target_clear (progs_t *pr, void *data) +{ + qwaq_target_t *target = pr->debug_data; + if (target) { + target_free (target->debugger, target); + } +} + +static int +qwaq_target_load (progs_t *pr) +{ + pthread_mutex_lock (&debug_data_mutex); + while (!qwaq_debug_data) { + pthread_cond_wait (&debug_data_cond, &debug_data_mutex); + } + pthread_mutex_unlock (&debug_data_mutex); + + qwaq_target_t *target = target_new (qwaq_debug_data); + target->pr = pr; + target->debugger = qwaq_debug_data; + target->handle = target_index (qwaq_debug_data, target); + qwaq_init_cond (&target->run_cond); + target->run_command = 0; + + pr->debug_handler = qwaq_debug_handler; + pr->debug_data = target; + + // start tracing immediately so the debugger has a chance to start up + // before the target progs begin running + pr->pr_trace = 1; + pr->pr_trace_depth = -1; + + return 1; +} + +static void +qdb_set_trace (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + int state = P_INT (pr, 1); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + + tpr->pr_trace = state; +} + +static void +qdb_set_breakpoint (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + unsigned staddr = P_INT (pr, 1); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + + if (staddr >= tpr->progs->numstatements) { + R_INT (pr) = -1; + return; + } + tpr->pr_statements[staddr].op |= OP_BREAK; + R_INT (pr) = 0; +} + +static void +qdb_clear_breakpoint (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + unsigned staddr = P_UINT (pr, 1); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + + if (staddr >= tpr->progs->numstatements) { + R_INT (pr) = -1; + return; + } + tpr->pr_statements[staddr].op &= ~OP_BREAK; + R_INT (pr) = 0; +} + +static void +qdb_set_watchpoint (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + pointer_t offset = P_UINT (pr, 1); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + + if (offset >= tpr->globals_size) { + R_INT (pr) = -1; + return; + } + tpr->watch = &tpr->pr_globals[offset]; + R_INT (pr) = 0; +} + +static void +qdb_clear_watchpoint (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + + tpr->watch = 0; + R_INT (pr) = 0; +} + +static void +qdb_continue (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + + pthread_mutex_lock (&target->run_cond.mut); + target->run_command = 1; + pthread_cond_signal (&target->run_cond.rcond); + pthread_mutex_unlock (&target->run_cond.mut); +} + +static void +qdb_get_state (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + pr_lineno_t *lineno; + pr_auxfunction_t *f; + string_t file = 0; + unsigned line = 0; + unsigned staddr = tpr->pr_xstatement; + func_t func = tpr->pr_xfunction - tpr->function_table; + + lineno = PR_Find_Lineno (tpr, staddr); + if (lineno) { + f = PR_Get_Lineno_Func (tpr, lineno); + //FIXME file is a permanent string. dynamic would be better + //but they're not merged (and would need refcounting) + file = PR_SetString (pr, PR_Get_Source_File (tpr, lineno)); + func = f->function; + line = PR_Get_Lineno_Line (tpr, lineno); + line += f->source_line; + } + + qdb_state_t state = {}; + state.staddr = staddr; + state.func = func; + state.file = file; + state.line = line; + + R_PACKED (pr, qdb_state_t) = state; +} + +static void +qdb_get_stack_depth (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + + R_INT (pr) = tpr->pr_depth; +} + +static void +qdb_get_stack (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + int count = tpr->pr_depth; + + R_POINTER (pr) = 0; + if (count > 0) { + size_t size = count * sizeof (qdb_stack_t); + string_t stack_block = PR_AllocTempBlock (pr, size); + __auto_type stack = (qdb_stack_t *) PR_GetString (pr, stack_block); + + for (int i = 0; i < count; i++) { + stack[i].staddr = tpr->pr_stack[i].staddr; + stack[i].func = tpr->pr_stack[i].func - tpr->pr_xfunction; + //XXX temp strings (need access somehow) + } + R_POINTER (pr) = PR_SetPointer (pr, stack); + } +} + +static void +qdb_get_event (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + __auto_type event = &G_STRUCT (pr, qdb_event_t, P_INT (pr, 1)); + + memset (event, 0, sizeof (*event)); + event->what = target->event; + switch (event->what) { + case prd_subenter: + event->function = *(func_t *) target->param; + break; + case prd_runerror: + case prd_error: + event->message = PR_SetReturnString (pr, *(char **) target->param); + break; + case prd_begin: + event->function = *(func_t *) target->param; + break; + case prd_terminate: + event->exit_code = *(int *) target->param; + break; + case prd_trace: + case prd_breakpoint: + case prd_watchpoint: + case prd_subexit: + case prd_none: + break; + } + R_INT (pr) = target->event != prd_none; +} + +static void +qdb_get_data (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + pointer_t srcoff = P_POINTER (pr, 1); + unsigned length = P_UINT (pr, 2); + pointer_t dstoff = P_POINTER(pr, 3); + + pr_type_t *src = PR_GetPointer(tpr, srcoff); + pr_type_t *dst = PR_GetPointer(pr, dstoff); + + if (srcoff >= tpr->globals_size || srcoff + length >= tpr->globals_size) { + R_INT (pr) = -1; + return; + } + if (dstoff >= pr->globals_size || dstoff + length >= pr->globals_size) { + R_INT (pr) = -1; + return; + } + memcpy (dst, src, length * sizeof (pr_type_t)); + R_INT (pr) = 0; +} + +static void +qdb_get_string (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + string_t string = P_STRING (pr, 1); + + R_STRING (pr) = 0; + if (PR_StringValid (tpr, string)) { + RETURN_STRING (pr, PR_GetString (tpr, string)); + } +} + +static void +qdb_get_file_path (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + const char *file = P_GSTRING (pr, 1); + const char *basedir = PR_Debug_GetBaseDirectory (tpr, file); + + if (basedir) { + size_t baselen = strlen (basedir); + size_t filelen = strlen (file); + char *path = alloca (baselen + filelen + 2); + strcpy (path, basedir); + path[baselen] = '/'; + strcpy (path + baselen + 1, file); + path = QFS_CompressPath (path); + RETURN_STRING (pr, path); + free (path); + } else { + R_STRING (pr) = P_STRING (pr, 1); + } +} + +static void +qdb_find_global (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + const char *name = P_GSTRING (pr, 1); + pr_def_t *def = PR_FindGlobal (tpr, name); + + if (def) { + R_PACKED (pr, qdb_def_t).type_size = (def->size << 16) | def->type; + R_PACKED (pr, qdb_def_t).offset = def->ofs; + R_PACKED (pr, qdb_def_t).name = def->name; + R_PACKED (pr, qdb_def_t).type_encoding = def->type_encoding; + } else { + memset (&R_PACKED (pr, qdb_def_t), 0, sizeof (qdb_def_t)); + } +} + +static void +qdb_find_field (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + const char *name = P_GSTRING (pr, 1); + pr_def_t *def = PR_FindField (tpr, name); + + if (def) { + R_PACKED (pr, qdb_def_t).type_size = (def->size << 16) | def->type; + R_PACKED (pr, qdb_def_t).offset = def->ofs; + R_PACKED (pr, qdb_def_t).name = def->name; + R_PACKED (pr, qdb_def_t).type_encoding = def->type_encoding; + } else { + memset (&R_PACKED (pr, qdb_def_t), 0, sizeof (qdb_def_t)); + } +} + +static void +return_function (progs_t *pr, dfunction_t *func) +{ + R_POINTER (pr) = 0; + if (func) { + __auto_type f + = (qdb_function_t *) PR_Zone_Malloc (pr, sizeof (qdb_function_t)); + f->staddr = func->first_statement; + f->local_data = func->parm_start; + f->local_size = func->locals; + f->profile = func->profile; + f->name = func->s_name; + f->file = func->s_file; + f->num_params = func->numparms; + R_POINTER (pr) = PR_SetPointer (pr, f); + } +} + +static void +qdb_find_function (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + const char *name = P_GSTRING (pr, 1); + dfunction_t *func = PR_FindFunction (tpr, name); + + return_function (pr, func); +} + +static void +qdb_get_function (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + pr_uint_t fnum = P_INT (pr, 1); + dfunction_t *func = tpr->pr_functions + fnum; + + if (fnum >= tpr->progs->numfunctions) { + func = 0; + } + return_function (pr, func); +} + +static void +return_auxfunction (progs_t *pr, pr_auxfunction_t *auxfunc) +{ + R_POINTER (pr) = 0; + if (auxfunc) { + __auto_type f + = (qdb_auxfunction_t *) PR_Zone_Malloc (pr, + sizeof (qdb_auxfunction_t)); + f->function = auxfunc->function; + f->source_line = auxfunc->source_line; + f->line_info = auxfunc->line_info; + f->local_defs = auxfunc->local_defs; + f->num_locals = auxfunc->num_locals; + f->return_type = auxfunc->return_type; + R_POINTER (pr) = PR_SetPointer (pr, f); + } +} + +static void +qdb_find_auxfunction (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + const char *name = P_GSTRING (pr, 1); + dfunction_t *func = PR_FindFunction (tpr, name); + pr_uint_t fnum = func - tpr->pr_functions; + pr_auxfunction_t *auxfunc = PR_Debug_MappedAuxFunction (tpr, fnum); + + if (fnum >= tpr->progs->numfunctions) { + func = 0; + } + return_auxfunction (pr, auxfunc); +} + +static void +qdb_get_auxfunction (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + pr_uint_t fnum = P_UINT (pr, 1); + pr_auxfunction_t *auxfunc = PR_Debug_MappedAuxFunction (tpr, fnum); + + return_auxfunction (pr, auxfunc); +} + +static void +qdb_get_local_defs (progs_t *pr) +{ + __auto_type debug = PR_Resources_Find (pr, "qwaq-debug"); + pointer_t handle = P_INT (pr, 0); + qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); + progs_t *tpr = target->pr; + pr_uint_t fnum = P_UINT (pr, 1); + pr_auxfunction_t *auxfunc = PR_Debug_MappedAuxFunction (tpr, fnum); + + R_POINTER (pr) = 0; + if (auxfunc && auxfunc->num_locals) { + pr_def_t *defs = PR_Debug_LocalDefs (tpr, auxfunc); + __auto_type qdefs + = (qdb_def_t *) PR_Zone_Malloc (pr, + auxfunc->num_locals * sizeof (qdb_def_t)); + for (unsigned i = 0; i < auxfunc->num_locals; i++) { + qdefs[i].type_size = (defs[i].size << 16) | defs[i].type; + qdefs[i].offset = defs[i].ofs; + qdefs[i].name = defs[i].name; + qdefs[i].type_encoding = defs[i].type_encoding; + } + R_POINTER (pr) = PR_SetPointer (pr, qdefs); + } +} + +static builtin_t builtins[] = { + {"qdb_set_trace", qdb_set_trace, -1}, + {"qdb_set_breakpoint", qdb_set_breakpoint, -1}, + {"qdb_clear_breakpoint", qdb_clear_breakpoint, -1}, + {"qdb_set_watchpoint", qdb_set_watchpoint, -1}, + {"qdb_clear_watchpoint", qdb_clear_watchpoint, -1}, + {"qdb_continue", qdb_continue, -1}, + {"qdb_get_state", qdb_get_state, -1}, + {"qdb_get_stack_depth", qdb_get_stack_depth, -1}, + {"qdb_get_stack", qdb_get_stack, -1}, + {"qdb_get_event", qdb_get_event, -1}, + {"qdb_get_data", qdb_get_data, -1}, + {"qdb_get_string|{tag qdb_target_s=}i", qdb_get_string, -1}, + {"qdb_get_string|{tag qdb_target_s=}*", qdb_get_string, -1}, + {"qdb_get_file_path", qdb_get_file_path, -1}, + {"qdb_find_global", qdb_find_global, -1}, + {"qdb_find_field", qdb_find_field, -1}, + {"qdb_find_function", qdb_find_function, -1}, + {"qdb_get_function", qdb_get_function, -1}, + {"qdb_find_auxfunction", qdb_find_auxfunction, -1}, + {"qdb_get_auxfunction", qdb_get_auxfunction, -1}, + {"qdb_get_local_defs", qdb_get_local_defs, -1}, + {} +}; + +void +QWAQ_Debug_Init (progs_t *pr) +{ + qwaq_debug_t *debug = calloc (sizeof (*debug), 1); + + debug->pr = pr; + debug->qwaq = PR_Resources_Find (pr, "qwaq"); + + PR_AddLoadFunc (pr, qwaq_debug_load); + PR_Resources_Register (pr, "qwaq-debug", debug, qwaq_debug_clear); + PR_RegisterBuiltins (pr, builtins); +} + +void +QWAQ_DebugTarget_Init (progs_t *pr) +{ + PR_AddLoadFunc (pr, qwaq_target_load); + PR_Resources_Register (pr, "qwaq-target", 0, qwaq_target_clear); +} diff --git a/ruamoko/qwaq/builtins/editbuffer.c b/ruamoko/qwaq/builtins/editbuffer.c new file mode 100644 index 000000000..666632944 --- /dev/null +++ b/ruamoko/qwaq/builtins/editbuffer.c @@ -0,0 +1,963 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "QF/progs.h" +#include "QF/ruamoko.h" +#include "QF/quakeio.h" +#include "QF/txtbuffer.h" + +#include "ruamoko/qwaq/qwaq.h" +#include "ruamoko/qwaq/editor/editbuffer.h" + +#define always_inline inline __attribute__((__always_inline__)) + +typedef struct editbuffer_s { + void *freenext; // for PR_RESMAP + txtbuffer_t *txtbuffer; + int modified; + int tabSize; +} editbuffer_t; + +typedef struct qwaq_ebresources_s { + progs_t *pr; + PR_RESMAP (editbuffer_t) buffers; +} qwaq_ebresources_t; + +static editbuffer_t * +editbuffer_new (qwaq_ebresources_t *res) +{ + return PR_RESNEW (res->buffers); +} + +static void +editbuffer_free (qwaq_ebresources_t *res, editbuffer_t *buffer) +{ + PR_RESFREE (res->buffers, buffer); +} + +static void +editbuffer_reset (qwaq_ebresources_t *res) +{ + PR_RESRESET (res->buffers); +} + +static inline editbuffer_t * +editbuffer_get (qwaq_ebresources_t *res, unsigned index) +{ + return PR_RESGET (res->buffers, index); +} + +static inline int __attribute__((pure)) +editbuffer_index (qwaq_ebresources_t *res, editbuffer_t *buffer) +{ + return PR_RESINDEX (res->buffers, buffer); +} + +static always_inline editbuffer_t * __attribute__((pure)) +get_editbuffer (qwaq_ebresources_t *res, const char *name, int handle) +{ + editbuffer_t *buffer = editbuffer_get (res, handle); + + if (!buffer || !buffer->txtbuffer) { + PR_RunError (res->pr, "invalid edit buffer passed to %s", name + 3); + } + return buffer; +} + +static always_inline int +isword (unsigned char c) +{ + return c >= 128 || c == '_' || isalnum(c); +} + +static always_inline unsigned +spanGap (txtbuffer_t *buffer, unsigned ptr) +{ + return ptr < buffer->gapOffset ? ptr : ptr + buffer->gapSize; +} + +static always_inline char +getChar (txtbuffer_t *buffer, unsigned ptr) +{ + return buffer->text[spanGap (buffer, ptr)]; +} + +static always_inline unsigned +nextChar (txtbuffer_t *buffer, unsigned ptr) +{ + if (ptr < buffer->textSize && getChar (buffer, ptr) != '\n') { + return ptr + 1; + } + return ptr; +} + +static always_inline unsigned +prevChar (txtbuffer_t *buffer, unsigned ptr) +{ + if (ptr > 0 && getChar (buffer, ptr - 1) != '\n') { + return ptr - 1; + } + return ptr; +} + +static always_inline unsigned __attribute__((pure)) +nextNonSpace (txtbuffer_t *buffer, unsigned ptr) +{ + while (ptr < buffer->textSize) { + char c = getChar (buffer, ptr); + if (!isspace (c) || c == '\n') { + break; + } + ptr++; + } + return ptr; +} + +static always_inline unsigned +prevNonSpace (txtbuffer_t *buffer, unsigned ptr) +{ + while (ptr > 0) { + char c = getChar (buffer, ptr - 1); + if (!isspace (c) || c == '\n') { + break; + } + ptr--; + } + return ptr; +} + +static always_inline unsigned __attribute__((pure)) +nextWord (txtbuffer_t *buffer, unsigned ptr) +{ + if (buffer->textSize && ptr < buffer->textSize - 1) { + while (ptr < buffer->textSize) { + char c = getChar (buffer, ptr); + if (!isword (c)) { + break; + } + ptr++; + } + while (ptr < buffer->textSize) { + char c = getChar (buffer, ptr); + if (c == '\n') { + return ptr; + } + if (isword (c)) { + break; + } + ptr++; + } + } + return ptr; +} + +static always_inline unsigned +prevWord (txtbuffer_t *buffer, unsigned ptr) +{ + if (ptr > 0) { + while (ptr > 0) { + char c = getChar (buffer, ptr - 1); + if (!isword (c)) { + break; + } + ptr--; + } + while (ptr > 0) { + char c = getChar (buffer, ptr - 1); + if (c == '\n') { + return ptr; + } + if (isword (c)) { + break; + } + ptr--; + } + } + return ptr; +} + +static always_inline unsigned __attribute__((pure)) +nextLine (txtbuffer_t *buffer, unsigned ptr) +{ + unsigned oldptr = ptr; + while (ptr < buffer->textSize && getChar (buffer, ptr++) != '\n') { + } + if (ptr == buffer->textSize && ptr > 0 + && getChar (buffer, ptr - 1) != '\n') { + return oldptr; + } + return ptr; +} + +static always_inline unsigned +prevLine (txtbuffer_t *buffer, unsigned ptr) +{ + if (ptr) { + ptr--; + while (ptr > 0 && getChar (buffer, ptr - 1) != '\n') { + ptr--; + } + } + return ptr; +} + +static always_inline unsigned +charPos (txtbuffer_t *buffer, unsigned ptr, unsigned target, int tabSize) +{ + unsigned pos = 0; + + while (ptr < target) { + if (getChar (buffer, ptr) == '\t') { + pos += tabSize - (pos % tabSize) - 1; // -1 for ++ + } + pos++; + ptr++; + } + return pos; +} + +static always_inline unsigned __attribute__((pure)) +charPtr (txtbuffer_t *buffer, unsigned ptr, unsigned target, int tabSize) +{ + unsigned pos = 0; + while (pos < target && ptr < buffer->textSize + && getChar (buffer, ptr) != '\n') { + if (getChar (buffer, ptr) == '\t') { + pos += tabSize - (pos % tabSize) - 1; // -1 for ++ + } + pos++; + ptr++; + } + if (pos > target) { + ptr--; + } + return ptr; +} + +static always_inline unsigned __attribute__((pure)) +getEOW (txtbuffer_t *buffer, unsigned ptr) +{ + while (ptr < buffer->textSize) { + char c = getChar (buffer, ptr); + if (!isword (c)) { + break; + } + ptr++; + } + return ptr; +} + +static always_inline unsigned +getBOW (txtbuffer_t *buffer, unsigned ptr) +{ + while (ptr > 0) { + char c = getChar (buffer, ptr - 1); + if (!isword (c)) { + break; + } + ptr--; + } + return ptr; +} + +static always_inline unsigned __attribute__((pure)) +getEOL (txtbuffer_t *buffer, unsigned ptr) +{ + while (ptr < buffer->textSize) { + char c = getChar (buffer, ptr); + if (c == '\n') { + break; + } + ptr++; + } + return ptr; +} + +static always_inline void +readString (txtbuffer_t *buffer, eb_sel_t *sel, char *str) +{ + unsigned start = sel->start; + unsigned length = sel->length; + unsigned end = sel->start + sel->length; + const char *ptr = buffer->text + spanGap (buffer, start); + if ((start < buffer->gapOffset && end <= buffer->gapOffset) + || start > buffer->gapOffset) { + memcpy (str, ptr, length); + } else { + length = buffer->gapOffset - start; + memcpy (str, ptr, length); + str += length; + ptr += length + buffer->gapOffset; + memcpy (str, ptr, sel->length - length); + } +} + +static always_inline unsigned +getBOL (txtbuffer_t *buffer, unsigned ptr) +{ + while (ptr > 0) { + char c = getChar (buffer, ptr - 1); + if (c == '\n') { + break; + } + ptr--; + } + return ptr; +} + +static always_inline unsigned +_countLines (txtbuffer_t *buffer, unsigned start, unsigned len) +{ + unsigned count = 0; + char *ptr = buffer->text + start; + + while (len-- > 0) { + count += *ptr++ == '\n'; + } + return count; +} + +static always_inline unsigned +countLines (txtbuffer_t *buffer, unsigned start, unsigned len) +{ + if (start < buffer->gapOffset) { + if (start + len <= buffer->gapOffset) { + return _countLines (buffer, start, len); + } else { + return _countLines (buffer, start, buffer->gapOffset - start) + + _countLines (buffer, buffer->gapOffset + buffer->gapSize, + len - (buffer->gapOffset - start)); + } + } else { + return _countLines (buffer, start + buffer->gapOffset, len); + } +} + +static const char * +_search (txtbuffer_t *buffer, const char *ptr, unsigned len, + const char *str, unsigned slen, int dir, + int (*cmp)(const char *, const char *, size_t)) +{ + while (len-- > 0) { + if (*ptr == *str) { + unsigned offset = ptr - buffer->text; + if (offset > buffer->gapOffset + || offset + slen < buffer->gapOffset) { + // search does not span gap + if (cmp (ptr, str, slen) == 0) { + return ptr; + } + } else { + // search spans gap + unsigned l = buffer->gapOffset - offset; + if (cmp (ptr, str, l) == 0 + && cmp (ptr + l + buffer->gapSize, + str + l, slen - l) == 0) { + return ptr; + } + } + } else { + ptr += dir; + } + } + return 0; +} + +static int +search (txtbuffer_t *buffer, const eb_sel_t *sel, const char *str, int dir, + eb_sel_t *find, int (*cmp)(const char *, const char *, size_t)) +{ + unsigned start = sel->start; + unsigned slen = strlen (str); + unsigned end = start + sel->length - slen; + const char *found = 0; + + find->start = 0; + find->length = 0; + + if (sel->length >= slen) { + if (dir < 0) { + const char *s = buffer->text + spanGap (buffer, end); + if ((start < buffer->gapOffset && end <= buffer->gapOffset) + || start > buffer->gapOffset) { + found = _search (buffer, s, end - start, str, slen, -1, cmp); + } else { + unsigned l = end - (buffer->gapOffset + buffer->gapSize); + found = _search (buffer, s, l, str, slen, 1, cmp); + if (!found) { + s -= l + buffer->gapSize; + l = buffer->gapOffset - start; + found = _search (buffer, s, l, str, slen, 1, cmp); + } + } + } else { + const char *s = buffer->text + spanGap (buffer, start); + if ((start < buffer->gapOffset && end <= buffer->gapOffset) + || start > buffer->gapOffset) { + found = _search (buffer, s, end - start, str, slen, 1, cmp); + } else { + unsigned l = buffer->gapOffset - start; + found = _search (buffer, s, l, str, slen, 1, cmp); + if (!found) { + s += l + buffer->gapSize; + l = end - start - l; + found = _search (buffer, s, l, str, slen, 1, cmp); + } + } + } + } + if (found) { + unsigned offset = found - buffer->text; + if (offset > buffer->gapOffset) { + offset -= buffer->gapSize; + } + find->start = offset; + find->length = slen; + return 1; + } + return 0; +} + +static int +saveFile (txtbuffer_t *buffer, const char *filename) +{ + QFile *file = Qopen (filename, "wt"); + + if (file) { + unsigned offset = buffer->gapOffset + buffer->gapSize; + Qwrite (file, buffer->text, buffer->gapOffset); + Qwrite (file, buffer->text + offset, buffer->textSize - offset); + Qclose (file); + return 1; + } + return 0; +} + +static int +loadFile (txtbuffer_t *buffer, const char *filename) +{ + QFile *file = Qopen (filename, "rtz"); + char *dst; + unsigned len; + + if (file) { + len = Qfilesize (file); + // ensure buffer is empty + TextBuffer_DeleteAt (buffer, 0, buffer->textSize); + dst = TextBuffer_OpenGap (buffer, 0, len); + Qread (file, dst, len); + + buffer->textSize += len; + buffer->gapOffset += len; + buffer->gapSize -= len; + + Qclose (file); + return 1; + } + return 0; +} + +static unsigned +formatLine (txtbuffer_t *buffer, unsigned linePtr, unsigned xpos, + int *dst, unsigned length, eb_sel_t *selection, eb_color_t *colors, + int tabSize) +{ + unsigned pos = 0; + unsigned ptr = linePtr; + unsigned sels = selection->start; + unsigned sele = selection->start + selection->length; + int coln = (colors->normal & ~0xff); + int cols = (colors->selected & ~0xff); + int col; + byte c = 0; + int count; + int *startdst = dst; + int startlen = length; + + while (pos < xpos && ptr < buffer->textSize) { + c = getChar (buffer, ptr); + if (c == '\n') { + break; + } + if (c == '\t') { + pos += tabSize - (pos % tabSize) - 1; // -1 for ++ + } + pos++; + ptr++; + } + col = ptr >= sels && ptr < sele ? cols : coln; + while (xpos < pos && length > 0) { + *dst++ = col | ' '; + length--; + xpos++; + } + while (length > 0 && ptr < buffer->textSize) { + col = ptr >= sels && ptr < sele ? cols : coln; + c = getChar (buffer, ptr++); + if (c == '\n') { + break; + } + count = 1; + if (c == '\t') { + c = ' '; + count = tabSize - (pos % tabSize); + } + while (length > 0 && count-- > 0) { + *dst++ = col | c; + pos++; + length--; + } + } + while (c != '\n' && ptr < buffer->textSize) { + c = getChar (buffer, ptr++); + } + while (length-- > 0) { + *dst++ = col | ' '; + } + if (dst - startdst > startlen) { + Sys_Error ("formatLine wrote too much: %zd %u %d", + dst - startdst, startlen, length); + } + return ptr; +} + +//=== + +static void +bi_i_EditBuffer__init (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + __auto_type self = &P_STRUCT (pr, qwaq_editbuffer_t, 0); + RUA_obj_increment_retaincount (pr);// [super init]; + txtbuffer_t *txtbuffer = TextBuffer_Create (); + editbuffer_t *buffer = editbuffer_new (res); + + buffer->txtbuffer = txtbuffer; + buffer->tabSize = 4; // FIXME + + self->buffer = editbuffer_index (res, buffer); + R_INT (pr) = PR_SetPointer (pr, self); +} + +static void +bi_i_EditBuffer__initWithFile_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + __auto_type self = &P_STRUCT (pr, qwaq_editbuffer_t, 0); + RUA_obj_increment_retaincount (pr);// [super init]; + const char *filename = P_GSTRING (pr, 2); + txtbuffer_t *txtbuffer = TextBuffer_Create (); + editbuffer_t *buffer = editbuffer_new (res); + + buffer->txtbuffer = txtbuffer; + buffer->tabSize = 4; // FIXME + + loadFile (buffer->txtbuffer, filename); + + self->buffer = editbuffer_index (res, buffer); + R_INT (pr) = PR_SetPointer (pr, self); +} + +static void +bi_i_EditBuffer__dealloc (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + __auto_type self = &P_STRUCT (pr, qwaq_editbuffer_t, 0); + int buffer_id = self->buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + + TextBuffer_Destroy (buffer->txtbuffer); + editbuffer_free (res, buffer); +} + +static void +bi_i_EditBuffer__nextChar_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = nextChar (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__prevChar_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = prevChar (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__nextNonSpace_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = nextNonSpace (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__prevNonSpace_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = prevNonSpace (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__nextWord_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = nextWord (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__prevWord_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = prevWord (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__nextLine_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = nextLine (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__prevLine_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = prevLine (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__nextLine__ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + unsigned count = P_UINT (pr, 3); + + while (count-- > 0) { + unsigned oldptr = ptr; + ptr = nextLine (buffer->txtbuffer, ptr); + if (ptr == buffer->txtbuffer->textSize && ptr > 0 + && getChar (buffer->txtbuffer, ptr - 1) != '\n') { + ptr = oldptr; + break; + } + } + R_INT (pr) = ptr; +} + +static void +bi_i_EditBuffer__prevLine__ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + unsigned count = P_UINT (pr, 3); + + while (ptr && count-- > 0) { + ptr = prevLine (buffer->txtbuffer, ptr); + } + R_INT (pr) = ptr; +} + +static void +bi_i_EditBuffer__charPos_at_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + unsigned target = P_UINT (pr, 3); + int tabSize = buffer->tabSize; + + R_INT (pr) = charPos (buffer->txtbuffer, ptr, target, tabSize); +} + +static void +bi_i_EditBuffer__charPtr_at_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + unsigned target = P_UINT (pr, 3); + int tabSize = buffer->tabSize; + + R_INT (pr) = charPtr (buffer->txtbuffer, ptr, target, tabSize); +} + +static void +bi_i_EditBuffer__getWord_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + unsigned s = getBOW (buffer->txtbuffer, ptr); + unsigned e = getEOW (buffer->txtbuffer, ptr); + + R_PACKED (pr, eb_sel_t).start = s; + R_PACKED (pr, eb_sel_t).length = e - s; +} + +static void +bi_i_EditBuffer__getLine_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + unsigned s = getBOL (buffer->txtbuffer, ptr); + unsigned e = getEOL (buffer->txtbuffer, ptr); + + R_PACKED (pr, eb_sel_t).start = s; + R_PACKED (pr, eb_sel_t).length = e - s; +} + +static void +bi_i_EditBuffer__getBOL_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = getBOL (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__getEOL_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned ptr = P_UINT (pr, 2); + + R_INT (pr) = getEOL (buffer->txtbuffer, ptr); +} + +static void +bi_i_EditBuffer__getBOT (progs_t *pr) +{ + //qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + //int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + //editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + + R_INT (pr) = 0; +} + +static void +bi_i_EditBuffer__getEOT (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + + R_INT (pr) = buffer->txtbuffer->textSize; +} + +static void +bi_i_EditBuffer__readString_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); + + char *str = alloca (selection->length + 1); + str[selection->length] = 0; + readString (buffer->txtbuffer, selection, str); + + RETURN_STRING (pr, str); +} + +static void +bi_i_EditBuffer__countLines_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); + + R_INT (pr) = countLines (buffer->txtbuffer, + selection->start, selection->length); +} + +static void +bi_i_EditBuffer__search_for_direction_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); + const char *str = P_GSTRING (pr, 3); + int dir = P_INT (pr, 4); + + search (buffer->txtbuffer, selection, str, dir, &R_PACKED (pr, eb_sel_t), + strncmp); +} + +static void +bi_i_EditBuffer__isearch_for_direction_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + __auto_type selection = &P_PACKED (pr, eb_sel_t, 2); + const char *str = P_GSTRING (pr, 3); + int dir = P_INT (pr, 4); + + search (buffer->txtbuffer, selection, str, dir, &R_PACKED (pr, eb_sel_t), + strncasecmp); +} + +static void +bi_i_EditBuffer__formatLine_from_into_width_highlight_colors_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + unsigned linePtr = P_UINT (pr, 2); + unsigned xpos = P_UINT (pr, 3); + int *dst = (int *) P_GPOINTER (pr, 4); + unsigned length = P_UINT (pr, 5); + __auto_type selection = &P_PACKED (pr, eb_sel_t, 6); + __auto_type colors = &P_PACKED (pr, eb_color_t, 7); + int tabSize = buffer->tabSize; + unsigned ptr; + + ptr = formatLine (buffer->txtbuffer, linePtr, xpos, dst, length, selection, + colors, tabSize); + R_INT (pr) = ptr; +} + +static void +bi_i_EditBuffer__modified (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + R_INT (pr) = buffer->modified; +} + +static void +bi_i_EditBuffer__textSize (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + R_INT (pr) = buffer->txtbuffer->textSize; +} + +static void +bi_i_EditBuffer__saveFile_ (progs_t *pr) +{ + qwaq_ebresources_t *res = PR_Resources_Find (pr, "qwaq-editbuffer"); + int buffer_id = P_STRUCT (pr, qwaq_editbuffer_t, 0).buffer; + editbuffer_t *buffer = get_editbuffer (res, __FUNCTION__, buffer_id); + const char *filename = P_GSTRING (pr, 2); + + if (saveFile (buffer->txtbuffer, filename)) { + buffer->modified = 0; + } +} + +static void +qwaq_ebresources_clear (progs_t *pr, void *data) +{ + __auto_type res = (qwaq_ebresources_t *) data; + + for (size_t i = 0; i < res->buffers._size; i++) { + editbuffer_t *buffer = editbuffer_get (res, ~i); + if (buffer->txtbuffer) { + TextBuffer_Destroy (buffer->txtbuffer); + buffer->txtbuffer = 0; + } + } + editbuffer_reset (res); +} + +static builtin_t builtins[] = { + {"_i_EditBuffer__init", bi_i_EditBuffer__init, -1}, + {"_i_EditBuffer__initWithFile_", bi_i_EditBuffer__initWithFile_, -1}, + {"_i_EditBuffer__dealloc", bi_i_EditBuffer__dealloc, -1}, + {"_i_EditBuffer__nextChar_", bi_i_EditBuffer__nextChar_, -1}, + {"_i_EditBuffer__prevChar_", bi_i_EditBuffer__prevChar_, -1}, + {"_i_EditBuffer__nextNonSpace_", bi_i_EditBuffer__nextNonSpace_, -1}, + {"_i_EditBuffer__prevNonSpace_", bi_i_EditBuffer__prevNonSpace_, -1}, + {"_i_EditBuffer__nextWord_", bi_i_EditBuffer__nextWord_, -1}, + {"_i_EditBuffer__prevWord_", bi_i_EditBuffer__prevWord_, -1}, + {"_i_EditBuffer__nextLine_", bi_i_EditBuffer__nextLine_, -1}, + {"_i_EditBuffer__prevLine_", bi_i_EditBuffer__prevLine_, -1}, + {"_i_EditBuffer__nextLine__", bi_i_EditBuffer__nextLine__, -1}, + {"_i_EditBuffer__prevLine__", bi_i_EditBuffer__prevLine__, -1}, + {"_i_EditBuffer__charPos_at_", bi_i_EditBuffer__charPos_at_, -1}, + {"_i_EditBuffer__charPtr_at_", bi_i_EditBuffer__charPtr_at_, -1}, + {"_i_EditBuffer__getWord_", bi_i_EditBuffer__getWord_, -1}, + {"_i_EditBuffer__getLine_", bi_i_EditBuffer__getLine_, -1}, + {"_i_EditBuffer__getBOL_", bi_i_EditBuffer__getBOL_, -1}, + {"_i_EditBuffer__getEOL_", bi_i_EditBuffer__getEOL_, -1}, + {"_i_EditBuffer__getBOT", bi_i_EditBuffer__getBOT, -1}, + {"_i_EditBuffer__getEOT", bi_i_EditBuffer__getEOT, -1}, + {"_i_EditBuffer__readString_", bi_i_EditBuffer__readString_, -1}, + {"_i_EditBuffer__countLines_", bi_i_EditBuffer__countLines_, -1}, + {"_i_EditBuffer__search_for_direction_", + bi_i_EditBuffer__search_for_direction_, -1}, + {"_i_EditBuffer__isearch_for_direction_", + bi_i_EditBuffer__isearch_for_direction_,-1}, + {"_i_EditBuffer__formatLine_from_into_width_highlight_colors_", + bi_i_EditBuffer__formatLine_from_into_width_highlight_colors_, -1}, + {"_i_EditBuffer__modified", bi_i_EditBuffer__modified, -1}, + {"_i_EditBuffer__textSize", bi_i_EditBuffer__textSize, -1}, + {"_i_EditBuffer__saveFile_", bi_i_EditBuffer__saveFile_, -1}, + {} +}; + +void +QWAQ_EditBuffer_Init (progs_t *pr) +{ + qwaq_ebresources_t *res = calloc (sizeof (*res), 1); + res->pr = pr; + + PR_Resources_Register (pr, "qwaq-editbuffer", res, qwaq_ebresources_clear); + PR_RegisterBuiltins (pr, builtins); +} diff --git a/ruamoko/qwaq/builtins/input.c b/ruamoko/qwaq/builtins/input.c new file mode 100644 index 000000000..ce47b1914 --- /dev/null +++ b/ruamoko/qwaq/builtins/input.c @@ -0,0 +1,473 @@ +/* + input.c + + Input handling + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/03/21 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/keys.h" +#include "QF/sys.h" + +#include "ruamoko/qwaq/qwaq.h" +#include "ruamoko/qwaq/ui/event.h" +#include "ruamoko/qwaq/ui/curses.h" + +#define always_inline inline __attribute__((__always_inline__)) + +#define MOUSE_MOVES_ON "\033[?1003h" +#define MOUSE_MOVES_OFF "\033[?1003l" +#define SGR_ON "\033[?1006h" +#define SGR_OFF "\033[?1006l" +#define WHEEL_BUTTONS 0x78 // scroll up/down/left/right - always click + +typedef struct qwaq_key_s { + const char *sequence; + knum_t key; + unsigned shift; +} qwaq_key_t; + +static qwaq_key_t default_keys[] = { + { "\033OP", QFK_F1 }, + { "\033OQ", QFK_F2 }, + { "\033OR", QFK_F3 }, + { "\033OS", QFK_F4 }, + { "\033[15~", QFK_F5 }, + { "\033[17~", QFK_F6 }, + { "\033[18~", QFK_F7 }, + { "\033[19~", QFK_F8 }, + { "\033[20~", QFK_F9 }, + { "\033[21~", QFK_F10 }, + { "\033[23~", QFK_F11 }, + { "\033[24~", QFK_F12 }, + // shift F1-F12 + { "\033[1;2P", QFK_F13 }, + { "\033[1;2Q", QFK_F14 }, + { "\033[1;2R", QFK_F15 }, + { "\033[1;2S", QFK_F16 }, + { "\033[15;2~", QFK_F17 }, + { "\033[17;2~", QFK_F18 }, + { "\033[18;2~", QFK_F19 }, + { "\033[19;2~", QFK_F20 }, + { "\033[20;2~", QFK_F21 }, + { "\033[21;2~", QFK_F22 }, + { "\033[23;2~", QFK_F23 }, + { "\033[24;2~", QFK_F24 }, + // control F1-F12 + { "\033[1;5P", QFK_F25 }, + { "\033[1;5Q", QFK_F26 }, + { "\033[1;5R", QFK_F27 }, + { "\033[1;5S", QFK_F28 }, + { "\033[15;5~", QFK_F29 }, + { "\033[17;5~", QFK_F30 }, + { "\033[18;5~", QFK_F31 }, + { "\033[19;5~", QFK_F32 }, + { "\033[20;5~", QFK_F33 }, + { "\033[21;5~", QFK_F34 }, + { "\033[23;5~", QFK_F35 }, + { "\033[24;5~", QFK_F36 }, + // shift control F1-F12 + { "\033[1;6P", QFK_F37 }, + { "\033[1;6Q", QFK_F38 }, + { "\033[1;6R", QFK_F39 }, + { "\033[1;6S", QFK_F40 }, + { "\033[15;6~", QFK_F41 }, + { "\033[17;6~", QFK_F42 }, + { "\033[18;6~", QFK_F43 }, + { "\033[19;6~", QFK_F44 }, + { "\033[20;6~", QFK_F45 }, + { "\033[21;6~", QFK_F46 }, + { "\033[23;6~", QFK_F47 }, + { "\033[24;6~", QFK_F48 }, + + { "\033[2~", QFK_INSERT, 0 }, + { "\033[3~", QFK_DELETE, 0 }, + { "\033[H", QFK_HOME, 0 }, + { "\033[F", QFK_END, 0 }, + { "\033[5~", QFK_PAGEUP, 0 }, + { "\033[6~", QFK_PAGEDOWN, 0 }, + { "\033[A", QFK_UP, 0 }, + { "\033[B", QFK_DOWN, 0 }, + { "\033[C", QFK_RIGHT, 0 }, + { "\033[D", QFK_LEFT, 0 }, + // shift + // there may be a setting to tell xterm to NOT act on shift ins/pgup/pgdn + { "\033[2;2~", QFK_INSERT, 1 }, // xterm gobbles (and pastes) + { "\033[3;2~", QFK_DELETE, 1 }, + { "\033[1;2H", QFK_HOME, 1 }, + { "\033[1;2F", QFK_END, 1 }, + { "\033[5;2~", QFK_PAGEUP, 1 }, // xterm gobbles (scrolls term) + { "\033[6;2~", QFK_PAGEDOWN, 1 }, // xterm gobbles (scrolls term) + { "\033[1;2A", QFK_UP, 1 }, + { "\033[1;2B", QFK_DOWN, 1 }, + { "\033[1;2C", QFK_RIGHT, 1 }, + { "\033[1;2D", QFK_LEFT, 1 }, + { "\033[Z", QFK_TAB, 1 }, + // control + { "\033[2;5~", QFK_INSERT, 4 }, + { "\033[3;5~", QFK_DELETE, 4 }, + { "\033[1;5H", QFK_HOME, 4 }, + { "\033[1;5F", QFK_END, 4 }, + { "\033[5;5~", QFK_PAGEUP, 4 }, + { "\033[6;5~", QFK_PAGEDOWN, 4 }, + { "\033[1;5A", QFK_UP, 4 }, + { "\033[1;5B", QFK_DOWN, 4 }, + { "\033[1;5C", QFK_RIGHT, 4 }, + { "\033[1;5D", QFK_LEFT, 4 }, + // shift control + { "\033[2;6~", QFK_INSERT, 5 }, + { "\033[3;6~", QFK_DELETE, 5 }, + { "\033[1;6H", QFK_HOME, 5 }, + { "\033[1;6F", QFK_END, 5 }, + { "\033[5;6~", QFK_PAGEUP, 5 }, + { "\033[6;6~", QFK_PAGEDOWN, 5 }, + { "\033[1;6A", QFK_UP, 5 }, + { "\033[1;6B", QFK_DOWN, 5 }, + { "\033[1;6C", QFK_RIGHT, 5 }, + { "\033[1;6D", QFK_LEFT, 5 }, +}; + +static struct sigaction save_winch; +static sigset_t winch_mask; +static volatile sig_atomic_t winch_arrived; + +static void +handle_winch (int sig) +{ + winch_arrived = 1; +} + +int +qwaq_add_event (qwaq_resources_t *res, qwaq_event_t *event) +{ + struct timespec timeout; + int merged = 0; + int ret = 0; + + // merge motion events + pthread_mutex_lock (&res->event_cond.mut); + unsigned last = RB_DATA_AVAILABLE (res->event_queue); + if (event->what == qe_mousemove && last > 1 + && RB_PEEK_DATA(res->event_queue, last - 1)->what == qe_mousemove) { + RB_POKE_DATA(res->event_queue, last - 1, *event); + merged = 1; + pthread_cond_broadcast (&res->event_cond.rcond); + } + pthread_mutex_unlock (&res->event_cond.mut); + if (merged) { + return 0; + } + + pthread_mutex_lock (&res->event_cond.mut); + qwaq_init_timeout (&timeout, 5000 * 1000000L); + while (RB_SPACE_AVAILABLE (res->event_queue) < 1 && ret == 0) { + ret = pthread_cond_timedwait (&res->event_cond.wcond, + &res->event_cond.mut, &timeout); + } + RB_WRITE_DATA (res->event_queue, event, 1); + pthread_cond_broadcast (&res->event_cond.rcond); + pthread_mutex_unlock (&res->event_cond.mut); + return ret; +} + +static void +resize_event (qwaq_resources_t *res) +{ + qwaq_event_t event = {}; + struct winsize size; + if (ioctl (fileno (stdout), TIOCGWINSZ, &size) != 0) { + return; + } + event.what = qe_resize; + event.resize.width = size.ws_col; + event.resize.height = size.ws_row; + qwaq_add_event (res, &event); +} + +static void +key_event (qwaq_resources_t *res, int key, unsigned shift) +{ + qwaq_event_t event = {}; + event.what = qe_keydown; + event.when = Sys_DoubleTime (); + event.key.code = key; + event.key.shift = shift; + qwaq_add_event (res, &event); +} + +static void +mouse_event (qwaq_resources_t *res, int what, int x, int y) +{ + qwaq_event_t event = {}; + + event.what = what; + event.when = Sys_DoubleTime (); + event.mouse.x = x; + event.mouse.y = y; + event.mouse.buttons = res->button_state; + + if (event.what == qe_mousedown) { + if (event.when - res->lastClick.when <= 0.4 + && res->lastClick.mouse.buttons == event.mouse.buttons + && res->lastClick.mouse.click < 3) { + event.mouse.click = res->lastClick.mouse.click + 1; + event.what = qe_mouseclick; + } + res->lastClick = event; + } else if (event.what == qe_mouseclick) { + // scroll button event, so always single click + event.mouse.click = 1; + } + qwaq_add_event (res, &event); +} + +static void +parse_mouse (qwaq_resources_t *res, unsigned ctrl, int x, int y, int cmd) +{ + int button = ctrl & 3; + int ext = (ctrl >> 6); + int what = qe_none; + + if (ctrl & 0x20) { + // motion-only event + button = -1; + what = qe_mousemove; + } else { + // xterm doesn't send release events for buttons 4-7 + res->button_state &= ~(0x78); + if (!ext && button == 3 && !cmd) { + res->button_state = 0; // unknown which button was released + button = -1; + what = qe_mouseup; + } else { + if (ext) { + button += 4 * ext - 1; + } + if (cmd == 'm') { + res->button_state &= ~(1 << button); + what = qe_mouseup; + } else { + res->button_state |= 1 << button; + if (res->button_state & WHEEL_BUTTONS) { + what = qe_mouseclick; + } else { + what = qe_mousedown; + } + } + } + } + res->mouse_x = x; + res->mouse_y = y; + mouse_event (res, what, x, y); +} + +static void +parse_x10 (qwaq_resources_t *res) +{ + int x = (byte) res->escbuff.str[1] - '!'; // want 0-based + int y = (byte) res->escbuff.str[2] - '!'; // want 0-based + unsigned ctrl = (byte) res->escbuff.str[0] - ' '; + + parse_mouse (res, ctrl, x, y, 0); +} + +static void +parse_sgr (qwaq_resources_t *res, char cmd) +{ + unsigned ctrl, x, y; + + sscanf (res->escbuff.str, "%u;%u;%u", &ctrl, &x, &y); + // mouse coords are 1-based, but want 0-based + parse_mouse (res, ctrl, x - 1, y - 1, cmd); +} + +static void +parse_key (qwaq_resources_t *res) +{ + qwaq_key_t *key = Hash_Find (res->key_sequences, res->escbuff.str); + + //Sys_Printf ("parse_key: %s\n", res->escbuff.str + 1); + if (key) { + //Sys_Printf (" %d %03x %s\n", key->key, key->shift, + // Key_KeynumToString (key->key)); + key_event (res, key->key, key->shift); + } +} + +static void process_char (qwaq_resources_t *res, char ch) +{ + if (ch == 0x1b) { + // always reset if escape is seen, may be a desync + res->escstate = esc_escape; + } else { + switch (res->escstate) { + case esc_ground: + key_event (res, (byte) ch, 0); // shift state unknown + break; + case esc_escape: + if (ch == '[') { + res->escstate = esc_csi; + } else if (ch == 'O') { + // will wind up accepting P;P... but meh + res->escstate = esc_key; + dstring_clear (&res->escbuff); + // start the buffer with what got us hear: eases key lookup + dstring_append (&res->escbuff, "\033O", 2); + } else { + res->escstate = esc_ground; + } + break; + case esc_csi: + if (ch == 'M') { + res->escstate = esc_mouse; + dstring_clear (&res->escbuff); + } else if (ch == '<') { + res->escstate = esc_sgr; + dstring_clear (&res->escbuff); + } else if (ch >= '0' && ch < 127) { + res->escstate = esc_key; + dstring_clear (&res->escbuff); + // start the buffer with what got us hear: eases key lookup + dstring_append (&res->escbuff, "\033[", 2); + // the csi code might be short (eg, \e[H for home) so + // need to check for end of string right away + goto esc_key_jump; + } else { + res->escstate = esc_ground; + } + break; + case esc_mouse: + dstring_append (&res->escbuff, &ch, 1); + if (res->escbuff.size == 3) { + parse_x10 (res); + res->escstate = esc_ground; + } + break; + case esc_sgr: + if (isdigit (ch) || ch == ';') { + dstring_append (&res->escbuff, &ch, 1); + } else { + if (ch == 'm' || ch == 'M') { + // terminate the string + dstring_append (&res->escbuff, "", 1); + parse_sgr (res, ch); + } + res->escstate = esc_ground; + } + break; + case esc_key: +esc_key_jump: + dstring_append (&res->escbuff, &ch, 1); + if (!isdigit (ch) && ch != ';') { + // terminate the string + dstring_append (&res->escbuff, "", 1); + // parse_key will sort out whether it was a valid sequence + parse_key (res); + res->escstate = esc_ground; + } + break; + } + //printf("res->escstate %d\n", res->escstate); + } +} + +static const char * +key_sequence_getkey (const void *_seq, void *unused) +{ + __auto_type seq = (const qwaq_key_t *) _seq; + return seq->sequence; +} + +void qwaq_input_init (qwaq_resources_t *res) +{ + if (res->key_sequences) { + Hash_FlushTable (res->key_sequences); + } else { + res->key_sequences = Hash_NewTable (127, key_sequence_getkey, 0, 0, + res->pr->hashlink_freelist); + } + for (size_t i = 0; i < sizeof (default_keys) / sizeof (default_keys[0]); + i++) { + Hash_Add (res->key_sequences, &default_keys[i]); + } + + sigemptyset (&winch_mask); + sigaddset (&winch_mask, SIGWINCH); + struct sigaction action = {}; + action.sa_handler = handle_winch; + sigaction (SIGWINCH, &action, &save_winch); + + // ncurses takes care of input mode for us, so need only tell xterm + // what we need + write(1, MOUSE_MOVES_ON, sizeof (MOUSE_MOVES_ON) - 1); + write(1, SGR_ON, sizeof (SGR_ON) - 1); +} + +void qwaq_input_shutdown (qwaq_resources_t *res) +{ + // ncurses takes care of input mode for us, so need only tell xterm + // what we need + write(1, SGR_OFF, sizeof (SGR_OFF) - 1); + write(1, MOUSE_MOVES_OFF, sizeof (MOUSE_MOVES_OFF) - 1); + + sigaction (SIGWINCH, &save_winch, 0); +} + +void qwaq_process_input (qwaq_resources_t *res) +{ + char buf[256]; + int len; + sigset_t save_set; + int saw_winch; + + pthread_sigmask (SIG_BLOCK, &winch_mask, &save_set); + saw_winch = winch_arrived; + winch_arrived = 0; + pthread_sigmask (SIG_SETMASK, &save_set, 0); + if (saw_winch) { + resize_event (res); + } + while (Sys_CheckInput (1, -1)) { + len = read(0, buf, sizeof (buf)); + for (int i = 0; i < len; i++) { + process_char (res, buf[i]); + } + } +} diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c new file mode 100644 index 000000000..f8800df93 --- /dev/null +++ b/ruamoko/qwaq/builtins/main.c @@ -0,0 +1,489 @@ +/* + #FILENAME# + + Qwaq + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/01 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "QF/cbuf.h" +#include "QF/cmd.h" +#include "QF/cvar.h" +#include "QF/gib.h" +#include "QF/idparse.h" +#include "QF/keys.h" +#include "QF/progs.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/ruamoko.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/zone.h" + +#include "ruamoko/qwaq/qwaq.h" +#include "ruamoko/qwaq/debugger/debug.h" + +#define MAX_EDICTS 1024 + +cbuf_t *qwaq_cbuf; + +const char *this_program; + +enum { + start_opts = 255, + OPT_QARGS, +}; + +static struct option const long_options[] = { + {"qargs", no_argument, 0, OPT_QARGS}, + {NULL, 0, NULL, 0}, +}; + +static const char *short_options = + "-" // magic option parsing mode doohicky (must come first) + ; + +struct DARRAY_TYPE(qwaq_thread_t *) thread_data; + +static QFile * +open_file (const char *path, int *len) +{ + QFile *file = Qopen (path, "rbz"); + char errbuff[1024]; + + if (!file) { + strerror_r(errno, errbuff, sizeof (errbuff)); + Sys_Printf ("%s\n", errbuff); + *len = 0; + return 0; + } + *len = Qfilesize (file); + return file; +} + +static void * +load_file (progs_t *pr, const char *name, off_t *_size) +{ + QFile *file; + int size; + char *sym; + + file = open_file (name, &size); + if (!file) { + file = open_file (va (0, "%s.gz", name), &size); + if (!file) { + return 0; + } + } + sym = malloc (size + 1); + sym[size] = 0; + Qread (file, sym, size); + *_size = size; + return sym; +} + +static void * +allocate_progs_mem (progs_t *pr, int size) +{ + return malloc (size); +} + +static void +free_progs_mem (progs_t *pr, void *mem) +{ + free (mem); +} + +static void +init_qf (void) +{ + qwaq_cbuf = Cbuf_New (&id_interp); + + Sys_Init (); + COM_ParseConfig (); + + //Cvar_Set (developer, "1"); + + Memory_Init (Sys_Alloc (8 * 1024 * 1024), 8 * 1024 * 1024); + + Cvar_Get ("pr_debug", "2", 0, 0, 0); + Cvar_Get ("pr_boundscheck", "0", 0, 0, 0); + + // Normally, this is done by PR_Init, but PR_Init is not called in the main + // thread. However, PR_Opcode_Init() is idempotent. + PR_Opcode_Init (); +} + +static progs_t * +create_progs (qwaq_thread_t *thread) +{ + progs_t *pr = calloc (1, sizeof (*pr)); + progsinit_f *funcs = thread->progsinit; + + pr->load_file = load_file; + pr->allocate_progs_mem = allocate_progs_mem; + pr->free_progs_mem = free_progs_mem; + pr->no_exec_limit = 1; + pr->hashlink_freelist = &thread->hashlink_freelist; + + PR_Init_Cvars (); + PR_Init (pr); + RUA_Init (pr, 0); + while (*funcs) { + (*funcs++) (pr); + } + + return pr; +} + +static int +load_progs (progs_t *pr, const char *name) +{ + QFile *file; + int size; + + file = open_file (name, &size); + if (!file) { + return 0; + } + pr->progs_name = name; + pr->max_edicts = 1; + pr->zone_size = 1024*1024; + PR_LoadProgsFile (pr, file, size); + Qclose (file); + if (!PR_RunLoadFuncs (pr)) + PR_Error (pr, "unable to load %s", pr->progs_name); + return 1; +} + +static void +spawn_progs (qwaq_thread_t *thread) +{ + dfunction_t *dfunc; + const char *name = 0; + string_t *pr_argv; + int pr_argc = 1, i; + progs_t *pr; + + thread->main_func = 0; + pr = thread->pr = create_progs (thread); + if (thread->args.size) { + name = thread->args.a[0]; + } + + if (!load_progs (pr, name)) { + Sys_Error ("couldn't load %s", name); + } + + if ((dfunc = PR_FindFunction (pr, ".main")) + || (dfunc = PR_FindFunction (pr, "main"))) { + thread->main_func = dfunc - pr->pr_functions; + } else { + PR_Undefined (pr, "function", "main"); + } + + if (thread->pr->debug_handler) { + thread->pr->debug_handler (prd_begin, &thread->main_func, + thread->pr->debug_data); + } + + if (!PR_RunPostLoadFuncs (pr)) { + PR_Error (pr, "unable to load %s", pr->progs_name); + } + + PR_PushFrame (pr); + if (thread->args.size) { + pr_argc = thread->args.size; + } + pr_argv = PR_Zone_Malloc (pr, (pr_argc + 1) * 4); + pr_argv[0] = PR_SetTempString (pr, name); + for (i = 1; i < pr_argc; i++) + pr_argv[i] = PR_SetTempString (pr, thread->args.a[i]); + pr_argv[i] = 0; + + PR_RESET_PARAMS (pr); + P_INT (pr, 0) = pr_argc; + P_POINTER (pr, 1) = PR_SetPointer (pr, pr_argv); + pr->pr_argc = 2; +} + +static void * +run_progs (void *data) +{ + __auto_type thread = (qwaq_thread_t *) data; + + spawn_progs (thread); + Sys_Printf ("starting thread for %s\n", thread->args.a[0]); + + PR_ExecuteProgram (thread->pr, thread->main_func); + PR_PopFrame (thread->pr); + thread->return_code = R_INT (thread->pr); + if (thread->pr->debug_handler) { + thread->pr->debug_handler (prd_terminate, &thread->return_code, + thread->pr->debug_data); + } + return thread; +} + +static void +start_progs_thread (qwaq_thread_t *thread) +{ + pthread_create (&thread->thread_id, 0, run_progs, thread); +} + +qwaq_thread_t * +create_thread (void *(*thread_func) (qwaq_thread_t *), void *data) +{ + qwaq_thread_t *thread = calloc (1, sizeof (*thread)); + + thread->data = data; + DARRAY_APPEND (&thread_data, thread); + pthread_create (&thread->thread_id, 0, + (void*(*)(void*))thread_func, thread); + return thread; +} + +static void +usage (int status) +{ + printf ("%s - QuakeForge runtime\n", this_program); + printf ("sorry, no help yet\n"); + exit (status); +} + +static int +parse_argset (int argc, char **argv) +{ + qwaq_thread_t *thread = calloc (1, sizeof (*thread)); + DARRAY_INIT (&thread->args, 8); + + DARRAY_APPEND (&thread->args, 0); + while (optind < argc && strcmp (argv[optind], "--")) { + DARRAY_APPEND (&thread->args, argv[optind++]); + } + if (optind < argc) { + optind++; + } + DARRAY_APPEND (&thread_data, thread); + return thread_data.size - 1; +} + +static int +parse_args (int argc, char **argv) +{ + int c; + qwaq_thread_t *main_thread = calloc (1, sizeof (*main_thread)); + int qargs_ind = -1; + + DARRAY_INIT (&main_thread->args, 8); + + while ((c = getopt_long (argc, argv, + short_options, long_options, 0)) != -1) { + switch (c) { + case 1: + DARRAY_APPEND (&main_thread->args, argv[optind - 1]); + break; + case OPT_QARGS: + if (qargs_ind < 0) { + qargs_ind = parse_argset (argc, argv); + thread_data.a[qargs_ind]->args.a[0] = "--qargs"; + goto done; + } else { + printf ("more than one set of qargs given"); + exit (1); + } + break; + default: + usage (1); + } + } +done: + + free (thread_data.a[0]->args.a); + free (thread_data.a[0]); + thread_data.a[0] = main_thread; + + while (optind < argc) { + parse_argset (argc, argv); + } + return qargs_ind; +} + +static void +bi_printf (progs_t *pr) +{ + const char *fmt = P_GSTRING (pr, 0); + int count = pr->pr_argc - 1; + pr_type_t **args = pr->pr_params + 1; + dstring_t *dstr = dstring_new (); + + PR_Sprintf (pr, dstr, "bi_printf", fmt, count, args); + if (dstr->str) + Sys_Printf (dstr->str, stdout); + dstring_delete (dstr); +} + +static void +bi_traceon (progs_t *pr) +{ + pr->pr_trace = true; + pr->pr_trace_depth = pr->pr_depth; +} + +static void +bi_traceoff (progs_t *pr) +{ + pr->pr_trace = false; +} + +static builtin_t common_builtins[] = { + {"printf", bi_printf, -1}, + {"traceon", bi_traceon, -1}, + {"traceoff", bi_traceoff, -1}, + {}, +}; + +static void +common_builtins_init (progs_t *pr) +{ + PR_RegisterBuiltins (pr, common_builtins); +} + +static progsinit_f main_app[] = { + Key_Progs_Init, + BI_Init, + common_builtins_init, + QWAQ_EditBuffer_Init, + QWAQ_Debug_Init, + 0 +}; + +static progsinit_f target_app[] = { + common_builtins_init, + QWAQ_DebugTarget_Init, + 0 +}; + +int +main (int argc, char **argv) +{ + int qargs_ind = -1; + int main_ind = -1; + int ret = 0; + size_t num_sys = 1; + + this_program = argv[0]; + + DARRAY_INIT (&thread_data, 4); + for (optind = 1; optind < argc; ) { + parse_argset (argc, argv); + } + if (thread_data.size) { + qwaq_thread_t *thread = thread_data.a[0]; + // the first arg is initialized to null, but this is for getopt, so + // set to main program name + thread->args.a[0] = this_program; + optind = 0; + qargs_ind = parse_args (thread->args.size, (char **) thread->args.a); + } else { + // create a blank main thread set + qwaq_thread_t *thread = calloc (1, sizeof (*thread)); + DARRAY_INIT (&thread->args, 4); + DARRAY_APPEND (&thread_data, thread); + } + + if (qargs_ind >= 0) { + qwaq_thread_t *qargs = thread_data.a[qargs_ind]; + // the first arg is initialized to --qargs, so + // set to main program name for now + qargs->args.a[0] = this_program; + COM_InitArgv (qargs->args.size, qargs->args.a); + num_sys++; + } else { + qwaq_thread_t qargs = {}; + DARRAY_INIT (&qargs.args, 2); + DARRAY_APPEND (&qargs.args, this_program); + COM_InitArgv (qargs.args.size, qargs.args.a); + } + + init_qf (); + + if (thread_data.a[0]->args.size < 1) { + DARRAY_APPEND (&thread_data.a[0]->args, "qwaq-app.dat"); + } + + while (thread_data.size < thread_data.a[0]->args.size + num_sys) { + qwaq_thread_t *thread = calloc (1, sizeof (*thread)); + DARRAY_INIT (&thread->args, 4); + DARRAY_APPEND (&thread->args, 0); + DARRAY_APPEND (&thread_data, thread); + } + + for (size_t i = 1, thread_ind = 0; i < thread_data.size; i++) { + qwaq_thread_t *thread = thread_data.a[i]; + progsinit_f *app_funcs = target_app; + + if (thread->args.size && thread->args.a[0] + && strcmp (thread->args.a[0], "--qargs")) { + // skip the args set that's passed to qargs + continue; + } + if (thread_ind < thread_data.a[0]->args.size) { + thread->args.a[0] = thread_data.a[0]->args.a[thread_ind++]; + } else { + printf ("ignoring extra arg sets\n"); + break; + } + if (main_ind < 0) { + main_ind = i; + app_funcs = main_app; + } + thread->progsinit = app_funcs; + } + if (main_ind >= 0) { + // threads might start new threads before the end is reached + size_t count = thread_data.size; + for (size_t i = 0; i < count; i++) { + if (thread_data.a[i]->progsinit) { + start_progs_thread (thread_data.a[i]); + } + } + pthread_join (thread_data.a[main_ind]->thread_id, 0); + ret = thread_data.a[main_ind]->return_code; + } + + Sys_Shutdown (); + return ret; +} diff --git a/tools/qwaq/qwaq-bi.c b/ruamoko/qwaq/builtins/qwaq-bi.c similarity index 94% rename from tools/qwaq/qwaq-bi.c rename to ruamoko/qwaq/builtins/qwaq-bi.c index 3c5964df7..a78dd7763 100644 --- a/tools/qwaq/qwaq-bi.c +++ b/ruamoko/qwaq/builtins/qwaq-bi.c @@ -60,7 +60,7 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$"; #include "QF/plugin/console.h" #include "QF/plugin/vid_render.h" -#include "qwaq.h" +#include "ruamoko/qwaq/qwaq.h" CLIENT_PLUGIN_PROTOS static plugin_list_t client_plugin_list[] = { @@ -127,7 +127,7 @@ bi_refresh (progs_t *pr) IN_ProcessEvents (); //GIB_Thread_Execute (); Cbuf_Execute_Stack (qwaq_cbuf); - r_funcs->SCR_UpdateScreen (con_realtime, bi_3d, bi_2dfuncs); + SCR_UpdateScreen (con_realtime, bi_3d, bi_2dfuncs); R_FLOAT (pr) = con_frametime; } @@ -143,20 +143,24 @@ bi_refresh_3d (progs_t *pr) qc3d = P_FUNCTION (pr, 0); } +static void +bi_shutdown_ (progs_t *pr) +{ + Sys_Shutdown (); +} + static builtin_t builtins[] = { {"printf", bi_printf, -1}, {"refresh", bi_refresh, -1}, {"refresh_2d", bi_refresh_2d, -1}, {"refresh_3d", bi_refresh_3d, -1}, + {"shutdown", bi_shutdown_, -1}, {0} }; static void -bi_shutdown (void) +bi_shutdown (void *data) { - S_Shutdown (); - IN_Shutdown (); - VID_Shutdown (); } void @@ -170,7 +174,7 @@ BI_Init (progs_t *pr) PI_Init (); PI_RegisterPlugins (client_plugin_list); - Sys_RegisterShutdown (bi_shutdown); + Sys_RegisterShutdown (bi_shutdown, 0); VID_Init_Cvars (); IN_Init_Cvars (); diff --git a/tools/qwaq/qwaq.c b/ruamoko/qwaq/builtins/qwaq.c similarity index 88% rename from tools/qwaq/qwaq.c rename to ruamoko/qwaq/builtins/qwaq.c index f1197ccfb..fa18d01b1 100644 --- a/tools/qwaq/qwaq.c +++ b/ruamoko/qwaq/builtins/qwaq.c @@ -46,7 +46,7 @@ #include "QF/va.h" #include "QF/zone.h" -#include "qwaq.h" +#include "ruamoko/qwaq/qwaq.h" #define MAX_EDICTS 1024 @@ -71,7 +71,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -79,7 +79,7 @@ load_file (progs_t *pr, const char *name) file = open_file (name, &size); if (!file) { - file = open_file (va ("%s.gz", name), &size); + file = open_file (va (0, "%s.gz", name), &size); if (!file) { return 0; } @@ -87,6 +87,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } @@ -113,12 +114,12 @@ init_qf (void) //Cvar_Set (developer, "1"); - Memory_Init (malloc (8 * 1024 * 1024), 8 * 1024 * 1024); + Memory_Init (Sys_Alloc (8 * 1024 * 1024), 8 * 1024 * 1024); Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "0", 0, 0, 0); - pr.edicts = &edicts; + pr.pr_edicts = &edicts; pr.num_edicts = &num_edicts; pr.reserved_edicts = &reserved_edicts; pr.load_file = load_file; @@ -127,7 +128,7 @@ init_qf (void) pr.no_exec_limit = 1; PR_Init_Cvars (); - PR_Init (); + PR_Init (&pr); RUA_Init (&pr, 0); PR_Cmds_Init (&pr); BI_Init (&pr); @@ -144,9 +145,11 @@ load_progs (const char *name) return 0; } pr.progs_name = name; - PR_LoadProgsFile (&pr, file, size, 1, 1024 * 1024); + pr.max_edicts = 1; + pr.zone_size = 1024*1024; + PR_LoadProgsFile (&pr, file, size); Qclose (file); - if (!PR_RunLoadFuncs (&pr)) + if (!PR_RunLoadFuncs (&pr) || !PR_RunPostLoadFuncs (&pr)) PR_Error (&pr, "unable to load %s", pr.progs_name); return 1; } @@ -167,7 +170,7 @@ main (int argc, const char **argv) name = argv[1]; if (!load_progs (name)) - Sys_Error ("couldn't load %s", "qwaq.dat"); + Sys_Error ("couldn't load %s", name); PR_PushFrame (&pr); if (argc > 2) @@ -186,6 +189,7 @@ main (int argc, const char **argv) PR_RESET_PARAMS (&pr); P_INT (&pr, 0) = pr_argc; P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); + pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); return R_INT (&pr); diff --git a/ruamoko/qwaq/debugger/debug.h b/ruamoko/qwaq/debugger/debug.h new file mode 100644 index 000000000..f6f58f5ed --- /dev/null +++ b/ruamoko/qwaq/debugger/debug.h @@ -0,0 +1,109 @@ +#ifndef __qwaq_debugger_debug_h +#define __qwaq_debugger_debug_h + +#include "ruamoko/qwaq/ui/event.h" + +typedef enum { + qe_debug_event = 0x0100, +} qwaq_debug_messages; + +#ifdef __QFCC__ + +#include + +//FIXME finish unsigned in qfcc +#ifndef umax +#define umax 0x7fffffff +#endif + +typedef string string_t; + +#endif + +typedef struct qdb_event_s { + prdebug_t what; + union { + string_t message; + unsigned function; + int exit_code; + }; +} qdb_event_t; + +typedef struct qdb_state_s { + unsigned staddr; + unsigned func; + string_t file; + unsigned line; +} qdb_state_t; + +typedef struct qdb_stack_s { + unsigned staddr; // return address + unsigned func; // calling function + // FIXME temp strings +} qdb_stack_t; + +typedef struct qdb_def_s { + unsigned type_size; // type in lower 16, size in upper 16 + unsigned offset; + unsigned name; // string + unsigned type_encoding; +} qdb_def_t; + +typedef struct qdb_function_s { + int staddr; + unsigned local_data; + unsigned local_size; + unsigned profile; + unsigned name; // string + unsigned file; // string + unsigned num_params; +} qdb_function_t; + +typedef struct qdb_auxfunction_s { + unsigned function; + unsigned source_line; + unsigned line_info; + unsigned local_defs; + unsigned num_locals; + unsigned return_type; +} qdb_auxfunction_t; + +#ifdef __QFCC__ + +typedef struct qdb_target_s { int handle; } qdb_target_t; + +void qdb_set_trace (qdb_target_t target, int state); +int qdb_set_breakpoint (qdb_target_t target, unsigned staddr); +int qdb_clear_breakpoint (qdb_target_t target, unsigned staddr); +int qdb_set_watchpoint (qdb_target_t target, unsigned offset); +int qdb_clear_watchpoint (qdb_target_t target); +int qdb_continue (qdb_target_t target); +qdb_state_t qdb_get_state (qdb_target_t target); +int qdb_get_stack_depth (qdb_target_t target); +qdb_stack_t *qdb_get_stack (qdb_target_t target); +int qdb_get_event (qdb_target_t target, qdb_event_t *event); +int qdb_get_data (qdb_target_t target, unsigned src, unsigned len, void *dst); +@overload string qdb_get_string (qdb_target_t target, unsigned str); +// note: str is likely not valid in the host progs, it's just a convinience to +// avoid cast shenanigans when getting type encoding strings +@overload string qdb_get_string (qdb_target_t target, string str); +string qdb_get_file_path (qdb_target_t target, string file); +qdb_def_t qdb_find_global (qdb_target_t target, string name); +qdb_def_t qdb_find_field (qdb_target_t target, string name); +qdb_function_t *qdb_find_function (qdb_target_t target, string name); +qdb_function_t *qdb_get_function (qdb_target_t target, unsigned fnum); +qdb_auxfunction_t *qdb_find_auxfunction (qdb_target_t target, string name); +qdb_auxfunction_t *qdb_get_auxfunction (qdb_target_t target, unsigned fnum); +qdb_def_t *qdb_get_local_defs (qdb_target_t target, unsigned fnum); + +void traceon(); +void traceoff(); + +#else//GCC + +void QWAQ_Debug_Init (progs_t *pr); +void QWAQ_DebugTarget_Init (progs_t *pr); + +#endif + +#endif//__qwaq_debugger_debug_h diff --git a/ruamoko/qwaq/debugger/debug.r b/ruamoko/qwaq/debugger/debug.r new file mode 100644 index 000000000..feb8adbdd --- /dev/null +++ b/ruamoko/qwaq/debugger/debug.r @@ -0,0 +1,29 @@ +#include "ruamoko/qwaq/debugger/debug.h" + +void traceon() = #0; +void traceoff() = #0; + +void qdb_set_trace (qdb_target_t target, int state) = #0; +int qdb_set_breakpoint (qdb_target_t target, unsigned staddr) = #0; +int qdb_clear_breakpoint (qdb_target_t target, unsigned staddr) = #0; +int qdb_set_watchpoint (qdb_target_t target, unsigned offset) = #0; +int qdb_clear_watchpoint (qdb_target_t target) = #0; +int qdb_continue (qdb_target_t target) = #0; +qdb_state_t qdb_get_state (qdb_target_t target) = #0; +int qdb_get_stack_depth (qdb_target_t target) = #0; +qdb_stack_t *qdb_get_stack (qdb_target_t target) = #0; +int qdb_get_event (qdb_target_t target, qdb_event_t *event) = #0; +int qdb_get_data (qdb_target_t target, unsigned src, unsigned len, + void *dst) = #0; +string qdb_get_string (qdb_target_t target, unsigned str) = #0; +string qdb_get_string (qdb_target_t target, string str) = #0; +string qdb_get_file_path (qdb_target_t target, string file) = #0; +qdb_def_t qdb_find_global (qdb_target_t target, string name) = #0; +qdb_def_t qdb_find_field (qdb_target_t target, string name) = #0; +qdb_function_t *qdb_find_function (qdb_target_t target, string name) = #0; +qdb_function_t *qdb_get_function (qdb_target_t target, unsigned fnum) = #0; +qdb_auxfunction_t *qdb_find_auxfunction (qdb_target_t target, + string name) = #0; +qdb_auxfunction_t *qdb_get_auxfunction (qdb_target_t target, + unsigned fnum) = #0; +qdb_def_t *qdb_get_local_defs (qdb_target_t target, unsigned fnum) = #0; diff --git a/ruamoko/qwaq/debugger/debugger.h b/ruamoko/qwaq/debugger/debugger.h new file mode 100644 index 000000000..8694d06c0 --- /dev/null +++ b/ruamoko/qwaq/debugger/debugger.h @@ -0,0 +1,49 @@ +#ifndef __qwaq_debugger_debugger_h +#define __qwaq_debugger_debugger_h + +#include +#include + +#include "ruamoko/qwaq/debugger/debug.h" +#include "ruamoko/qwaq/debugger/localsdata.h" + +@class ProxyView; +@class Editor; +@class ScrollBar; +@class Window; +@class Array; +@class TableView; + +@interface Debugger : Object +{ + qdb_target_t target; + qdb_event_t event; + struct { + qdb_state_t state; + int depth; + int until_function; + } trace_cond; + struct { + int onEnter; + int onExit; + } sub_cond; + SEL traceHandler; + int running; + + Window *source_window; + ScrollBar *source_scrollbar; + ProxyView *file_proxy; + Array *files; + Editor *current_file; + + Window *locals_window; + LocalsData *locals_data; + TableView *locals_view; +} ++(Debugger *)withTarget:(qdb_target_t)target; +-initWithTarget:(qdb_target_t) target; +-(qdb_target_t)target; +-handleDebugEvent; +@end + +#endif//__qwaq_debugger_debugger_h diff --git a/ruamoko/qwaq/debugger/debugger.r b/ruamoko/qwaq/debugger/debugger.r new file mode 100644 index 000000000..3acf1707e --- /dev/null +++ b/ruamoko/qwaq/debugger/debugger.r @@ -0,0 +1,284 @@ +#include +#include +#include +#include + +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/ui/listener.h" +#include "ruamoko/qwaq/ui/proxyview.h" +#include "ruamoko/qwaq/ui/scrollbar.h" +#include "ruamoko/qwaq/ui/tableview.h" +#include "ruamoko/qwaq/ui/window.h" +#include "ruamoko/qwaq/debugger/debugger.h" +#include "ruamoko/qwaq/debugger/typeencodings.h" +#include "ruamoko/qwaq/editor/editor.h" +#include "ruamoko/qwaq/qwaq-app.h" + +@implementation Debugger ++(Debugger *)withTarget:(qdb_target_t)target +{ + return [[[self alloc] initWithTarget:target] autorelease]; +} + +-(qdb_target_t)target +{ + return target; +} + +-initWithTarget:(qdb_target_t) target +{ + if (!(self = [super init])) { + return nil; + } + self.target = target; + + Extent s = [application size]; + files = [[Array array] retain]; + source_window = [Window withRect: {nil, s}]; + [application addView:source_window]; + + source_scrollbar = [ScrollBar vertical:s.height - 2 at:{s.width - 1, 1}]; + [source_window insert:source_scrollbar]; + + return self; +} + +-(void)dealloc +{ + [files release]; + [locals_data release]; + [super dealloc]; +} + +-(Editor *) find_file:(string) filename +{ + Editor *file; + filename = qdb_get_file_path (target, filename); + for (int i = [files count]; i-- > 0; ) { + file = [files objectAtIndex: i]; + if ([file filename] == filename) { + return file; + } + } + Rect rect = {{1, 1}, [source_window size]}; + rect.extent.width -= 2; + rect.extent.height -= 2; + file = [Editor withRect:rect file:filename]; + [files addObject: file]; + return file; +} + +-(void) setup +{ + qdb_state_t state = qdb_get_state (target); + + current_file = [self find_file: state.file]; + file_proxy = [ProxyView withView: current_file]; + [[current_file gotoLine:state.line - 1] highlightLine]; + [[current_file onEvent] addListener: self :@selector(proxy_event::)]; + [current_file setVerticalScrollBar:source_scrollbar]; + //FIXME id? + [source_window insertSelected: (View *) file_proxy]; + [source_window setTitle:[current_file filename]]; + [source_window redraw]; + + locals_window = [Window withRect:{{0, 0}, {40, 10}}]; + [locals_window setBackground: color_palette[064]]; + [locals_window setTitle: "Locals"]; + locals_data = [[LocalsData withTarget:target] retain]; + locals_view = [TableView withRect:{{1, 1}, {38, 8}}]; + [locals_view addColumn:[TableViewColumn named:"name" width:12]]; + [locals_view addColumn:[[TableViewColumn named:"value" width:26] + setGrowMode:gfGrowHiX]]; + ScrollBar *sb = [ScrollBar vertical:8 at:{39, 1}]; + [locals_view setVerticalScrollBar:sb]; + [locals_view setDataSource:locals_data]; + [locals_window insertSelected: locals_view]; + [locals_window insert: sb]; + [application addView: locals_window]; + + [[locals_view onEvent] addListener:self :@selector(proxy_event::)]; +} + +-(void) show_line +{ + qdb_state_t state = qdb_get_state (target); + Editor *file = [self find_file: state.file]; + + if (current_file != file) { + [current_file setVerticalScrollBar:nil]; + [[current_file onEvent] removeListener:self :@selector(proxy_event::)]; + [file_proxy setView:file]; + [[file onEvent] addListener:self :@selector(proxy_event::)]; + [file setVerticalScrollBar:source_scrollbar]; + [source_window setTitle:[file filename]]; + current_file = file; + } + [[current_file gotoLine:state.line - 1] highlightLine]; + [source_window redraw]; +} + +-(void)update_watchvars +{ + qdb_state_t state = qdb_get_state (target); + [locals_data setFunction:state.func]; + [locals_data fetchData]; + [locals_view redraw]; +} + +static int +proxy_event_stopped (Debugger *self, id proxy, qwaq_event_t *event) +{ + if (event.what == qe_mouseclick && !(event.mouse.buttons & 0x78)) { + if (proxy == self.current_file) { + printf ("%s\n", [proxy getWordAt: {event.mouse.x, event.mouse.y}]); + [self.source_window redraw]; + return 1; + } + } else if (event.what == qe_keydown) { + switch (event.key.code) { + case QFK_F7: + case 's': + self.traceHandler = @selector(traceStep); + qdb_set_trace (self.target, 1); + self.trace_cond.state = qdb_get_state (self.target); + self.running = 1; + qdb_continue (self.target); + return 1; + case QFK_F8: + case 'n': + self.traceHandler = @selector(traceNext); + qdb_set_trace (self.target, 1); + self.trace_cond.state = qdb_get_state (self.target); + self.trace_cond.depth = qdb_get_stack_depth (self.target); + self.running = 1; + qdb_continue (self.target); + return 1; + } + } + return 0; +} + +static int +proxy_event_running (Debugger *self, id proxy, qwaq_event_t *event) +{ + return 0; +} + +-(void)proxy_event:(id)proxy :(qwaq_event_t *)event +{ + if (running) { + if (proxy_event_running (self, proxy, event)) { + event.what = qe_none; + } + } else { + if (proxy_event_stopped (self, proxy, event)) { + event.what = qe_none; + } + } +} + +-stop:(prdebug_t)reason +{ + running = 0; + if (!file_proxy) { + [self setup]; + } + [self show_line]; + [self update_watchvars]; + return self; +} + +// stop only if the progs have not advanced (may be a broken jump) +// or the progs have advanced to a different source line +static int +is_new_line (qdb_state_t last_state, qdb_state_t state) +{ + return !(last_state.staddr != state.staddr + && last_state.func == state.func + && last_state.file == state.file + && last_state.line == state.line); +} + +-traceStep +{ + qdb_state_t state = qdb_get_state (target); + + if (trace_cond.until_function && trace_cond.until_function == state.func) { + trace_cond.until_function = 0; + [self stop:prd_trace]; + return self; + } + if (is_new_line(trace_cond.state, state)) { + [self stop:prd_trace]; + return self; + } + trace_cond.state = state; + qdb_continue (self.target); + return self; +} + +-traceNext +{ + qdb_state_t state = qdb_get_state (target); + if (trace_cond.until_function && trace_cond.until_function == state.func) { + trace_cond.until_function = 0; + [self stop:prd_trace]; + return self; + } + if (is_new_line(trace_cond.state, state) + && qdb_get_stack_depth (target) <= trace_cond.depth) { + [self stop:prd_trace]; + return self; + } + trace_cond.state = state; + qdb_continue (self.target); + return self; +} + +-handleDebugEvent +{ + if (qdb_get_event (target, &event)) { + switch (event.what) { + case prd_none: + break; // shouldn't happen + case prd_trace: + [self performSelector:traceHandler]; + break; + case prd_breakpoint: + case prd_watchpoint: + [self stop:event.what]; + break; + case prd_subenter: + if (sub_cond.onEnter) { + [self stop:event.what]; + } else { + qdb_continue (self.target); + } + break; + case prd_subexit: + if (sub_cond.onExit) { + [self stop:event.what]; + } else { + qdb_continue (self.target); + } + break; + case prd_begin: + trace_cond.until_function = event.function; + [self stop:event.what]; + break; + case prd_terminate: + wprintf(stdscr, "Program ended: %d\n", event.exit_code); + [self stop:event.what]; + break; + case prd_runerror: + case prd_error: + wprintf(stdscr, "%s\n", event.message); + [self stop:event.what]; + break; + } + } + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/localsdata.h b/ruamoko/qwaq/debugger/localsdata.h new file mode 100644 index 000000000..3428219cb --- /dev/null +++ b/ruamoko/qwaq/debugger/localsdata.h @@ -0,0 +1,23 @@ +#ifndef __qwaq_debugger_localsview_h +#define __qwaq_debugger_localsview_h + +#include +#include "ruamoko/qwaq/ui/tableview.h" +#include "ruamoko/qwaq/debugger/debug.h" + +@interface LocalsData : Object +{ + qdb_target_t target; + qfot_type_encodings_t target_encodings; + unsigned current_fnum; + qdb_function_t *func; + qdb_auxfunction_t *aux_func; + qdb_def_t *defs; + void *data; +} ++(LocalsData *)withTarget:(qdb_target_t)target; +-setFunction:(unsigned)fnum; +-fetchData; +@end + +#endif diff --git a/ruamoko/qwaq/debugger/localsdata.r b/ruamoko/qwaq/debugger/localsdata.r new file mode 100644 index 000000000..c974cdd98 --- /dev/null +++ b/ruamoko/qwaq/debugger/localsdata.r @@ -0,0 +1,103 @@ +#include +#include +#include "ruamoko/qwaq/debugger/views/defview.h" +#include "ruamoko/qwaq/debugger/views/nameview.h" +#include "ruamoko/qwaq/debugger/localsdata.h" +#include "ruamoko/qwaq/debugger/typeencodings.h" + +@implementation LocalsData + +-initWithTarget:(qdb_target_t) target +{ + if (!(self = [super init])) { + return nil; + } + self.target = target; + + qdb_def_t encodings_def = qdb_find_global (target, ".type_encodings"); + qdb_get_data (target, encodings_def.offset, sizeof(target_encodings), + &target_encodings); + + return self; +} + ++(LocalsData *)withTarget:(qdb_target_t)target +{ + return [[[self alloc] initWithTarget:target] autorelease]; +} + +-(void)dealloc +{ + if (defs) { + obj_free (defs); + defs = nil; + } + if (data) { + obj_free (data); + data = nil; + } +} + +-setFunction:(unsigned) fnum +{ + if (current_fnum == fnum) { + return self; + } + current_fnum =fnum; + + if (defs) { + obj_free (defs); + defs = nil; + } + if (data) { + obj_free (data); + data = nil; + } + func = qdb_get_function (target, fnum); + aux_func = qdb_get_auxfunction (target, fnum); + if (aux_func) { + defs = qdb_get_local_defs (target, fnum); + } + if (func && func.local_size) { + data = obj_malloc (func.local_size); + } + return self; +} + +-fetchData +{ + if (data && func.local_size && func.local_data) { + qdb_get_data (target, func.local_data, func.local_size, data); + } + return self; +} + +-(int)numberOfRows:(TableView *)tableview +{ + if (aux_func) { + return aux_func.num_locals; + } else if (func) { + return (func.local_size + 3) / 4; + } + return 0; +} + +-(View *)tableView:(TableView *)tableview + forColumn:(TableViewColumn *)column + row:(int)row +{ + View *view; + + if ([column name] == "name") { + view = [NameView withName:qdb_get_string (target, defs[row].name)]; + } else { + qfot_type_t *type = [TypeEncodings getType:defs[row].type_encoding + fromTarget:target]; + unsigned offset = defs[row].offset; + view = [DefView withType:type at:offset in:data target:target]; + } + [view resizeTo:{[column width], 1}]; + return view; +} + +@end diff --git a/ruamoko/qwaq/debugger/typeencodings.h b/ruamoko/qwaq/debugger/typeencodings.h new file mode 100644 index 000000000..11b78d0da --- /dev/null +++ b/ruamoko/qwaq/debugger/typeencodings.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_typeencodings_h +#define __qwaq_debugger_typeencodings_h + +#include +#include + +#include "ruamoko/qwaq/debugger/debug.h" + +@interface TypeEncodings : Object ++(qfot_type_t *)getType:(unsigned)typeAddr fromTarget:(qdb_target_t)target; +@end + +#endif//__qwaq_debugger_typeencodings_h diff --git a/ruamoko/qwaq/debugger/typeencodings.r b/ruamoko/qwaq/debugger/typeencodings.r new file mode 100644 index 000000000..7a5fd26d7 --- /dev/null +++ b/ruamoko/qwaq/debugger/typeencodings.r @@ -0,0 +1,145 @@ +#include +#include +#include + +#include "ruamoko/qwaq/ui/curses.h" // printf FIXME +#include "ruamoko/qwaq/debugger/typeencodings.h" + +@implementation TypeEncodings + +// these are encodings that we already have so don't need to copy them from +// the target +static hashtab_t *static_encodings; +// these are condings that had to be copied from the target +static hashtab_t *dynamic_encodings; + +static qfot_type_t * +next_type (qfot_type_t *type) +{ + int size = type.size; + + if (!size) { // null type + size = TYPESIZE; + } + return (qfot_type_t *) ((int *) type + size); +} + +static string +type_get_key (void *t, void *unusded) +{ + qfot_type_t *type = (qfot_type_t *) t; + return type.encoding; +} + +static void type_free (void *t, void *unused) +{ + qfot_type_t *type = (qfot_type_t *) t; + str_free (type.encoding); + switch (type.meta) { + case ty_basic: + case ty_array: + break; + case ty_struct: + case ty_union: + case ty_enum: + str_free (type.strct.tag); + for (int i = 0; i < type.strct.num_fields; i++) { + str_free (type.strct.fields[i].name); + } + break; + case ty_class: + str_free (type.class); + break; + case ty_alias: + str_free (type.alias.name); + break; + } + obj_free (t); +} + ++initialize +{ + qfot_type_encodings_t *encodings; + qfot_type_t *type; + + static_encodings = Hash_NewTable (1023, type_get_key, nil, nil); + dynamic_encodings = Hash_NewTable (1023, type_get_key, type_free, nil); + + encodings = PR_FindGlobal (".type_encodings"); + for (type = encodings.types; + ((int *)type - (int *) encodings.types) < encodings.size; + type = next_type (type)) { + Hash_Add (static_encodings, type); + } + return self; +} + ++(qfot_type_t *) getType:(unsigned)typeAddr fromTarget:(qdb_target_t)target +{ + qfot_type_t buffer = {}; + string encoding; + qfot_type_t *type; + + if (qdb_get_data (target, typeAddr, TYPESIZE, &buffer) < 0) { + return nil; + } + if (!buffer.size) { + return nil; + } + encoding = qdb_get_string (target, buffer.encoding); + if (!encoding) { + return nil; + } + if ((type = Hash_Find (static_encodings, encoding))) { + return type; + } + if ((type = Hash_Find (dynamic_encodings, encoding))) { + return type; + } + type = obj_calloc (1, buffer.size); + if (qdb_get_data (target, typeAddr, buffer.size, type) < 0) { + goto error; + } + if (!(type.encoding = qdb_get_string (target, type.encoding))) { + goto error; + } + switch (type.meta) { + case ty_basic: + case ty_array: + goto hash_type; + case ty_struct: + case ty_union: + case ty_enum: + if (!(type.strct.tag = qdb_get_string (target, type.strct.tag))) { + goto error; + } + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (!(var.name = qdb_get_string (target, var.name))) { + goto error; + } + } + goto hash_type; + case ty_class: + if (!(type.class = qdb_get_string (target, type.class))) { + goto error; + } + goto hash_type; + case ty_alias: + if (!(type.alias.name = qdb_get_string (target, type.alias.name))) { + goto error; + } + goto hash_type; + } + goto error; +hash_type: + printf ("fetched type %s\n", type.encoding); + Hash_Add (dynamic_encodings, type); + return type; + // not a valid type +error: + type_free (type, nil); + return nil; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/basicview.h b/ruamoko/qwaq/debugger/views/basicview.h new file mode 100644 index 000000000..d5424c487 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/basicview.h @@ -0,0 +1,11 @@ +#ifndef __qwaq_debugger_basicview_h +#define __qwaq_debugger_basicview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface BasicView : DefView +// might return a NameView (which is also a DefView) ++(DefView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_basicview_h diff --git a/ruamoko/qwaq/debugger/views/basicview.r b/ruamoko/qwaq/debugger/views/basicview.r new file mode 100644 index 000000000..96abfc302 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/basicview.r @@ -0,0 +1,48 @@ +#include +#include "ruamoko/qwaq/debugger/views/basicview.h" +#include "ruamoko/qwaq/debugger/views/nameview.h" + +static string type_views[] = { + "VoidView", + "StringView", + "FloatView", + "VectorView", + "EntityView", + "FieldView", + "FuncView", + "PointerView", + "QuatView", + "IntView", + "UIntView", // uinteger + "IntView", // short + "DoubleView", +}; + +@implementation BasicView + +-init +{ + if (!(self = [super init])) { + return nil; + } + return self; +} + ++(DefView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + string typename = nil; + if (type.type == ty_alias) { + type = type.alias.aux_type; + } + if (type.type >= 0 + && type.type < sizeof(type_views) / sizeof (type_views[0])) { + typename = type_views[type.type]; + } + id class = obj_lookup_class (typename); + if (class) { + return [class withType:type at:offset in:data]; + } + return [NameView withName:"Invalid Type"]; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/defview.h b/ruamoko/qwaq/debugger/views/defview.h new file mode 100644 index 000000000..7e2562104 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/defview.h @@ -0,0 +1,20 @@ +#ifndef __qwaq_debugger_defview_h +#define __qwaq_debugger_defview_h + +#include +#include "ruamoko/qwaq/ui/view.h" +#include "ruamoko/qwaq/debugger/debug.h" + +@interface DefView : View +{ + qfot_type_t *type; + qdb_target_t target; +} ++(DefView *)withType:(qfot_type_t *)type + at:(unsigned)offset + in:(void *)data + target:(qdb_target_t)target; +-initWithType:(qfot_type_t *)type; +@end + +#endif//__qwaq_debugger_defview_h diff --git a/ruamoko/qwaq/debugger/views/defview.r b/ruamoko/qwaq/debugger/views/defview.r new file mode 100644 index 000000000..a972b972f --- /dev/null +++ b/ruamoko/qwaq/debugger/views/defview.r @@ -0,0 +1,65 @@ +#include +#include "ruamoko/qwaq/debugger/views/defview.h" +#include "ruamoko/qwaq/debugger/views/nameview.h" + +static string meta_views[] = { + "BasicView", + "StructView", + "UnionView", + "EnumView", + "ArrayView", + "ClassView", + "AliasView", // shouldn't happen, but... +}; + +@implementation DefView + +-init +{ + if (!(self = [super init])) { + return nil; + } + return self; +} + +-initWithType:(qfot_type_t *)type +{ + if (!(self = [super init])) { + return nil; + } + self.type = type; + return self; +} + +-setTarget:(qdb_target_t)target +{ + self.target = target; + return self; +} + ++(DefView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [self withType:type at:offset in:data target:nil]; +} + ++(DefView *)withType:(qfot_type_t *)type + at:(unsigned)offset + in:(void *)data + target:(qdb_target_t)target +{ + string metaname = nil; + if (type.meta == ty_alias) { + type = type.alias.aux_type; + } + if (type.meta >= 0 + && type.meta < sizeof(meta_views) / sizeof (meta_views[0])) { + metaname = meta_views[type.meta]; + } + id class = obj_lookup_class (metaname); + if (class) { + return [[class withType:type at:offset in:data] setTarget:target]; + } + return [NameView withName:"Invalid Meta"]; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/doubleview.h b/ruamoko/qwaq/debugger/views/doubleview.h new file mode 100644 index 000000000..90637ecf3 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/doubleview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_doubleview_h +#define __qwaq_debugger_doubleview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface DoubleView : DefView +{ + double *data; +} ++(DoubleView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_doubleview_h diff --git a/ruamoko/qwaq/debugger/views/doubleview.r b/ruamoko/qwaq/debugger/views/doubleview.r new file mode 100644 index 000000000..d94f4e231 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/doubleview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/doubleview.h" + +@implementation DoubleView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (double *)(data + offset); + return self; +} + ++(DoubleView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("%.17g", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/entityview.h b/ruamoko/qwaq/debugger/views/entityview.h new file mode 100644 index 000000000..5ad8bd908 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/entityview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_entityview_h +#define __qwaq_debugger_entityview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface EntityView : DefView +{ + entity *data; +} ++(EntityView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_entityview_h diff --git a/ruamoko/qwaq/debugger/views/entityview.r b/ruamoko/qwaq/debugger/views/entityview.r new file mode 100644 index 000000000..1170a3f7d --- /dev/null +++ b/ruamoko/qwaq/debugger/views/entityview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/entityview.h" + +@implementation EntityView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (entity *)(data + offset); + return self; +} + ++(EntityView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("FIXME [%x]", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/fieldview.h b/ruamoko/qwaq/debugger/views/fieldview.h new file mode 100644 index 000000000..0cd314b6b --- /dev/null +++ b/ruamoko/qwaq/debugger/views/fieldview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_fieldview_h +#define __qwaq_debugger_fieldview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface FieldView : DefView +{ + unsigned *data; +} ++(FieldView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_fieldview_h diff --git a/ruamoko/qwaq/debugger/views/fieldview.r b/ruamoko/qwaq/debugger/views/fieldview.r new file mode 100644 index 000000000..f8d1547e3 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/fieldview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/fieldview.h" + +@implementation FieldView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (unsigned *)(data + offset); + return self; +} + ++(FieldView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("FIXME [%x]", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/floatview.h b/ruamoko/qwaq/debugger/views/floatview.h new file mode 100644 index 000000000..5c33da88b --- /dev/null +++ b/ruamoko/qwaq/debugger/views/floatview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_floatview_h +#define __qwaq_debugger_floatview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface FloatView : DefView +{ + float *data; +} ++(FloatView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_floatview_h diff --git a/ruamoko/qwaq/debugger/views/floatview.r b/ruamoko/qwaq/debugger/views/floatview.r new file mode 100644 index 000000000..5b4d534eb --- /dev/null +++ b/ruamoko/qwaq/debugger/views/floatview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/floatview.h" + +@implementation FloatView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (float *)(data + offset); + return self; +} + ++(FloatView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("%.9", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/funcview.h b/ruamoko/qwaq/debugger/views/funcview.h new file mode 100644 index 000000000..132812dd3 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/funcview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_funcview_h +#define __qwaq_debugger_funcview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface FuncView : DefView +{ + unsigned *data; +} ++(FuncView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_funcview_h diff --git a/ruamoko/qwaq/debugger/views/funcview.r b/ruamoko/qwaq/debugger/views/funcview.r new file mode 100644 index 000000000..2fa2218f0 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/funcview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/funcview.h" + +@implementation FuncView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (unsigned *)(data + offset); + return self; +} + ++(FuncView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("FIXME [%x]", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/intview.h b/ruamoko/qwaq/debugger/views/intview.h new file mode 100644 index 000000000..d2f271b21 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/intview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_intview_h +#define __qwaq_debugger_intview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface IntView : DefView +{ + int *data; +} ++(IntView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_intview_h diff --git a/ruamoko/qwaq/debugger/views/intview.r b/ruamoko/qwaq/debugger/views/intview.r new file mode 100644 index 000000000..a7df120ed --- /dev/null +++ b/ruamoko/qwaq/debugger/views/intview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/intview.h" + +@implementation IntView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (int *)(data + offset); + return self; +} + ++(IntView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("%d", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/nameview.h b/ruamoko/qwaq/debugger/views/nameview.h new file mode 100644 index 000000000..ee5622062 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/nameview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_nameview_h +#define __qwaq_debugger_nameview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface NameView : DefView +{ + string name; +} ++(NameView *)withName:(string)name; +@end + +#endif//__qwaq_debugger_nameview_h diff --git a/ruamoko/qwaq/debugger/views/nameview.r b/ruamoko/qwaq/debugger/views/nameview.r new file mode 100644 index 000000000..0b66d838e --- /dev/null +++ b/ruamoko/qwaq/debugger/views/nameview.r @@ -0,0 +1,33 @@ +#include +#include "ruamoko/qwaq/debugger/views/nameview.h" + +@implementation NameView + +-initWithName:(string)name +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.name = name; + return self; +} + +-(void)dealloc +{ + str_free (name); + [super dealloc]; +} + ++(NameView *)withName:(string)name +{ + return [[[self alloc] initWithName:name] autorelease]; +} + +-draw +{ + [super draw]; + [self mvaddstr:{0, 0}, str_mid (name, 0, xlen)]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/pointerview.h b/ruamoko/qwaq/debugger/views/pointerview.h new file mode 100644 index 000000000..fb45f1ae3 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/pointerview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_pointerview_h +#define __qwaq_debugger_pointerview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface PointerView : DefView +{ + unsigned *data; +} ++(PointerView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_pointerview_h diff --git a/ruamoko/qwaq/debugger/views/pointerview.r b/ruamoko/qwaq/debugger/views/pointerview.r new file mode 100644 index 000000000..3a000ecf5 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/pointerview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/pointerview.h" + +@implementation PointerView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (unsigned *)(data + offset); + return self; +} + ++(PointerView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("FIXME [%x]", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/quatview.h b/ruamoko/qwaq/debugger/views/quatview.h new file mode 100644 index 000000000..b88f75811 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/quatview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_quatview_h +#define __qwaq_debugger_quatview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface QuatView : DefView +{ + quaternion *data; +} ++(QuatView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_quatview_h diff --git a/ruamoko/qwaq/debugger/views/quatview.r b/ruamoko/qwaq/debugger/views/quatview.r new file mode 100644 index 000000000..fe8ca0ea1 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/quatview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/quatview.h" + +@implementation QuatView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (quaternion *)(data + offset); + return self; +} + ++(QuatView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("%.9q", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/stringview.h b/ruamoko/qwaq/debugger/views/stringview.h new file mode 100644 index 000000000..c8a49d131 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/stringview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_stringview_h +#define __qwaq_debugger_stringview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface StringView : DefView +{ + int *data; +} ++(StringView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_stringview_h diff --git a/ruamoko/qwaq/debugger/views/stringview.r b/ruamoko/qwaq/debugger/views/stringview.r new file mode 100644 index 000000000..d686fd636 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/stringview.r @@ -0,0 +1,29 @@ +#include +#include "ruamoko/qwaq/debugger/views/stringview.h" + +@implementation StringView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (int *)(data + offset); + return self; +} + ++(StringView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("\"%s\"", + str_quote (qdb_get_string (target, data[0]))); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/uintview.h b/ruamoko/qwaq/debugger/views/uintview.h new file mode 100644 index 000000000..5211b2ff7 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/uintview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_uintview_h +#define __qwaq_debugger_uintview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface UIntView : DefView +{ + unsigned *data; +} ++(UIntView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_uintview_h diff --git a/ruamoko/qwaq/debugger/views/uintview.r b/ruamoko/qwaq/debugger/views/uintview.r new file mode 100644 index 000000000..c80b9b517 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/uintview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/uintview.h" + +@implementation UIntView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (unsigned *)(data + offset); + return self; +} + ++(UIntView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("%u", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/vectorview.h b/ruamoko/qwaq/debugger/views/vectorview.h new file mode 100644 index 000000000..2a00c4e39 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/vectorview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_vectorview_h +#define __qwaq_debugger_vectorview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface VectorView : DefView +{ + vector *data; +} ++(VectorView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_vectorview_h diff --git a/ruamoko/qwaq/debugger/views/vectorview.r b/ruamoko/qwaq/debugger/views/vectorview.r new file mode 100644 index 000000000..61a50c6af --- /dev/null +++ b/ruamoko/qwaq/debugger/views/vectorview.r @@ -0,0 +1,28 @@ +#include +#include "ruamoko/qwaq/debugger/views/vectorview.h" + +@implementation VectorView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (vector *)(data + offset); + return self; +} + ++(VectorView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("%.9v", data[0]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/debugger/views/voidview.h b/ruamoko/qwaq/debugger/views/voidview.h new file mode 100644 index 000000000..1c6655bb1 --- /dev/null +++ b/ruamoko/qwaq/debugger/views/voidview.h @@ -0,0 +1,13 @@ +#ifndef __qwaq_debugger_voidview_h +#define __qwaq_debugger_voidview_h + +#include "ruamoko/qwaq/debugger/views/defview.h" + +@interface VoidView : DefView +{ + unsigned *data; +} ++(VoidView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data; +@end + +#endif//__qwaq_debugger_voidview_h diff --git a/ruamoko/qwaq/debugger/views/voidview.r b/ruamoko/qwaq/debugger/views/voidview.r new file mode 100644 index 000000000..81e58b62c --- /dev/null +++ b/ruamoko/qwaq/debugger/views/voidview.r @@ -0,0 +1,29 @@ +#include +#include "ruamoko/qwaq/debugger/views/voidview.h" + +@implementation VoidView + +-initWithType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + if (!(self = [super initWithType:type])) { + return nil; + } + self.data = (unsigned *) (data + offset); + return self; +} + ++(VoidView *)withType:(qfot_type_t *)type at:(unsigned)offset in:(void *)data +{ + return [[[self alloc] initWithType:type at:offset in:data] autorelease]; +} + +-draw +{ + [super draw]; + string val = sprintf ("%08x %08x %08x %08x", + data[0], data[1], data[2], data[3]); + [self mvprintf:{0, 0}, "%*.*s", xlen, xlen, val]; + return self; +} + +@end diff --git a/ruamoko/qwaq/editor/editbuffer.h b/ruamoko/qwaq/editor/editbuffer.h new file mode 100644 index 000000000..a1bfae616 --- /dev/null +++ b/ruamoko/qwaq/editor/editbuffer.h @@ -0,0 +1,84 @@ +#ifndef __qwaq_editor_editbuffer_h +#define __qwaq_editor_editbuffer_h + +#ifdef __QFCC__ +#include + +//FIXME finish unsigned in qfcc +#ifndef umax +#define umax 0x7fffffff +#endif + +#endif//__QFCC__ + +typedef struct eb_sel_s { + unsigned start; + unsigned length; +} eb_sel_t; + +typedef struct eb_color_s { + int normal; + int selected; +} eb_color_t; + +#ifdef __QFCC__ +@interface EditBuffer : Object +{ + struct edit_buffer_s *buffer; +} ++(EditBuffer *)buffer; ++(EditBuffer *)withFile:(string)filename; +-init; +-initWithFile: (string) filename; +- (unsigned) nextChar: (unsigned) charPtr; +- (unsigned) prevChar: (unsigned) charPtr; +- (unsigned) nextNonSpace: (unsigned) charPtr; +- (unsigned) prevNonSpace: (unsigned) charPtr; +- (unsigned) nextWord: (unsigned) wordPtr; +- (unsigned) prevWord: (unsigned) wordPtr; +- (unsigned) nextLine: (unsigned) linePtr; +- (unsigned) prevLine: (unsigned) linePtr; +- (unsigned) nextLine: (unsigned) linePtr : (unsigned) count; +- (unsigned) prevLine: (unsigned) linePtr : (unsigned) count; + +- (unsigned) charPos: (unsigned) linePtr at: (unsigned) target; +- (unsigned) charPtr: (unsigned) linePtr at: (unsigned) target; + +- (eb_sel_t) getWord: (unsigned) wordPtr; +- (eb_sel_t) getLine: (unsigned) linePtr; +- (unsigned) getBOL: (unsigned) linePtr; +- (unsigned) getEOL: (unsigned) linePtr; +- (unsigned) getBOT; +- (unsigned) getEOT; +- (string) readString: (eb_sel_t) selection; + +- (unsigned) countLines: (eb_sel_t) selection; +- (eb_sel_t) search: (eb_sel_t) selection + for: (string) str + direction: (int) dir; +- (eb_sel_t) isearch: (eb_sel_t) selection + for: (string) str + direction: (int) dir; +- (unsigned) formatLine: (unsigned) linePtr + from: (unsigned) xpos + into: (int *) buf + width: (unsigned) length + highlight: (eb_sel_t) selection + colors: (eb_color_t) colors; + +- (BOOL) modified; +- (unsigned) textSize; +- (int) saveFile: (string) fileName; +@end +#else//__QFCC__ + +#include "QF/pr_obj.h" + +typedef struct qwaq_editbuffer_s { + pr_id_t isa; + pointer_t buffer; +} qwaq_editbuffer_t; + +#endif//!__QFCC__ + +#endif//__qwaq_editor_editbuffer_h diff --git a/ruamoko/qwaq/editor/editbuffer.r b/ruamoko/qwaq/editor/editbuffer.r new file mode 100644 index 000000000..cd7644f7d --- /dev/null +++ b/ruamoko/qwaq/editor/editbuffer.r @@ -0,0 +1,58 @@ +#include "ruamoko/qwaq/editor/editbuffer.h" + +@implementation EditBuffer ++(EditBuffer *)buffer +{ + return [[[self alloc] init] autorelease]; +} + ++(EditBuffer *)withFile:(string)filename +{ + return [[[self alloc] initWithFile:filename] autorelease]; +} + +- init = #0; +- initWithFile: (string) filename = #0; +- (void) dealloc = #0; +- (unsigned) nextChar: (unsigned) charPtr = #0; +- (unsigned) prevChar: (unsigned) charPtr = #0; +- (unsigned) nextNonSpace: (unsigned) charPtr = #0; +- (unsigned) prevNonSpace: (unsigned) charPtr = #0; +- (unsigned) nextWord: (unsigned) wordPtr = #0; +- (unsigned) prevWord: (unsigned) wordPtr = #0; +- (unsigned) nextLine: (unsigned) linePtr = #0; +- (unsigned) prevLine: (unsigned) linePtr = #0; +- (unsigned) nextLine: (unsigned) linePtr : (unsigned) count = #0; +- (unsigned) prevLine: (unsigned) linePtr : (unsigned) count = #0; + +- (unsigned) charPos: (unsigned) linePtr + at: (unsigned) target = #0; +- (unsigned) charPtr: (unsigned) linePtr + at: (unsigned) target = #0; + +- (eb_sel_t) getWord: (unsigned) wordPtr = #0; +- (eb_sel_t) getLine: (unsigned) linePtr = #0; +- (unsigned) getBOL: (unsigned) linePtr = #0; +- (unsigned) getEOL: (unsigned) linePtr = #0; +- (unsigned) getBOT = #0; +- (unsigned) getEOT = #0; +- (string) readString: (eb_sel_t) selection = #0; + +- (unsigned) countLines: (eb_sel_t) selection = #0; +- (eb_sel_t) search: (eb_sel_t) selection + for: (string) str + direction: (int) dir = #0; +- (eb_sel_t) isearch: (eb_sel_t) selection + for: (string) str + direction: (int) dir = #0; +- (unsigned) formatLine: (unsigned) linePtr + from: (unsigned) xpos + into: (int *) buf + width: (unsigned) length + highlight: (eb_sel_t) selection + colors: (eb_color_t) colors = #0; + +- (BOOL) modified = #0; +- (unsigned) textSize = #0; +- (int) saveFile: (string) fileName = #0; +@end diff --git a/ruamoko/qwaq/editor/editor.h b/ruamoko/qwaq/editor/editor.h new file mode 100644 index 000000000..cd04f8a8e --- /dev/null +++ b/ruamoko/qwaq/editor/editor.h @@ -0,0 +1,38 @@ +#ifndef __qwaq_editor_editor_h +#define __qwaq_editor_editor_h + +#include "ruamoko/qwaq/editor/editbuffer.h" +#include "ruamoko/qwaq/ui/view.h" + +@class Editor; +@class EditBuffer; +@class ListenerGroup; + +@interface Editor : View +{ + EditBuffer *buffer; + DrawBuffer *linebuffer; + eb_sel_t selection; + unsigned base_index; // top left corner + unsigned line_index; // current line + unsigned char_index; // current character + unsigned old_cind; // previous character + Point base; + Point cursor; + unsigned line_count; + string filename; +} ++(Editor *)withRect:(Rect)rect file:(string)filename; +-(string)filename; +-scrollUp:(unsigned) count; +-scrollDown:(unsigned) count; +-scrollLeft:(unsigned) count; +-scrollRight:(unsigned) count; + +-recenter:(int) force; +-gotoLine:(unsigned) line; +-highlightLine; +-(string)getWordAt:(Point) pos; // view relative coordinates +@end + +#endif//__qwaq_editor_editor_h diff --git a/ruamoko/qwaq/editor/editor.r b/ruamoko/qwaq/editor/editor.r new file mode 100644 index 000000000..62158dfe9 --- /dev/null +++ b/ruamoko/qwaq/editor/editor.r @@ -0,0 +1,230 @@ +#include +#include +#include "ruamoko/qwaq/qwaq-app.h" +#include "ruamoko/qwaq/editor/editor.h" +#include "ruamoko/qwaq/ui/listener.h" +#include "ruamoko/qwaq/ui/scrollbar.h" + +@implementation Editor + +-initWithRect:(Rect) rect file:(string) filename +{ + if (!(self = [super initWithRect: rect])) { + return nil; + } + self.filename = str_hold (filename); + buffer = [[EditBuffer withFile:filename] retain]; + line_count = [buffer countLines: {0, [buffer textSize]}]; + linebuffer = [[DrawBuffer buffer: { xlen, 1 }] retain]; + growMode = gfGrowHi; + options = ofCanFocus | ofRelativeEvents; + [onViewScrolled addListener:self :@selector(onScroll:)]; + return self; +} + ++(Editor *)withRect:(Rect)rect file:(string)filename +{ + return [[[self alloc] initWithRect:rect file:filename] autorelease]; +} + +-(void)dealloc +{ + str_free (filename); + [vScrollBar release]; + [buffer release]; + [linebuffer release]; + [super dealloc]; +} + +-(string)filename +{ + return filename; +} + +-draw +{ + [super draw]; + unsigned lind = base_index; + int *lbuf = [linebuffer buffer]; + for (int y = 0; y < ylen; y++) { + lind = [buffer formatLine:lind from:base.x into:lbuf width:xlen + highlight:selection colors: {color_palette[047], + color_palette[007]}]; + [textContext blitFromBuffer: linebuffer to: {xpos, ypos + y} + from: [linebuffer rect]]; + } + return self; +} + +-resize: (Extent) delta +{ + [super resize: delta]; + [linebuffer resizeTo: {xlen, 1}]; + return self; +} + +static int handleEvent (Editor *self, qwaq_event_t *event) +{ + if (event.what & qe_mouse) { + if (event.what == qe_mouseclick) { + if (event.mouse.buttons & (1 << 3)) { + [self scrollUp: 1]; + return 1; + } + if (event.mouse.buttons & (1 << 4)) { + [self scrollDown: 1]; + return 1; + } + if (event.mouse.buttons & (1 << 5)) { + [self scrollLeft: 1]; + return 1; + } + if (event.mouse.buttons & (1 << 6)) { + [self scrollRight: 1]; + return 1; + } + } + } else if (event.what == qe_keydown) { + switch (event.key.code) { + case QFK_PAGEUP: + [self scrollUp: self.ylen]; + return 1; + case QFK_PAGEDOWN: + [self scrollDown: self.ylen]; + return 1; + } + } + return 0; +} + +-handleEvent:(qwaq_event_t *) event +{ + [super handleEvent: event]; + + if (handleEvent (self, event)) { + event.what = qe_none; + } + return self; +} + +-scrollUp:(unsigned) count +{ + if (count == 1) { + base_index = [buffer prevLine: base_index]; + } else { + base_index = [buffer prevLine: base_index :count]; + } + [self redraw]; + return self; +} + +-scrollDown:(unsigned) count +{ + if (count == 1) { + base_index = [buffer nextLine: base_index]; + } else { + base_index = [buffer nextLine: base_index :count]; + } + [self redraw]; + return self; +} + +-scrollLeft:(unsigned) count +{ + if (base.x > count) { + base.x -= count; + } else { + base.x = 0; + } + [self redraw]; + return self; +} + +-scrollRight:(unsigned) count +{ + if (1024 - base.x > count) { + base.x += count; + } else { + base.x = 1024; + } + [self redraw]; + return self; +} + +-scrollTo:(unsigned)target +{ + if (target > base.y) { + base_index = [buffer nextLine:base_index :target - base.y]; + } else if (target < base.y) { + base_index = [buffer prevLine:base_index :base.y - target]; + } + base.y = target; + return self; +} + +-(void)onScroll:(id)sender +{ + base.x = scroll.x; + [self scrollTo:scroll.y]; +} + +-setVerticalScrollBar:(ScrollBar *)scrollbar +{ + [super setVerticalScrollBar:scrollbar]; + [vScrollBar setRange:line_count]; + [vScrollBar setPageStep: ylen]; + return self; +} + +-recenter:(int) force +{ + if (!force) { + if (cursor.y >= base.y && cursor.y - base.y < ylen) { + return self; + } + } + unsigned target; + if (cursor.y < ylen / 2) { + target = 0; + } else { + target = cursor.y - ylen / 2; + } + [self scrollTo:target]; + return self; +} + +-gotoLine:(unsigned) line +{ + if (line > cursor.y) { + line_index = [buffer nextLine:line_index :line - cursor.y]; + } else if (line < cursor.y) { + line_index = [buffer prevLine:line_index :cursor.y - line]; + } + cursor.y = line; + [self recenter: 0]; + return self; +} + +-highlightLine +{ + selection.start = line_index; + selection.length = [buffer nextLine: line_index] - line_index; + if (!selection.length) { + selection.length = [buffer getEOL: line_index] - line_index; + } + return self; +} + +-(string)getWordAt:(Point) pos +{ + if (pos.x < 0 || pos.y < 0 || pos.x >= xlen || pos.y >= ylen) { + return nil; + } + pos.x += base.x; + unsigned lind = [buffer nextLine:base_index :pos.y]; + unsigned cind = [buffer charPtr:lind at:pos.x]; + eb_sel_t word = [buffer getWord: cind]; + return [buffer readString:word]; +} + +@end diff --git a/tools/qfcc/test/old/gcd.r b/ruamoko/qwaq/gcd.r similarity index 100% rename from tools/qfcc/test/old/gcd.r rename to ruamoko/qwaq/gcd.r diff --git a/ruamoko/qwaq/qdb b/ruamoko/qwaq/qdb new file mode 100755 index 000000000..7f1ed27e2 --- /dev/null +++ b/ruamoko/qwaq/qdb @@ -0,0 +1,3 @@ +#! /bin/bash -x + +./qwaq-curses qwaq-app.dat $1 diff --git a/ruamoko/qwaq/qwaq-app.h b/ruamoko/qwaq/qwaq-app.h new file mode 100644 index 000000000..a35cee787 --- /dev/null +++ b/ruamoko/qwaq/qwaq-app.h @@ -0,0 +1,37 @@ +#ifndef __qwaq_app_h +#define __qwaq_app_h + +#include + +#include "ruamoko/qwaq/ui/event.h" +#include "ruamoko/qwaq/ui/rect.h" + +@class Array; +@class Group; +@class TextContext; +@class View; + +extern int color_palette[64]; + +@interface QwaqApplication: Object +{ + qwaq_event_t event; + qwaq_command endState; + + Group *objects; + + TextContext *screen; + Extent screenSize; + int autocount; + + Array *debuggers; +} +-(Extent)size; +-(TextContext *)screen; +-addView:(View *)view; +-run; +@end + +extern QwaqApplication *application; + +#endif//__qwaq_app_h diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r new file mode 100644 index 000000000..9520cf67e --- /dev/null +++ b/ruamoko/qwaq/qwaq-app.r @@ -0,0 +1,166 @@ +int fence; + +#include +#include + +#include "ruamoko/qwaq/ui/color.h" +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/ui/group.h" +#include "ruamoko/qwaq/ui/view.h" +#include "ruamoko/qwaq/debugger/debugger.h" +#include "ruamoko/qwaq/qwaq-app.h" + +int color_palette[64]; + +static AutoreleasePool *autorelease_pool; +static void +arp_start (void) +{ + autorelease_pool = [[AutoreleasePool alloc] init]; +} + +static void +arp_end (void) +{ + [autorelease_pool release]; + autorelease_pool = nil; +} + +@implementation QwaqApplication ++app +{ + return [[[self alloc] init] autorelease]; +} + +-init +{ + if (!(self = [super init])) { + return nil; + } + + initialize (); + for (int i = 1; i < 64; i++) { + init_pair (i, i & 0x7, i >> 3); + color_palette[i] = COLOR_PAIR (i); + } + + screen = [TextContext screen]; + screenSize = [screen size]; + objects = [[Group withContext: screen owner: nil] retain]; + + [screen bkgd: color_palette[047]]; + [screen scrollok: 1]; + [screen clear]; + wrefresh (stdscr);//FIXME + + debuggers = [[Array array] retain]; + return self; +} + +-(Extent)size +{ + return screenSize; +} + +-(TextContext *)screen +{ + return screen; +} + +-draw +{ + [objects draw]; + [TextContext refresh]; + return self; +} + +-(Debugger *)find_debugger:(qdb_target_t) target +{ + Debugger *debugger; + + for (int i = [debuggers count]; i-- > 0; ) { + debugger = [debuggers objectAtIndex: i]; + if ([debugger target].handle == target.handle) { + return debugger; + } + } + debugger = [Debugger withTarget: target]; + [debuggers addObject: debugger]; + return debugger; +} + +-handleEvent: (qwaq_event_t *) event +{ + switch (event.what) { + case qe_resize: + Extent delta; + delta.width = event.resize.width - screenSize.width; + delta.height = event.resize.height - screenSize.height; + + resizeterm (event.resize.width, event.resize.height); + [screen resizeTo: {event.resize.width, event.resize.height}]; + screenSize = [screen size]; + [objects resize: delta]; + [screen refresh]; + event.what = qe_none; + break; + case qe_key: + if (event.key.code == '\x18' || event.key.code == '\x11') { + endState = event.message.int_val; + event.what = qe_none; + } + break; + case qe_debug_event: + [[self find_debugger:{event.message.int_val}] handleDebugEvent]; + event.what = qe_none; + break; + } + if (event.what != qe_none) { + [objects handleEvent: event]; + } + return self; +} + +-run +{ + [objects takeFocus]; + [self draw]; + do { + arp_start (); + + get_event (&event); + if (event.what != qe_none) { + [self handleEvent: &event]; + } + + arp_end (); + } while (!endState); + return self; +} + +-addView:(View *)view +{ + [objects insertSelected: view]; + [screen refresh]; + return self; +} +@end + +QwaqApplication *application; + +int main (int argc, string *argv) +{ + fence = 0; + //while (!fence) {} + + arp_start (); + application = [[QwaqApplication app] retain]; + arp_end (); + + [application run]; + [application release]; + qwaq_event_t event; + get_event (&event); // XXX need a "wait for queue idle" + + return 0; +} diff --git a/ruamoko/qwaq/qwaq.h b/ruamoko/qwaq/qwaq.h new file mode 100644 index 000000000..43efc4700 --- /dev/null +++ b/ruamoko/qwaq/qwaq.h @@ -0,0 +1,27 @@ +#ifndef __qwaq_h +#define __qwaq_h + +#include "QF/darray.h" +#include "QF/progs.h" +#include "QF/sys.h" + +typedef void (*progsinit_f) (progs_t *pr); + +typedef struct qwaq_thread_s { + pthread_t thread_id; + int return_code; + struct DARRAY_TYPE (const char *) args; + sys_printf_t sys_printf; + progsinit_f*progsinit; + progs_t *pr; + struct hashlink_s *hashlink_freelist; + func_t main_func; + void *data; +} qwaq_thread_t; + +void BI_Init (progs_t *pr); +void QWAQ_EditBuffer_Init (progs_t *pr); +extern struct cbuf_s *qwaq_cbuf; +qwaq_thread_t *create_thread (void *(*thread_func) (qwaq_thread_t *), void *); + +#endif//__qwaq_h diff --git a/ruamoko/qwaq/ui/button.h b/ruamoko/qwaq/ui/button.h new file mode 100644 index 000000000..7fc2e9716 --- /dev/null +++ b/ruamoko/qwaq/ui/button.h @@ -0,0 +1,40 @@ +#ifndef __qwaq_ui_button_h +#define __qwaq_ui_button_h + +#include "ruamoko/qwaq/ui/draw.h" +#include "ruamoko/qwaq/ui/view.h" + +@class ListenerGroup; + +@interface Button : View +{ + DrawBuffer *icon[2]; + int pressed; + int click; + Point dragBase; + Point dragPos; + ListenerGroup *onPress; + ListenerGroup *onRelease; + ListenerGroup *onClick; + ListenerGroup *onDrag; + ListenerGroup *onAuto; + ListenerGroup *onHover; +} ++(Button *)withPos: (Point) pos releasedIcon: (DrawBuffer *) released + pressedIcon: (DrawBuffer *) pressed; ++(Button *)withRect: (Rect) rect; // invisible button +-initWithPos: (Point) pos releasedIcon: (DrawBuffer *) released + pressedIcon: (DrawBuffer *) pressed; +-initWithRect: (Rect) rect; // invisible button +-(ListenerGroup *) onPress; +-(ListenerGroup *) onRelease; +-(ListenerGroup *) onClick; +-(ListenerGroup *) onDrag; +-(ListenerGroup *) onAuto; +-(ListenerGroup *) onHover; + +- (int) click; +- (Point) delta; +@end + +#endif//__qwaq_ui_button_h diff --git a/ruamoko/qwaq/ui/button.r b/ruamoko/qwaq/ui/button.r new file mode 100644 index 000000000..7f42fb3e4 --- /dev/null +++ b/ruamoko/qwaq/ui/button.r @@ -0,0 +1,180 @@ +#include "ruamoko/qwaq/ui/button.h" +#include "ruamoko/qwaq/ui/listener.h" + +@implementation Button + ++(Button *)withPos:(Point)pos releasedIcon:(DrawBuffer *)released + pressedIcon:(DrawBuffer *)pressed +{ + return [[[self alloc] initWithPos:pos + releasedIcon:released + pressedIcon:pressed] autorelease]; +} + ++(Button *)withRect:(Rect)rect +{ + return [[[self alloc] initWithRect:rect] autorelease]; +} + +-initWithPos: (Point) pos releasedIcon: (DrawBuffer *) released + pressedIcon: (DrawBuffer *) pressed +{ + Extent size = mergeExtents ([released size], [pressed size]); + + if (!(self = [super initWithRect: {pos, size}])) { + return nil; + } + icon[0] = [released retain]; + icon[1] = [pressed retain]; + onPress = [[ListenerGroup listener] retain]; + onRelease = [[ListenerGroup listener] retain]; + onClick = [[ListenerGroup listener] retain]; + onDrag = [[ListenerGroup listener] retain]; + onAuto = [[ListenerGroup listener] retain]; + onHover = [[ListenerGroup listener] retain]; + return self; +} + +-initWithRect: (Rect) rect +{ + if (!(self = [super initWithRect: rect])) { + return nil; + } + icon[0] = nil; + icon[1] = nil; + onPress = [[ListenerGroup listener] retain]; + onRelease = [[ListenerGroup listener] retain]; + onClick = [[ListenerGroup listener] retain]; + onDrag = [[ListenerGroup listener] retain]; + onAuto = [[ListenerGroup listener] retain]; + onHover = [[ListenerGroup listener] retain]; + return self; +} + +-(void)dealloc +{ + [icon[0] release]; + [icon[1] release]; + [onPress release]; + [onRelease release]; + [onClick release]; + [onDrag release]; + [onAuto release]; + [onHover release]; + [super dealloc]; +} + +-draw +{ + [super draw]; + if (icon[pressed]) { + [textContext blitFromBuffer: icon[pressed] + to: pos + from: [icon[pressed] rect]]; + } + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + ListenerGroup *action = nil; + + [super handleEvent: event]; + + if (event.what & qe_mouse) { + switch ((qwaq_mouse_event) (event.what & qe_mouse)) { + case qe_mousedown: + pressed = 1; + click = 0; + dragBase = {event.mouse.x, event.mouse.y}; + action = onPress; + [self grabMouse]; + [self redraw]; + break; + case qe_mouseup: + pressed = 0; + click = 0; + action = onRelease; + [self releaseMouse]; + if ([self containsPoint: {event.mouse.x, event.mouse.y}]) { + [onClick respond: self]; + } + [self redraw]; + break; + case qe_mouseclick: + action = onClick; + click = event.mouse.click; + break; + case qe_mousemove: + click = 0; + if (pressed) { + dragPos = {event.mouse.x, event.mouse.y}; + action = onDrag; + } + break; + case qe_mouseauto: + if (pressed + && [self containsPoint: {event.mouse.x, event.mouse.y}]) { + click = 0; + action = onAuto; + } + break; + } + if (action) { + [action respond: self]; + } + event.what = qe_none; + } + return self; +} + +-(ListenerGroup *) onPress +{ + return onPress; +} + +-(ListenerGroup *) onRelease +{ + return onRelease; +} + +-(ListenerGroup *) onClick +{ + return onClick; +} + +-(ListenerGroup *) onDrag +{ + return onDrag; +} + +-(ListenerGroup *) onAuto +{ + return onAuto; +} + +-(ListenerGroup *) onHover +{ + return onHover; +} + +- (int) click +{ + return click; +} + +- (Point) delta +{ + return {dragPos.x - dragBase.x, dragPos.y - dragBase.y}; +} + +-move:(Point) delta +{ + Point pos = self.pos; + [super move:delta]; + dragBase.x += self.pos.x - pos.x; + dragBase.y += self.pos.y - pos.y; + return self; +} + +@end diff --git a/ruamoko/qwaq/ui/color.h b/ruamoko/qwaq/ui/color.h new file mode 100644 index 000000000..3b5ce2b2a --- /dev/null +++ b/ruamoko/qwaq/ui/color.h @@ -0,0 +1,21 @@ +#ifndef __qwaq_ui_color_h +#define __qwaq_ui_color_h + +#ifndef COLOR_PAIR +// double protection in case this header is included in a C file + +#define COLOR_PAIR(cp) ((cp) << 8) + +// taken from ncurses.h +#define COLOR_BLACK 0 +#define COLOR_RED 1 +#define COLOR_GREEN 2 +#define COLOR_YELLOW 3 +#define COLOR_BLUE 4 +#define COLOR_MAGENTA 5 +#define COLOR_CYAN 6 +#define COLOR_WHITE 7 + +#endif + +#endif//__qwaq_ui_color_h diff --git a/ruamoko/qwaq/ui/curses.h b/ruamoko/qwaq/ui/curses.h new file mode 100644 index 000000000..f3038365e --- /dev/null +++ b/ruamoko/qwaq/ui/curses.h @@ -0,0 +1,209 @@ +#ifndef __qwaq_ui_curses_h +#define __qwaq_ui_curses_h + +#include "ruamoko/qwaq/ui/event.h" + +typedef struct box_sides_s { + int ls; + int rs; + int ts; + int bs; +} box_sides_t; + +typedef struct box_corners_s { + int tl; + int tr; + int bl; + int br; +} box_corners_t; + +#ifdef __QFCC__ +#include "ruamoko/qwaq/ui/rect.h" + +// names, order and comments lifted from ncurses.h +typedef enum { +/* VT100 symbols begin here */ + ACS_ULCORNER = 256, /* upper left corner */ + ACS_LLCORNER, /* lower left corner */ + ACS_URCORNER, /* upper right corner */ + ACS_LRCORNER, /* lower right corner */ + ACS_LTEE, /* tee pointing right */ + ACS_RTEE, /* tee pointing left */ + ACS_BTEE, /* tee pointing up */ + ACS_TTEE, /* tee pointing down */ + ACS_HLINE, /* horizontal line */ + ACS_VLINE, /* vertical line */ + ACS_PLUS, /* large plus or crossover */ + ACS_S1, /* scan line 1 */ + ACS_S9, /* scan line 9 */ + ACS_DIAMOND, /* diamond */ + ACS_CKBOARD, /* checker board (stipple) */ + ACS_DEGREE, /* degree symbol */ + ACS_PLMINUS, /* plus/minus */ + ACS_BULLET, /* bullet */ +/* Teletype 5410v1 symbols begin here */ + ACS_LARROW, /* arrow pointing left */ + ACS_RARROW, /* arrow pointing right */ + ACS_DARROW, /* arrow pointing down */ + ACS_UARROW, /* arrow pointing up */ + ACS_BOARD, /* board of squares */ + ACS_LANTERN, /* lantern symbol */ + ACS_BLOCK, /* solid square block */ +/* + * These aren't documented, but a lot of System Vs have them anyway + * (you can spot pprryyzz{{||}} in a lot of AT&T terminfo strings). + * The ACS_names may not match AT&T's, our source didn't know them. + */ + ACS_S3, /* scan line 3 */ + ACS_S7, /* scan line 7 */ + ACS_LEQUAL, /* less/equal */ + ACS_GEQUAL, /* greater/equal */ + ACS_PI, /* Pi */ + ACS_NEQUAL, /* not equal */ + ACS_STERLING, /* UK pound sign */ + +/* + * Line drawing ACS names are of the form ACS_trbl, where t is the top, r + * is the right, b is the bottom, and l is the left. t, r, b, and l might + * be B (blank), S (single), D (double), or T (thick). The subset defined + * here only uses B and S. + */ + ACS_BSSB = ACS_ULCORNER, + ACS_SSBB = ACS_LLCORNER, + ACS_BBSS = ACS_URCORNER, + ACS_SBBS = ACS_LRCORNER, + ACS_SBSS = ACS_RTEE, + ACS_SSSB = ACS_LTEE, + ACS_SSBS = ACS_BTEE, + ACS_BSSS = ACS_TTEE, + ACS_BSBS = ACS_HLINE, + ACS_SBSB = ACS_VLINE, + ACS_SSSS = ACS_PLUS, +} qwaq_acs_chars; + +typedef struct window_s *window_t; +typedef struct panel_s *panel_t; + +extern window_t stdscr; + +void initialize (void); +void syncprintf (string fnt, ...); +window_t create_window (int xpos, int ypos, int xlen, int ylen); +void destroy_window (window_t win); +void mvwprintf (window_t win, int x, int y, string fmt, ...); +void wprintf (window_t win, string fmt, ...); +void wvprintf (window_t win, string fmt, @va_list args); +void mvwvprintf (window_t win, int x, int y, string fmt, @va_list args); +void wrefresh (window_t win); +void mvwaddch (window_t win, int x, int y, int ch); +void waddch (window_t win, int ch); +void mvwaddstr (window_t win, int x, int y, string str); +void waddstr (window_t win, string str); +void mvwhline (window_t win, int x, int y, int ch, int n); + +panel_t create_panel (window_t window); +void destroy_panel (panel_t panel); +void hide_panel (panel_t panel); +void show_panel (panel_t panel); +void top_panel (panel_t panel); +void bottom_panel (panel_t panel); +void move_panel (panel_t panel, int x, int y); +window_t panel_window (panel_t panel); +void update_panels (void); +void replace_panel (panel_t panel, window_t window); +void doupdate (void); + +int get_event (qwaq_event_t *event); +int max_colors (void); +int max_color_pairs (void); +int init_pair (int pair, int f, int b); +void wbkgd (window_t win, int ch); +void werase (window_t win); +void scrollok (window_t win, int flag); + +int acs_char (int acs); +int curs_set (int visibility); +int move (int x, int y); + +void wborder (window_t window, box_sides_t sides, box_corners_t corners); +void mvwblit_line (window_t window, int x, int y, int *wch, int len); +void wresize (window_t window, int width, int height); +void resizeterm (int width, int height); + +Rect getwrect (struct window_s *window); + +void printf(string fmt, ...); +// qfcc stuff +#else +// gcc stuff + +#include +#include + +#include "QF/dstring.h" +#include "QF/progs.h" +#include "QF/ringbuffer.h" + +#define QUEUE_SIZE 16 +#define STRING_ID_QUEUE_SIZE 8 // must be > 1 +#define COMMAND_QUEUE_SIZE 1280 + +typedef struct window_s { + WINDOW *win; +} window_t; + +typedef struct panel_s { + PANEL *panel; + int window_id; +} panel_t; + +typedef struct rwcond_s { + pthread_cond_t rcond; + pthread_cond_t wcond; + pthread_mutex_t mut; +} rwcond_t; + +typedef enum { + esc_ground, + esc_escape, + esc_csi, + esc_mouse, + esc_sgr, + esc_key, +} esc_state_t; + +typedef struct qwaq_resources_s { + progs_t *pr; + int initialized; + window_t stdscr; + PR_RESMAP (window_t) window_map; + PR_RESMAP (panel_t) panel_map; + rwcond_t event_cond; + RING_BUFFER (qwaq_event_t, QUEUE_SIZE) event_queue; + rwcond_t command_cond; + RING_BUFFER (int, COMMAND_QUEUE_SIZE) command_queue; + rwcond_t results_cond; + RING_BUFFER (int, COMMAND_QUEUE_SIZE) results; + rwcond_t string_id_cond; + RING_BUFFER (int, STRING_ID_QUEUE_SIZE) string_ids; + dstring_t strings[STRING_ID_QUEUE_SIZE - 1]; + + dstring_t escbuff; + esc_state_t escstate; + unsigned button_state; + int mouse_x; + int mouse_y; + qwaq_event_t lastClick; + struct hashtab_s *key_sequences; +} qwaq_resources_t; +// gcc stuff + +void qwaq_input_init (qwaq_resources_t *res); +void qwaq_input_shutdown (qwaq_resources_t *res); +void qwaq_process_input (qwaq_resources_t *res); +void qwaq_init_timeout (struct timespec *timeout, long time); +int qwaq_add_event (qwaq_resources_t *res, qwaq_event_t *event); +void qwaq_init_cond (rwcond_t *cond); +#endif + +#endif//__qwaq_ui_curses_h diff --git a/ruamoko/qwaq/ui/draw.h b/ruamoko/qwaq/ui/draw.h new file mode 100644 index 000000000..e9a9e44b5 --- /dev/null +++ b/ruamoko/qwaq/ui/draw.h @@ -0,0 +1,48 @@ +#ifndef __qwaq_ui_draw_h +#define __qwaq_ui_draw_h + +#include + +#include "ruamoko/qwaq/ui/rect.h" + +@class DrawBuffer; + +@protocol DrawBuffer +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; +- (Rect) rect; +- (Extent) size; +- (int *) buffer; +@end + +@protocol TextContext +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; +- clearReact: (Rect) rect; +- (Extent) size; +- (void) resizeTo: (Extent) newSize; // absolute size + +- (void) bkgd: (int) ch; +- (void) clear; +- (void) printf: (string) fmt, ...; +- (void) vprintf: (string) fmt, @va_list args; +- (void) addch: (int) ch; +- (void) addstr: (string) str; +- (void) mvprintf: (Point) pos, string fmt, ...; +- (void) mvvprintf: (Point) pos, string fmt, @va_list args; +- (void) mvaddch: (Point) pos, int ch; +- (void) mvaddstr: (Point) pos, string str; +- (void) mvhline:(Point)pos, int ch, int len; +- (void) mvvline:(Point)pos, int ch, int len; +@end + +@interface DrawBuffer : Object +{ + int *buffer; + Extent size; + Point cursor; + int background; +} ++(DrawBuffer *)buffer:(Extent)size; +-initWithSize:(Extent)size; +@end + +#endif//__qwaq_ui_draw_h diff --git a/ruamoko/qwaq/ui/draw.r b/ruamoko/qwaq/ui/draw.r new file mode 100644 index 000000000..aeaa00475 --- /dev/null +++ b/ruamoko/qwaq/ui/draw.r @@ -0,0 +1,267 @@ +#include + +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/ui/draw.h" + +@implementation DrawBuffer + ++(DrawBuffer *)buffer:(Extent)size +{ + return [[[self alloc] initWithSize: size] autorelease]; +} + +- initWithSize: (Extent) size +{ + if (!(self = [super init])) { + return nil; + } + buffer = obj_malloc (size.width * size.height); + self.size = size; + return self; +} + +-(void)dealloc +{ + obj_free (buffer); + [super dealloc]; +} + +- (Extent) size +{ + return size; +} + +- (void) resizeTo: (Extent) newSize +{ + size = newSize; + buffer = obj_realloc (buffer, size.width * size.height); +} + +- (int *) buffer +{ + return buffer; +} +- (Rect) rect +{ + Rect rect = { nil, size }; + return rect; +} + +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect +{ + Extent srcSize = srcBuffer.size; + Rect r = { {}, size }; + Rect t = { pos, rect.extent }; + + //wprintf (stdscr, "src: %p\n", srcBuffer); + //wprintf (stdscr, "srcSize: %d %d\n", srcSize.width, srcSize.height); + + t = clipRect (r, t); + if (t.extent.width < 0 || t.extent.height < 0) { + return self; + } + + rect.offset.x += t.offset.x - pos.x; + rect.offset.y += t.offset.y - pos.y; + rect.extent = t.extent; + pos = t.offset; + + r.offset = nil; + r.extent = size; + + rect = clipRect (r, rect); + if (rect.extent.width < 0 || rect.extent.height < 0) { + return self; + } + + int *dst = buffer + pos.y * size.width + pos.x; + int *src = srcBuffer.buffer + + rect.offset.y * srcSize.width + rect.offset.x; + for (int y = 0; y < rect.extent.height; y++) { + int *d = dst; + int *s = src; + dst += size.width; + src += srcSize.width; + for (int x = 0; x < rect.extent.width; x++) { + // FIXME 1) need memcpy/memmove + // 2) the generated code could be better + // github issue #3 + *d++ = *s++; + } + } + return self; +} + +- clearReact: (Rect) rect +{ + Point pos = rect.offset; + int len = rect.extent.width; + int count = rect.extent.height; + + if (pos.x + len > size.width) { + len = size.width - pos.x; + } + if (pos.x < 0) { + len += pos.x; + pos.x = 0; + } + if (len < 1) { + return self; + } + if (pos.y + count > size.height) { + count = size.height - pos.y; + } + if (pos.y < 0) { + count += pos.y; + pos.y = 0; + } + if (count < 1) { + return self; + } + int width = size.width; + int ch = background; + if (!(ch & 0xff)) { + ch |= ' '; + } + while (count-- > 0) { + int *p = buffer + pos.y * width + pos.x; + for (int i = 0; i < len; i++) { + *p++ = ch; + } + pos.y++; + } + return self; +} + +- (void) bkgd: (int) ch +{ + background = ch; +} + +- (void) clear +{ + int ch = background; + int *dst = buffer; + int *end = buffer + size.width * size.height; + + if (ch && !(ch & 0xff)) { + ch |= ' '; + } + while (dst < end) { + *dst++ = ch; + } + cursor = {0, 0}; +} + +- (void) printf: (string) fmt, ... +{ + string str = vsprintf (fmt, @args); + [self addstr: str]; +} + +- (void) vprintf: (string) fmt, @va_list args +{ + string str = vsprintf (fmt, args); + [self addstr: str]; +} + +- (void) addch: (int) ch +{ + if (cursor.x < 0) { + cursor.x = 0; + } + if (cursor.y < 0) { + cursor.y = 0; + } + if (cursor.x >= size.width && cursor.y < size.height) { + cursor.x = 0; + cursor.y++; + } + if (cursor.y >= size.height) { + return; + } + if (ch == '\n') { + cursor.x = 0; + cursor.y++; + } else if (ch == '\r') { + cursor.x = 0; + } else { + if (!(ch & ~0xff)) { + ch |= background & ~0xff; + } + buffer[cursor.y * size.width + cursor.x++] = ch; + } +} + +- (void) addstr: (string) str +{ + int ind = 0; + int ch; + + if (cursor.y >= size.height) { + return; + } + while (cursor.x < size.width && (ch = str_char (str, ind++))) { + [self addch: ch]; + } +} + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + string str = vsprintf (fmt, @args); + [self addstr: str]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + string str = vsprintf (fmt, args); + [self addstr: str]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + [self addch: ch]; +} + +- (void) mvaddstr: (Point) pos, string str +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + [self addstr: str]; +} + +- (void) mvhline:(Point)pos, int ch, int len +{ + while (len-- > 0) { + [self mvaddch:pos, ch]; + pos.x++; + } +} + +- (void) mvvline:(Point)pos, int ch, int len +{ + while (len-- > 0) { + [self mvaddch:pos, ch]; + pos.y++; + } +} + +@end diff --git a/ruamoko/qwaq/ui/event.h b/ruamoko/qwaq/ui/event.h new file mode 100644 index 000000000..d8fe09c6c --- /dev/null +++ b/ruamoko/qwaq/ui/event.h @@ -0,0 +1,80 @@ +#ifndef __qwaq_ui_event_h +#define __qwaq_ui_event_h + +typedef enum { + qe_mousedown = 0x0001, + qe_mouseup = 0x0002, + qe_mouseclick= 0x0004, + qe_mousemove = 0x0008, + qe_mouseauto = 0x0010, +} qwaq_mouse_event; + +typedef enum { + qe_keydown = 0x0020, +} qwaq_key_event; + +typedef enum { + qe_command = 0x0200, // application level command + qe_broadcast = 0x0400, + qe_resize = 0x0800, // screen resized +} qwaq_message_event; + +typedef enum { + qe_none = 0x0000, + qe_mouse = 0x001f, + qe_key = 0x0020, + qe_system = 0x01c0, //FIXME this isn't very manageable + qe_message = 0xfe00, + + qe_focused = qe_key | qe_command, + qe_positional = qe_mouse, +} qwaq_event_mask; + +typedef enum { + qc_valid, + qc_exit, + qc_error, +} qwaq_command; + +typedef struct qwaq_mevent_s { + int x, y; + int buttons; // current button state + int click; +} qwaq_mevent_t; + +typedef struct qwaq_kevent_s { + int code; + int shift; +} qwaq_kevent_t; + +typedef struct qwaq_resize_s { + int width; + int height; +} qwaq_resize_t; + +typedef union qwaq_message_s { + int int_val; + float float_val; + float vector_val[4]; // vector and quaternion + double double_val; +#ifdef __QFCC__ + void *pointer_val; + string string_val; +#else + pointer_t pointer_val; + string_t string_val; +#endif +} qwaq_message_t; + +typedef struct qwaq_event_s { + int what; + double when; // NOTE: 1<<32 based + union { + qwaq_kevent_t key; + qwaq_mevent_t mouse; + qwaq_message_t message; + qwaq_resize_t resize; + }; +} qwaq_event_t; + +#endif//__qwaq_ui_event_h diff --git a/ruamoko/qwaq/ui/garray.h b/ruamoko/qwaq/ui/garray.h new file mode 100644 index 000000000..3ba1a0ef2 --- /dev/null +++ b/ruamoko/qwaq/ui/garray.h @@ -0,0 +1,29 @@ +#ifndef __qwaq_ui_garray_h +#define __qwaq_ui_garray_h + +#include + +typedef BOOL condition_func (id object, void *data); +typedef BOOL condition_func2 (id object, void *anObject, void *data); + +@interface Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +@end + +#endif//__qwaq_ui_garray_h diff --git a/ruamoko/qwaq/ui/garray.r b/ruamoko/qwaq/ui/garray.r new file mode 100644 index 000000000..55aa35e88 --- /dev/null +++ b/ruamoko/qwaq/ui/garray.r @@ -0,0 +1,66 @@ +#include +#include "ruamoko/qwaq/ui/event.h" +#include "ruamoko/qwaq/ui/garray.h" + +@implementation Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector withObject: anObject]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} +@end diff --git a/ruamoko/qwaq/ui/group.h b/ruamoko/qwaq/ui/group.h new file mode 100644 index 000000000..c1b96b80d --- /dev/null +++ b/ruamoko/qwaq/ui/group.h @@ -0,0 +1,44 @@ +#ifndef __qwaq_ui_group_h +#define __qwaq_ui_group_h + +#include + +#include "ruamoko/qwaq/ui/event.h" +#include "ruamoko/qwaq/ui/draw.h" + +@class View; + +@interface Group : Object +{ + View *owner; + Array *views; + View *mouse_grabbed; + View *mouse_within; + int focused; + id context; +} ++(Group *)withContext:(id)context owner:(View *)owner; +-initWithContext:(id)context owner:(View *)owner; +-(id)context; +-setContext: (id) context; +-insert: (View *) view; +-insertDrawn: (View *) view; +-insertSelected: (View *) view; +-remove: (View *) view; +-(Rect) rect; +-(Point) origin; +-(Extent) size; +-draw; +-redraw; +-resize: (Extent) delta; +-handleEvent: (qwaq_event_t *) event; +-takeFocus; +-loseFocus; +-selectNext; +-selectPrev; +-selectView: (View *) view; +-(void) grabMouse; +-(void) releaseMouse; +@end + +#endif//__qwaq_ui_group_h diff --git a/ruamoko/qwaq/ui/group.r b/ruamoko/qwaq/ui/group.r new file mode 100644 index 000000000..e2e8e1890 --- /dev/null +++ b/ruamoko/qwaq/ui/group.r @@ -0,0 +1,318 @@ +#include +#include "ruamoko/qwaq/ui/event.h" +#include "ruamoko/qwaq/ui/draw.h" +#include "ruamoko/qwaq/ui/garray.h" +#include "ruamoko/qwaq/ui/group.h" +#include "ruamoko/qwaq/ui/view.h" + +@implementation Group + ++(Group *)withContext:(id)context owner:(View *)owner +{ + return [[[self alloc] initWithContext:context owner:owner] autorelease]; +} + +-initWithContext: (id) context owner: (View *) owner +{ + if (!(self = [super init])) { + return nil; + } + self.owner = owner; + self.context = context; + focused = -1; + views = [[Array array] retain]; + return self; +} + +-(void)dealloc +{ + [views release]; + [super dealloc]; +} + +-(id)context +{ + return context; +} + +-setContext: (id) context +{ + self.context = context; + [views makeObjectsPerformSelector:@selector(setContext:) + withObject:context]; + return self; +} + +-insert: (View *) view +{ + [views addObject: view]; + [view setOwner: self]; + [view setContext: context]; + return self; +} + +-insertDrawn: (View *) view +{ + [self insert: view]; + [view draw]; + return self; +} + +-insertSelected: (View *) view +{ + [self insertDrawn: view]; + [self selectView: view]; + return self; +} + +-remove: (View *) view +{ + int index = [views indexOfObject: view]; + if (index != NotFound) { + if (focused == index) { + [self selectPrev]; + if (focused == index) { + focused = -1; + } + } else if (focused > index) { + focused--; + } + [views removeObjectAtIndex: index]; + if (mouse_within == view) { + mouse_within = nil; + } + if (mouse_grabbed == view) { + [self releaseMouse]; + } + } + return self; +} + +static int +makeFirst (Group *self, int viewIndex) +{ + View *view = [self.views objectAtIndex: viewIndex]; + + // add before remove to avoid freeing view + [self.views addObject: view]; + [self.views removeObjectAtIndex: viewIndex]; + [view raise]; + return [self.views count] - 1; +} + +static int +trySetFocus (Group *self, int viewIndex) +{ + View *view = [self.views objectAtIndex:viewIndex]; + if (([view state] & (sfDrawn | sfDisabled)) == sfDrawn + && [view options] & ofCanFocus) { + if (!self.owner || ([self.owner state] & sfInFocus)) { + if (self.focused >= 0) { + [[self.views objectAtIndex: self.focused] loseFocus]; + } + self.focused = viewIndex; + if ([view options] & ofMakeFirst) { + self.focused = makeFirst (self, viewIndex); + } + [view takeFocus]; + } else { + self.focused = viewIndex; + } + return 1; + } + return 0; +} + +-takeFocus +{ + if (focused >= 0) { + [[views objectAtIndex:focused] takeFocus]; + } + return self; +} + +-loseFocus +{ + if (focused >= 0) { + [[views objectAtIndex:focused] loseFocus]; + } + return self; +} + +-selectNext +{ + for (int i = focused + 1; i < [views count]; i++) { + if (trySetFocus (self, i)) { + return self; + } + } + // hit end, start again at the beginning + for (int i = 0; i < focused; i++) { + if (trySetFocus (self, i)) { + return self; + } + } + // did not find another view that can be focused + return self; +} + +-selectPrev +{ + for (int i = focused - 1; i >= 0; i--) { + if (trySetFocus (self, i)) { + return self; + } + } + // hit end, start again at the beginning + for (int i = [views count] - 1; i > focused; i++) { + if (trySetFocus (self, i)) { + return self; + } + } + // did not find another view that can be focused + return self; +} + +-selectView:(View *)view +{ + int index = [views indexOfObject: view]; + if (index != NotFound) { + trySetFocus (self, index); + } + return self; +} + +-(Rect) rect +{ + if (owner) { + return [owner rect]; + } + return {[self origin], [self size]}; +} + +-(Point) origin +{ + if (owner) { + return [owner origin]; + } + return {0, 0}; +} + +-(Extent) size +{ + if (owner) { + return [owner size]; + } + return [context size]; +} + +static BOOL +not_dont_draw (id aView, void *aGroup) +{ + View *view = aView; + Group *group = (Group *) aGroup; + + return !([view options] & ofDontDraw); +} + +-draw +{ + [views makeObjectsPerformSelector: @selector(draw) + if: not_dont_draw + with: self]; + return self; +} + +-redraw +{ + if (owner) { + [owner redraw]; + } else { + [self draw]; + if (__obj_responds_to (context, @selector(refresh))) { + [(id)context refresh]; + } + } + return self; +} + +-resize: (Extent) delta +{ + for (int i = [views count]; i-- > 0; ) { + [[views objectAtIndex: i] grow: delta]; + } + return self; +} + +static View * +find_mouse_view(Group *group, Point pos) +{ + for (int i = [group.views count]; i--; ) { + View *v = [group.views objectAtIndex: i]; + if ([v containsPoint: pos]) { + return v; + } + } + return nil; +} + +static void +handlePositionalEvent (qwaq_event_t *event, View *view) +{ + Point pos = [view origin]; + int options = [view options]; + + if (options & ofRelativeEvents) { + event.mouse.x -= pos.x; + event.mouse.y -= pos.y; + } + + [view handleEvent: event]; + + if (options & ofRelativeEvents) { + event.mouse.x += pos.x; + event.mouse.y += pos.y; + } +} + +-handleEvent: (qwaq_event_t *) event +{ + if (event.what & qe_focused) { + if (focused >= 0) { + [[views objectAtIndex:focused] handleEvent: event]; + } + } else if (event.what & qe_positional) { + if (mouse_grabbed) { + handlePositionalEvent (event, mouse_grabbed); + } else { + Point pos = {event.mouse.x, event.mouse.y}; + View *mouse_view = find_mouse_view (self, pos); + if (mouse_within != mouse_view) { + [mouse_within onMouseLeave: pos]; + [mouse_view onMouseEnter: pos]; + mouse_within = mouse_view; + } + if (mouse_within) { + handlePositionalEvent (event, mouse_within); + } + } + } else { + // broadcast + [views makeObjectsPerformSelector: @selector(draw) withObject: event]; + } + return self; +} + +-(void) grabMouse +{ + mouse_grabbed = mouse_within; + [owner grabMouse]; +} + +-(void) releaseMouse +{ + mouse_grabbed = nil; + [owner releaseMouse]; +} + +@end diff --git a/ruamoko/qwaq/ui/listener.h b/ruamoko/qwaq/ui/listener.h new file mode 100644 index 000000000..8df0c949c --- /dev/null +++ b/ruamoko/qwaq/ui/listener.h @@ -0,0 +1,33 @@ +#ifndef __qwaq_ui_listener_h +#define __qwaq_ui_listener_h + +#include + +@class Array; + +@interface Listener : Object +{ + id responder; + SEL message; + IMP imp; +} ++(Listener *)listenerWithResponder:(id)responder :(SEL)message; +-initWithResponder: (id) responder :(SEL)message; +-(void) respond: (void *) caller_data; +-(void) respond: (void *) caller_data withObject:(void *)anObject; +-(BOOL) matchResponder: (id) responder :(SEL)message; +@end + +@interface ListenerGroup : Object +{ + Array *listeners; +} ++(ListenerGroup *)listener; +-init; +-addListener: (id) responder :(SEL)message; +-removeListener: (id) responder :(SEL)message; +-(void) respond: (void *) caller_data; +-(void) respond: (void *) caller_data withObject:(void *)anObject; +@end + +#endif//__qwaq_ui_listener_h diff --git a/ruamoko/qwaq/ui/listener.r b/ruamoko/qwaq/ui/listener.r new file mode 100644 index 000000000..8fa43b01f --- /dev/null +++ b/ruamoko/qwaq/ui/listener.r @@ -0,0 +1,97 @@ +#include + +#include "ruamoko/qwaq/ui/listener.h" +#include "ruamoko/qwaq/ui/curses.h" + +@class Array; + +@implementation Listener ++(Listener *)listenerWithResponder:(id)responder :(SEL)message +{ + return [[[self alloc] initWithResponder:responder :message] autorelease]; +} + +-initWithResponder: (id) responder :(SEL)message +{ + if (!(self = [super init])) { + return nil; + } + self.responder = responder; + self.message = message; + imp = [responder methodForSelector: message]; + if (!imp) { + [self error:"method not found: %s", sel_get_name (message)]; + } + return self; +} + +-(void)respond: (void *) caller_data +{ + imp (responder, message, caller_data); +} + +-(void)respond: (void *) caller_data withObject:(void *)anObject +{ + imp (responder, message, caller_data, anObject); +} + +-(BOOL) matchResponder: (id) responder :(SEL)message +{ + return self.responder == responder && self.message == message; +} +@end + +@implementation ListenerGroup : Object ++(ListenerGroup *)listener +{ + return [[[self alloc] init] autorelease]; +} + +-init +{ + if (!(self = [super init])) { + return nil; + } + listeners = [[Array array] retain]; + return self; +} + +-(void)dealloc +{ + [listeners release]; + [super dealloc]; +} + +-addListener: (id) responder :(SEL)message +{ + Listener *listener = [Listener listenerWithResponder:responder :message]; + if (listener) { + [listeners addObject:listener]; + } + return self; +} + +-removeListener: (id) responder :(SEL)message +{ + for (int i = [listeners count]; i-- > 0; ) { + Listener *l = [listeners objectAtIndex: i]; + if ([l matchResponder: responder : message]) { + [listeners removeObjectAtIndex: i]; + } + } + return self; +} + +-(void)respond: (void *) caller_data +{ + [listeners makeObjectsPerformSelector: @selector (respond:) + withObject: caller_data]; +} + +-(void)respond: (void *) caller_data withObject:(void *)anObject +{ + [listeners makeObjectsPerformSelector: @selector (respond:) + withObject: caller_data + withObject: anObject]; +} +@end diff --git a/ruamoko/qwaq/ui/proxyview.h b/ruamoko/qwaq/ui/proxyview.h new file mode 100644 index 000000000..c7d062cdc --- /dev/null +++ b/ruamoko/qwaq/ui/proxyview.h @@ -0,0 +1,21 @@ +#ifndef __qwaq_ui_proxyview_h +#define __qwaq_ui_proxyview_h + +#include "ruamoko/qwaq/ui/view.h" + +@class Group; + +@interface ProxyView : Object +{ + View *view; + Group *owner; +} ++(ProxyView *)withView:(View *)view; +-initWithView:(View *)view; +-setView:(View *)view; +@end + +@interface ProxyView (View) +@end + +#endif//__qwaq_ui_proxyview_h diff --git a/ruamoko/qwaq/ui/proxyview.r b/ruamoko/qwaq/ui/proxyview.r new file mode 100644 index 000000000..714b3fd9d --- /dev/null +++ b/ruamoko/qwaq/ui/proxyview.r @@ -0,0 +1,58 @@ +#include "ruamoko/qwaq/ui/group.h" +#include "ruamoko/qwaq/ui/proxyview.h" + +@implementation ProxyView ++(ProxyView *)withView:(View *)view +{ + return [[[self alloc] initWithView:view] autorelease]; +} + +- (void) forward: (SEL) sel : (@va_list) args +{ + if (!view) { + return; + } + obj_msg_sendv (view, sel, args); +} + +-initWithView:(View *) view +{ + if (!(self = [super init])) { + return nil; + } + self.view = [view retain]; + return self; +} + +-setOwner:(Group *)owner +{ + self.owner = owner; + return [view setOwner:owner]; +} + +-setView:(View *) view +{ + int state = [self.view state]; + + if (state & sfInFocus) { + [self.view loseFocus]; + } + [self.view hide]; + [self.view setContext:nil]; + [self.view setOwner:nil]; + + [view retain]; + [self.view release]; + self.view = view; + + [view setOwner:owner]; + [view setContext:[owner context]]; + if (state & sfDrawn) { + [view draw]; + } + if (state & sfInFocus) { + [view takeFocus]; + } + return self; +} +@end diff --git a/ruamoko/qwaq/ui/rect.h b/ruamoko/qwaq/ui/rect.h new file mode 100644 index 000000000..007dcb9e6 --- /dev/null +++ b/ruamoko/qwaq/ui/rect.h @@ -0,0 +1,28 @@ +#ifndef __qwaq_ui_rect_h +#define __qwaq_ui_rect_h + +typedef struct Point_s { + int x; + int y; +} Point; + +typedef struct Extent_s { + int width; + int height; +} Extent; + +typedef struct Rect_s { + Point offset; + Extent extent; +} Rect; + +#ifdef __QFCC__ +Rect makeRect (int xpos, int ypos, int xlen, int ylen); +Point makePoint (int x, int y); +Extent makeExtent (int width, int height); +Extent mergeExtents (Extent a, Extent b); +int rectContainsPoint (Rect rect, Point point); +Rect clipRect (Rect clipRect, Rect rect); +#endif + +#endif//__qwaq_ui_rect_h diff --git a/ruamoko/qwaq/ui/rect.r b/ruamoko/qwaq/ui/rect.r new file mode 100644 index 000000000..905ee0385 --- /dev/null +++ b/ruamoko/qwaq/ui/rect.r @@ -0,0 +1,55 @@ +#include "ruamoko/qwaq/ui/rect.h" + +Rect +clipRect (Rect clipRect, Rect rect) +{ + if (rect.offset.x < clipRect.offset.x) { + int dist = clipRect.offset.x - rect.offset.x; + rect.offset.x += dist; + rect.extent.width -= dist; + } + if (rect.offset.y < clipRect.offset.y) { + int dist = clipRect.offset.y - rect.offset.y; + rect.offset.y += dist; + rect.extent.height -= dist; + } + if (rect.offset.x + rect.extent.width > clipRect.extent.width) { + rect.extent.width = clipRect.extent.width - rect.offset.x; + } + if (rect.offset.y + rect.extent.height > clipRect.extent.height) { + rect.extent.height = clipRect.extent.height - rect.offset.y; + } + return rect; +} + +Rect +makeRect (int xpos, int ypos, int xlen, int ylen) +{ + Rect rect = {{xpos, ypos}, {xlen, ylen}}; + return rect; +} + +Point makePoint (int x, int y) +{ + return {x, y}; +} + +Extent makeExtent (int width, int height) +{ + return {width, height}; +} + +Extent mergeExtents (Extent a, Extent b) +{ + return { a.width < b.width ? b.width : a.width, + a.height < b.height ? b.height : a.height }; +} + +int +rectContainsPoint (Rect rect, Point point) +{ + return ((point.x >= rect.offset.x + && point.x < rect.offset.x + rect.extent.width) + && (point.y >= rect.offset.y + && point.y < rect.offset.y + rect.extent.height)); +} diff --git a/ruamoko/qwaq/ui/scrollbar.h b/ruamoko/qwaq/ui/scrollbar.h new file mode 100644 index 000000000..404dbfaf7 --- /dev/null +++ b/ruamoko/qwaq/ui/scrollbar.h @@ -0,0 +1,40 @@ +#ifndef __qwaq_ui_scrollbar_h +#define __qwaq_ui_scrollbar_h + +#include "ruamoko/qwaq/ui/view.h" + +@class Button; +@class DrawBuffer; +@class Group; +@class ListenerGroup; + +@interface ScrollBar : View +{ + int vertical; + int bgchar; + double mouseTime; + Point mouseStart; + Point tabStart; + DrawBuffer *buffer; + Button *backButton; + Button *forwardButton; + Button *thumbTab; + Group *objects; + ListenerGroup *onScrollBarModified; + + unsigned pageStep; + unsigned singleStep; + unsigned range; + unsigned index; +} ++(ScrollBar *)horizontal:(unsigned)len at:(Point)pos; ++(ScrollBar *)vertical:(unsigned)len at:(Point)pos; +-(ListenerGroup *)onScrollBarModified; +-setRange:(unsigned)range; +-setPageStep:(unsigned)pageStep; +-setSingleStep:(unsigned)singleStep; +-setIndex:(unsigned)index; +-(unsigned)index; +@end + +#endif//__qwaq_ui_scrollbar_h diff --git a/ruamoko/qwaq/ui/scrollbar.r b/ruamoko/qwaq/ui/scrollbar.r new file mode 100644 index 000000000..3d0eee6ce --- /dev/null +++ b/ruamoko/qwaq/ui/scrollbar.r @@ -0,0 +1,247 @@ +#include "ruamoko/qwaq/ui/button.h" +#include "ruamoko/qwaq/ui/group.h" +#include "ruamoko/qwaq/ui/listener.h" +#include "ruamoko/qwaq/ui/scrollbar.h" + +@implementation ScrollBar + +-initWithRect:(Rect)rect +{ + if (!(self = [super initWithRect:rect])) { + return nil; + } + options = ofRelativeEvents; + buffer = [[DrawBuffer buffer:size] retain]; + objects = [[Group withContext:buffer owner:self] retain]; + onScrollBarModified = [[ListenerGroup listener] retain]; + vertical = xlen == 1; + DrawBuffer *icons[3] = { + [DrawBuffer buffer:{1, 1}], + [DrawBuffer buffer:{1, 1}], + [DrawBuffer buffer:{1, 1}], + }; + [icons[2] addch:acs_char (ACS_DIAMOND)]; + Point thumbPos; + SEL thumbSel; + growMode = gfGrowAll; + if (vertical) { + [icons[0] addch:acs_char (ACS_UARROW)]; + [icons[1] addch:acs_char (ACS_DARROW)]; + thumbPos = {0, 1}; + thumbSel = @selector(verticalSlide:); + growMode &= ~gfGrowLoY; + } else { + [icons[0] addch:acs_char (ACS_LARROW)]; + [icons[1] addch:acs_char (ACS_RARROW)]; + thumbPos = {1, 0}; + thumbSel = @selector(horizontalSlide:); + growMode &= ~gfGrowLoX; + } + bgchar = acs_char (ACS_CKBOARD); + backButton = [Button withPos:{0, 0} + releasedIcon:icons[0] pressedIcon:icons[0]]; + forwardButton = [Button withPos:{xlen - 1, ylen - 1} + releasedIcon:icons[1] pressedIcon:icons[1]]; + thumbTab = [Button withPos:thumbPos + releasedIcon:icons[2] pressedIcon:icons[2]]; + + [[backButton onClick] addListener:self :@selector(scrollBack:)]; + [[forwardButton onClick] addListener:self :@selector(scrollForward:)]; + [[thumbTab onPress] addListener:self :thumbSel]; + + singleStep = 1; + + [objects insert:backButton]; + [objects insert:forwardButton]; + [objects insert:thumbTab]; + return self; +} + +-(void)dealloc +{ + [objects release]; + [buffer release]; + [onScrollBarModified release]; + [super dealloc]; +} + ++(ScrollBar *)horizontal:(unsigned)len at:(Point)pos +{ + if (len == 1) { + [self error:"can't make scrollbar of length 1"]; + } + return [[[self alloc] initWithRect:{pos, {len, 1}}] autorelease]; +} + ++(ScrollBar *)vertical:(unsigned)len at:(Point)pos +{ + if (len == 1) { + [self error:"can't make scrollbar of length 1"]; + } + return [[[self alloc] initWithRect:{pos, {1, len}}] autorelease]; +} + +-(ListenerGroup *)onScrollBarModified +{ + return onScrollBarModified; +} + +-draw +{ + [super draw]; + if (vertical) { + [buffer mvvline:{0,0}, bgchar, ylen]; + } else { + [buffer mvhline:{0,0}, bgchar, xlen]; + } + [objects draw]; + [textContext blitFromBuffer:buffer to:pos from:[buffer rect]]; + return self; +} + +static void +position_tab (ScrollBar *self) +{ + Point p = {0, 0}; + Point o = [self.thumbTab origin]; + if (self.range > 0) { + if (self.vertical) { + p.y = 1 + self.index * (self.ylen - 2) / (self.range - 1); + } else { + p.x = 1 + self.index * (self.xlen - 2) / (self.range - 1); + } + } + [self.thumbTab move:{p.x - o.x, p.y - o.y}]; + [self redraw]; +} + +-resize:(Extent)delta +{ + Extent size = self.size; + [super resize:delta]; + delta = {self.size.width - size.width, self.size.height - size.height}; + [objects resize:delta]; + [buffer resizeTo:self.size]; + position_tab (self); + return self; +} + +-page:(unsigned)step dir:(unsigned) dir +{ + unsigned oind = index; + + if (dir) { + if (range - 1 - index < step) { + step = range - 1 - index; + } + index += step; + } else { + if (index < step) { + step = index; + } + index -= step; + } + + if (index != oind) { + [onScrollBarModified respond:self]; + position_tab (self); + } + return self; +} + +static void +page (ScrollBar *self, Point pos, Point thumb) +{ + unsigned pageDir = 0; + if (self.vertical) { + if (pos.y < thumb.y) { + pageDir = 0; + } else { + pageDir = 1; + } + } else { + if (pos.x < thumb.x) { + pageDir = 0; + } else { + pageDir = 1; + } + } + [self page:self.pageStep dir:pageDir]; +} + +-(void)scrollBack:(id)sender +{ + [self page:singleStep dir:0]; +} + +-(void)scrollForward:(id)sender +{ + [self page:singleStep dir:1]; +} + +-(void)horizontalSlide:(id)sender +{ +} + +-(void)verticalSlide:(id)sender +{ +} + +-handleEvent:(qwaq_event_t *)event +{ + [super handleEvent: event]; + [objects handleEvent: event]; + if (event.what == qe_mousedown) { + [self grabMouse]; + mouseTime = event.when; + mouseStart = {event.mouse.x, event.mouse.y}; + tabStart = [thumbTab origin]; + page(self, mouseStart, tabStart); + event.what = qe_none; + } else if (event.what==qe_mouseauto) { + if (event.when - mouseTime > 0.1) { + mouseTime = event.when; + page(self, mouseStart, tabStart); + } + event.what = qe_none; + } else if (event.what == qe_mouseup) { + [self releaseMouse]; + event.what = qe_none; + } + return self; +} + +-setRange:(unsigned)range +{ + self.range = range; + return self; +} + +-setPageStep:(unsigned)pageStep +{ + self.pageStep = pageStep; + return self; +} + +-setSingleStep:(unsigned)singleStep +{ + self.singleStep = singleStep; + return self; +} + +-setIndex:(unsigned)index +{ + if (index > self.index) { + [self page:index - self.index dir:1]; + } else { + [self page:self.index - index dir:0]; + } + return self; +} + +-(unsigned)index +{ + return index; +} + +@end diff --git a/ruamoko/qwaq/ui/tableview.h b/ruamoko/qwaq/ui/tableview.h new file mode 100644 index 000000000..52bca6880 --- /dev/null +++ b/ruamoko/qwaq/ui/tableview.h @@ -0,0 +1,49 @@ +#ifndef __qwaq_ui_tableview_h +#define __qwaq_ui_tableview_h + +#include "ruamoko/qwaq/ui/view.h" + +@class DrawBuffer; +@class TableView; +@class TableViewColumn; +@class Array; + +@protocol TableViewDataSource +-(int)numberOfRows:(TableView *)tableview; +-(View *)tableView:(TableView *)tableView + forColumn:(TableViewColumn *)column + row:(int)row; +-retain; +-release; +@end + +@interface TableViewColumn : Object +{ + string name; + int width; + int growMode; // Y flags ignored +} ++(TableViewColumn *)named:(string)name; ++(TableViewColumn *)named:(string)name width:(int)width; + +-setGrowMode: (int) mode; +-(int)growMode; + +-(string)name; +-(int)width; +@end + +@interface TableView : View +{ + Array *columns; + DrawBuffer *buffer; + int columns_dirty; + id dataSource; + Point base; +} ++(TableView *)withRect:(Rect)rect; +-addColumn:(TableViewColumn *)column; +-setDataSource:(id)dataSource; +@end + +#endif//__qwaq_ui_tableview_h diff --git a/ruamoko/qwaq/ui/tableview.r b/ruamoko/qwaq/ui/tableview.r new file mode 100644 index 000000000..940bf1793 --- /dev/null +++ b/ruamoko/qwaq/ui/tableview.r @@ -0,0 +1,146 @@ +#include +#include "ruamoko/qwaq/ui/listener.h" +#include "ruamoko/qwaq/ui/tableview.h" + +@implementation TableViewColumn +-initWithName:(string)name width:(int)width +{ + if (!(self = [super init])) { + return nil; + } + self.name = name; + self.width = width; + return self; +} + ++(TableViewColumn *)named:(string)name +{ + return [[[self alloc] initWithName:name width:-1] autorelease]; +} + ++(TableViewColumn *)named:(string)name width:(int)width +{ + return [[[self alloc] initWithName:name width:width] autorelease]; +} + +-setGrowMode: (int) mode +{ + growMode = mode; + return self; +} + +-(int)growMode +{ + return growMode; +} + +-(string)name +{ + return name; +} + +-(int)width +{ + return width; +} + +-setWidth:(int)width +{ + self.width = width; + return self; +} + +-grow:(Extent)delta +{ + if (growMode & gfGrowHiX) { + width += delta.width; + } + return self; +} +@end + +@implementation TableView +-initWithRect:(Rect)rect +{ + if (!(self = [super initWithRect:rect])) { + return nil; + } + options = ofCanFocus | ofRelativeEvents; + columns = [[Array array] retain]; + buffer = [[DrawBuffer buffer:size] retain]; + [buffer bkgd:' ']; + [onViewScrolled addListener:self :@selector(onScroll:)]; + growMode = gfGrowHi; + return self; +} + +-(void)dealloc +{ + [columns release]; + [buffer release]; + [dataSource release]; + [super dealloc]; +} + ++(TableView *)withRect:(Rect)rect +{ + return [[[self alloc] initWithRect:rect] autorelease]; +} + +-addColumn:(TableViewColumn *)column +{ + [columns addObject:column]; + columns_dirty = 1; + return self; +} + +-setDataSource:(id)dataSource +{ + self.dataSource = [dataSource retain]; + return self; +} + +-resize:(Extent)delta +{ + Extent size = self.size; + [super resize:delta]; + [buffer resizeTo:self.size]; + for (int i = [columns count]; i-- > 0; ) { + [[columns objectAtIndex: i] grow: delta]; + } + return self; +} + +-draw +{ + View *cell; + TableViewColumn *col; + [super draw]; + int numCols = [columns count]; + int numRows = [dataSource numberOfRows:self]; + [buffer clear]; + for (int y = 0; y < ylen; y++) { + for (int i = 0, x = 0; i < numCols; i++) { + int row = base.y + y; + if (row >= numRows) { + break; + } + col = [columns objectAtIndex:i]; + cell = [dataSource tableView:self forColumn:col row:row]; + [[[cell setContext:buffer] moveTo:{x, y}] draw]; + x += [col width]; + } + } + [textContext blitFromBuffer:buffer to:pos from:[buffer rect]]; + return self; +} + +-(void)onScroll:(id)sender +{ + if (base.y != scroll.y) { + base.y = scroll.y; + [self redraw]; + } +} + +@end diff --git a/ruamoko/qwaq/ui/textcontext.h b/ruamoko/qwaq/ui/textcontext.h new file mode 100644 index 000000000..21f21b5ae --- /dev/null +++ b/ruamoko/qwaq/ui/textcontext.h @@ -0,0 +1,87 @@ +#ifndef __qwaq_ui_textcontect_h +#define __qwaq_ui_textcontect_h + +#ifdef __QFCC__ +#include +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/ui/draw.h" +#include "ruamoko/qwaq/ui/rect.h" + +@class DrawBuffer; + +@interface TextContext : Object +{ + window_t window; + union { + Rect rect; + struct { + Point offset; + Extent size; + }; + struct { + int xpos; + int ypos; + int xlen; + int ylen; + }; + }; + int background; +} ++ (int) max_colors; ++ (int) max_color_pairs; ++ (void) init_pair: (int) pair, int fg, int bg; ++ (int) acs_char: (int) acs; ++ (void) move: (Point) pos; ++ (void) curs_set: (int) visibility; ++ (void) doupdate; ++ (TextContext *) screen; + ++(TextContext *)textContext; ++(TextContext *)withRect:(Rect)rect; ++(TextContext *)withWindow:(window_t)window; + +-init; +-initWithRect: (Rect) rect; +-initWithWindow: (window_t) window; + +- (window_t) window; +- (Extent) size; + +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; + +- (void) refresh; ++ (void) refresh; +- (void) bkgd: (int) ch; +- (void) scrollok: (int) flag; +- (void) border: (box_sides_t) sides, box_corners_t corners; +- (void) mvhline: (Point) pos, int ch, int n; +- (void) mvvline: (Point) pos, int ch, int n; +-clearReact: (Rect) rect; +@end + +#else + +#include "QF/pr_obj.h" + +typedef struct qwaq_textcontext_s { + pr_id_t isa; + pointer_t window; + union { + Rect rect; + struct { + Point offset; + Extent size; + }; + struct { + int xpos; + int ypos; + int xlen; + int ylen; + }; + }; + int background; +} qwaq_textcontext_t; + +#endif + +#endif//__qwaq_ui_textcontect_h diff --git a/ruamoko/qwaq/ui/textcontext.r b/ruamoko/qwaq/ui/textcontext.r new file mode 100644 index 000000000..9d05765d7 --- /dev/null +++ b/ruamoko/qwaq/ui/textcontext.r @@ -0,0 +1,225 @@ +#include "ruamoko/qwaq/ui/draw.h" +#include "ruamoko/qwaq/ui/textcontext.h" + +@implementation TextContext ++ (int) is_initialized = #0; ++ (void) initialize +{ + if (![self is_initialized]) { + initialize (); + } +} + ++ (int) max_colors = #0; ++ (int) max_color_pairs = #0; ++ (void) init_pair: (int) pair, int fg, int bg = #0; ++ (int) acs_char: (int) acs = #0; ++ (void) move: (Point) pos = #0; ++ (void) curs_set: (int) visibility = #0; ++ (void) doupdate = #0; + +static TextContext *screen; ++ (TextContext *) screen +{ + if (!screen) { + screen = [[TextContext textContext] retain]; + } + return screen; +} + ++(TextContext *)textContext +{ + return [[[self alloc] init] autorelease]; +} + ++(TextContext *)withRect:(Rect)rect +{ + return [[[self alloc] initWithRect:rect] autorelease]; +} + ++(TextContext *)withWindow:(window_t)window +{ + return [[[self alloc] initWithWindow:window] autorelease]; +} + +- init +{ + if (!(self = [super init])) { + return nil; + } + window = stdscr; + rect = getwrect (window); + return self; +} + +- initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + window = create_window (rect.offset.x, rect.offset.y, + rect.extent.width, rect.extent.height); + offset = {}; + size = rect.extent; + return self; +} + +- initWithWindow: (window_t) window +{ + if (!(self = [super init])) { + return nil; + } + self.window = window; + return self; +} + +-(window_t) window +{ + return window; +} + +-(Extent) size +{ + return size; +} + +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect +{ + Extent srcSize = [srcBuffer size]; + Rect r = { {}, size }; + Rect t = { pos, rect.extent }; + + t = clipRect (r, t); + if (t.extent.width < 0 || t.extent.height < 0) { + return self; + } + + rect.offset.x += t.offset.x - pos.x; + rect.offset.y += t.offset.y - pos.y; + rect.extent = t.extent; + pos = t.offset; + + r.offset = nil; + r.extent = size; + + rect = clipRect (r, rect); + if (rect.extent.width < 0 || rect.extent.height < 0) { + return self; + } + + int *src = [srcBuffer buffer] + + rect.offset.y * srcSize.width + rect.offset.x; + for (int y = 0; y < rect.extent.height; y++) { + mvwblit_line (window, pos.x, y + pos.y, src, rect.extent.width); + src += srcSize.width; + } + return self; +} + +-clearReact: (Rect) rect +{ + Point pos = rect.offset; + int len = rect.extent.width; + int count = rect.extent.height; + + if (pos.x + len > xlen) { + len = xlen - pos.x; + } + if (pos.x < 0) { + len += pos.x; + pos.x = 0; + } + if (len < 1) { + return self; + } + if (pos.y + count > ylen) { + count = ylen - pos.y; + } + if (pos.y < 0) { + count += pos.y; + pos.y = 0; + } + if (count < 1) { + return self; + } + int ch = background; + if (!(ch & 0xff)) { + ch |= ' '; + } + while (count-- > 0) { + [self mvhline:pos, ch, len]; + pos.y++; + } + return self; +} + +- (void) printf: (string) fmt, ... = #0; +- (void) vprintf: (string) mft, @va_list args = #0; +- (void) addch: (int) ch = #0; +- (void) addstr: (string) str = #0; + +- (void) mvprintf: (Point) pos, string fmt, ... = #0; +- (void) mvvprintf: (Point) pos, string mft, @va_list args = #0; +- (void) mvaddch: (Point) pos, int ch = #0; +- (void) mvaddstr: (Point) pos, string str = #0; +- (void) mvhline: (Point) pos, int ch, int n = #0; +- (void) mvvline: (Point) pos, int ch, int n = #0; + +- (void) resizeTo: (Extent) newSize = #0; // absolute size +- (void) refresh = #0; ++ (void) refresh = #0; + +- (void) bkgd: (int) ch = #0; +- (void) clear = #0; +- (void) scrollok: (int) flag = #0; +- (void) border: (box_sides_t) sides, box_corners_t corners = #0; + +@end + +window_t stdscr = (window_t) 1; + +void initialize (void) = #0; +void syncprintf (string fnt, ...) = #0; +window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; +void destroy_window (window_t win) = #0; +void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; +void wprintf (window_t win, string fmt, ...) = #0; +void wvprintf (window_t win, string fmt, @va_list args) = #0; +void mvwvprintf (window_t win, int x, int y, string fmt, @va_list args) = #0; +void wrefresh (window_t win) = #0; +void mvwaddch (window_t win, int x, int y, int ch) = #0; +void waddch (window_t win, int ch) = #0; +void mvwaddstr (window_t win, int x, int y, string str) = #0; +void waddstr (window_t win, string str) = #0; +int get_event (qwaq_event_t *event) = #0; +int max_colors (void) = #0; +int max_color_pairs (void) = #0; +int init_pair (int pair, int f, int b) = #0; +void wbkgd (window_t win, int ch) = #0; +void werase (window_t win) = #0; +void scrollok (window_t win, int flag) = #0; +int acs_char (int acs) = #0; + +panel_t create_panel (window_t window) = #0; +void destroy_panel (panel_t panel) = #0; +void hide_panel (panel_t panel) = #0; +void show_panel (panel_t panel) = #0; +void top_panel (panel_t panel) = #0; +void bottom_panel (panel_t panel) = #0; +void move_panel (panel_t panel, int x, int y) = #0; +window_t panel_window (panel_t panel) = #0; +void replace_panel (panel_t panel, window_t window) = #0; +void update_panels (void) = #0; + +void doupdate (void) = #0; +int curs_set (int visibility) = #0; +int move (int x, int y) = #0; +void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; +void mvwblit_line (window_t window, int x, int y, int *wch, int len) = #0; +void wresize (window_t window, int width, int height) = #0; +void resizeterm (int width, int height) = #0; +Rect getwrect (window_t window) = #0; +void mvwhline (window_t win, int x, int y, int ch, int n) = #0; +void mvwvline (window_t win, int x, int y, int ch, int n) = #0; + +void printf(string fmt, ...) = #0; diff --git a/ruamoko/qwaq/ui/titlebar.h b/ruamoko/qwaq/ui/titlebar.h new file mode 100644 index 000000000..a3290a20d --- /dev/null +++ b/ruamoko/qwaq/ui/titlebar.h @@ -0,0 +1,17 @@ +#ifndef __qwaq_ui_titlebar_h +#define __qwaq_ui_titlebar_h + +#include "ruamoko/qwaq/ui/view.h" + +@interface TitleBar : View +{ + string title; + int length; +} +// title always centered at top of owner ++(TitleBar *)withTitle:(string)title; +-initWithTitle:(string)title; +-setTitle:(string)newTitle; +@end + +#endif//__qwaq_ui_titlebar_h diff --git a/ruamoko/qwaq/ui/titlebar.r b/ruamoko/qwaq/ui/titlebar.r new file mode 100644 index 000000000..d6634c2ad --- /dev/null +++ b/ruamoko/qwaq/ui/titlebar.r @@ -0,0 +1,46 @@ +#include + +#include "ruamoko/qwaq/ui/group.h" +#include "ruamoko/qwaq/ui/titlebar.h" + +@implementation TitleBar + ++(TitleBar *)withTitle:(string)title +{ + return [[[self alloc] initWithTitle:title] autorelease]; +} + +-initWithTitle:(string) title +{ + if (!(self = [super init])) { + return nil; + } + self.title = title; + length = strlen (title); + growMode = gfGrowHiX; + return self; +} + +-setTitle:(string) newTitle +{ + title = newTitle; + length = strlen (title); + [self redraw]; + return self; +} + +-setOwner: (Group *) owner +{ + [super setOwner: owner]; + size = [owner size]; + return self; +} + +-draw +{ + [super draw]; + [self mvaddstr: { (xlen - length) / 2, 0}, title]; + return self; +} + +@end diff --git a/ruamoko/qwaq/ui/view.h b/ruamoko/qwaq/ui/view.h new file mode 100644 index 000000000..15e8d22d3 --- /dev/null +++ b/ruamoko/qwaq/ui/view.h @@ -0,0 +1,137 @@ +#ifndef __qwaq_ui_view_h +#define __qwaq_ui_view_h + +#include +#include + +#include "ruamoko/qwaq/ui/draw.h" +#include "ruamoko/qwaq/ui/rect.h" +#include "ruamoko/qwaq/ui/textcontext.h" + +@class Group; +@class ListenerGroup; +@class ScrollBar; + +enum { + ofCanFocus = 0x0001, + ofFirstClick = 0x0002, + ofMakeFirst = 0x0004, + ofDontDraw = 0x0008, + ofRelativeEvents= 0x0010, + + ofTileable = 0x0020, + ofCentered = 0x0040, +}; + +enum { + sfDrawn = 0x0001, + sfDisabled = 0x0002, + sfInFocus = 0x0004, + sfModal = 0x0008, + sfLocked = 0x0010, +}; + +enum { + gfGrowNone = 0x0000, + gfGrowLoX = 0x0001, + gfGrowLoY = 0x0002, + gfGrowHiX = 0x0004, + gfGrowHiY = 0x0008, + gfGrowRel = 0x0010, + gfGrowLo = gfGrowLoX | gfGrowLoY, + gfGrowHi = gfGrowHiX | gfGrowHiY, + gfGrowX = gfGrowLoX | gfGrowHiX, + gfGrowY = gfGrowLoY | gfGrowHiY, + gfGrowAll = gfGrowX | gfGrowY, +}; + +@protocol View +-setOwner: (Group *) owner; +-setGrowMode: (int) mode; + +-(Rect)rect; +-(Point)origin; +-(Extent)size; + +-(int) containsPoint: (Point) point; +-(void) grabMouse; +-(void) releaseMouse; + +-(int) options; +-(int) state; + +-setVerticalScrollBar:(ScrollBar *)scrollbar; +-setHorizontalScrollBar:(ScrollBar *)scrollbar; +-(ListenerGroup *) onViewScrolled; + +-(id)context; +-setContext: (id) context; +-draw; +-hide; +-redraw; +-move: (Point) delta; +-resize: (Extent) delta; +-move:(Point)dpos andResize:(Extent)dsize; +-moveTo:(Point)pos; // does not redraw +-resizeTo:(Extent)size; // does not redraw +-grow: (Extent) delta; +-(ListenerGroup *)onEvent; +-handleEvent: (qwaq_event_t *) event; +-takeFocus; +-loseFocus; +-(ListenerGroup *) onReceiveFocus; +-(ListenerGroup *) onReleaseFocus; +-raise; + +- (void) onMouseEnter: (Point) pos; +- (void) onMouseLeave: (Point) pos; + +- (void) refresh; +- (void) mvprintf: (Point) pos, string fmt, ...; +- (void) mvvprintf: (Point) pos, string fmt, @va_list args; +- (void) mvaddch: (Point) pos, int ch; +-clear; +@end + +@interface View: Object +{ + union { + Rect rect; + struct { + int xpos; + int ypos; + int xlen; + int ylen; + }; + struct { + Point pos; + Extent size; + }; + }; + Rect absRect; + Group *owner; + id textContext; + int state; + int options; + int growMode; + int cursorState; + Point cursor; + ListenerGroup *onReceiveFocus; + ListenerGroup *onReleaseFocus; + ListenerGroup *onEvent; + ListenerGroup *onViewScrolled; + ScrollBar *hScrollBar; + ScrollBar *vScrollBar; + Point scroll; +} ++(View *)viewWithRect:(Rect)rect; ++(View *)viewWithRect:(Rect)rect options:(int)options; + +-initWithRect:(Rect)rect; +-initWithRect:(Rect)rect options:(int)options; +@end + +@interface View (TextContext) +@end + +#endif//__qwaq_ui_view_h diff --git a/ruamoko/qwaq/ui/view.r b/ruamoko/qwaq/ui/view.r new file mode 100644 index 000000000..014560ffd --- /dev/null +++ b/ruamoko/qwaq/ui/view.r @@ -0,0 +1,415 @@ +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/ui/listener.h" +#include "ruamoko/qwaq/ui/group.h" +#include "ruamoko/qwaq/ui/scrollbar.h" +#include "ruamoko/qwaq/ui/view.h" + +@implementation View + ++(View *)viewWithRect:(Rect)rect +{ + return [[[self alloc] initWithRect:rect] autorelease]; +} + ++(View *)viewWithRect:(Rect)rect options:(int)options +{ + return [[[self alloc] initWithRect:rect options:options] autorelease]; +} + +static void view_init(View *self) +{ + self.onReceiveFocus = [[ListenerGroup listener] retain]; + self.onReleaseFocus = [[ListenerGroup listener] retain]; + self.onEvent = [[ListenerGroup listener] retain]; + self.onViewScrolled = [[ListenerGroup listener] retain]; +} + +-init +{ + if (!(self = [super init])) { + return nil; + } + view_init (self); + return self; +} + +-initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + view_init (self); + + self.rect = rect; + self.absRect = rect; + return self; +} + +-initWithRect: (Rect) rect options:(int)options +{ + if (!(self = [super init])) { + return nil; + } + view_init (self); + + self.rect = rect; + self.absRect = rect; + self.options = options; + return self; +} + +- (void) dealloc +{ + [onReceiveFocus release]; + [onReleaseFocus release]; + [onEvent release]; + [onViewScrolled release]; + [super dealloc]; +} + +-(id)context +{ + return textContext; +} + +-setContext: (id) context +{ + textContext = context; + return self; +} + +- (int) options +{ + return options; +} + +- (int) state +{ + return state; +} + +-(void)onScrollBarModified:(id)sender +{ + if (sender == vScrollBar) { + scroll.y = [sender index]; + } else if (sender == hScrollBar) { + scroll.x = [sender index]; + } + [onViewScrolled respond:self]; +} + +static void +setScrollBar (View *self, ScrollBar **sb, ScrollBar *scrollbar) +{ + SEL sel = @selector(onScrollBarModified:); + [scrollbar retain]; + [[*sb onScrollBarModified] removeListener:self :sel]; + [*sb release]; + + *sb = scrollbar; + [[*sb onScrollBarModified] addListener:self :sel]; +} + +-setVerticalScrollBar:(ScrollBar *)scrollbar +{ + setScrollBar (self, &vScrollBar, scrollbar); + return self; +} + +-setHorizontalScrollBar:(ScrollBar *)scrollbar +{ + setScrollBar (self, &hScrollBar, scrollbar); + return self; +} + +static void +updateScreenCursor (View *view) +{ + // XXX this does not work +/* while ((view.state & sfInFocus) && view.owner) { + View *owner = (View *) view.owner; + if (view.cursor.x >= 0 && view.cursor.x < view.xlen + && view.cursor.y >= 0 && view.cursor.y < view.ylen) { + owner.cursor.x = view.cursor.x + view.xpos; + owner.cursor.y = view.cursor.y + view.ypos; + owner.cursorState = view.cursorState; + } else { + owner.cursorState = 0; + } + view = owner; + } + if (view.state & sfInFocus) { + if (view.cursor.x >= 0 && view.cursor.x < view.xlen + && view.cursor.y >= 0 && view.cursor.y < view.ylen) { + curs_set (view.cursorState); + move(view.cursor.x, view.cursor.y); + } else { + curs_set (0); + } + }*/ +} + +-draw +{ + state |= sfDrawn; + updateScreenCursor (self); + return self; +} + +-hide +{ + if (state & sfDrawn) { + state &= ~sfDrawn; + updateScreenCursor (self); + } + return self; +} + +-redraw +{ + if ((state & sfDrawn) && !(options & ofDontDraw)) { + [self draw]; + [owner redraw]; + } + return self; +} + +-setOwner: (Group *) owner +{ + self.owner = owner; + return self; +} + +-setGrowMode: (int) mode +{ + growMode = mode; + return self; +} + +- (Rect) rect +{ + return rect; +} + +-(Point)origin +{ + return pos; +} + +-(Extent)size +{ + return size; +} + + +-(int) containsPoint: (Point) point +{ + return rectContainsPoint (rect, point); +} + +-(void) grabMouse +{ + [owner grabMouse]; +} + +-(void) releaseMouse +{ + [owner releaseMouse]; +} + +- (void) forward: (SEL) sel : (@va_list) args +{ + if (!textContext) { + return; + } + if (!__obj_responds_to (textContext, sel)) { + [self error: "no implementation for %s", sel_get_name (sel)]; + } + obj_msg_sendv (textContext, sel, args); +} + +- (void) refresh +{ + if (__obj_responds_to (textContext, @selector(refresh))) { + [(id)textContext refresh]; + } +} + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvvprintf: pos, fmt, va_copy (@args)]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvvprintf: pos, fmt, args]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvaddch: pos, ch]; +} + +- (void) mvaddstr: (Point) pos, string str +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvaddstr: pos, str]; +} + +-clear +{ + [textContext clearReact:rect]; + return self; +} + +-move: (Point) delta +{ + xpos += delta.x; + ypos += delta.y; + if (xpos + xlen < 1) { + xpos = 1 - xlen; + } + if (ypos < 0) { + ypos = 0; + } + if (owner) { + Extent s = [owner size]; + if (xpos > s.width - 1) { + xpos = s.width - 1; + } + if (ypos > s.height - 1) { + ypos = s.height - 1; + } + } + return self; +} + +-resize: (Extent) delta +{ + xlen += delta.width; + ylen += delta.height; + if (xlen < 1) { + xlen = 1; + } + if (ylen < 1) { + ylen = 1; + } + return self; +} + +-move:(Point)dpos andResize:(Extent)dsize +{ + [self move: dpos]; + [self resize: dsize]; + return self; +} + +-moveTo:(Point)pos +{ + self.pos = pos; + return self; +} + +-resizeTo:(Extent)size +{ + self.size = size; + return self; +} + +-grow: (Extent) delta +{ + Point dpos = {}; + Extent dsize = {}; + + if (growMode & gfGrowLoX) { + dpos.x += delta.width; + dsize.width -= delta.width; + } + if (growMode & gfGrowHiX) { + dsize.width += delta.width; + } + if (growMode & gfGrowLoY) { + dpos.y += delta.height; + dsize.height -= delta.height; + } + if (growMode & gfGrowHiY) { + dsize.height += delta.height; + } + int save_state = state; + state &= ~sfDrawn; + [self move: dpos andResize: dsize]; + state = save_state; + [self redraw]; + return self; +} + +-(ListenerGroup *) onReceiveFocus +{ + return onReceiveFocus; +} + +-(ListenerGroup *) onReleaseFocus +{ + return onReleaseFocus; +} + +-(ListenerGroup *)onEvent +{ + return onEvent; +} + +-(ListenerGroup *) onViewScrolled +{ + return onViewScrolled; +} + +-handleEvent: (qwaq_event_t *) event +{ + // give any listeners a chance to override or extend event handling + [onEvent respond:self withObject:event]; + if (event.what & (qe_mousedown | qe_mouseclick) + && options & ofCanFocus && !(state & (sfDisabled | sfInFocus))) { + [owner selectView: self]; + if (!(options & ofFirstClick)) { + event.what = qe_none; + } + } + return self; +} + +-takeFocus +{ + state |= sfInFocus; + [onReceiveFocus respond:self]; + return self; +} + +-loseFocus +{ + state &= ~sfInFocus; + [onReleaseFocus respond:self]; + return self; +} + +-raise +{ + return self; +} + +- (void) onMouseEnter: (Point) pos +{ +} + +- (void) onMouseLeave: (Point) pos +{ +} + + +@end diff --git a/ruamoko/qwaq/ui/window.h b/ruamoko/qwaq/ui/window.h new file mode 100644 index 000000000..8464a68ee --- /dev/null +++ b/ruamoko/qwaq/ui/window.h @@ -0,0 +1,39 @@ +#ifndef __qwaq_ui_window_h +#define __qwaq_ui_window_h + +#include "Object.h" + +@class Group; +@class Button; +@class TitleBar; + +#include "ruamoko/qwaq/ui/draw.h" +#include "ruamoko/qwaq/ui/rect.h" +#include "ruamoko/qwaq/ui/view.h" + +@interface Window: View +{ + struct panel_s *panel; + Group *objects; + Point point; // FIXME can't be local :( + DrawBuffer *buf; + + Button *topDrag; // move-only + Button *topLeftDrag; + Button *topRightDrag; + Button *leftDrag; + Button *rightDrag; + Button *bottomLeftDrag; + Button *bottomRightDrag; + Button *bottomDrag; + TitleBar *titleBar; +} ++(Window *)withRect: (Rect) rect; +-setTitle:(string) title; +-setBackground: (int) ch; +-insert: (View *) view; +-insertDrawn: (View *) view; +-insertSelected: (View *) view; +@end + +#endif//__qwaq_ui_window_h diff --git a/ruamoko/qwaq/ui/window.r b/ruamoko/qwaq/ui/window.r new file mode 100644 index 000000000..54dc574d6 --- /dev/null +++ b/ruamoko/qwaq/ui/window.r @@ -0,0 +1,288 @@ +#include +#include + +#include "ruamoko/qwaq/ui/event.h" +#include "ruamoko/qwaq/ui/button.h" +#include "ruamoko/qwaq/ui/curses.h" +#include "ruamoko/qwaq/ui/group.h" +#include "ruamoko/qwaq/ui/listener.h" +#include "ruamoko/qwaq/ui/titlebar.h" +#include "ruamoko/qwaq/ui/window.h" +#include "ruamoko/qwaq/ui/view.h" + +@implementation Window + ++(Window *)withRect: (Rect) rect +{ + return [[[self alloc] initWithRect: rect] autorelease]; +} + +-initWithRect: (Rect) rect +{ + return [self initWithRect: rect options:ofCanFocus | ofMakeFirst]; +} + +-initWithRect: (Rect) rect options:(int)options +{ + if (!(self = [super init])) { + return nil; + } + self.rect = rect; + textContext = [[TextContext withRect: rect] retain]; + panel = create_panel ([(id)textContext window]); + + objects = [[Group withContext:textContext owner:self] retain]; + + [self insert:titleBar = [TitleBar withTitle:""]]; + + topDrag = [Button withRect:{{2, 0}, {xlen - 4, 1}}]; + topLeftDrag = [Button withRect:{{0, 0}, {2, 2}}]; + topRightDrag = [Button withRect:{{xlen - 2, 0}, {2, 2}}]; + leftDrag = [Button withRect:{{0, 2}, {1, ylen - 4}}]; + rightDrag = [Button withRect:{{xlen - 1, 2}, {1, ylen - 4}}]; + bottomLeftDrag = [Button withRect:{{0, ylen - 2} , {2, 2}}]; + bottomRightDrag = [Button withRect:{{xlen - 2, ylen - 2}, {2, 2}}]; + bottomDrag = [Button withRect:{{2, ylen - 1}, {xlen - 4, 1}}]; + [self insert: [topDrag setGrowMode: gfGrowHiX]]; + [self insert: [topLeftDrag setGrowMode: gfGrowNone]]; + [self insert: [topRightDrag setGrowMode: gfGrowX]]; + [self insert: [leftDrag setGrowMode: gfGrowHiY]]; + [self insert: [rightDrag setGrowMode: gfGrowX | gfGrowHiY]]; + [self insert: [bottomLeftDrag setGrowMode: gfGrowY]]; + [self insert: [bottomRightDrag setGrowMode: gfGrowAll]]; + [self insert: [bottomDrag setGrowMode: gfGrowHiX | gfGrowY]]; + + [[topDrag onDrag] addListener: self : @selector(dragWindow:)]; + [[topLeftDrag onDrag] addListener: self : @selector(dragWindow:)]; + [[topRightDrag onDrag] addListener: self : @selector(dragWindow:)]; + [[leftDrag onDrag] addListener: self : @selector(dragWindow:)]; + [[rightDrag onDrag] addListener: self : @selector(dragWindow:)]; + [[bottomLeftDrag onDrag] addListener: self : @selector(dragWindow:)]; + [[bottomRightDrag onDrag] addListener: self : @selector(dragWindow:)]; + [[bottomDrag onDrag] addListener: self : @selector(dragWindow:)]; + + buf = [DrawBuffer buffer: {3, 3}]; + [buf mvaddstr: {0, 0}, "XOX"]; + [buf mvaddstr: {0, 1}, "OXO"]; + [buf mvaddstr: {0, 2}, "XOX"]; + + growMode = gfGrowHi; + self.options = options; + return self; +} + +-setTitle:(string) title +{ + [titleBar setTitle:title]; + return self; +} + +#ifndef max +# define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef min +# define min(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef bound +# define bound(a,b,c) (max(a, min(b, c))) +#endif + +- (void) dragWindow: (Button *) sender +{ + Point delta = [sender delta]; + Point dp = nil; + Point ds = nil; + Extent b = [owner size]; + + if (sender == topDrag) { + dp.x = bound (0, xpos + delta.x, b.width - xlen) - xpos; + dp.y = bound (0, ypos + delta.y, b.height - ylen) - ypos; + } else if (sender == topLeftDrag) { + dp.x = bound (0, xpos + delta.x, xpos + xlen - delta.x - 1) - xpos; + dp.y = bound (0, ypos + delta.y, ypos + ylen - delta.y - 1) - ypos; + ds.x = bound (1, xlen - delta.x, b.width - xpos - delta.x) - xlen; + ds.y = bound (1, ylen - delta.y, b.height - ypos - delta.y) - ylen; + } else if (sender == topRightDrag) { + dp.y = bound (0, ypos + delta.y, ypos + ylen - delta.y - 1) - ypos; + ds.x = bound (1, xlen + delta.x, b.width - xpos) - xlen; + ds.y = bound (1, ylen - delta.y, b.height - ypos - delta.y) - ylen; + } else if (sender == leftDrag) { + dp.x = bound (0, xpos + delta.x, xpos + xlen - delta.x - 1) - xpos; + ds.x = bound (1, xlen - delta.x, b.width - xpos - delta.x) - xlen; + } else if (sender == rightDrag) { + ds.x = bound (1, xlen + delta.x, b.width - xpos) - xlen; + } else if (sender == bottomLeftDrag) { + dp.x = bound (0, xpos + delta.x, xpos + xlen - delta.x - 1) - xpos; + ds.x = bound (1, xlen - delta.x, b.width - xpos - delta.x) - xlen; + ds.y = bound (1, ylen + delta.y, b.height - ypos) - ylen; + } else if (sender == bottomRightDrag) { + ds.x = bound (1, xlen + delta.x, b.width - xpos) - xlen; + ds.y = bound (1, ylen + delta.y, b.height - ypos) - ylen; + } else if (sender == bottomDrag) { + ds.y = bound (1, ylen + delta.y, b.height - ypos) - ylen; + } + int save_state = state; + state &= ~sfDrawn; + [self move:dp andResize:{ds.x, ds.y}]; + state = save_state; + [self redraw]; +} + +-setContext: (id) context +{ + return self; +} + +-move:(Point)dpos andResize:(Extent)dsize +{ + int save_state = state; + state &= ~sfDrawn; + + Point pos = self.pos; + Extent size = self.size; + [super resize: dsize]; + [super move: dpos]; + // need to move the panel both before and after the resize to avoid + // HoM effects or window/panel possition errors + move_panel (panel, xpos, ypos); + [(id)textContext resizeTo: self.size]; + replace_panel (panel, [(id)textContext window]); + move_panel (panel, xpos, ypos); + + dsize = {self.size.width - size.width, self.size.height - size.height}; + [objects resize:dsize]; + + state = save_state; + [self redraw]; + return self; +} + +-move: (Point) delta +{ + int save_state = state; + state &= ~sfDrawn; + [super move: delta]; + move_panel (panel, xpos, ypos); + state = save_state; + [self redraw]; + return self; +} + +-resize: (Extent) delta +{ + Extent size = self.size; + [super resize:delta]; + delta = {self.size.width - size.width, self.size.height - size.height}; + [(id)textContext resizeTo: self.size]; + replace_panel (panel, [(id)textContext window]); + [objects resize:delta]; + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + [super handleEvent: event]; + + int offset = event.what & qe_positional; + if (offset) { + event.mouse.x -= xpos; + event.mouse.y -= ypos; + } + [objects handleEvent: event]; + if (offset) { + event.mouse.x += xpos; + event.mouse.y += ypos; + } + return self; +} + +-takeFocus +{ + [super takeFocus]; + [objects takeFocus]; + return self; +} + +-loseFocus +{ + [super loseFocus]; + [objects loseFocus]; + return self; +} + +-raise +{ + top_panel (panel); + [self redraw]; + return self; +} + +-insert: (View *) view +{ + [objects insert: view]; + return self; +} + +-insertDrawn: (View *) view +{ + [objects insertDrawn: view]; + return self; +} + +-insertSelected: (View *) view +{ + [objects insertSelected: view]; + return self; +} + +-setBackground: (int) ch +{ + [(id)textContext bkgd: ch]; + return self; +} + +-draw +{ + static box_sides_t box_sides = { + ACS_VLINE, ACS_VLINE, + ACS_HLINE, ACS_HLINE, + }; + static box_corners_t box_corners = { + ACS_ULCORNER, ACS_URCORNER, + ACS_LLCORNER, ACS_LRCORNER, + }; + if (box_sides.ls == ACS_VLINE) { + int *foo = &box_sides.ls; + for (int i = 0; i < 8; i++) { + foo[i] = acs_char (foo[i]); + } + } + [super draw]; + [(id)textContext border: box_sides, box_corners]; + [objects draw]; + return self; +} + +-redraw +{ + if (state & sfDrawn) { + [owner redraw]; + } + return self; +} + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + [textContext mvvprintf: pos, fmt, @args]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + [textContext mvvprintf: pos, fmt, args]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + [textContext mvaddch: pos, ch]; +} +@end diff --git a/ruamoko/scheme/Lexer.r b/ruamoko/scheme/Lexer.r index 20b026599..32d2958a5 100644 --- a/ruamoko/scheme/Lexer.r +++ b/ruamoko/scheme/Lexer.r @@ -1,5 +1,6 @@ #include "Lexer.h" #include "Number.h" +#include "legacy_string.h" #include "string.h" #include "Boolean.h" #include "Error.h" diff --git a/ruamoko/scheme/Machine.h b/ruamoko/scheme/Machine.h index 7c99a2433..a7da59f61 100644 --- a/ruamoko/scheme/Machine.h +++ b/ruamoko/scheme/Machine.h @@ -11,7 +11,7 @@ { state_t state; SchemeObject *value; - hashtab_t globals; + hashtab_t *globals; SchemeObject *all_globals; } - (void) loadCode: (CompiledCode *) code; diff --git a/ruamoko/scheme/Makefile.am b/ruamoko/scheme/Makefile.am deleted file mode 100644 index 75f784ef5..000000000 --- a/ruamoko/scheme/Makefile.am +++ /dev/null @@ -1,63 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -pkglibdir=$(datarootdir)/qfcc/lib - -QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) -PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) -GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi -GZ=@progs_gz@ -# BSD make can't handle $(shell foo) directives, and GNU make can't handle |= -# so we have to bite the bullet and pass this to the shell every time. -STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` - -RANLIB=touch - -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include - -scheme_libs=libscheme.a -libs=$(scheme_libs) -data=$(scheme_data) - -pkglib_LIBRARIES= $(libs) -EXTRA_LIBRARIES= $(scheme_libs) -#pkgdata_DATA= $(data) -EXTRA_DATA = $(scheme_data) - -EXTRA_DIST = \ - BaseContinuation.h Boolean.h CompiledCode.h Compiler.h Cons.h \ - Continuation.h Error.h Frame.h Instruction.h Lambda.h Lexer.h \ - Machine.h Nil.h Number.h Parser.h Primitive.h Procedure.h \ - SchemeObject.h SchemeString.h Scope.h Symbol.h Void.h builtins.h \ - debug.h defs.h state.h \ - \ - main.r defs.r - -SUFFIXES=.qc .qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< -.r.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< - -libscheme_a_SOURCES=\ - SchemeObject.r Cons.r Number.r SchemeString.r Symbol.r Lexer.r Parser.r \ - Nil.r Procedure.r Primitive.r Lambda.r Scope.r Instruction.r builtins.r \ - Frame.r CompiledCode.r Compiler.r Continuation.r Machine.r Void.r \ - Error.r Boolean.r BaseContinuation.r -libscheme_a_AR=$(PAK) -cf - -scheme_data=\ - main.dat$(GZ) - -scheme_src=\ - main.r defs.r - -scheme_obj=$(scheme_src:.qc=.o) - -main.dat$(GZ): $(scheme_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a libscheme.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o main.dat $(scheme_obj) libscheme.a ../lib/libcsqc.a ../lib/libr.a - $(GZIP) - -CLEANFILES= *.dat *.sym *.gz *.qfo *.o diff --git a/ruamoko/scheme/Makemodule.am b/ruamoko/scheme/Makemodule.am new file mode 100644 index 000000000..8c1d43622 --- /dev/null +++ b/ruamoko/scheme/Makemodule.am @@ -0,0 +1,88 @@ +ruamoko_scheme_libs=ruamoko/scheme/libscheme.a +ruamoko_scheme_libexec=ruamoko/scheme/main.dat$(EXEEXT) + +ruamoko_lib_LIBRARIES += $(ruamoko_scheme_libs) +EXTRA_LIBRARIES += $(ruamoko_scheme_libs) + +noinst_PROGRAMS += $(ruamoko_scheme_libexec) +EXTRA_PROGRAMS += $(ruamoko_scheme_libexec) + +ruamoko_scheme_libscheme_a_SOURCES=\ + ruamoko/scheme/SchemeObject.r \ + ruamoko/scheme/Cons.r \ + ruamoko/scheme/Number.r \ + ruamoko/scheme/SchemeString.r \ + ruamoko/scheme/Symbol.r \ + ruamoko/scheme/Lexer.r \ + ruamoko/scheme/Parser.r \ + ruamoko/scheme/Nil.r \ + ruamoko/scheme/Procedure.r \ + ruamoko/scheme/Primitive.r \ + ruamoko/scheme/Lambda.r \ + ruamoko/scheme/Scope.r \ + ruamoko/scheme/Instruction.r \ + ruamoko/scheme/builtins.r \ + ruamoko/scheme/Frame.r \ + ruamoko/scheme/CompiledCode.r \ + ruamoko/scheme/Compiler.r \ + ruamoko/scheme/Continuation.r \ + ruamoko/scheme/Machine.r \ + ruamoko/scheme/Void.r \ + ruamoko/scheme/Error.r \ + ruamoko/scheme/Boolean.r \ + ruamoko/scheme/BaseContinuation.r +ruamoko_scheme_libscheme_a_dep=$(call qcautodep,$(ruamoko_scheme_libscheme_a_SOURCES)) +ruamoko_scheme_libscheme_a_AR=$(PAK) -cf +EXTRA_ruamoko_scheme_libscheme_a_DEPENDENCIES=pak +include $(ruamoko_scheme_libscheme_a_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_scheme_libscheme_a_dep) + +ruamoko_scheme_src=\ + ruamoko/scheme/main.r \ + ruamoko/scheme/defs.r + +ruamoko_scheme_main_dat_SOURCES=$(ruamoko_scheme_src) +ruamoko_scheme_main_obj=$(ruamoko_scheme_main_dat_SOURCES:.r=.o) +ruamoko_scheme_main_dep=$(call qcautodep,$(ruamoko_scheme_main_dat_SOURCES)) +ruamoko/scheme/main.dat$(EXEEXT): $(ruamoko_scheme_main_obj) $(QFCC_DEP) ruamoko/scheme/libscheme.a ruamoko/lib/libcsqc.a ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_scheme_main_obj) -Lruamoko/scheme -lscheme -lcsqc -lr +include $(ruamoko_scheme_main_dep) # am--include-marker +r_depfiles_remade += $(ruamoko_scheme_main_dep) + +ruamoko/scheme/main.sym: ruamoko/scheme/main.dat$(EXEEXT) + +EXTRA_DIST += \ + ruamoko/scheme/BaseContinuation.h \ + ruamoko/scheme/Boolean.h \ + ruamoko/scheme/CompiledCode.h \ + ruamoko/scheme/Compiler.h \ + ruamoko/scheme/Cons.h \ + ruamoko/scheme/Continuation.h \ + ruamoko/scheme/Error.h \ + ruamoko/scheme/Frame.h \ + ruamoko/scheme/Instruction.h \ + ruamoko/scheme/Lambda.h \ + ruamoko/scheme/Lexer.h \ + ruamoko/scheme/Machine.h \ + ruamoko/scheme/Nil.h \ + ruamoko/scheme/Number.h \ + ruamoko/scheme/Parser.h \ + ruamoko/scheme/Primitive.h \ + ruamoko/scheme/Procedure.h \ + ruamoko/scheme/SchemeObject.h \ + ruamoko/scheme/SchemeString.h \ + ruamoko/scheme/Scope.h \ + ruamoko/scheme/Symbol.h \ + ruamoko/scheme/Void.h \ + ruamoko/scheme/builtins.h \ + ruamoko/scheme/debug.h \ + ruamoko/scheme/defs.h \ + ruamoko/scheme/state.h \ + ruamoko/scheme/main.r \ + ruamoko/scheme/defs.r +CLEANFILES += \ + ruamoko/scheme/*.dat \ + ruamoko/scheme/*.sym +DISTCLEANFILES += \ + $(ruamoko_scheme_libscheme_a_dep) \ + $(ruamoko_scheme_main_dep) diff --git a/ruamoko/scheme/Number.r b/ruamoko/scheme/Number.r index 53e7f6975..530bcd46a 100644 --- a/ruamoko/scheme/Number.r +++ b/ruamoko/scheme/Number.r @@ -1,4 +1,5 @@ #include "Number.h" +#include "legacy_string.h" #include "string.h" @implementation Number diff --git a/ruamoko/scheme/SchemeObject.h b/ruamoko/scheme/SchemeObject.h index 262c700f4..e831b50bd 100644 --- a/ruamoko/scheme/SchemeObject.h +++ b/ruamoko/scheme/SchemeObject.h @@ -14,6 +14,7 @@ int line; string source; } ++ (void) finishCollecting; + (void) collectCheckPoint; - (void) mark; - (void) markReachable; diff --git a/ruamoko/scheme/Symbol.r b/ruamoko/scheme/Symbol.r index 0704b3a50..2adfc6a25 100644 --- a/ruamoko/scheme/Symbol.r +++ b/ruamoko/scheme/Symbol.r @@ -16,7 +16,7 @@ void SymbolFree (void *ele, void *data) [s release]; } -hashtab_t symbols; +hashtab_t *symbols; Symbol *lparen; Symbol *rparen; Symbol *quote; @@ -45,7 +45,7 @@ Symbol *symbol (string str) { local Symbol *res; - if ((res = Hash_Find (symbols, s))) { + if ((res = (Symbol *) Hash_Find (symbols, s))) { return res; } else { res = (Symbol*) [self newFromString: s]; diff --git a/ruamoko/scheme/defs.h b/ruamoko/scheme/defs.h index a1d691684..7f1e4289c 100644 --- a/ruamoko/scheme/defs.h +++ b/ruamoko/scheme/defs.h @@ -1,13 +1,13 @@ -@extern void (string str) print = #0; -@extern int () errno = #0; -@extern string (int err) strerror = #0; -@extern int (...) open = #0; // string path, float flags[, float mode] -@extern int (int handle) close = #0; -@extern string read (int handle, int count, int *result) = #0; -@extern int (int handle, string buffer, int count) write = #0; -@extern int (int handle, int pos, int whence) seek = #0; +@extern void (string str) print; +@extern int () errno; +@extern string (int err) strerror; +@extern int (...) open; // string path, float flags[, float mode] +@extern int (int handle) close; +@extern string read (int handle, int count, int *result); +@extern int (int handle, string buffer, int count) write; +@extern int (int handle, int pos, int whence) seek; -@extern void() traceon = #0; // turns statment trace on -@extern void() traceoff = #0; +@extern void() traceon; // turns statment trace on +@extern void() traceoff; -@extern void (...) printf = #0; +@extern void (...) printf; diff --git a/ruamoko/scheme/defs.r b/ruamoko/scheme/defs.r index 943ef9173..1c638232d 100644 --- a/ruamoko/scheme/defs.r +++ b/ruamoko/scheme/defs.r @@ -3,7 +3,7 @@ int () errno = #0; string (int err) strerror = #0; int (...) open = #0; // string path, float flags[, float mode] int (int handle) close = #0; -string (int handle, int count, int []result) read = #0; +string read (int handle, int count, int *result) = #0; int (int handle, string buffer, int count) write = #0; int (int handle, int pos, int whence) seek = #0; diff --git a/ruamoko/scheme/main.r b/ruamoko/scheme/main.r index fb1fa3e33..be7d8bca6 100644 --- a/ruamoko/scheme/main.r +++ b/ruamoko/scheme/main.r @@ -22,23 +22,23 @@ string readfile (string filename) str_copy(res, acc); return res; } - -int main (int argc, string []argv) +int main (int argc, string *argv) { - local Parser parser; - local CompiledCode code; - local Compiler comp; - local Machine vm; - local Lambda lm; - local SchemeObject stuff, res; + local Parser *parser; + local CompiledCode *code; + local Compiler *comp; + local Machine *vm; + local Lambda *lm; + local SchemeObject *stuff, *res; + local Error *err; if (argc < 1) { return -1; } //traceon(); - + parser = [Parser newFromSource: readfile(argv[1]) file: argv[1]]; vm = [Machine new]; [vm makeRootCell]; @@ -46,26 +46,29 @@ int main (int argc, string []argv) builtin_addtomachine (vm); while ((stuff = [parser read])) { if ([stuff isError]) { - printf(">> %s: %i\n", [stuff source], [stuff line]); - printf(">> Error (%s): %s\n", [stuff type], [stuff message]); + err = (Error *) stuff; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } comp = [Compiler newWithLambda: cons ([Symbol forString: "lambda"], cons ([Nil nil], cons(stuff, [Nil nil]))) scope: nil]; - code = (CompiledCode) [comp compile]; + code = (CompiledCode *) [comp compile]; if ([code isError]) { - printf(">> %s: %i\n", [code source], [code line]); - printf(">> Error (%s): %s\n", [code type], [code message]); + err = (Error *) code; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } lm = [Lambda newWithCode: code environment: nil]; [lm invokeOnMachine: vm]; res = [vm run]; if ([res isError]) { - printf(">> %s: %i\n", [res source], [res line]); - printf(">> Error (%s): %s\n", [res type], [res message]); + err = (Error *) res; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } [vm reset]; diff --git a/tools/Makefile.am b/tools/Makefile.am deleted file mode 100644 index 008638b4a..000000000 --- a/tools/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -SUBDIRS=@tools_dirs@ -DIST_SUBDIRS=bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav -EXTRA_DIST= \ - io_mesh_qfmdl/export_mdl.py io_mesh_qfmdl/import_mdl.py \ - io_mesh_qfmdl/__init__.py io_mesh_qfmdl/mdl.py io_mesh_qfmdl/qfplist.py \ - io_mesh_qfmdl/quakepal.py diff --git a/tools/Makemodule.am b/tools/Makemodule.am new file mode 100644 index 000000000..7a3805526 --- /dev/null +++ b/tools/Makemodule.am @@ -0,0 +1,20 @@ +include tools/bsp2img/Makemodule.am +include tools/carne/Makemodule.am +include tools/pak/Makemodule.am +include tools/qfbsp/Makemodule.am +include tools/qfcc/Makemodule.am +include tools/qflight/Makemodule.am +include tools/qflmp/Makemodule.am +include tools/qfmodelgen/Makemodule.am +include tools/qfspritegen/Makemodule.am +include tools/qfvis/Makemodule.am +include tools/wad/Makemodule.am +include tools/wav/Makemodule.am + +EXTRA_DIST += \ + tools/io_mesh_qfmdl/export_mdl.py \ + tools/io_mesh_qfmdl/import_mdl.py \ + tools/io_mesh_qfmdl/__init__.py \ + tools/io_mesh_qfmdl/mdl.py \ + tools/io_mesh_qfmdl/qfplist.py \ + tools/io_mesh_qfmdl/quakepal.py diff --git a/tools/bsp2img/Makefile.am b/tools/bsp2img/Makemodule.am similarity index 60% rename from tools/bsp2img/Makefile.am rename to tools/bsp2img/Makemodule.am index ceaeca266..bf58c14aa 100644 --- a/tools/bsp2img/Makefile.am +++ b/tools/bsp2img/Makemodule.am @@ -2,10 +2,8 @@ BSP2IMG_LIBS=@BSP2IMG_LIBS@ BSP2IMG_DEPS=@BSP2IMG_DEPS@ BSP2IMG_INCS=@BSP2IMG_INCS@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(BSP2IMG_INCS) +bin_PROGRAMS += bsp2img -bin_PROGRAMS=bsp2img - -bsp2img_SOURCES= bsp2img.c +bsp2img_SOURCES= tools/bsp2img/bsp2img.c bsp2img_LDADD= $(BSP2IMG_LIBS) bsp2img_DEPENDENCIES= $(BSP2IMG_DEPS) diff --git a/tools/bsp2img/bsp2img.c b/tools/bsp2img/bsp2img.c index 649fe1427..bf99eea67 100644 --- a/tools/bsp2img/bsp2img.c +++ b/tools/bsp2img/bsp2img.c @@ -672,14 +672,14 @@ render_map (bsp_t *bsp) vertexlist[i].X = -vertexlist[i].X; tempf = vertexlist[i].Z; vertexlist[i].Z = vertexlist[i].Y; - vertexlist[i].Y = tempf;; + vertexlist[i].Y = tempf; break; case 2: /* +Y -- (-x <--> +x; +y out of screen, +z up) */ tempf = vertexlist[i].Z; vertexlist[i].Z = -vertexlist[i].Y; - vertexlist[i].Y = tempf;; + vertexlist[i].Y = tempf; break; case -3: /* -Z -- negate X and Z (ie. 180 rotate @@ -925,7 +925,7 @@ write_pcx (image_t *image) Sys_Init (); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); pcx = EncodePCX (image->image, image->width, image->height, image->width, palette, false, &pcx_len); if (Qwrite (outfile, pcx, pcx_len) != pcx_len) { diff --git a/tools/carne/Makefile.am b/tools/carne/Makefile.am deleted file mode 100644 index bec57857d..000000000 --- a/tools/carne/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -CARNE_LIBS=@CARNE_LIBS@ -CARNE_DEPS=@CARNE_DEPS@ -PAK_INCS=@CARNE_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(CARNE_INCS) - -noinst_PROGRAMS= carne - -carne_SOURCES= main.c -carne_LDADD= $(CARNE_LIBS) -carne_DEPENDENCIES= $(CARNE_DEPS) diff --git a/tools/carne/Makemodule.am b/tools/carne/Makemodule.am new file mode 100644 index 000000000..24f5f056b --- /dev/null +++ b/tools/carne/Makemodule.am @@ -0,0 +1,8 @@ +CARNE_LIBS=@CARNE_LIBS@ +CARNE_DEPS=@CARNE_DEPS@ + +noinst_PROGRAMS += carne + +carne_SOURCES= tools/carne/main.c +carne_LDADD= $(CARNE_LIBS) +carne_DEPENDENCIES= $(CARNE_DEPS) diff --git a/tools/io_mesh_qfmdl/__init__.py b/tools/io_mesh_qfmdl/__init__.py index 5ee7375ef..3d9be7b20 100644 --- a/tools/io_mesh_qfmdl/__init__.py +++ b/tools/io_mesh_qfmdl/__init__.py @@ -24,14 +24,14 @@ bl_info = { "name": "Quake MDL format", "author": "Bill Currie", - "blender": (2, 6, 3), + "blender": (2, 80, 0), "api": 35622, "location": "File > Import-Export", "description": "Import-Export Quake MDL (version 6) files. (.mdl)", - "warning": "not even alpha", + "warning": "still work in progress", "wiki_url": "", "tracker_url": "", -# "support": 'OFFICIAL', +# "support": 'OFFICIAL', "category": "Import-Export"} # To support reload properly, try to access a package var, if it's there, @@ -66,28 +66,33 @@ EFFECTS=( ) class QFMDLSettings(bpy.types.PropertyGroup): - eyeposition = FloatVectorProperty( + eyeposition : FloatVectorProperty( name="Eye Position", description="View possion relative to object origin") - synctype = EnumProperty( + synctype : EnumProperty( items=SYNCTYPE, name="Sync Type", description="Add random time offset for automatic animations") - rotate = BoolProperty( + rotate : BoolProperty( name="Rotate", description="Rotate automatically (for pickup items)") - effects = EnumProperty( + effects : EnumProperty( items=EFFECTS, name="Effects", description="Particle trail effects") - #doesn't work :( - #script = PointerProperty( - # type=bpy.types.Object, - # name="Script", - # description="Script for animating frames and skins") - script = StringProperty( + + script : PointerProperty( + type=bpy.types.Text, name="Script", description="Script for animating frames and skins") + + xform : BoolProperty( + name="Auto transform", + description="Auto-apply location/rotation/scale when exporting", + default=True) + md16 : BoolProperty( + name="16-bit", + description="16 bit vertex coordinates: QuakeForge only") xform = BoolProperty( name="Auto transform", description="Auto-apply location/rotation/scale when exporting", @@ -102,7 +107,7 @@ class ImportMDL6(bpy.types.Operator, ImportHelper): bl_label = "Import MDL" filename_ext = ".mdl" - filter_glob = StringProperty(default="*.mdl", options={'HIDDEN'}) + filter_glob : StringProperty(default="*.mdl", options={'HIDDEN'}) def execute(self, context): from . import import_mdl @@ -116,7 +121,7 @@ class ExportMDL6(bpy.types.Operator, ExportHelper): bl_label = "Export MDL" filename_ext = ".mdl" - filter_glob = StringProperty(default="*.mdl", options={'HIDDEN'}) + filter_glob : StringProperty(default="*.mdl", options={'HIDDEN'}) @classmethod def poll(cls, context): @@ -128,11 +133,12 @@ class ExportMDL6(bpy.types.Operator, ExportHelper): keywords = self.as_keywords (ignore=("check_existing", "filter_glob")) return export_mdl.export_mdl(self, context, **keywords) -class MDLPanel(bpy.types.Panel): +class OBJECT_PT_MDLPanel(bpy.types.Panel): + bl_label = "MDL Properties" bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'object' - bl_label = 'QF MDL' + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): @@ -157,21 +163,28 @@ def menu_func_import(self, context): def menu_func_export(self, context): self.layout.operator(ExportMDL6.bl_idname, text="Quake MDL (.mdl)") +classes = ( + QFMDLSettings, + OBJECT_PT_MDLPanel, + ImportMDL6, + ExportMDL6 +) def register(): - bpy.utils.register_module(__name__) + for cls in classes: + bpy.utils.register_class(cls) bpy.types.Object.qfmdl = PointerProperty(type=QFMDLSettings) - bpy.types.INFO_MT_file_import.append(menu_func_import) - bpy.types.INFO_MT_file_export.append(menu_func_export) - + bpy.types.TOPBAR_MT_file_import.append(menu_func_import) + bpy.types.TOPBAR_MT_file_export.append(menu_func_export) def unregister(): - bpy.utils.unregister_module(__name__) + for cls in classes: + bpy.utils.unregister_class(cls) - bpy.types.INFO_MT_file_import.remove(menu_func_import) - bpy.types.INFO_MT_file_export.remove(menu_func_export) + bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) + bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) if __name__ == "__main__": register() diff --git a/tools/io_mesh_qfmdl/export_mdl.py b/tools/io_mesh_qfmdl/export_mdl.py index 9b98ee20a..2590bace6 100644 --- a/tools/io_mesh_qfmdl/export_mdl.py +++ b/tools/io_mesh_qfmdl/export_mdl.py @@ -27,6 +27,7 @@ from .qfplist import pldata, PListError from .quakepal import palette from .quakenorm import map_normal from .mdl import MDL +from .__init__ import SYNCTYPE, EFFECTS def check_faces(mesh): #Check that all faces are tris because mdl does not support anything else. @@ -35,17 +36,17 @@ def check_faces(mesh): faces_ok = True save_select = [] for f in mesh.polygons: - save_select.append(f.select) - f.select = False + save_select.append(f.select_get()) + f.select_set('DESELECT') if len(f.vertices) > 3: - f.select = True + f.select_set('SELECT') faces_ok = False if not faces_ok: mesh.update() return False #reset selection to what it was before the check. for f, s in map(lambda x, y: (x, y), mesh.polygons, save_select): - f.select = s + f.select_set('SELECT' if s else 'DESELECT') mesh.update() return True @@ -85,7 +86,7 @@ def null_skin(size): return skin def active_uv(mesh): - for uvt in mesh.uv_textures: + for uvt in mesh.uv_layers: if uvt.active: return uvt return None @@ -94,6 +95,40 @@ def make_skin(operator, mdl, mesh): uvt = active_uv(mesh) mdl.skinwidth, mdl.skinheight = (4, 4) skin = null_skin((mdl.skinwidth, mdl.skinheight)) + + materials = mesh.materials + + if len(materials) > 0: + for mat in materials: + allTextureNodes = list(filter(lambda node: node.type == "TEX_IMAGE", mat.node_tree.nodes)) + if len(allTextureNodes) > 1: #=== skingroup + skingroup = MDL.Skin() + skingroup.type = 1 + skingroup.skins = [] + skingroup.times = [] + sortedNodes = list(allTextureNodes) + sortedNodes.sort(key=lambda x: x.location[1], reverse=True) + for node in sortedNodes: + if node.type == "TEX_IMAGE": + image = node.image + mdl.skinwidth, mdl.skinheight = image.size + skin = convert_image(image) + skingroup.skins.append(skin) + skingroup.times.append(0.1) # hardcoded at the moment + mdl.skins.append(skingroup) + elif len(allTextureNodes) == 1: #=== single skin + for node in allTextureNodes: + if node.type == "TEX_IMAGE": + image = node.image + mdl.skinwidth, mdl.skinheight = image.size + skin = convert_image(image) + mdl.skins.append(skin) + else: + mdl.skins.append(skin) # add empty skin - no texture nodes + else: + mdl.skins.append(skin) # add empty skin - no materials + + ''' if (uvt and uvt.data and uvt.data[0].image): image = uvt.data[0].image if (uvt.data[0].image.size[0] and uvt.data[0].image.size[1]): @@ -102,7 +137,9 @@ def make_skin(operator, mdl, mesh): else: operator.report({'WARNING'}, "Texture '%s' invalid (missing?)." % image.name) + mdl.skins.append(skin) + ''' def build_tris(mesh): # mdl files have a 1:1 relationship between stverts and 3d verts. @@ -182,7 +219,7 @@ def calc_average_area(mdl): a = Vector(verts[0].r) - Vector(verts[1].r) b = Vector(verts[2].r) - Vector(verts[1].r) c = a.cross(b) - totalarea += (c * c) ** 0.5 / 2.0 + totalarea += (c @ c) ** 0.5 / 2.0 return totalarea / len(mdl.tris) def get_properties(operator, mdl, obj): @@ -192,16 +229,11 @@ def get_properties(operator, mdl, obj): | MDL.EFFECTS[obj.qfmdl.effects]) if obj.qfmdl.md16: mdl.ident = "MD16" + script = obj.qfmdl.script mdl.script = None if script: - try: - script = bpy.data.texts[script].as_string() - except KeyError: - operator.report({'ERROR'}, - "Script '%s' not found." % script) - return False - pl = pldata(script) + pl = pldata(script.as_string()) try: mdl.script = pl.parse() except PListError as err: @@ -268,17 +300,29 @@ def process_frame(mdl, scene, frame, vertmap, ingroup = False, return fr mdl.frames += fr.frames[:-1] return fr.frames[-1] - scene.frame_set(int(frameno), frameno - int(frameno)) - mesh = mdl.obj.to_mesh(scene, True, 'PREVIEW') #wysiwyg? + scene.frame_set(int(frameno), subframe = frameno - int(frameno)) + depsgraph = bpy.context.evaluated_depsgraph_get() + mesh = mdl.obj.evaluated_get(depsgraph).to_mesh() #wysiwyg? if mdl.obj.qfmdl.xform: mesh.transform(mdl.obj.matrix_world) fr = make_frame(mesh, vertmap) fr.name = name return fr +def get_frame_name(mesh, idx): + name = "frame" + str(idx) + if mesh.shape_keys: + shape_keys_amount = len(mesh.shape_keys.key_blocks) + if shape_keys_amount > idx: + name = mesh.shape_keys.key_blocks[idx].name + return name + def export_mdl(operator, context, filepath): obj = context.active_object - mesh = obj.to_mesh(context.scene, True, 'PREVIEW') #wysiwyg? + obj.update_from_editmode() + depsgraph = context.evaluated_depsgraph_get() + ob_eval = obj.evaluated_get(depsgraph) + mesh = ob_eval.to_mesh() #if not check_faces(mesh): # operator.report({'ERROR'}, # "Mesh has faces with more than 3 vertices.") @@ -287,6 +331,7 @@ def export_mdl(operator, context, filepath): mdl.obj = obj if not get_properties(operator, mdl, obj): return {'CANCELLED'} + mdl.tris, mdl.stverts, vertmap = build_tris(mesh) if mdl.script: if 'skins' in mdl.script: @@ -299,13 +344,19 @@ def export_mdl(operator, context, filepath): if not mdl.skins: make_skin(operator, mdl, mesh) if not mdl.frames: - curframe = context.scene.frame_current - for fno in range(1, curframe + 1): + scene = context.scene + for fno in range(scene.frame_start, scene.frame_end + 1): context.scene.frame_set(fno) - mesh = obj.to_mesh(context.scene, True, 'PREVIEW') #wysiwyg? - if mdl.obj.qfmdl.xform: + obj.update_from_editmode() + depsgraph = context.evaluated_depsgraph_get() + ob_eval = obj.evaluated_get(depsgraph) + mesh = ob_eval.to_mesh() + if obj.qfmdl.xform: mesh.transform(mdl.obj.matrix_world) - mdl.frames.append(make_frame(mesh, vertmap)) + frame = make_frame(mesh, vertmap) + frame.name = get_frame_name(obj.data, fno) + mdl.frames.append(frame) + convert_stverts(mdl, mdl.stverts) mdl.size = calc_average_area(mdl) scale_verts(mdl) diff --git a/tools/io_mesh_qfmdl/import_mdl.py b/tools/io_mesh_qfmdl/import_mdl.py index feca0fa08..d27ed45a1 100644 --- a/tools/io_mesh_qfmdl/import_mdl.py +++ b/tools/io_mesh_qfmdl/import_mdl.py @@ -39,7 +39,7 @@ def make_verts(mdl, framenum, subframenum=0): ( 0, 0,s.z,o.z), ( 0, 0, 0, 1))) for v in frame.verts: - verts.append(m * Vector(v.r)) + verts.append(m @ Vector(v.r)) return verts def make_faces(mdl): @@ -87,7 +87,7 @@ def load_skins(mdl): p[l + 2] = c[2] / 255.0 p[l + 3] = 1.0 img.pixels[:] = p[:] - img.pack(True) + img.pack() img.use_fake_user = True mdl.images=[] @@ -98,30 +98,80 @@ def load_skins(mdl): else: load_skin(skin, "%s_%d" % (mdl.name, i)) +def setup_main_material(mdl): + mat = bpy.data.materials.new(mdl.name) + mat.blend_method = 'OPAQUE' + mat.diffuse_color = (1, 1, 1, 1) + mat.metallic = 1 + mat.roughness = 1 + mat.specular_intensity = 0 + mat.use_nodes = True + return mat + def setup_skins(mdl, uvs): load_skins(mdl) - img = mdl.images[0] # use the first skin for now - uvlay = mdl.mesh.uv_textures.new(mdl.name) - uvloop = mdl.mesh.uv_layers[0] - for i, texpoly in enumerate(uvlay.data): +# img = mdl.images[0] # use the first skin for now +# uvlay = mdl.mesh.uv_textures.new(mdl.name) +# uvloop = mdl.mesh.uv_layers[0] +# for i, texpoly in enumerate(uvlay.data): + uvloop = mdl.mesh.uv_layers.new(name = mdl.name) + for i in range(len(mdl.mesh.polygons)): poly = mdl.mesh.polygons[i] mdl_uv = uvs[i] - texpoly.image = img +# texpoly.image = img # TODO: commented out by jazz for j,k in enumerate(poly.loop_indices): uvloop.data[k].uv = mdl_uv[j] - mat = bpy.data.materials.new(mdl.name) - mat.diffuse_color = (1,1,1) - mat.use_raytrace = False - tex = bpy.data.textures.new(mdl.name, 'IMAGE') - tex.extension = 'CLIP' - tex.use_preview_alpha = True - tex.image = img - mat.texture_slots.add() - ts = mat.texture_slots[0] - ts.texture = tex - ts.use_map_alpha = True - ts.texture_coords = 'UV' - mdl.mesh.materials.append(mat) + + #Load all skins + img_counter = 0 + for i, skin in enumerate(mdl.skins): + if skin.type: + mat = setup_main_material(mdl) + emissionNode = mat.node_tree.nodes.new("ShaderNodeEmission") + shaderOut = mat.node_tree.nodes["Material Output"] + mat.node_tree.nodes.remove(mat.node_tree.nodes["Principled BSDF"]) + + emissionNode.location = (0, 0) + shaderOut.location = (200, 0) + + yPos = 0 + + for j, subskin in enumerate(skin.skins): + tex_node = mat.node_tree.nodes.new("ShaderNodeTexImage") + tex_node.image = mdl.images[img_counter] + img_counter += 1 + tex_node.interpolation = "Closest" + + tex_node.location = (-300, yPos) + yPos -= 280 + + if j == 0: + # connect only first texture (we'll need something smarter in the future) + mat.node_tree.links.new(tex_node.outputs[0], emissionNode.inputs[0]) + + mat.node_tree.links.new(emissionNode.outputs[0], shaderOut.inputs[0]) + mdl.mesh.materials.append(mat) + + else: + mat = setup_main_material(mdl) + + # TODO: turn transform to True and position it properly in editor + emissionNode = mat.node_tree.nodes.new("ShaderNodeEmission") + shaderOut = mat.node_tree.nodes["Material Output"] + mat.node_tree.nodes.remove(mat.node_tree.nodes["Principled BSDF"]) + + tex_node = mat.node_tree.nodes.new("ShaderNodeTexImage") + tex_node.image = mdl.images[img_counter] + img_counter += 1 + tex_node.interpolation = "Closest" + + emissionNode.location = (0, 0) + shaderOut.location = (200, 0) + tex_node.location = (-300, 0) + + mat.node_tree.links.new(tex_node.outputs[0], emissionNode.inputs[0]) + mat.node_tree.links.new(emissionNode.outputs[0], shaderOut.inputs[0]) + mdl.mesh.materials.append(mat) def make_shape_key(mdl, framenum, subframenum=0): frame = mdl.frames[framenum] @@ -133,7 +183,7 @@ def make_shape_key(mdl, framenum, subframenum=0): name = frame.name else: frame.name = name - frame.key = mdl.obj.shape_key_add(name) + frame.key = mdl.obj.shape_key_add(name=name) frame.key.value = 0.0 mdl.keys.append(frame.key) s = Vector(mdl.scale) @@ -143,20 +193,25 @@ def make_shape_key(mdl, framenum, subframenum=0): ( 0, 0,s.z,o.z), ( 0, 0, 0, 1))) for i, v in enumerate(frame.verts): - frame.key.data[i].co = m * Vector(v.r) + frame.key.data[i].co = m @ Vector(v.r) def build_shape_keys(mdl): mdl.keys = [] - mdl.obj.shape_key_add("Basis") + mdl.obj.shape_key_add(name="Basis",from_mix=False) mdl.mesh.shape_keys.name = mdl.name mdl.obj.active_shape_key_index = 0 + bpy.context.scene.frame_end = 0 for i, frame in enumerate(mdl.frames): frame = mdl.frames[i] if frame.type: for j in range(len(frame.frames)): make_shape_key(mdl, i, j) + bpy.context.scene.frame_end += 1 else: make_shape_key(mdl, i) + bpy.context.scene.frame_end += 1 + + bpy.context.scene.frame_start = 1 def set_keys(act, data): for d in data: @@ -241,8 +296,8 @@ def write_text(mdl): /* This script represents the animation data within the model file. It is generated automatically on import, and is optional when exporting. If no script is used when exporting, frames will be exported one per - blender frame from frame 1 to the current frame (inclusive), and only - one skin will be exported. + blender frame from the scene start frame to the scene end frame + (inclusive), and one skin per teximage node will be exported. The fundamental format of the script is documented at http://quakeforge.net/doxygen/property-list.html @@ -335,14 +390,14 @@ def set_properties(mdl): mdl.obj.qfmdl.synctype = 'ST_SYNC' mdl.obj.qfmdl.rotate = (mdl.flags & MDL.EF_ROTATE) and True or False mdl.obj.qfmdl.effects = parse_flags(mdl.flags) - mdl.obj.qfmdl.script = mdl.text.name #FIXME really want the text object + mdl.obj.qfmdl.script = mdl.text mdl.obj.qfmdl.md16 = (mdl.ident == "MD16") -def import_mdl(operator, context, filepath): - bpy.context.user_preferences.edit.use_global_undo = False +def import_mdl(operator, context, filepath, **opts): + bpy.context.preferences.edit.use_global_undo = False - for obj in bpy.context.scene.objects: - obj.select = False + for obj in bpy.context.scene.collection.objects: + obj.select_set(False) mdl = MDL() if not mdl.read(filepath): @@ -354,10 +409,14 @@ def import_mdl(operator, context, filepath): mdl.mesh = bpy.data.meshes.new(mdl.name) mdl.mesh.from_pydata(verts, [], faces) mdl.obj = bpy.data.objects.new(mdl.name, mdl.mesh) - bpy.context.scene.objects.link(mdl.obj) - bpy.context.scene.objects.active = mdl.obj - mdl.obj.select = True + + bpy.context.scene.collection.objects.link(mdl.obj) + mdl.obj.select_set(True) + bpy.context.view_layer.objects.active = mdl.obj setup_skins(mdl, uvs) + + bpy.context.scene.frame_start = 1 + bpy.context.scene.frame_end = 1 if len(mdl.frames) > 1 or mdl.frames[0].type: build_shape_keys(mdl) merge_frames(mdl) @@ -367,5 +426,5 @@ def import_mdl(operator, context, filepath): mdl.mesh.update() - bpy.context.user_preferences.edit.use_global_undo = True + bpy.context.preferences.edit.use_global_undo = True return {'FINISHED'} diff --git a/tools/io_mesh_qfmdl/quakepal.py b/tools/io_mesh_qfmdl/quakepal.py index da7e4adec..7c2a6678f 100644 --- a/tools/io_mesh_qfmdl/quakepal.py +++ b/tools/io_mesh_qfmdl/quakepal.py @@ -1,4 +1,27 @@ -palette = ( +# vim:ts=4:et +# ##### 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. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +from struct import unpack + +default_palette = ( (0x00, 0x00, 0x00), (0x0f, 0x0f, 0x0f), (0x1f, 0x1f, 0x1f), @@ -256,3 +279,23 @@ palette = ( (0xff, 0xff, 0xff), (0x9f, 0x5b, 0x53), ) + +palette = default_palette + +def load_palette(filepath): + if not filepath: + palette = default_palette + else: + try: + f = open(filepath, "rb") + pal = f.read(768) + if len(pal) < 768: + pal = pal + b'\0' * (768 - len(pal)) + palette = [] + for i in range(256): + palette.append(unpack("<3B", pal[i * 3 : i * 3 + 3])) + palette = tuple(palette) + except IOError: + palette = default_palette + return None + return palette diff --git a/tools/io_qfmap/__init__.py b/tools/io_qfmap/__init__.py index c67158aff..2cabf517f 100644 --- a/tools/io_qfmap/__init__.py +++ b/tools/io_qfmap/__init__.py @@ -24,7 +24,7 @@ bl_info = { "name": "Quake map format", "author": "Bill Currie", - "blender": (2, 6, 3), + "blender": (2, 80, 0), "api": 35622, "location": "File > Import-Export", "description": "Import-Export Quake maps", @@ -34,286 +34,83 @@ bl_info = { # "support": 'OFFICIAL', "category": "Import-Export"} -# To support reload properly, try to access a package var, if it's there, -# reload everything -if "bpy" in locals(): - import imp - if "import_map" in locals(): - imp.reload(import_map) - if "export_map" in locals(): - imp.reload(export_map) - -from pprint import pprint +submodule_names = ( + "entity", + "entityclass", + "export_map", + "import_map", + "init", + "map", + "qfplist", + "quakechr", + "quakepal", + "wad", +) import bpy -from bpy.props import BoolProperty, FloatProperty, StringProperty, EnumProperty -from bpy.props import FloatVectorProperty, PointerProperty -from bpy_extras.io_utils import ExportHelper, ImportHelper, path_reference_mode, axis_conversion -from bpy.app.handlers import persistent +from bpy.props import PointerProperty +from bpy.utils import register_class, unregister_class -from .entityclass import EntityClassDict, EntityClassError -from . import entity -from . import import_map -from . import export_map +import importlib +import sys -def ecm_draw(self, context): - layout = self.layout - for item in self.menu_items: - if type(item[1]) is str: - ec = context.scene.qfmap.entity_classes[item[1]] - if ec.size: - icon = 'OBJECT_DATA' - else: - icon = 'MESH_DATA' - op = layout.operator("object.add_entity", text=item[0], icon=icon) - op.entclass=item[1] - if ec.comment: - pass - else: - layout.menu(item[1].bl_idname) +registered_submodules = [] -class EntityClassMenu: - @classmethod - def clear(cls): - while cls.menu_items: - if type(cls.menu_item[0][1]) is not str: - bpy.utils.unregister_class(cls.menu_items[0][1]) - cls.menu_items[0][1].clear() - del cls.menu_items[0] - @classmethod - def build(cls, menudict, name="INFO_MT_entity_add", label="entity"): - items = list(menudict.items()) - items.sort() - menu_items = [] - for i in items: - i = list(i) - if type(i[1]) is dict: - if i[0]: - nm = "_".join((name, i[0])) - else: - nm = name - i[1] = cls.build(i[1], nm, i[0]) - menu_items.append(i) - attrs = {} - attrs["menu_items"] = menu_items - attrs["draw"] = ecm_draw - attrs["bl_idname"] = name - attrs["bl_label"] = label - attrs["clear"] = cls.clear - menu = type(name, (bpy.types.Menu,), attrs) - bpy.utils.register_class(menu) - return menu +# When the addon is reloaded, this module gets reloaded, however none +# of the other modules from this addon get reloaded. As a result, they +# don't call register_submodules (only run when the module is loaded) and +# thus they don't end up registering everything. +# +# This is set before any loading starts (in register), to a set of all the +# names of the modules loaded as of when loading starts. While doing the +# module loading, check if a module is present in this list. If so, reload +# it and remove it from the set (to prevent it from getting reloaded twice). +preloaded_modules = None -@persistent -def scene_load_handler(dummy): - for scene in bpy.data.scenes: - if hasattr(scene, "qfmap"): - scene.qfmap.script_update(bpy.context) - -class MapeditMessage(bpy.types.Operator): - bl_idname = "qfmapedit.message" - bl_label = "Message" - type = StringProperty() - message = StringProperty() - - def execute(self, context): - self.report({'INFO'}, message) - return {'FINISHED'} - def invoke(self, context, event): - wm = context.window_manager - return wm.invoke_popup(self, width=400, height=200) - def draw(self, context): - self.layout.label(self.type, icon='ERROR') - self.layout.label(self.message) - -def scan_entity_classes(context): - qfmap = context.scene.qfmap - if not qfmap.dirpath: - return - qfmap.entity_classes.from_source_tree(qfmap.dirpath) - name = context.scene.name + '-EntityClasses' - if name in bpy.data.texts: - txt = bpy.data.texts[name] - else: - txt = bpy.data.texts.new(name) - txt.from_string(qfmap.entity_classes.to_plist()) - qfmap.script = name - -def parse_entity_classes(context): - context.scene.qfmap.script_update(context) - -def ec_dir_update(self, context): - try: - scan_entity_classes(context) - except EntityClassError as err: - self.dirpath = "" - bpy.ops.qfmapedit.message('INVOKE_DEFAULT', type="Error", - message="Entity Class Error: %s" % err) - -def ec_script_update(self, context): - self.script_update(context) - -class AddEntity(bpy.types.Operator): - '''Add an entity''' - bl_idname = "object.add_entity" - bl_label = "Entity" - entclass = StringProperty(name = "entclass") - - def execute(self, context): - keywords = self.as_keywords() - return entity.add_entity(self, context, **keywords) - -class QFEntityClassScan(bpy.types.Operator): - '''Rescan the specified QuakeC source tree''' - bl_idname = "scene.scan_entity_classes" - bl_label = "RELOAD" - - def execute(self, context): - scan_entity_classes(context) - return {'FINISHED'} - -class QFEntityClassParse(bpy.types.Operator): - '''Reparse the specified entity class script''' - bl_idname = "scene.parse_entity_classes" - bl_label = "RELOAD" - - def execute(self, context): - parse_entity_classes(context) - return {'FINISHED'} - -class QFEntityClasses(bpy.types.PropertyGroup): - wadpath = StringProperty( - name="wadpath", - description="Path to search for wad files", - subtype='DIR_PATH') - dirpath = StringProperty( - name="dirpath", - description="Path to qc source tree", - subtype='DIR_PATH', - update=ec_dir_update) - script = StringProperty( - name="script", - description="entity class storage", - update=ec_script_update) - entity_classes = EntityClassDict() - ecm = EntityClassMenu.build({}) - entity_targets = {} - target_entities = [] - - def script_update(self, context): - if self.script in bpy.data.texts: - script = bpy.data.texts[self.script].as_string() - self.entity_classes.from_plist(script) - menudict = {} - entclasses = self.entity_classes.keys() - for ec in entclasses: - ecsub = ec.split("_") - d = menudict - for sub in ecsub[:-1]: - if sub not in d: - d[sub] = {} - elif type(d[sub]) is str: - d[sub] = {"":d[sub]} - d = d[sub] - sub = ecsub[-1] - if sub in d: - d[sub][""] = ec - else: - d[sub] = ec - self.__class__.ecm = EntityClassMenu.build(menudict) - -class QFECPanel(bpy.types.Panel): - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = 'scene' - bl_label = 'QF Entity Classes' - - @classmethod - def poll(cls, context): - return True - - def draw(self, context): - layout = self.layout - scene = context.scene - row = layout.row() - layout.prop(scene.qfmap, "wadpath") - row = layout.row() - row.prop(scene.qfmap, "dirpath") - row.operator("scene.scan_entity_classes", text="", icon="FILE_REFRESH") - row = layout.row() - row.prop(scene.qfmap, "script") - row.operator("scene.parse_entity_classes", text="", icon="FILE_REFRESH") - -class ImportPoints(bpy.types.Operator, ImportHelper): - '''Load a Quake points File''' - bl_idname = "import_mesh.quake_points" - bl_label = "Import points" - - filename_ext = ".pts" - filter_glob = StringProperty(default="*.pts", options={'HIDDEN'}) - - def execute(self, context): - keywords = self.as_keywords (ignore=("filter_glob",)) - return import_map.import_pts(self, context, **keywords) - -class ImportMap(bpy.types.Operator, ImportHelper): - '''Load a Quake map File''' - bl_idname = "import_mesh.quake_map" - bl_label = "Import map" - - filename_ext = ".map" - filter_glob = StringProperty(default="*.map", options={'HIDDEN'}) - - def execute(self, context): - keywords = self.as_keywords (ignore=("filter_glob",)) - return import_map.import_map(self, context, **keywords) - -class ExportMap(bpy.types.Operator, ExportHelper): - '''Save a Quake map File''' - - bl_idname = "export_mesh.quake_map" - bl_label = "Export map" - - filename_ext = ".map" - filter_glob = StringProperty(default="*.map", options={'HIDDEN'}) - - @classmethod - def poll(cls, context): - return True - - def execute(self, context): - keywords = self.as_keywords (ignore=("check_existing", "filter_glob")) - return export_map.export_map(self, context, **keywords) - -def menu_func_import(self, context): - self.layout.operator(ImportMap.bl_idname, text="Quake map (.map)") - self.layout.operator(ImportPoints.bl_idname, text="Quake points (.pts)") - -def menu_func_export(self, context): - self.layout.operator(ExportMap.bl_idname, text="Quake map (.map)") - -def menu_func_add(self, context): - self.layout.menu(context.scene.qfmap.ecm.bl_idname, icon='PLUGIN') +def register_submodules(name, submodule_names): + global preloaded_modules + module = __import__(name=name, fromlist=submodule_names) + submodules = [getattr(module, name) for name in submodule_names] + for mod in submodules: + # Look through the modules present when register was called. If this + # module was already loaded, then reload it. + if mod.__name__ in preloaded_modules: + mod = importlib.reload(mod) + # Prevent the module from getting reloaded more than once + preloaded_modules.remove(mod.__name__) + m = [(),(),()] + if hasattr(mod, "classes_to_register"): + m[0] = mod.classes_to_register + for cls in mod.classes_to_register: + register_class(cls) + if hasattr(mod, "menus_to_register"): + m[1] = mod.menus_to_register + for menu in mod.menus_to_register: + menu[0].append(menu[1]) + if hasattr(mod, "custom_properties_to_register"): + for prop in mod.custom_properties_to_register: + setattr(prop[0], prop[1], PointerProperty(type=prop[2])) + if hasattr(mod, "handlers_to_register"): + m[2] = mod.handlers_to_register + for handler in mod.handlers_to_register: + getattr(bpy.app.handlers, handler[0]).append(handler[1]) + if m[0] or m[1] or m[2]: + registered_submodules.append(m) def register(): - bpy.utils.register_module(__name__) - - bpy.types.Scene.qfmap = PointerProperty(type=QFEntityClasses) - - bpy.types.INFO_MT_file_import.append(menu_func_import) - bpy.types.INFO_MT_file_export.append(menu_func_export) - bpy.types.INFO_MT_add.append(menu_func_add) - - bpy.app.handlers.load_post.append(scene_load_handler) - entity.register() - + global preloaded_modules + preloaded_modules = set(sys.modules.keys()) + register_submodules(__name__, submodule_names) + preloaded_modules = None def unregister(): - bpy.utils.unregister_module(__name__) - - bpy.types.INFO_MT_file_import.remove(menu_func_import) - bpy.types.INFO_MT_file_export.remove(menu_func_export) - bpy.types.INFO_MT_add.remove(menu_func_add) + for mod in reversed(registered_submodules): + for handler in reversed(mod[2]): + getattr(bpy.app.handlers, handler[0]).remove(handler[1]) + for menu in reversed(mod[1]): + menu[0].remove(menu[1]) + for cls in reversed(mod[0]): + unregister_class(cls) if __name__ == "__main__": register() diff --git a/tools/io_qfmap/entity.py b/tools/io_qfmap/entity.py index ecf9180c8..86a316234 100644 --- a/tools/io_qfmap/entity.py +++ b/tools/io_qfmap/entity.py @@ -19,7 +19,8 @@ # -import bpy, bgl +import bpy, bgl, gpu +from gpu_extras.batch import batch_for_shader from bpy.props import BoolProperty, FloatProperty, StringProperty, EnumProperty from bpy.props import BoolVectorProperty, CollectionProperty, PointerProperty from bpy.props import FloatVectorProperty, IntProperty @@ -27,7 +28,8 @@ from mathutils import Vector from .entityclass import EntityClass -def draw_callback(self, context): + +def build_batch(qfmap): def obj_location(obj): ec = None if obj.qfentity.classname in entity_classes: @@ -38,13 +40,13 @@ def draw_callback(self, context): for i in range(8): loc += Vector(obj.bound_box[i]) return obj.location + loc/8.0 - qfmap = context.scene.qfmap entity_classes = qfmap.entity_classes entity_targets = qfmap.entity_targets target_entities = qfmap.target_entities - bgl.glLineWidth(3) ents = 0 targs = 0 + verts = [] + colors = [] for obj in target_entities: #obj = bpy.data.objects[objname] qfentity = obj.qfentity @@ -54,30 +56,40 @@ def draw_callback(self, context): ec = entity_classes[qfentity.classname] target = None killtarget = None - for field in qfentity.fields: - if field.name == "target" and field.value: - target = field.value - if field.name == "killtarget" and field.value: - killtarget = field.value + if "target" in qfentity.fields: + target = qfentity.fields["target"].value + if "killtarget" in qfentity.fields: + killtarget = qfentity.fields["killtarget"].value targetlist = [target, killtarget] if target == killtarget: del targetlist[1] for tname in targetlist: if tname and tname in entity_targets: targets = entity_targets[tname] - bgl.glColor4f(ec.color[0], ec.color[1], ec.color[2], 1) + color = (ec.color[0], ec.color[1], ec.color[2], 1) for ton in targets: targs += 1 to = bpy.data.objects[ton] - bgl.glBegin(bgl.GL_LINE_STRIP) - loc = obj_location(obj) - bgl.glVertex3f(loc.x, loc.y, loc.z) - loc = obj_location(to) - bgl.glVertex3f(loc.x, loc.y, loc.z) - bgl.glEnd() + start = obj_location(obj) + end = obj_location(to) + + verts.append(start) + colors.append(color) + verts.append(end) + colors.append(color) + return {"pos": verts, "color": colors} + +def draw_callback(self, context): + #FIXME horribly inefficient + qfmap = context.scene.qfmap + content = build_batch(qfmap) + shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') + batch = batch_for_shader(shader, 'LINES', content) + bgl.glLineWidth(3) + batch.draw(shader) bgl.glLineWidth(1) -class QFEntityRelations(bpy.types.Panel): +class VIEW3D_PT_QFEntityRelations(bpy.types.Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_label = "Register callback" @@ -100,30 +112,30 @@ class QFEntityRelations(bpy.types.Panel): def draw(self, context): pass -class EntityField_list(bpy.types.UIList): +class OBJECT_UL_EntityField_list(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - layout.label(item.name) - layout.label(item.value) + layout.label(text=item.name) + layout.label(text=item.value) def qfentity_items(self, context): qfmap = context.scene.qfmap entclasses = qfmap.entity_classes eclist = list(entclasses.keys()) eclist.sort() - enum = (('', "--", ""),) + enum = (('.', "--", ""),) enum += tuple(map(lambda ec: (ec, ec, ""), eclist)) return enum class QFEntityProp(bpy.types.PropertyGroup): - value = StringProperty(name="") - template_list_controls = StringProperty(default="value", options={'HIDDEN'}) + value: StringProperty(name="") + template_list_controls: StringProperty(default="value", options={'HIDDEN'}) class QFEntity(bpy.types.PropertyGroup): - classname = EnumProperty(items = qfentity_items, name = "Entity Class") - flags = BoolVectorProperty(size=12) - fields = CollectionProperty(type=QFEntityProp, name="Fields") - field_idx = IntProperty() + classname: EnumProperty(items = qfentity_items, name = "Entity Class") + flags: BoolVectorProperty(size=12) + fields: CollectionProperty(type=QFEntityProp, name="Fields") + field_idx: IntProperty() class QFEntpropAdd(bpy.types.Operator): '''Add an entity field/value pair''' @@ -163,7 +175,7 @@ def reflow_text(text, max_width): lines.append(flowed_line) return lines -class EntityPanel(bpy.types.Panel): +class OBJECT_PT_EntityPanel(bpy.types.Panel): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'object' @@ -188,7 +200,7 @@ class EntityPanel(bpy.types.Panel): box=layout.box() lines = reflow_text(ec.comment, 40) for l in lines: - box.label(l) + box.label(text=l) row = layout.row() for c in range(3): col = row.column() @@ -198,11 +210,11 @@ class EntityPanel(bpy.types.Panel): sub.prop(qfentity, "flags", text=flags[idx], index=idx) row = layout.row() col = row.column() - col.template_list("EntityField_list", "", qfentity, "fields", + col.template_list("OBJECT_UL_EntityField_list", "", qfentity, "fields", qfentity, "field_idx", rows=3) col = row.column(align=True) - col.operator("object.entprop_add", icon='ZOOMIN', text="") - col.operator("object.entprop_remove", icon='ZOOMOUT', text="") + col.operator("object.entprop_add", icon='ADD', text="") + col.operator("object.entprop_remove", icon='REMOVE', text="") if len(qfentity.fields) > qfentity.field_idx >= 0: row = layout.row() field = qfentity.fields[qfentity.field_idx] @@ -246,8 +258,7 @@ def entity_box(entityclass): mesh = bpy.data.meshes.new(name) mesh.from_pydata(verts, [], faces) mat = bpy.data.materials.new(name) - mat.diffuse_color = color - mat.use_raytrace = False + mat.diffuse_color = color + (1,) mesh.materials.append(mat) return mesh @@ -258,7 +269,7 @@ def set_entity_props(obj, ent): qfe.classname = ent.d["classname"] except TypeError: #FIXME hmm, maybe an enum wasn't the most brilliant idea? - qfe.classname + qfe.classname = '' if "spawnflags" in ent.d: flags = int(float(ent.d["spawnflags"])) for i in range(12): @@ -296,5 +307,17 @@ def add_entity(self, context, entclass): context.user_preferences.edit.use_global_undo = True return {'FINISHED'} -def register(): - bpy.types.Object.qfentity = PointerProperty(type=QFEntity) +classes_to_register = ( + VIEW3D_PT_QFEntityRelations, + OBJECT_UL_EntityField_list, + QFEntityProp, + QFEntity, + QFEntpropAdd, + QFEntpropRemove, + OBJECT_PT_EntityPanel, +) +menus_to_register = ( +) +custom_properties_to_register = ( + (bpy.types.Object, "qfentity", QFEntity), +) diff --git a/tools/io_qfmap/entityclass.py b/tools/io_qfmap/entityclass.py index f659c5d53..c7b9cbd0e 100644 --- a/tools/io_qfmap/entityclass.py +++ b/tools/io_qfmap/entityclass.py @@ -140,6 +140,8 @@ class EntityClassDict: def __len__(self): return self.entity_classes.__len__() def __getitem__(self, key): + if key == '.': + return EntityClass.null() return self.entity_classes.__getitem__(key) def __iter__(self): return self.entity_classes.__iter__() diff --git a/tools/io_qfmap/import_map.py b/tools/io_qfmap/import_map.py index 7d22912a0..c247d4920 100644 --- a/tools/io_qfmap/import_map.py +++ b/tools/io_qfmap/import_map.py @@ -61,9 +61,8 @@ def load_material(tx): if tx.name in bpy.data.materials: return bpy.data.materials[tx.name] mat = bpy.data.materials.new(tx.name) - mat.diffuse_color = (1, 1, 1) + mat.diffuse_color = (1, 1, 1, 1) mat.specular_intensity = 0 - mat.use_raytrace = False if tx.image: tex = bpy.data.textures.new(tx.name, 'IMAGE') tex.extension = 'REPEAT' @@ -77,19 +76,23 @@ def load_material(tx): return mat def load_textures(texdefs, wads): + class MT: + def __init__(self, x, y): + self.width = x + self.height = y for tx in texdefs: if hasattr(tx, "miptex"): continue - try: - tx.miptex = wads[0].getData(tx.name) - tx.image = load_image(tx) - except KeyError: - class MT: - def __init__(self, x, y): - self.width = x - self.height = y + if not wads or not wads[0]: tx.miptex = MT(64,64) tx.image = None + else: + try: + tx.miptex = wads[0].getData(tx.name) + tx.image = load_image(tx) + except KeyError: + tx.miptex = MT(64,64) + tx.image = None tx.material = load_material(tx) def build_uvs(verts, faces, texdefs): @@ -110,7 +113,7 @@ def process_entity(ent, wads): classname = ent.d["classname"] name = classname if "classname" in ent.d and ent.d["classname"][:5] == "light": - light = bpy.data.lamps.new("light", 'POINT') + light = bpy.data.lights.new("light", 'POINT') if "light" in ent.d: light.distance = float(ent.d["light"]) elif "_light" in ent.d: @@ -150,7 +153,7 @@ def process_entity(ent, wads): tx.matindex = len(mesh.materials) mesh.materials.append(tx.material) mesh.from_pydata(verts, [], faces) - uvlay = mesh.uv_textures.new(name) + """uvlay = mesh.uv_textures.new(name) uvloop = mesh.uv_layers[0] for i, texpoly in enumerate(uvlay.data): poly = mesh.polygons[i] @@ -159,7 +162,7 @@ def process_entity(ent, wads): texpoly.image = tx.image poly.material_index = tx.matindex for j, k in enumerate(poly.loop_indices): - uvloop.data[k].uv = uv[j] + uvloop.data[k].uv = uv[j]"""#FIXME mesh.update() obj = bpy.data.objects.new(name, mesh) else: @@ -189,50 +192,52 @@ def process_entity(ent, wads): del ent.d["angles"] obj.rotation_mode = 'XZY' obj.rotation_euler = angles * pi / 180 - bpy.context.scene.objects.link(obj) - bpy.context.scene.objects.active=obj - obj.select = True + bpy.context.layer_collection.collection.objects.link(obj) + bpy.context.view_layer.objects.active = obj + obj.select_set(True) set_entity_props(obj, ent) def import_map(operator, context, filepath): - bpy.context.user_preferences.edit.use_global_undo = False - - for obj in bpy.context.scene.objects: - obj.select = False + undo = bpy.context.preferences.edit.use_global_undo + bpy.context.preferences.edit.use_global_undo = False try: + for obj in bpy.context.scene.objects: + obj.select_set(False) entities = parse_map (filepath) except MapError as err: operator.report({'ERROR'}, repr(err)) return {'CANCELLED'} - wads=[] - if entities: - if "_wad" in entities[0].d: - wads = entities[0].d["_wad"].split(";") - elif "wad" in entities[0].d: - wads = entities[0].d["wad"].split(";") - wadpath = bpy.context.scene.qfmap.wadpath - for i in range(len(wads)): - try: - wads[i] = WadFile.load(os.path.join(wadpath, wads[i])) - except IOError: + else: + wads=[] + if entities: + if "_wad" in entities[0].d: + wads = entities[0].d["_wad"].split(";") + elif "wad" in entities[0].d: + wads = entities[0].d["wad"].split(";") + wadpath = bpy.context.scene.qfmap.wadpath + for i in range(len(wads)): try: - wads[i] = WadFile.load(os.path.join(wadpath, - os.path.basename(wads[i]))) + wads[i] = WadFile.load(os.path.join(wadpath, wads[i])) except IOError: - #give up - operator.report({'INFO'}, "Cant't find %s" % wads[i]) - wads[i] = None - for ent in entities: - process_entity(ent, wads) - bpy.context.user_preferences.edit.use_global_undo = True + try: + wads[i] = WadFile.load(os.path.join(wadpath, + os.path.basename(wads[i]))) + except IOError: + #give up + operator.report({'INFO'}, "Cant't find %s" % wads[i]) + wads[i] = None + for ent in entities: + process_entity(ent, wads) + finally: + bpy.context.preferences.edit.use_global_undo = undo return {'FINISHED'} def import_pts(operator, context, filepath): bpy.context.user_preferences.edit.use_global_undo = False for obj in bpy.context.scene.objects: - obj.select = False + obj.select_set(False) lines = open(filepath, "rt").readlines() verts = [None] * len(lines) @@ -248,6 +253,6 @@ def import_pts(operator, context, filepath): obj = bpy.data.objects.new("leak points", mesh) bpy.context.scene.objects.link(obj) bpy.context.scene.objects.active=obj - obj.select = True + obj.select_set(True) bpy.context.user_preferences.edit.use_global_undo = True return {'FINISHED'} diff --git a/tools/io_qfmap/init.py b/tools/io_qfmap/init.py new file mode 100644 index 000000000..199bb71fa --- /dev/null +++ b/tools/io_qfmap/init.py @@ -0,0 +1,294 @@ +# vim:ts=4:et +# ##### 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. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import bpy +from bpy.props import BoolProperty, FloatProperty, StringProperty, EnumProperty +from bpy.props import FloatVectorProperty, PointerProperty +from bpy_extras.io_utils import ExportHelper, ImportHelper, path_reference_mode, axis_conversion +from bpy.app.handlers import persistent + +from .entityclass import EntityClassDict, EntityClassError +from . import entity +from . import import_map +from . import export_map + +def ecm_draw(self, context): + layout = self.layout + for item in self.menu_items: + if type(item[1]) is str: + ec = context.scene.qfmap.entity_classes[item[1]] + if ec.size: + icon = 'OBJECT_DATA' + else: + icon = 'MESH_DATA' + op = layout.operator("object.add_entity", text=item[0], icon=icon) + op.entclass=item[1] + if ec.comment: + pass + else: + layout.menu(item[1].bl_idname) + +class EntityClassMenu: + @classmethod + def clear(cls): + while cls.menu_items: + if type(cls.menu_item[0][1]) is not str: + bpy.utils.unregister_class(cls.menu_items[0][1]) + cls.menu_items[0][1].clear() + del cls.menu_items[0] + @classmethod + def build(cls, menudict, name="INFO_MT_entity_add", label="entity"): + items = list(menudict.items()) + items.sort() + menu_items = [] + for i in items: + i = list(i) + if type(i[1]) is dict: + if i[0]: + nm = "_".join((name, i[0])) + else: + nm = name + i[1] = cls.build(i[1], nm, i[0]) + menu_items.append(i) + attrs = {} + attrs["menu_items"] = menu_items + attrs["draw"] = ecm_draw + attrs["bl_idname"] = name + attrs["bl_label"] = label + attrs["clear"] = cls.clear + menu = type(name, (bpy.types.Menu,), attrs) + bpy.utils.register_class(menu) + return menu + +@persistent +def scene_load_handler(dummy): + for scene in bpy.data.scenes: + if hasattr(scene, "qfmap"): + scene.qfmap.script_update(bpy.context) + +class MapeditMessage(bpy.types.Operator): + bl_idname = "qfmapedit.message" + bl_label = "Message" + type: StringProperty() + message: StringProperty() + + def execute(self, context): + self.report({'INFO'}, message) + return {'FINISHED'} + def invoke(self, context, event): + wm = context.window_manager + return wm.invoke_popup(self, width=400, height=200) + def draw(self, context): + self.layout.label(self.type, icon='ERROR') + self.layout.label(self.message) + +def scan_entity_classes(context): + qfmap = context.scene.qfmap + if not qfmap.dirpath: + return + qfmap.entity_classes.from_source_tree(qfmap.dirpath) + name = context.scene.name + '-EntityClasses' + if name in bpy.data.texts: + txt = bpy.data.texts[name] + else: + txt = bpy.data.texts.new(name) + txt.from_string(qfmap.entity_classes.to_plist()) + qfmap.script = name + +def parse_entity_classes(context): + context.scene.qfmap.script_update(context) + +def ec_dir_update(self, context): + try: + scan_entity_classes(context) + except EntityClassError as err: + self.dirpath = "" + bpy.ops.qfmapedit.message('INVOKE_DEFAULT', type="Error", + message="Entity Class Error: %s" % err) + +def ec_script_update(self, context): + self.script_update(context) + +class AddEntity(bpy.types.Operator): + '''Add an entity''' + bl_idname = "object.add_entity" + bl_label = "Entity" + entclass: StringProperty(name = "entclass") + + def execute(self, context): + keywords = self.as_keywords() + return entity.add_entity(self, context, **keywords) + +class QFEntityClassScan(bpy.types.Operator): + '''Rescan the specified QuakeC source tree''' + bl_idname = "scene.scan_entity_classes" + bl_label = "RELOAD" + + def execute(self, context): + scan_entity_classes(context) + return {'FINISHED'} + +class QFEntityClassParse(bpy.types.Operator): + '''Reparse the specified entity class script''' + bl_idname = "scene.parse_entity_classes" + bl_label = "RELOAD" + + def execute(self, context): + parse_entity_classes(context) + return {'FINISHED'} + +class QFEntityClasses(bpy.types.PropertyGroup): + wadpath: StringProperty( + name="wadpath", + description="Path to search for wad files", + subtype='DIR_PATH') + dirpath: StringProperty( + name="dirpath", + description="Path to qc source tree", + subtype='DIR_PATH', + update=ec_dir_update) + script: StringProperty( + name="script", + description="entity class storage", + update=ec_script_update) + entity_classes = EntityClassDict() + ecm = EntityClassMenu.build({}) + entity_targets = {} + target_entities = [] + + def script_update(self, context): + if self.script in bpy.data.texts: + script = bpy.data.texts[self.script].as_string() + self.entity_classes.from_plist(script) + menudict = {} + entclasses = self.entity_classes.keys() + for ec in entclasses: + ecsub = ec.split("_") + d = menudict + for sub in ecsub[:-1]: + if sub not in d: + d[sub] = {} + elif type(d[sub]) is str: + d[sub] = {"":d[sub]} + d = d[sub] + sub = ecsub[-1] + if sub in d: + d[sub][""] = ec + else: + d[sub] = ec + self.__class__.ecm = EntityClassMenu.build(menudict) + +class OBJECT_PT_QFECPanel(bpy.types.Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + #bl_context = 'scene' + bl_category = "View" + bl_label = 'QF Entity Classes' + + @classmethod + def poll(cls, context): + return True + + def draw(self, context): + layout = self.layout + scene = context.scene + row = layout.row() + layout.prop(scene.qfmap, "wadpath") + row = layout.row() + row.prop(scene.qfmap, "dirpath") + row.operator("scene.scan_entity_classes", text="", icon="FILE_REFRESH") + row = layout.row() + row.prop(scene.qfmap, "script") + row.operator("scene.parse_entity_classes", text="", icon="FILE_REFRESH") + +class ImportPoints(bpy.types.Operator, ImportHelper): + '''Load a Quake points File''' + bl_idname = "import_mesh.quake_points" + bl_label = "Import points" + + filename_ext = ".pts" + filter_glob: StringProperty(default="*.pts", options={'HIDDEN'}) + + def execute(self, context): + keywords = self.as_keywords (ignore=("filter_glob",)) + return import_map.import_pts(self, context, **keywords) + +class ImportMap(bpy.types.Operator, ImportHelper): + '''Load a Quake map File''' + bl_idname = "import_mesh.quake_map" + bl_label = "Import map" + + filename_ext = ".map" + filter_glob: StringProperty(default="*.map", options={'HIDDEN'}) + + def execute(self, context): + keywords = self.as_keywords (ignore=("filter_glob",)) + return import_map.import_map(self, context, **keywords) + +class ExportMap(bpy.types.Operator, ExportHelper): + '''Save a Quake map File''' + + bl_idname = "export_mesh.quake_map" + bl_label = "Export map" + + filename_ext = ".map" + filter_glob: StringProperty(default="*.map", options={'HIDDEN'}) + + @classmethod + def poll(cls, context): + return True + + def execute(self, context): + keywords = self.as_keywords (ignore=("check_existing", "filter_glob")) + return export_map.export_map(self, context, **keywords) + +def menu_func_import(self, context): + self.layout.operator(ImportMap.bl_idname, text="Quake map (.map)") + self.layout.operator(ImportPoints.bl_idname, text="Quake points (.pts)") + +def menu_func_export(self, context): + self.layout.operator(ExportMap.bl_idname, text="Quake map (.map)") + +def menu_func_add(self, context): + self.layout.menu(context.scene.qfmap.ecm.bl_idname, icon='PLUGIN') + +classes_to_register = ( + MapeditMessage, + AddEntity, + QFEntityClassScan, + QFEntityClassParse, + QFEntityClasses, + OBJECT_PT_QFECPanel, + ImportPoints, + ImportMap, + ExportMap, +) +menus_to_register = ( + (bpy.types.TOPBAR_MT_file_import, menu_func_import), + (bpy.types.TOPBAR_MT_file_export, menu_func_export), + (bpy.types.VIEW3D_MT_add, menu_func_add), +) +custom_properties_to_register = ( + (bpy.types.Scene, "qfmap", QFEntityClasses), +) +handlers_to_register = ( + ("load_post", scene_load_handler), +) diff --git a/tools/io_qfmap/map.py b/tools/io_qfmap/map.py index b0820de69..e47b7563a 100644 --- a/tools/io_qfmap/map.py +++ b/tools/io_qfmap/map.py @@ -38,8 +38,8 @@ class Texinfo: norm = s_vec.cross(t_vec) q = Quaternion(norm, rotate * pi / 180) self.vecs = [None] * 2 - self.vecs[0] = (q * s_vec / scale[0], s_offs) - self.vecs[1] = (q * t_vec / scale[1], t_offs) + self.vecs[0] = (q @ s_vec / scale[0], s_offs) + self.vecs[1] = (q @ t_vec / scale[1], t_offs) def __cmp__(self, other): return self.name == other.name and self.vecs == other.vecs @classmethod diff --git a/tools/io_qfmap/script.py b/tools/io_qfmap/script.py index 9e34934f9..fc030e3e5 100644 --- a/tools/io_qfmap/script.py +++ b/tools/io_qfmap/script.py @@ -25,10 +25,15 @@ class ScriptError(Exception): self.line = line class Script: - def __init__(self, filename, text, single="{}()':"): + def __init__(self, filename, text, single="{}()':", quotes=True): self.filename = filename + if text[0:3] == "\xef\xbb\xbf": + text = text[3:] + elif text[0] == u"\ufeff": + text = text[1:] self.text = text self.single = single + self.quotes = quotes self.pos = 0 self.line = 1 self.unget = False @@ -87,7 +92,7 @@ class Script: if not crossline: self.error("line is incomplete") return None - if self.text[self.pos] == "\"": + if self.quotes and self.text[self.pos] == "\"": self.pos += 1 start = self.pos if self.text[self.pos] == len(self.text): diff --git a/tools/misc/mdl.py b/tools/misc/mdl.py index 00c788316..f9b6698c4 100644 --- a/tools/misc/mdl.py +++ b/tools/misc/mdl.py @@ -22,8 +22,8 @@ for i in range(m[6]): else: n = unpack ("i", model[:4])[0] model = model [4:] - print n - k = (n, unpack (`n`+"f", model[:n*4]), []) + print (n) + k = (n, unpack (("%df" % n), model[:n*4]), []) model = model [n*4:] for j in range (n): k[2].append (model[:s]) @@ -67,7 +67,7 @@ for i in range (m[11]): g = (t, unpack ("i 3B B 3B B", model[:12])) model = model[12:] n = g[1][0] - g = g + (unpack (`n`+"f", model[:n*4]), []) + g = g + (unpack (("%df" % n), model[:n*4]), []) model = model[n*4:] for k in range (g[1][0]): f = (unpack ("3B B 3B B 16s", model[:24]), []) diff --git a/tools/pak/Makefile.am b/tools/pak/Makefile.am deleted file mode 100644 index 5461c399e..000000000 --- a/tools/pak/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -PAK_LIBS=@PAK_LIBS@ -PAK_DEPS=@PAK_DEPS@ -PAK_INCS=@PAK_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(PAK_INCS) - -bin_PROGRAMS= pak -bin_SCRIPTS= zpak - -mans= pak.1 zpak.1 -man_MANS= $(mans) - -pak_SOURCES= pak.c -pak_LDADD= $(PAK_LIBS) -pak_DEPENDENCIES= $(PAK_DEPS) - -EXTRA_DIST=pak.h zpak $(mans) diff --git a/tools/pak/Makemodule.am b/tools/pak/Makemodule.am new file mode 100644 index 000000000..d7a247e88 --- /dev/null +++ b/tools/pak/Makemodule.am @@ -0,0 +1,14 @@ +PAK_LIBS=@PAK_LIBS@ +PAK_DEPS=@PAK_DEPS@ +PAK_INCS=@PAK_INCS@ + +bin_PROGRAMS += pak +bin_SCRIPTS += tools/pak/zpak + +man_MANS += tools/pak/pak.1 tools/pak/zpak.1 + +pak_SOURCES= tools/pak/pak.c +pak_LDADD= $(PAK_LIBS) +pak_DEPENDENCIES= $(PAK_DEPS) + +EXTRA_DIST += tools/pak/pak.h tools/pak/zpak $(man_MANS) diff --git a/tools/qfbsp/Makefile.am b/tools/qfbsp/Makefile.am deleted file mode 100644 index f2bd807e0..000000000 --- a/tools/qfbsp/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source diff --git a/tools/qfbsp/Makemodule.am b/tools/qfbsp/Makemodule.am new file mode 100644 index 000000000..c73468397 --- /dev/null +++ b/tools/qfbsp/Makemodule.am @@ -0,0 +1,2 @@ +include tools/qfbsp/include/Makemodule.am +include tools/qfbsp/source/Makemodule.am diff --git a/tools/qfbsp/include/Makefile.am b/tools/qfbsp/include/Makefile.am deleted file mode 100644 index d4ab30d4e..000000000 --- a/tools/qfbsp/include/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST= brush.h bsp5.h csg4.h draw.h map.h merge.h options.h outside.h \ - portals.h readbsp.h region.h solidbsp.h surfaces.h tjunc.h \ - writebsp.h diff --git a/tools/qfbsp/include/Makemodule.am b/tools/qfbsp/include/Makemodule.am new file mode 100644 index 000000000..0cf8e31dd --- /dev/null +++ b/tools/qfbsp/include/Makemodule.am @@ -0,0 +1,16 @@ +EXTRA_DIST += \ + tools/qfbsp/include/brush.h \ + tools/qfbsp/include/bsp5.h \ + tools/qfbsp/include/csg4.h \ + tools/qfbsp/include/draw.h \ + tools/qfbsp/include/map.h \ + tools/qfbsp/include/merge.h \ + tools/qfbsp/include/options.h \ + tools/qfbsp/include/outside.h \ + tools/qfbsp/include/portals.h \ + tools/qfbsp/include/readbsp.h \ + tools/qfbsp/include/region.h \ + tools/qfbsp/include/solidbsp.h \ + tools/qfbsp/include/surfaces.h \ + tools/qfbsp/include/tjunc.h \ + tools/qfbsp/include/writebsp.h diff --git a/tools/qfbsp/include/brush.h b/tools/qfbsp/include/brush.h index 66cdff5a4..345b14747 100644 --- a/tools/qfbsp/include/brush.h +++ b/tools/qfbsp/include/brush.h @@ -30,7 +30,7 @@ /** \defgroup qfbsp_brush Brush Functions \ingroup qfbsp */ -//@{ +///@{ #define NUM_HULLS 2 // normal and +16 @@ -69,7 +69,7 @@ brushset_t *Brush_LoadEntity (entity_t *ent, int hullnum); \param normal Must be canonical. */ -int PlaneTypeForNormal (const vec3_t normal); +int PlaneTypeForNormal (const vec3_t normal) __attribute__((pure)); /** Make the plane canonical. @@ -95,6 +95,6 @@ int NormalizePlane (plane_t *dp); */ int FindPlane (const plane_t *dplane, int *side); -//@} +///@} #endif//qfbsp_brush_h diff --git a/tools/qfbsp/include/bsp5.h b/tools/qfbsp/include/bsp5.h index 4cacb23ae..b949cf77c 100644 --- a/tools/qfbsp/include/bsp5.h +++ b/tools/qfbsp/include/bsp5.h @@ -32,7 +32,7 @@ /** \defgroup qfbsp_general General functions \ingroup qfbsp */ -//@{ +///@{ #define MAX_THREADS 4 @@ -129,6 +129,6 @@ node_t *AllocNode (void); extern bsp_t *bsp; -//@} +///@} #endif//qfbsp_bsp5_h diff --git a/tools/qfbsp/include/csg4.h b/tools/qfbsp/include/csg4.h index dd48047f4..e6ff8b4a3 100644 --- a/tools/qfbsp/include/csg4.h +++ b/tools/qfbsp/include/csg4.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_csg4 CSG Functions \ingroup qfbsp */ -//@{ +///@{ struct plane_s; struct visfacet_s; @@ -84,6 +84,6 @@ struct surface_s *CSGFaces (struct brushset_s *bs); void SplitFace (struct visfacet_s *in, struct plane_s *split, struct visfacet_s **front, struct visfacet_s **back); -//@} +///@} #endif//qfbsp_csg4_h diff --git a/tools/qfbsp/include/draw.h b/tools/qfbsp/include/draw.h index ecaa3fd53..740fa9050 100644 --- a/tools/qfbsp/include/draw.h +++ b/tools/qfbsp/include/draw.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_draw Debug Drawing Functions \ingroup qfbsp */ -//@{ +///@{ struct visfacet_s; struct portal_s; @@ -53,6 +53,6 @@ void DrawBrush (const struct brush_s *b); void DrawWinding (const struct winding_s *w); void DrawTri (const vec3_t p1, const vec3_t p2, const vec3_t p3); -//@} +///@} #endif//qfbsp_draw_h diff --git a/tools/qfbsp/include/map.h b/tools/qfbsp/include/map.h index 1e6c18f29..25c56d4ef 100644 --- a/tools/qfbsp/include/map.h +++ b/tools/qfbsp/include/map.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_map Map Parser \ingroup qfbsp */ -//@{ +///@{ #define MAX_FACES 256 typedef struct mface_s { @@ -95,7 +95,7 @@ void PrintEntity (const entity_t *ent); \return The value for the key, or the empty string if the key does not exist in this entity. */ -const char *ValueForKey (const entity_t *ent, const char *key); +const char *ValueForKey (const entity_t *ent, const char *key) __attribute__((pure)); /** Set the value of the entity's key. If the key does not exist, one will be added. @@ -120,6 +120,6 @@ void GetVectorForKey (const entity_t *ent, const char *key, vec3_t vec); */ void WriteEntitiesToString (void); -//@} +///@} #endif//qfbsp_map_h diff --git a/tools/qfbsp/include/merge.h b/tools/qfbsp/include/merge.h index 81e8b2c1c..c65ee15ff 100644 --- a/tools/qfbsp/include/merge.h +++ b/tools/qfbsp/include/merge.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_merge Merge Functions \ingroup qfbsp */ -//@{ +///@{ /** Add a face to the list of faces, doing any possible merging. @@ -63,6 +63,6 @@ void MergePlaneFaces (surface_t *plane); */ void MergeAll (surface_t *surfhead); -//@} +///@} #endif//qfbsp_merge_h diff --git a/tools/qfbsp/include/options.h b/tools/qfbsp/include/options.h index 4b062f27e..47a8e0df7 100644 --- a/tools/qfbsp/include/options.h +++ b/tools/qfbsp/include/options.h @@ -33,7 +33,7 @@ /** \defgroup qfbsp_options Command-line Options Parsing \ingroup qfbsp */ -//@{ +///@{ typedef struct { int verbosity; // 0=silent @@ -65,6 +65,6 @@ extern options_t options; int DecodeArgs (int argc, char **argv); extern const char *this_program; -//@} +///@} #endif//qfbsp_options_h diff --git a/tools/qfbsp/include/outside.h b/tools/qfbsp/include/outside.h index 8ad85fe49..e45e11496 100644 --- a/tools/qfbsp/include/outside.h +++ b/tools/qfbsp/include/outside.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_outside Outside Functions \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -41,6 +41,6 @@ struct node_s; */ qboolean FillOutside (struct node_s *node); -//@} +///@} #endif//qfbsp_outside_h diff --git a/tools/qfbsp/include/portals.h b/tools/qfbsp/include/portals.h index 381bbf0f9..6d5da460e 100644 --- a/tools/qfbsp/include/portals.h +++ b/tools/qfbsp/include/portals.h @@ -31,7 +31,7 @@ Decision nodes will not have portals on them, though as part of the portal building process, they will temporarily have portals. */ -//@{ +///@{ struct node_s; @@ -89,6 +89,6 @@ void FreeAllPortals (struct node_s *node); */ void WritePortalfile (struct node_s *headnode); -//@} +///@} #endif//qfbsp_portals_h diff --git a/tools/qfbsp/include/readbsp.h b/tools/qfbsp/include/readbsp.h index 17f1b2890..5887a68ea 100644 --- a/tools/qfbsp/include/readbsp.h +++ b/tools/qfbsp/include/readbsp.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_readbsp BSP Reading Functions \ingroup qfbsp */ -//@{ +///@{ /** Load the bspfile into memory. */ @@ -47,6 +47,6 @@ void extract_entities (void); */ void extract_hull (void); -//@} +///@} #endif//qfbsp_readbsp_h diff --git a/tools/qfbsp/include/region.h b/tools/qfbsp/include/region.h index ce30e71f7..2a17734c5 100644 --- a/tools/qfbsp/include/region.h +++ b/tools/qfbsp/include/region.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_region Region Functions \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -35,6 +35,6 @@ struct node_s; */ void GrowNodeRegions (struct node_s *headnode); -//@} +///@} #endif//qfbsp_region_h diff --git a/tools/qfbsp/include/solidbsp.h b/tools/qfbsp/include/solidbsp.h index 18bd306a6..5a3d7fbe4 100644 --- a/tools/qfbsp/include/solidbsp.h +++ b/tools/qfbsp/include/solidbsp.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_solidbsp BSP Creation Functions \ingroup qfbsp */ -//@{ +///@{ struct visfacet_s; struct plane_s; @@ -48,6 +48,6 @@ void CalcSurfaceInfo (struct surface_s *surf); */ struct node_s *SolidBSP (struct surface_s *surfhead, qboolean midsplit); -//@} +///@} #endif//qfbsp_solidbsp_h diff --git a/tools/qfbsp/include/surfaces.h b/tools/qfbsp/include/surfaces.h index ebb8314cc..561d21048 100644 --- a/tools/qfbsp/include/surfaces.h +++ b/tools/qfbsp/include/surfaces.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_surface Surface Functions \ingroup qfbsp */ -//@{ +///@{ struct visfacet_s; struct node_s; @@ -104,6 +104,6 @@ struct surface_s *GatherNodeFaces (struct node_s *headnode); */ void MakeFaceEdges (struct node_s *headnode); -//@} +///@} #endif//surfaces_h diff --git a/tools/qfbsp/include/tjunc.h b/tools/qfbsp/include/tjunc.h index 46fa939fc..3557e4df7 100644 --- a/tools/qfbsp/include/tjunc.h +++ b/tools/qfbsp/include/tjunc.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_tjunc T-Junction Repair \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -35,6 +35,6 @@ struct node_s; */ void tjunc (struct node_s *headnode); -//@} +///@} #endif//qfbsp_tjunc_h diff --git a/tools/qfbsp/include/writebsp.h b/tools/qfbsp/include/writebsp.h index 6d2a5cf0f..759220904 100644 --- a/tools/qfbsp/include/writebsp.h +++ b/tools/qfbsp/include/writebsp.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_writebsp BSP Writing Functions \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -78,6 +78,6 @@ void BeginBSPFile (void); */ void FinishBSPFile (void); -//@} +///@} #endif//qfbsp_writebsp_h diff --git a/tools/qfbsp/source/Makefile.am b/tools/qfbsp/source/Makefile.am deleted file mode 100644 index 8fd7f660b..000000000 --- a/tools/qfbsp/source/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -QFBSP_LIBS=@QFBSP_LIBS@ -QFBSP_DEPS=@QFBSP_DEPS@ -QFBSP_INCS=@QFBSP_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFBSP_INCS) - -bin_PROGRAMS= qfbsp - -qfbsp_SOURCES= \ - brush.c csg4.c map.c merge.c nodraw.c options.c outside.c portals.c \ - qfbsp.c readbsp.c region.c solidbsp.c surfaces.c tjunc.c writebsp.c - -qfbsp_LDADD= $(QFBSP_LIBS) -qfbsp_DEPENDENCIES= $(QFBSP_DEPS) diff --git a/tools/qfbsp/source/Makemodule.am b/tools/qfbsp/source/Makemodule.am new file mode 100644 index 000000000..2e3e9a524 --- /dev/null +++ b/tools/qfbsp/source/Makemodule.am @@ -0,0 +1,25 @@ +QFBSP_LIBS=@QFBSP_LIBS@ +QFBSP_DEPS=@QFBSP_DEPS@ +QFBSP_INCS=@QFBSP_INCS@ + +bin_PROGRAMS += qfbsp + +qfbsp_SOURCES= \ + tools/qfbsp/source/brush.c \ + tools/qfbsp/source/csg4.c \ + tools/qfbsp/source/map.c \ + tools/qfbsp/source/merge.c \ + tools/qfbsp/source/nodraw.c \ + tools/qfbsp/source/options.c \ + tools/qfbsp/source/outside.c \ + tools/qfbsp/source/portals.c \ + tools/qfbsp/source/qfbsp.c \ + tools/qfbsp/source/readbsp.c \ + tools/qfbsp/source/region.c \ + tools/qfbsp/source/solidbsp.c \ + tools/qfbsp/source/surfaces.c \ + tools/qfbsp/source/tjunc.c \ + tools/qfbsp/source/writebsp.c + +qfbsp_LDADD= $(QFBSP_LIBS) +qfbsp_DEPENDENCIES= $(QFBSP_DEPS) diff --git a/tools/qfbsp/source/brush.c b/tools/qfbsp/source/brush.c index f27c253b8..e0b05f2d9 100644 --- a/tools/qfbsp/source/brush.c +++ b/tools/qfbsp/source/brush.c @@ -32,11 +32,11 @@ #include "compat.h" -#include "brush.h" -#include "bsp5.h" -#include "draw.h" -#include "options.h" -#include "surfaces.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/draw.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/surfaces.h" /** \addtogroup qfbsp_brush */ @@ -347,7 +347,7 @@ CreateBrushFaces (void) GetVectorForKey (FoundEntity, "origin", offset); SetKeyValue (CurrentEntity, "origin", - va ("%g %g %g", VectorExpand (offset))); + va (0, "%g %g %g", VectorExpand (offset))); } for (i = 0; i < numbrushfaces; i++) { @@ -736,7 +736,7 @@ LoadBrush (const mbrush_t *mb, int hullnum) CreateBrushFaces (); } else if (mb->detail) { face_t *f; - for (f = brush_faces; f; f = f->next); + for (f = brush_faces; f; f = f->next) f->detail = 1; } diff --git a/tools/qfbsp/source/csg4.c b/tools/qfbsp/source/csg4.c index 444627334..76d11e2d1 100644 --- a/tools/qfbsp/source/csg4.c +++ b/tools/qfbsp/source/csg4.c @@ -27,13 +27,13 @@ #include "QF/sys.h" -#include "brush.h" -#include "bsp5.h" -#include "csg4.h" -#include "draw.h" -#include "merge.h" -#include "solidbsp.h" -#include "surfaces.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/csg4.h" +#include "tools/qfbsp/include/draw.h" +#include "tools/qfbsp/include/merge.h" +#include "tools/qfbsp/include/solidbsp.h" +#include "tools/qfbsp/include/surfaces.h" /** \addtogroup qfbsp_csg4 */ diff --git a/tools/qfbsp/source/map.c b/tools/qfbsp/source/map.c index f2038e44d..870fb7c07 100644 --- a/tools/qfbsp/source/map.c +++ b/tools/qfbsp/source/map.c @@ -40,7 +40,7 @@ #include "compat.h" -#include "map.h" +#include "tools/qfbsp/include/map.h" /** \addtogroup qfbsp_map */ @@ -97,7 +97,7 @@ FindMiptex (const char *name) if (strcmp (name, "skip") == 0) return TEX_SKIP; if (!miptex_hash) - miptex_hash = Hash_NewTable (1023, miptex_getkey, 0, 0); + miptex_hash = Hash_NewTable (1023, miptex_getkey, 0, 0, 0); if (miptexnames) { index = (intptr_t) Hash_Find (miptex_hash, mpname); if (index) @@ -620,7 +620,7 @@ WriteEntitiesToString (void) dstring_appendstr (buf, "{\n"); for (ep = entities[i].epairs; ep; ep = ep->next) { - dstring_appendstr (buf, va ("\"%s\" \"%s\"\n", + dstring_appendstr (buf, va (0, "\"%s\" \"%s\"\n", ep->key, ep->value)); } dstring_appendstr (buf, "}\n"); diff --git a/tools/qfbsp/source/merge.c b/tools/qfbsp/source/merge.c index 8551336df..480af3896 100644 --- a/tools/qfbsp/source/merge.c +++ b/tools/qfbsp/source/merge.c @@ -23,12 +23,12 @@ #include "QF/sys.h" -#include "brush.h" -#include "bsp5.h" -#include "csg4.h" -#include "draw.h" -#include "merge.h" -#include "surfaces.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/csg4.h" +#include "tools/qfbsp/include/draw.h" +#include "tools/qfbsp/include/merge.h" +#include "tools/qfbsp/include/surfaces.h" /** \addtogroup qfbsp_merge */ @@ -74,7 +74,6 @@ TryMerge (const face_t *f1, const face_t *f2) return NULL; p1 = p2 = NULL; - j = 0; // find a common edge for (i = 0; i < f1p->numpoints; i++) { diff --git a/tools/qfbsp/source/nodraw.c b/tools/qfbsp/source/nodraw.c index c333313c5..b7db6dc94 100644 --- a/tools/qfbsp/source/nodraw.c +++ b/tools/qfbsp/source/nodraw.c @@ -21,7 +21,7 @@ # include "config.h" #endif -#include "draw.h" +#include "tools/qfbsp/include/draw.h" /** \addtogroup qfbsp_draw */ diff --git a/tools/qfbsp/source/options.c b/tools/qfbsp/source/options.c index 214065f9b..70b022b5d 100644 --- a/tools/qfbsp/source/options.c +++ b/tools/qfbsp/source/options.c @@ -40,7 +40,7 @@ #include "QF/quakefs.h" -#include "options.h" +#include "tools/qfbsp/include/options.h" /** \addtogroup qfbsp_options */ diff --git a/tools/qfbsp/source/outside.c b/tools/qfbsp/source/outside.c index 0907d4dee..d7ba0d142 100644 --- a/tools/qfbsp/source/outside.c +++ b/tools/qfbsp/source/outside.c @@ -22,12 +22,12 @@ #include "QF/sys.h" -#include "brush.h" -#include "bsp5.h" -#include "draw.h" -#include "options.h" -#include "portals.h" -#include "outside.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/draw.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/portals.h" +#include "tools/qfbsp/include/outside.h" /** \addtogroup qfbsp_outside */ @@ -41,7 +41,7 @@ int outleafs; \param point The point's location. \return The leaf node in which the point is. */ -static node_t * +static __attribute__((pure)) node_t * PointInLeaf (node_t *node, const vec3_t point) { vec_t d; @@ -180,6 +180,8 @@ MarkLeakTrail2 (void) vec3_t wc, pwc; const vec_t *v; + VectorZero (wc); + leakfile = fopen (options.pointfile, "w"); if (!leakfile) Sys_Error ("Couldn't open %s\n", options.pointfile); diff --git a/tools/qfbsp/source/portals.c b/tools/qfbsp/source/portals.c index edad5724a..cbc128f1e 100644 --- a/tools/qfbsp/source/portals.c +++ b/tools/qfbsp/source/portals.c @@ -28,11 +28,11 @@ #include "QF/sys.h" -#include "brush.h" -#include "bsp5.h" -#include "draw.h" -#include "options.h" -#include "portals.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/draw.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/portals.h" /** \addtogroup qfbsp_portals */ @@ -280,7 +280,6 @@ CutNodePortals_r (node_t *node) /// cutting plane and clipping it by all of the planes from the other /// portals on the node. w = BaseWindingForPlane (plane); - side = 0; for (p = node->portals; p; p = p->next[side]) { clipplane = planes[p->planenum]; // copy the plane if (p->nodes[0] == node) @@ -423,7 +422,7 @@ int num_realleafs; \param cont The contents for which to check. \return 1 if the node has the specified contents, otherwise 0. */ -static int +static __attribute__((pure)) int HasContents (const node_t *n, int cont) { if (n->contents == cont) @@ -440,7 +439,7 @@ HasContents (const node_t *n, int cont) \param n1 The first node to check. \param n2 The second node to check. */ -static int +static __attribute__((pure)) int ShareContents (const node_t *n1, const node_t *n2) { if (n1->contents) { @@ -462,7 +461,7 @@ ShareContents (const node_t *n1, const node_t *n2) \param n1 The first node to check. \param n2 The second node to check. */ -static int +static __attribute__((pure)) int SameContents (const node_t *n1, const node_t *n2) { if (n1->contents == CONTENTS_SOLID || n2->contents == CONTENTS_SOLID) @@ -472,7 +471,7 @@ SameContents (const node_t *n1, const node_t *n2) if (options.watervis) //FIXME be more picky? return 1; if (n1->detail && n2->detail) - ShareContents (n1, n2); + return ShareContents (n1, n2); if (n1->detail) return HasContents (n1, n2->contents); if (n2->detail) diff --git a/tools/qfbsp/source/qfbsp.c b/tools/qfbsp/source/qfbsp.c index e3948acb8..abbc81029 100644 --- a/tools/qfbsp/source/qfbsp.c +++ b/tools/qfbsp/source/qfbsp.c @@ -43,18 +43,18 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "csg4.h" -#include "brush.h" -#include "bsp5.h" -#include "merge.h" -#include "options.h" -#include "outside.h" -#include "portals.h" -#include "readbsp.h" -#include "solidbsp.h" -#include "surfaces.h" -#include "writebsp.h" -#include "tjunc.h" +#include "tools/qfbsp/include/csg4.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/merge.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/outside.h" +#include "tools/qfbsp/include/portals.h" +#include "tools/qfbsp/include/readbsp.h" +#include "tools/qfbsp/include/solidbsp.h" +#include "tools/qfbsp/include/surfaces.h" +#include "tools/qfbsp/include/writebsp.h" +#include "tools/qfbsp/include/tjunc.h" /** \addtogroup qfbsp */ diff --git a/tools/qfbsp/source/readbsp.c b/tools/qfbsp/source/readbsp.c index 4168a2ae5..c554755c5 100644 --- a/tools/qfbsp/source/readbsp.c +++ b/tools/qfbsp/source/readbsp.c @@ -48,11 +48,11 @@ #include "QF/va.h" #include "QF/wad.h" -#include "brush.h" -#include "bsp5.h" -#include "options.h" -#include "portals.h" -#include "readbsp.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/portals.h" +#include "tools/qfbsp/include/readbsp.h" /** \addtogroup qfbsp_readbsp */ @@ -359,13 +359,13 @@ unique_name (wad_t *wad, const char *name) do { strncpy (uname, name, MIPTEXNAME); uname[(MIPTEXNAME - 1)] = 0; - tag = va ("~%x", i++); + tag = va (0, "~%x", i++); if (strlen (uname) + strlen (tag) <= (MIPTEXNAME - 1)) strcat (uname, tag); else strcpy (uname + (MIPTEXNAME - 1) - strlen (tag), tag); } while (wad_find_lump (wad, uname)); - return va ("%s", uname); // just to make a safe returnable that doesn't + return va (0, "%s", uname); // just to make a safe returnable that doesn't // need to be freed } diff --git a/tools/qfbsp/source/region.c b/tools/qfbsp/source/region.c index b7c875a22..03dfd2efd 100644 --- a/tools/qfbsp/source/region.c +++ b/tools/qfbsp/source/region.c @@ -29,9 +29,9 @@ #include "compat.h" -#include "bsp5.h" -#include "region.h" -#include "surfaces.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/region.h" +#include "tools/qfbsp/include/surfaces.h" /** \addtogroup qfbsp_region */ diff --git a/tools/qfbsp/source/solidbsp.c b/tools/qfbsp/source/solidbsp.c index 5e04f3c32..c49422c20 100644 --- a/tools/qfbsp/source/solidbsp.c +++ b/tools/qfbsp/source/solidbsp.c @@ -28,12 +28,12 @@ #include "QF/sys.h" -#include "brush.h" -#include "csg4.h" -#include "bsp5.h" -#include "draw.h" -#include "solidbsp.h" -#include "surfaces.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/csg4.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/draw.h" +#include "tools/qfbsp/include/solidbsp.h" +#include "tools/qfbsp/include/surfaces.h" /** \addtogroup qfbsp_solidbsp */ @@ -121,7 +121,7 @@ FaceSide (const face_t *in, const plane_t *split) \param maxs The maximum coordinate of the boundiing box. \return The chosen surface. */ -static surface_t * +static __attribute__((pure)) surface_t * ChooseMidPlaneFromList (surface_t *surfaces, const vec3_t mins, const vec3_t maxs) { @@ -186,7 +186,7 @@ ChooseMidPlaneFromList (surface_t *surfaces, \return The chosen surface, or NULL if a suitable surface could not be found. */ -static surface_t * +static __attribute__((pure)) surface_t * ChoosePlaneFromList (surface_t *surfaces, const vec3_t mins, const vec3_t maxs, qboolean usefloors, qboolean usedetail) { diff --git a/tools/qfbsp/source/surfaces.c b/tools/qfbsp/source/surfaces.c index 9c467c0e1..2c9c08897 100644 --- a/tools/qfbsp/source/surfaces.c +++ b/tools/qfbsp/source/surfaces.c @@ -28,11 +28,11 @@ #include "QF/sys.h" -#include "bsp5.h" -#include "csg4.h" -#include "options.h" -#include "region.h" -#include "surfaces.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/csg4.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/region.h" +#include "tools/qfbsp/include/surfaces.h" /** \addtogroup qfbsp_surface */ diff --git a/tools/qfbsp/source/tjunc.c b/tools/qfbsp/source/tjunc.c index 50882df87..64588837d 100644 --- a/tools/qfbsp/source/tjunc.c +++ b/tools/qfbsp/source/tjunc.c @@ -29,10 +29,10 @@ #include "compat.h" -#include "brush.h" -#include "bsp5.h" -#include "options.h" -#include "tjunc.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/tjunc.h" /** \addtogroup qfbsp_tjunc */ diff --git a/tools/qfbsp/source/writebsp.c b/tools/qfbsp/source/writebsp.c index fa95b4d57..dd7d0fa99 100644 --- a/tools/qfbsp/source/writebsp.c +++ b/tools/qfbsp/source/writebsp.c @@ -37,10 +37,10 @@ #include "QF/va.h" #include "QF/wad.h" -#include "brush.h" -#include "bsp5.h" -#include "options.h" -#include "writebsp.h" +#include "tools/qfbsp/include/brush.h" +#include "tools/qfbsp/include/bsp5.h" +#include "tools/qfbsp/include/options.h" +#include "tools/qfbsp/include/writebsp.h" /** \addtogroup qfbsp_writebsp */ @@ -301,7 +301,7 @@ TEX_InitFromWad (const char *path) wad = wad_open (path); #ifdef HAVE_ZLIB if (!wad) - wad = wad_open (path = va ("%s.gz", path)); + wad = wad_open (path = va (0, "%s.gz", path)); #endif if (!wad) return -1; diff --git a/tools/qfcc/Makefile.am b/tools/qfcc/Makefile.am deleted file mode 100644 index b9050ce13..000000000 --- a/tools/qfcc/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -# Makefile.am -# -# Automake-using build system for QuakeForge -# -# Copyright (C) 2000 Jeff Teunissen -# -# This Makefile 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: -# -# Free Software Foundation, Inc. -# 59 Temple Place - Suite 330 -# Boston, MA 02111-1307, USA -# -# $Id$ -# -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source doc test - -dist-zip: distdir - -chmod -R a+r $(distdir) - ZIP="-r9q" zip $(distdir).zip $(NOCONV_DIST) - ZIP="-r9ql" zip $(distdir).zip $(distdir) -x $(NOCONV_DIST) - -rm -rf $(distdir) - -dist-bz2: distdir - -chmod -R a+r $(distdir) - BZIP2="-9" $(TAR) Ichof $(distdir).tar.bz2 $(distdir) - -rm -rf $(distdir) - -dist-all-local: distdir - -chmod -R a+r $(distdir) - GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) - BZIP2="-9" $(TAR) Ichof $(distdir).tar.bz2 $(distdir) - ZIP="-r9q" zip $(distdir).zip $(NOCONV_DIST) - ZIP="-r9ql" zip $(distdir).zip $(distdir) -x $(NOCONV_DIST) - -rm -rf $(distdir) diff --git a/tools/qfcc/Makemodule.am b/tools/qfcc/Makemodule.am new file mode 100644 index 000000000..e4159fbf3 --- /dev/null +++ b/tools/qfcc/Makemodule.am @@ -0,0 +1,4 @@ +include tools/qfcc/include/Makemodule.am +include tools/qfcc/source/Makemodule.am +include tools/qfcc/doc/Makemodule.am +include tools/qfcc/test/Makemodule.am diff --git a/tools/qfcc/TODO b/tools/qfcc/TODO index ed68de57c..8180ed95d 100644 --- a/tools/qfcc/TODO +++ b/tools/qfcc/TODO @@ -12,11 +12,12 @@ M unnamed function parameters for prototypes/typdefs etc. I optimizations (esp CSE) I fix used/uninitialized warnings o id id; -o vec = [x, y, z]; expressions (nice feature in fteqcc) +M vec = [x, y, z]; expressions (nice feature in fteqcc) M finish -Fifstring o isset() intrinsic for more consistent string handling. o arrays in entities o optional arguments for functions (alternative to overloading) vector(vector fwd, optional vector up) vectoangles = #51; +o rewrite type system to be const-correct (hard!) ? try to reduce memory consumption ?? embedded nul characters in strings (why?) diff --git a/tools/qfcc/bootstrap b/tools/qfcc/bootstrap deleted file mode 100755 index 071d87a77..000000000 --- a/tools/qfcc/bootstrap +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -cd `dirname $0` -aclocal && autoheader && automake --add-missing && autoconf diff --git a/tools/qfcc/configure.in b/tools/qfcc/configure.in deleted file mode 100644 index 21934d623..000000000 --- a/tools/qfcc/configure.in +++ /dev/null @@ -1,144 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.13) -AC_INIT(source/qfcc.c) -AC_REVISION($Revision$) dnl -AM_CONFIG_HEADER(include/config.h) -AC_CANONICAL_SYSTEM - -dnl Every other copy of the package version number gets its value from here -AM_INIT_AUTOMAKE(qfcc, 0.1.0) - -AC_SUBST(VERSION) - -ISODATE=`date +%Y-%m-%d` -AC_SUBST(ISODATE) - -AC_LANG_C - -dnl Checks for programs. -AC_PROG_INSTALL -AC_PROG_CC -AC_PROG_CPP -AC_PROG_YACC -AM_PROG_LEX - -AC_ARG_WITH(cpp, -[ --with-cpp=CPP how qfcc should invoke cpp], - cpp_name="$withval", cpp_name=auto -) -if test "x$cpp_name" != xauto; then - CPP_NAME="$cpp_name" -else - CPP_NAME="cpp %d -o %o %i" - case "$target_os" in - *bsd*) - touch conftest.c - CPP_NAME="`(f=\`$CC -v -E -Dfoo conftest.c -o conftest.i 2>&1 | grep -e -Dfoo\`; set $f; echo "$1")` %d %i %o" - rm -f conftest.[ci] - ;; - esac -fi -AC_DEFINE_UNQUOTED(CPP_NAME, "$CPP_NAME", [Define this to the command line for the C preprocessor]) - -dnl We want warnings, lots of warnings... -if test "x$GCC" = xyes; then - CFLAGS="$CFLAGS -Wall -Werror" - # CFLAGS="$CFLAGS -Wall -pedantic" -fi - -dnl Checks for libraries. -AC_CHECK_LIB(z, gztell,, -) - -dnl Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS(process.h string.h strings.h fcntl.h sys/stat.h sys/types.h sys/wait.h unistd.h) - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_ARG_ENABLE(profile, - [ --enable-profile compile with profiling (for development)], - profile=$enable_profile -) -if test "x$profile" = xyes; then - BUILD_TYPE="$BUILD_TYPE Profile" - if test "x$GCC" = xyes; then - CFLAGS="`echo $CFLAGS | sed -e 's/-fomit-frame-pointer//g'` -pg" - LDFLAGS="$LDFLAGS -pg" - else - CFLAGS="$CFLAGS -p" - fi -fi - -AC_DEFINE_UNQUOTED(PATH_SEPARATOR, '/', - [Define this to your operating system's path separator character]) - -dnl Checks for library functions. - -AC_CHECK_FUNCS(snprintf _snprintf vsnprintf _vsnprintf) - -AC_MSG_CHECKING(for timeGetTime in -lwinmm) -save_LIBS="$LIBS" -LIBS="$LIBS -lwinmm" -AC_TRY_COMPILE( - [#include ], - [timeGetTime ();], - AC_MSG_RESULT(yes), - LIBS="$save_LIBS" - AC_MSG_RESULT(no) -) - -AC_ARG_WITH(qf, -[ --with-qf=DIR location of QF libs and headers (prefix)], - if test "x$withval" != xyes ; then - LDFLAGS="$LDFLAGS -L${withval}/lib" - CFLAGS="$CFLAGS -I${withval}/include" - fi - , - HAVE_QF=auto -) -AC_MSG_CHECKING(for QF/qtypes.h) -AC_TRY_COMPILE( - [#include "QF/qtypes.h"], - [qboolean foo = false; - foo = true;], - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no) - HAVE_QF=no -) -if test "x$HAVE_QF" != xno; then - AC_CHECK_LIB(QFutil, Hash_NewTable, - :, HAVE_QF=no, - [] - ) -fi -if test "x$HAVE_QF" != xno; then - AC_CHECK_LIB(QFgamecode, PR_Opcode, - :, HAVE_QF=no, - [-lQFutil] - ) -fi - -QFCC_LIBS="-lQFgamecode -lQFutil" -QFCC_DEPS="" -QFCC_INCS="" - -if test "x$HAVE_QF" = xno; then - echo '***' - echo '*** You seem to not have the QuakeForge libs & headers installed' - echo '***' - exit 1 -fi - -AC_SUBST(QFCC_LIBS) -AC_SUBST(QFCC_DEPS) -AC_SUBST(QFCC_INCS) - -AC_OUTPUT( - doc/Makefile - doc/man/Makefile - include/Makefile - source/Makefile - Makefile - qfcc.lsm -) diff --git a/tools/qfcc/doc/Makefile.am b/tools/qfcc/doc/Makefile.am deleted file mode 100644 index 8d0026abb..000000000 --- a/tools/qfcc/doc/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= man - -EXTRA_DIST= expressions.txt \ - dot/vector-alias.dot diff --git a/tools/qfcc/doc/Makemodule.am b/tools/qfcc/doc/Makemodule.am new file mode 100644 index 000000000..121e06e82 --- /dev/null +++ b/tools/qfcc/doc/Makemodule.am @@ -0,0 +1,5 @@ +man_MANS += tools/qfcc/doc/man/qfcc.1 + +EXTRA_DIST += \ + tools/qfcc/doc/expressions.txt \ + tools/qfcc/doc/dot/vector-alias.dot diff --git a/tools/qfcc/doc/man/Makefile.am b/tools/qfcc/doc/man/Makefile.am deleted file mode 100644 index cca3e62a5..000000000 --- a/tools/qfcc/doc/man/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -man_MANS=qfcc.1 -EXTRA_DIST=qfcc.1 diff --git a/tools/qfcc/doc/man/qfcc.1 b/tools/qfcc/doc/man/qfcc.1 index 2857ffedd..045aa8963 100644 --- a/tools/qfcc/doc/man/qfcc.1 +++ b/tools/qfcc/doc/man/qfcc.1 @@ -31,49 +31,68 @@ .ds qfcc \fBqfcc\fP .ds cpp \fBcpp\fP .ds progs.src \fIprogs.src\fP + .TH QFCC 1 "28 April, 2004" QuakeForge "QuakeForge Developer's Manual" .\" Please update the above date whenever this man page is modified. + + .SH NAME qfcc \- The QuakeForge Code Compiler + + .SH SYNOPSIS .B qfcc .RI [ options ] .RI [ files ] + + .SH DESCRIPTION \*[qfcc] compiles Ruamoko source into a form that the QuakeForge engine can understand. + + .SH OPTIONS \*[qfcc] takes the following arguments: + .TP .B \-\-advanced Use advanced Ruamoko features. This is the default when using separate compilation. + .TP .B \-C, \-\-code OPTION,... Set code generation options. See \fBCODE GENERATION OPTIONS\fP for details. + .TP .B \-c Only compile, do not link. Can be used in either \fBprogs.src\fP or separate compilation modes. + .TP .B \-\-cpp CPPSPEC \*[cpp] execution command line. See \fBCPP NAME\fP for details. + .TP .B \-D, \-\-define SYMBOL[=VAL] Define a symbol for the preprocessor, if it is in use. + .TP .B \-E Only preprocess. No compilation or linking is done. + .TP .B \-\-extended -Allow extended keywords in traditional mode. +Allow extended keywords in traditional mode. Otherwise, it has \fIall\fP +the implications of \fB\-\-traditional\fP. + .TP .B \-F, \-\-files Generate \fIfiles.dat\fP. This list is created by checking the parameters to the precache_* functions. + .TP .B \-\-frames Generate \fI.frame\fP files. @@ -81,134 +100,163 @@ For each source file (listed either on the command line, or in \fBprogs.src\fP, write a file whose name is the base name of the source file with an extension of \fB.frame\fP, and contains a list of frame macro names with their associated frame numbers. Eg, \fBplayer.qc\fP will produce -\fBplayer.frame\fPa. Note that files that do not create frame macros will +\fBplayer.frame\fP. Note that files that do not create frame macros will not generate a frame file. At this time, the file is always written to the current directory. + .TP .B \-g Generate debugging info. Synonym for \fB\-\-code debug\fP. + .TP .B \-h, \-\-help Show summary of options. + .TP .B \-I DIR Add DIR to the list of directories for the preprocessor to search when looking for include files. + .TP .B \-\-include FILE Process FILE as if \fB#include "FILE"\fP appeared as the first line of the primary source file. See the \*[cpp] man page (\fB\-include\fP) for details. + .TP .B \-L DIR Add DIR to the search path used for finding libraries specified with \fB-l\fP. + .TP .B \-l LIB Add libLIB.a to the list of libraries to be used for resolving undefined symbols. \*[qfcc] expects libraries to be \fBpak\fP files of \*[qfcc] object files built using the \fBpak\fP utility. + .TP .B \-M, \-MD, \-MMD Generate dependency info. Dependent on \*[cpp] version, so check \*[cpp]'s documentation. + .TP .B \-\-no\-default\-paths Do not use default paths for include files or libraries. + .TP .B \-N, \-\-notice OPTION,... Set notice options. See \fBNOTICE OPTIONS\fP for details. + .TP .B \-o, \-\-output\-file FILE Specify output file name. In \fBprogs.src\fP mode, this overrides the output file in \*[progs.src]. + .TP .B \-\-progdefs Generate \fIprogdefs.h\fP. Forces \fB\-\-code crc\fP. + .TP .B \-P, \-\-progs\-src FILE File to use instead of \*[progs.src]. No effect in separate compilation mode. + .TP .B \-\-qccx\-escapes Use QCCX escape sequences instead of standard C/QuakeForge sequences in strings. See \fBESCAPE SEQUENCES\fP for details. -.TP -.B \-p, \-\-strip\-path NUM -Strip NUM leading path elements from file names. -eg. -p 3 will strip the -.I ../../../ -from -.I ../../../src/foo.r -when embedding the source file name in the output code. + .TP .B \-q, \-\-quiet Inhibit some of \*[qfcc]'s normal output. Specifying this option multiple times further inhibits \*[qfcc]'s output. Counteracts the effects of \fB-v\fP. + .TP .B \-r, \-\-relocatable Incremental linking. Generate a larger object file from other object files and libraries. + .TP .B \-S, \-\-save\-temps Do not delete temporary files. + .TP .B \-s, \-\-source DIR Look for \*[progs.src] in \fBDIR\fP instead of the current directory. + .TP .B \-\-traditional Use traditional QuakeC syntax, semantics and \*(lqbugs\*(rq. -Also implies the \fBv6only\fP, \fBno-short-circuit\fP and -\fBno-local-merging\fP code generation options (see -\fBCODE GENERATION OPTIONS\fP). +Also implies the \fBv6only\fP, \fBno-short-circuit\fP, +\fBconst-initializers\fP and \fBno-local-merging\fP code generation options +(see \fBCODE GENERATION OPTIONS\fP). This is the default when using \fBprogs.src\fP mode. + .TP .B \-U, \-\-undefine SYMBOL Undefine a preprocessor symbol, if the preprocessor is in use. + .TP .B \-V, \-\-version Show the version of \*[qfcc]. + .TP .B \-v, \-\-verbose Display more output than usual. Specifying this option multiple times further increases \*[qfcc]'s output. Counteracts the effects of \fB-q\fP. + .TP .B \-W, \-\-warn OPTION,... Set warning options. See \fBWARNING OPTIONS\fP for details. + .TP .B \-z Compress object files when writing them. This is especially useful when creating libraries, especially if using the object oriented features, but can be quite slow. This has no effect when creating \fBprogs.dat\fP. + + .SH "CODE GENERATION OPTIONS" Code generation options are processed in the order of their appearance on the command line. Unsupported options are ignored. The following options are supported by \*[qfcc]'s \fB\-\-code\fP argument: + +.TP +.B const-initializers +Treat initialized globals as constants. +This option is implied by \fB\-\-traditional\fP and \fB\-\-extended\fP, and is +turned off by \fB\-\-advanced\fP. + .TP .B cow Allow assignment to initialized globals. -In Quake-C and Ruamoko, a global that has been initialized to a value is not -a variable, but a named constant. +When initialized globals are treated as constants (traditional Quake-C, or +when const-initializers is activated), a global that has been initialized to a +value is not a variable, but a named constant. However, \fBqcc\fP never really enforced this. The \fBcow\fP option allows \*[qfcc] to gracefully cope with QuakeC source that assigns values to initialized globals in this manner. -(also known as \*(lqcopy on write\*(rq\(emnever mind the bovine connotations) +(also known as \*(lqcopy on write\*(rq\(emlo and behold the bovine +connotations) + .TP .B cpp Preprocess all input files with \*[cpp]. This includes the \*[progs.src] file when used. + .TP .B crc Write the CRC of \fBprogdefs.h\fP to \*(lqprogs.dat\*(rq. Default for v6 progs, otherwise defaults to off. However, \fB\-\-progdefs\fP has the effect of forcing this option. + .TP .B debug Generate debug code for QuakeForge engines. @@ -218,12 +266,14 @@ This option tells \*[qfcc] to generate this information. It is written to a secondary file with the extension \*(lqsym\*(rq\(emif your output file is \*(lqprogs.dat\*(rq, the symbol file will be \*(lqprogs.sym\*(rq. + .TP .B fast\-float Use float values directly in \*(lqif\*(rq statements. Defaults to on. This option is always enabled when using version 6 progs (\fBv6only\fP is in effect). + .TP .B local-merging Clump the local variables from all functions into one block of data the size @@ -235,6 +285,13 @@ data. This can be a problem because instructions can access addresses up to 32767 in older servers or 65535 in most modern servers. Defaults to off for traditional mode, and on for advanced mode. + +.TP +.B promote\-float +Promote float when passed to a function that takes a variable number of +arguements. Defaults to enabled for advanced code, is forced off for +traditional or v6only code (mostly because such code does not have doubles). + .TP .B short\-circuit Generate short circuit code for logical operators (\fB&&\fP and \fB||\fP). @@ -243,6 +300,7 @@ the code for \fBB\fP will not be executed. Similar for \fBA || B\fP, but if \fBA\fP is true, the expression is known to be true and the code for \fBB\fP will not be executed. Defaults to off for traditional mode, and on for advanced mode. + .TP .B single-cpp In \fBprogs.src\fP mode, when \*[cpp] is used, produce an intermediate file @@ -255,6 +313,7 @@ Without this option, each source file is independent with respect to the preprocessor. Has no effect in separate compilation mode. Defaults to on. + .TP .B vector\-calls When a function is passed a constant vector, this causes the vector to be @@ -263,12 +322,14 @@ instruction. This can save a good number of pr_globals where those vectors contain many duplicate coordinates but do not match entirely. However, this will generate slower code for such calls. + .TP .B vector\-components Create extra symbols for accessing the components of a vector variable or field. For example, \fBvector vel\fP will also create \fBvel_x\fP, \fBvel_y\fP, and \fBvel_z\fP. Defaults to on for traditional code and off for advanced. + .TP .B v6only Restrict the compiler to only version 6 progs (original Quake/QuakeWorld) @@ -280,64 +341,80 @@ support) that require extensions. Defaults to on for traditional mode and off for advanced mode. .PP Any of the above can be prefixed with \fBno\-\fP to negate its meaning. + + .SH "WARNING OPTIONS" Warning options are processed in the order of their appearance on the command line. Unsupported options are ignored. The following options are supported by \*[qfcc]'s \fB\-\-warn\fP argument: + .TP .B cow Emit a warning when the source assigns a value to a named constant. See the description of the \fBcow\fP code generation option above for a description of what this means. + .TP .B error Promote warnings to errors. + .TP .B executable Emit a warning when non-executable statements (eg, \fB==\fP used for assignment) are encountered. + .TP .B initializer Emit a warning when too many structure/array initializer elements are given. + .TP .B integer-divide Emit a warning when both constants in a division operation are integers. + .TP .B interface\-check Emit a warning when a method is declared in an implementation but not in the interface for a class. + .TP .B precedence Emit a warning when potentially ambiguous logic is used without parentheses. + .TP .B redeclared Emit a warning when a local variable is redeclared. + .TP .B switch Emit a warning when an enum value is not handled in a switch statement that tests an enum. Using a default label will cause all otherwise unhandled enum values to be handled (for good or evil). -.TP + .TP .B traditional Emit a warning when code that should be an error is allowed by traditional \fBqcc\fP. Has effect only in traditional mode. + .TP .B undef\-function Emit a warning when a function is called, but has not yet been defined. + .TP .B unimplemented Emit a warning when a class method has not been implemented. + .TP .B unused Emit a warning for unused local variables. + .TP .B uninited\-var Emit a warning when a variable is read from that has not been initialized to a value. + .TP .B vararg\-integer Emit a warning when a function that takes a variable number of arguments is @@ -345,26 +422,34 @@ passed a constant of an integer type. .PP Any of the above can be prefixed with \fBno\-\fP to negate its meaning. There are also two special options: + .TP .B all Turns on all warning options except \fBerror\fP. + .TP .B none Turns off all warning options except \fBerror\fP. + + .SH "NOTICE OPTIONS" Notices are used to flag code constructs that may have changed semantics but shouldn't be treated as warnings. They are also used for internal debugging purposes, so if you see any cryptic notices, please report them as a bug (normal notices should be fairly self-explanatory). + .TP .B none Silences all notice messages. + .TP .B warn Promote notices to warnings. If warnings are being treated as errors, so will notices. Disabling warnings has no effect on this option. + + .SH "CPP NAME" When preprocessing source files, \*[qfcc] calls \*[cpp] (the C preprocessor) with a configurable command line. @@ -379,19 +464,24 @@ This spec is similar in concept to a \fBprintf\fP string. The name of the program may be either absolute (eg \fB/lib/cpp\fP) or relative as the \fBPATH\fP will be searched. Available substitutions: + .TP .B %d Mainly for defines (\-D, \-U and \-I) but \fB%d\fP will be replaced by all \*[cpp] options that \*[qfcc] passes to \*[cpp] + .TP .B %o This will be replaced by the output file path. Could be either absolute or relative, depending on whether \*[qfcc] is deleting temporary files or not. + .TP .B %i This will be replaced by the input file path. Generally as given to \*[qfcc]. + + .SH "COMPILATION MODES" \*[qfcc] has two, mutually exclusive, modes of operation: \fBprogs.src\fP mode and \*(lqseparate compilation\*(rq mode. @@ -466,99 +556,153 @@ overridden using \fB--traditional\fP. When using \*[cpp], each source file is passed through the preprocessor individually. Each file is truly independent of any other file on the command line. + + .SH "ESCAPE SEQUENCES" \*[qfcc] supports a variety of string escape sequences. This includes those of \fBqcc\fP (which are a subset of those in standard C), standard C and \fBqccx\fP. There are some conflicts between the escape sequences, but \fB\-\-qccx\-escapes\fP selects which set to use. -.TP -.B \(rs\(rs -Backslash. -.TP -.B \(rsn -Line feed. -.TP -.B \(rs" -Double quote. -.TP -.B \(rs\' -Single quote. -.TP -.B \(rs0-7 -Octal character code, up to three digits. This conflicts with \fBqccx\fP. In -\fBqccx\fP, this produces gold digits. Use \fB\-\-qccx\-escapes\fP to select -\fBqccx\fP behaviour. -.TP -.B \(rs8-9 -Produce gold digits. -.TP -.B \(rsx0-9A-Fa-f -Hexadecimal character code, any number of digits, but only the least -significant byte will be used. +.SS Standard escape sequences: +These are the supported escape sequences from standard C, with the addition of +\(rse (escape), which would be nice if it was in standard C. + .TP .B \(rsa Bell character (not in quake engines). Equivalent to \(rsx07. + .TP .B \(rsb Backspace character (not in quake engines). Equivalent to \(rsx08. This conflicts with \fBqccx\fP. In \fBqccx\fP, this toggles bronze characters. Use \fB\-\-qccx\-escapes\fP to select \fBqccx\fP behaviour. + .TP .B \(rse -Escape character (not in quake engines). Equivalent to \(rsx1b (dull 9). +Escape character (not in quake engines). Equivalent to \(rsx1b. Not actually +standard, but it should be. + .TP .B \(rsf Formfeed character (not in quake engines). Equivalent to \(rsx0c. + +.TP +.B \(rsn +Line feed. + .TP .B \(rsr Carriage return. Equivalent to \(rsx0d. + .TP -.B \(rss -Toggle "bold" characters (add 0x80). .B \(rst Tab character. Equivalent to \(rsx09. + .TP .B \(rsv Vertical tab. Equivalent to \(rsx0b. + .TP -.B \(rs^ -Make the next character "bold" (add 0x80). +.B \(rs\(rs +Backslash. + +.TP +.B \(rs\' +Single quote. + +.TP +.B \(rs" +Double quote. + +.TP +.B \(rs? +Question mark. Avoids trigraphs in standard C, but supported for compatibility. + +.TP +.B \(rs0-7 +Octal character code, up to three digits. This conflicts with \fBqccx\fP. In +\fBqccx\fP, this produces gold digits. Use \fB\-\-qccx\-escapes\fP to select +\fBqccx\fP behaviour. + +.TP +.B \(rs8-9 +Produce gold digits. + +.TP +.B \(rsx0-9A-Fa-f +Hexadecimal character code, any number of digits, but only the least +significant byte will be used. + + +.SS Quake character set extension escape sequences: + +.TP +.B \(rsb +Toggle bronze characters. Requires \fB\-\-qccx\-escapes\fP. + +.TP +.B \(rss +Toggle "bold" characters (add 0x80). + .TP .B \(rs[ Gold [ character. Equivalent to \(rsx90. + .TP .B \(rs] Gold ] character. Equivalent to \(rsx91. + .TP .B \(rs. Center dot. Equivalent to \(rsx1c. + .TP .B \(rs< Turn on "bold" characters (add 0x80). This conflicts with \fBqccx\fP. In -\fBqccx\fP, this produces the brown left end. Equivalent to \(rsx1d. Use +\fBqccx\fP, this produces the separator left end. Equivalent to \(rsx1d. Use \fB\-\-qccx\-escapes\fP to select \fBqccx\fP behaviour. + .TP .B \(rs\- -Brown center bit. Equivalent to \(rsx1e. +Separator center. Equivalent to \(rsx1e. + .TP .B \(rs> Turn off "bold" characters (add 0x80). This conflicts with \fBqccx\fP. In -\fBqccx\fP, this produces the brown right end. Equivalent to \(rsx1f. Use +\fBqccx\fP, this produces the separator right end. Equivalent to \(rsx1f. Use \fB\-\-qccx\-escapes\fP to select \fBqccx\fP behaviour. + +.TP +.B \(rs^ +Make the next character "bold" (add 0x80). + +.TP +.B \(rs0-9 +Produce gold digits. Requires \fB\-\-qccx\-escapes\fP (except \(rs8 and \(rs9: +they are always available). + .TP .B \(rs( -Left slider end. Equivalent to \(rsx80. +Slider left end. Equivalent to \(rsx80. + .TP .B \(rs= Slider center. Equivalent to \(rsx81. + .TP .B \(rs) -Right slider end. Equivalent to \(rsx82. +Slider right end. Equivalent to \(rsx82. + .TP .B \(rs{0-255} -Decimal character code. +Decimal character code. Quake specific as qccx added this to allow specifying +the character code directly as \(rs0-\(rs9 were already used for specifying +gold digits. + .P \fB\-\-qccx\-escapes\fP has no effect on sequences that do not conflict. + + .SH TRADITIONAL VS ADVANCED Compared to \fBqcc\fP, \*[qfcc] has many advanced features and is much stricter about type checking. @@ -586,13 +730,17 @@ a lot of data space). Advanced mode is simply \*[qfcc] in its natural state. Using \fB--advanced\fP, \*[qfcc] can be put in to advanced mode while using the \fBprogs.src\fP compilation mode. + + .SH "FAQ" + .TP .B Where did the name Ruamoko come from? In Maori mythology, Ruamoko is the youngest child of Ranginui, the Sky-father, and Papatuanuku, the Earth-mother. Ruamoko is the god of volcanoes and earthquakes. For more information, see the Web site at <\fBhttp://maori.com/kmst1.htm\fP>. + .TP .B qfcc hangs This is almost always caused by qfcc incorrectly invoking \*[cpp]. @@ -600,11 +748,13 @@ Using the \fB--cpp\fP option (refer to the \fBCPP NAME\fP section above), the correct method for invoking \*[cpp] can be specified. Once you have found this, please send the correct \*[cpp] command line, preferably along with the output of \fBconfig.guess\fP, to the team. + .TP .B qfcc is singing a bad 80s rap song to me. What's going on? \*(lqice ice baby\*(rq is QuakeForge-speak for \*(lqInternal Compiler Error\*(rq. It usually means there's a bug in \*[qfcc], so please report it to the team. + .TP .B qfcc is mooing at me. What's wrong with you people? The compiler doesn't like being treated like a slab of beef. @@ -615,11 +765,17 @@ while, but you told it not to do that by passing the \fBcow\fP option to \fB\-\-code\fP, so it has its revenge by mooing out a warning. Or something like that. To disable the warning, pass \fBno-cow\fP to \fB\-\-warn\fP. + + .SH "FILES" .I progs.src + + .SH "SEE ALSO" .BR quakeforge (1), .BR pak (1) + + .SH AUTHORS The original \fBqcc\fP program, for compiling the QuakeC language, was written by Id Software, Inc. diff --git a/tools/qfcc/include/Makefile.am b/tools/qfcc/include/Makefile.am deleted file mode 100644 index 140cae90a..000000000 --- a/tools/qfcc/include/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST= class.h codespace.h cpp.h dags.h debug.h def.h defspace.h \ - diagnostic.h dot.h emit.h expr.h flow.h function.h grab.h idstuff.h \ - linker.h method.h obj_file.h obj_type.h opcodes.h options.h pragma.h \ - qfcc.h qfprogs.h reloc.h shared.h statements.h strpool.h struct.h \ - switch.h symtab.h type.h value.h diff --git a/tools/qfcc/include/Makemodule.am b/tools/qfcc/include/Makemodule.am new file mode 100644 index 000000000..689ebad68 --- /dev/null +++ b/tools/qfcc/include/Makemodule.am @@ -0,0 +1,34 @@ +EXTRA_DIST += \ + tools/qfcc/include/class.h \ + tools/qfcc/include/codespace.h \ + tools/qfcc/include/cpp.h \ + tools/qfcc/include/dags.h \ + tools/qfcc/include/debug.h \ + tools/qfcc/include/def.h \ + tools/qfcc/include/defspace.h \ + tools/qfcc/include/diagnostic.h \ + tools/qfcc/include/dot.h \ + tools/qfcc/include/emit.h \ + tools/qfcc/include/expr.h \ + tools/qfcc/include/flow.h \ + tools/qfcc/include/function.h \ + tools/qfcc/include/grab.h \ + tools/qfcc/include/idstuff.h \ + tools/qfcc/include/linker.h \ + tools/qfcc/include/method.h \ + tools/qfcc/include/obj_file.h \ + tools/qfcc/include/obj_type.h \ + tools/qfcc/include/opcodes.h \ + tools/qfcc/include/options.h \ + tools/qfcc/include/pragma.h \ + tools/qfcc/include/qfcc.h \ + tools/qfcc/include/qfprogs.h \ + tools/qfcc/include/reloc.h \ + tools/qfcc/include/shared.h \ + tools/qfcc/include/statements.h \ + tools/qfcc/include/strpool.h \ + tools/qfcc/include/struct.h \ + tools/qfcc/include/switch.h \ + tools/qfcc/include/symtab.h \ + tools/qfcc/include/type.h \ + tools/qfcc/include/value.h diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index a2cf55182..ec160e1d9 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -48,6 +48,7 @@ typedef struct class_type_s { typedef struct class_s { int defined; + int interface_declared; const char *name; struct class_s *super_class; struct category_s *categories; @@ -74,6 +75,7 @@ typedef struct protocol_s { const char *name; struct methodlist_s *methods; struct protocollist_s *protocols; + struct def_s *def; class_type_t class_type; } protocol_t; @@ -82,19 +84,24 @@ typedef struct protocollist_s { protocol_t **list; } protocollist_t; +typedef struct static_instance_s { + const char *class; + struct def_s *instance; +} static_instance_t; + extern struct type_s type_id; -extern struct type_s type_obj_object; -extern struct type_s type_obj_class; +extern struct type_s type_object; +extern struct type_s type_class; extern struct type_s type_Class; -extern struct type_s type_obj_protocol; +extern struct type_s type_protocol; extern struct type_s type_SEL; extern struct type_s type_IMP; extern struct type_s type_supermsg; -extern struct type_s type_obj_exec_class; -extern struct type_s type_obj_method; -extern struct type_s type_obj_super; -extern struct type_s type_obj_method_description; -extern struct type_s type_obj_category; +extern struct type_s type_exec_class; +extern struct type_s type_method; +extern struct type_s type_super; +extern struct type_s type_method_description; +extern struct type_s type_category; extern struct type_s type_ivar; extern struct type_s type_module; @@ -106,14 +113,19 @@ struct dstring_s; struct expr_s; struct method_s; struct symbol_s; +struct selector_s; -int obj_is_id (const struct type_s *type); -int obj_is_class (const struct type_s *type); -int obj_is_Class (const struct type_s *type); -int obj_is_classptr (const struct type_s *type); +int is_id (const struct type_s *type) __attribute__((pure)); +int is_class (const struct type_s *type) __attribute__((pure)); +int is_Class (const struct type_s *type) __attribute__((const)); +int is_classptr (const struct type_s *type) __attribute__((pure)); +int is_SEL (const struct type_s *type) __attribute__((const)); +int is_object (const struct type_s *type) __attribute__((const)); +int is_method (const struct type_s *type) __attribute__((const)); +int is_method_description (const struct type_s *type) __attribute__((const)); int obj_types_assignable (const struct type_s *dst, const struct type_s *src); -class_t *extract_class (class_type_t *class_type); +class_t *extract_class (class_type_t *class_type) __attribute__((pure)); const char *get_class_name (class_type_t *class_type, int pretty); struct symbol_s *class_symbol (class_type_t *class_type, int external); void class_init (void); @@ -125,7 +137,7 @@ void class_add_ivars (class_t *class, struct symtab_s *ivars); void class_check_ivars (class_t *class, struct symtab_s *ivars); void class_begin (class_type_t *class_type); void class_finish (class_type_t *class_type); -int class_access (class_type_t *current_class, class_t *class); +int class_access (class_type_t *current_class, class_t *class) __attribute__((pure)); struct symbol_s *class_find_ivar (class_t *class, int vis, const char *name); struct symtab_s *class_ivar_scope (class_type_t *class_type, struct symtab_s *parent); @@ -134,7 +146,7 @@ void class_finish_ivar_scope (class_type_t *class_type, struct symtab_s *param_scope); struct method_s *class_find_method (class_type_t *class_type, struct method_s *method); -struct method_s *class_message_response (class_t *class, int class_msg, +struct method_s *class_message_response (struct type_s *clstype, int class_msg, struct expr_s *sel); struct symbol_s *class_pointer_symbol (class_t *class_type); category_t *get_category (struct symbol_s *class_name, @@ -153,8 +165,13 @@ void protocol_add_protocols (protocol_t *protocol, protocollist_t *protocols); struct def_s *protocol_def (protocol_t *protocol); protocollist_t *new_protocol_list (void); protocollist_t *add_protocol (protocollist_t *protocollist, const char *name); -int procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto); -int compare_protocols (protocollist_t *protos1, protocollist_t *protos2); +int procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto) __attribute__((pure)); +struct method_s *protocollist_find_method (protocollist_t *protocollist, + struct selector_s *selector, + int nstance) + __attribute__((pure)); + +int compare_protocols (protocollist_t *protos1, protocollist_t *protos2) __attribute__((pure)); void print_protocollist (struct dstring_s *dstr, protocollist_t *protocollist); struct def_s *emit_protocol (protocol_t *protocol); struct def_s *emit_protocol_list (protocollist_t *protocols, const char *name); diff --git a/tools/qfcc/include/cpp.h b/tools/qfcc/include/cpp.h index 6b599b439..81274c353 100644 --- a/tools/qfcc/include/cpp.h +++ b/tools/qfcc/include/cpp.h @@ -34,6 +34,8 @@ struct dstring_s; void parse_cpp_name (void); +void add_cpp_sysinc (const char *arg); +void add_cpp_undef (const char *arg); void add_cpp_def (const char *arg); void intermediate_file (struct dstring_s *ifile, const char *filename, const char *ext, int local); diff --git a/tools/qfcc/include/dags.h b/tools/qfcc/include/dags.h index 21ac8c943..2c677a972 100644 --- a/tools/qfcc/include/dags.h +++ b/tools/qfcc/include/dags.h @@ -33,7 +33,7 @@ /** \defgroup qfcc_dags DAG building \ingroup qfcc */ -//@{ +///@{ #include "QF/pr_comp.h" @@ -46,7 +46,7 @@ typedef struct daglabel_s { struct daglabel_s *next; struct daglabel_s *daglabel_chain; ///< all labels created for a dag int number; ///< index into array of labels in dag_t - unsigned live:1; ///< accessed via an alias + unsigned live:1; ///< accessed via an alias FIXME redundant? const char *opcode; ///< not if op struct operand_s *op; ///< not if opcode; struct dagnode_s *dagnode; ///< node with which this label is associated @@ -59,10 +59,10 @@ typedef struct dagnode_s { int topo; ///< topological sort order struct set_s *parents; ///< empty if root node int cost; ///< cost of this node in temp vars - unsigned killed:1; ///< node is unavailable for cse - st_type_t type; ///< type of node (st_node = leaf) + struct dagnode_s *killed; ///< node is unavailable for cse (by node) + st_type_t type; ///< type of node (st_none = leaf) daglabel_t *label; ///< ident/const if leaf node, or operator - etype_t tl; + struct type_s *tl; struct operand_s *value; ///< operand holding the value of this node /// \name child nodes /// if \a children[0] is null, the rest must be null as well. Similar for @@ -75,7 +75,7 @@ typedef struct dagnode_s { /// topological sort of the DAG. //@{ struct dagnode_s *children[3]; - etype_t types[3]; ///< desired type of each operand (to alias) + struct type_s *types[3]; ///< desired type of each operand (to alias) struct set_s *edges; ///< includes nodes pointed to by \a children //@} struct set_s *identifiers; ///< set of identifiers attached to this node @@ -89,7 +89,7 @@ typedef struct dag_s { int num_topo; ///< number of nodes in topo (may be < ///< num_nodes after dead node removal) daglabel_t **labels; ///< array of all daglabels in this dag - int num_labels;; + int num_labels; struct set_s *roots; ///< set of root nodes struct flownode_s *flownode;///< flow node this dag represents } dag_t; @@ -110,6 +110,6 @@ dag_t *dag_create (struct flownode_s *flownode); void dag_remove_dead_nodes (dag_t *dag); void dag_generate (dag_t *dag, sblock_t *block); -//@} +///@} #endif//dags_h diff --git a/tools/qfcc/include/debug.h b/tools/qfcc/include/debug.h index a5d5b5a1f..af5f322b7 100644 --- a/tools/qfcc/include/debug.h +++ b/tools/qfcc/include/debug.h @@ -35,6 +35,8 @@ void line_info (char *text); pr_lineno_t *new_lineno (void); +void add_source_file (const char *file); +void debug_finish_module (const char *modname); extern int lineno_base; diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index 7e24506b9..691c5d602 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -37,7 +37,7 @@ /** \defgroup qfcc_def Def handling \ingroup qfcc */ -//@{ +///@{ struct symbol_s; struct expr_s; @@ -71,7 +71,7 @@ typedef struct def_s { def they alias, including relocation records. However, they do keep track of the source file and line that first created the alias. - The relations between a def an any of its aliases are maintained by + The relations between a def and any of its aliases are maintained by a linked list headed by def_t::alias_defs and connected by def_t::next. def_t::alias is used to find the main def via one if its aliases. The order of the aliases in the list is arbitrary: it is the @@ -110,7 +110,7 @@ typedef struct def_s { /** Specify the storage class of a def. */ typedef enum storage_class_e { - sc_global, ///< def is globally visibil across units + sc_global, ///< def is globally visible across units sc_system, ///< def may be redefined once sc_extern, ///< def is externally allocated sc_static, ///< def is private to the current unit @@ -180,7 +180,7 @@ void free_def (def_t *def); Temporary defs are bound to the current function (::current_func must be valid). They are always allocated from the funciont's local defspace. */ -//@{ +///@{ /** Get a temporary def. If the current function has a free temp def of the same size as \a size, @@ -190,14 +190,13 @@ void free_def (def_t *def); \note ::current_func must be valid. - \param type The low-level type of the temporary variable. - \param size The amount of space to allocate to the temp. + \param type The type of the temporary variable. \return The def for the temparary variable. - \bug \a size is not checked for validity (must be 1-4). + \bug size of type must be 1 to 4. \todo support arbitrary sizes */ -def_t *temp_def (etype_t type, int size); +def_t *temp_def (struct type_s *type); /** Free a tempary def so it may be recycled. @@ -208,7 +207,7 @@ def_t *temp_def (etype_t type, int size); \param temp The temp def to be recycled. */ void free_temp_def (def_t *temp); -//@} +///@} /** Initialize a vm def from a qfcc def. @@ -222,7 +221,9 @@ void def_to_ddef (def_t *def, ddef_t *ddef, int aux); /** Initialize a def referenced by the given symbol. - The symbol is checked for redefinition. (FIXME check rules) + The symbol is checked for redefinition. A symbol is considered to be + redefined if the previous definition is in the same symbol table and + of a different type or already initialized. If \a type is null, then the def will be given the default type (as specified by ::type_default). @@ -237,13 +238,11 @@ void def_to_ddef (def_t *def, ddef_t *ddef, int aux); For \a space and \a storage, see new_def(). \param sym The symbol for which to create and initialize a def. - \param type The type of the def. sym_t::type is set to this. If null, - the default type is used. \param init If not null, the expressions to use to initialize the def. \param space The space from which to allocate space for the def. \param storage The storage class of the def. */ -void initialize_def (struct symbol_s *sym, struct type_s *type, +void initialize_def (struct symbol_s *sym, struct expr_s *init, struct defspace_s *space, storage_class_t storage); @@ -254,7 +253,7 @@ void initialize_def (struct symbol_s *sym, struct type_s *type, \return 1 if the defs overlap, 2 if \a d1 fully overlaps \a d2, otherwise 0. */ -int def_overlap (def_t *d1, def_t *d2); +int def_overlap (def_t *d1, def_t *d2) __attribute__((pure)); /** Convenience function for obtaining a def's actual offset. @@ -263,7 +262,7 @@ int def_overlap (def_t *d1, def_t *d2); \param def The def of which to obtain the offset. May be an alias def. \return The actual offset of the def in the def's defspace. */ -int def_offset (def_t *def); +int def_offset (def_t *def) __attribute__((pure)); /** Convenience function for obtaining a def's size. @@ -272,7 +271,7 @@ int def_offset (def_t *def); \param def The def of which to obtain the size. \return The size of the def. */ -int def_size (def_t *def); +int def_size (def_t *def) __attribute__((pure)); /** Visit all defs that alias the given def, including itself. @@ -307,6 +306,6 @@ int def_size (def_t *def); */ int def_visit_all (def_t *def, int overlap, int (*visit) (def_t *, void *), void *data); -//@} +///@} #endif//__def_h diff --git a/tools/qfcc/include/defspace.h b/tools/qfcc/include/defspace.h index 371af492e..e0414f1c9 100644 --- a/tools/qfcc/include/defspace.h +++ b/tools/qfcc/include/defspace.h @@ -37,7 +37,7 @@ /** \defgroup qfcc_defspace Defspace handling \ingroup qfcc */ -//@{ +///@{ typedef enum { ds_backed, ///< data space is globally addressable (near/far/type) and @@ -90,6 +90,8 @@ typedef struct defspace_s { */ defspace_t *defspace_new (ds_type_t type); +void defspace_delete (defspace_t *defspace); + /** Allocate space from the defspace's backing memory. If the memory is fragmented, then the first available location at least @@ -109,20 +111,41 @@ defspace_t *defspace_new (ds_type_t type); */ int defspace_alloc_loc (defspace_t *space, int size); +/** Allocate space from the defspace's backing memory. + + If the memory is fragmented, then the first available location at least + as large as \a size plus padding for alignment is returned. This means + that freeing a location then allocating the same amount of space may + return a different location. + + If memory cannot be allocated (there is no free space in the currently + available memory and defspace_t::grow is null), then an internal error + will be generated. + + \param space The space from which to allocate data. + \param size The amount of pr_type_t words to allocated. int and float + need 1 word, vector 3 words, and quaternion 4. + \param alignment The alignment of the allocated space. + \return The offset of the first word of the freshly allocated + space. May be 0 if the allocated space is at the beginning + of the defspace. +*/ +int defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment); + /** Free a block of contiguous words, returning them to the defspace. The block to be freed is specified by \a ofs indicating the offset of the first word of the block and \a size indicating the number of words in the block. - If the block to be freed has 0 words, or if the is partly or fully outside - the defspace (as defined by defspace_t::size), or if the block overlaps - any unallocated space in the defspace, then an internal error will be - generated. However, it is perfectly valid to allocate a large block and - subsequently free a small block from anywhere within the larger block. - This is because when memory is not fragmented, there is no difference - between allocating one large block and allocating several smaller blocks - when allocating the same amount of memory. + If the block to be freed has 0 words, or if the block is partly or fully + outside the defspace (as defined by defspace_t::size), or if the block + overlaps any unallocated space in the defspace, then an internal error + will be generated. However, it is perfectly valid to allocate a large + block and subsequently free a small block from anywhere within the larger + block. This is because when memory is not fragmented, there is no + difference between allocating one large block and allocating several + smaller blocks when allocating the same amount of memory. \param space The space to which the freed block will be returned. \param ofs The first word of the block to be freed. @@ -136,7 +159,7 @@ void defspace_free_loc (defspace_t *space, int ofs, int size); defspace_alloc_loc(). If \a data is null, then the copying stage is skipped and this function - because a synonym for defspace_alloc_loc(). + becomes a synonym for defspace_alloc_loc(). \param space The space to which the data will be added. \param data The data to be copied into the space. @@ -145,6 +168,6 @@ void defspace_free_loc (defspace_t *space, int ofs, int size); */ int defspace_add_data (defspace_t *space, pr_type_t *data, int size); -//@} +///@} #endif//__defspace_h diff --git a/tools/qfcc/include/diagnostic.h b/tools/qfcc/include/diagnostic.h index 51eea07a5..3a19c9722 100644 --- a/tools/qfcc/include/diagnostic.h +++ b/tools/qfcc/include/diagnostic.h @@ -36,22 +36,43 @@ /** \defgroup qfcc_diagnostic Diagnostic Messages \ingroup qfcc */ -//@{ +///@{ -struct expr_s *error (struct expr_s *e, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -void -internal_error (struct expr_s *e, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3), noreturn)); -struct expr_s *warning (struct expr_s *e, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -struct expr_s *notice (struct expr_s *e, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -void debug (struct expr_s *e, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -void bug (struct expr_s *e, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); +typedef void (*diagnostic_hook)(const char *message); +extern diagnostic_hook bug_hook; +extern diagnostic_hook error_hook; +extern diagnostic_hook warning_hook; +extern diagnostic_hook notice_hook; -//@} +struct expr_s *_error (struct expr_s *e, const char *file, int line, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); +#define error(e, fmt...) _error(e, __FILE__, __LINE__, fmt) + +void _internal_error (struct expr_s *e, const char *file, int line, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5), noreturn)); +#define internal_error(e, fmt...) _internal_error(e, __FILE__, __LINE__, fmt) + +struct expr_s *_warning (struct expr_s *e, const char *file, int line, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); +#define warning(e, fmt...) _warning(e, __FILE__, __LINE__, fmt) + +struct expr_s *_notice (struct expr_s *e, const char *file, int line, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); +#define notice(e, fmt...) _notice(e, __FILE__, __LINE__, fmt) + +void _debug (struct expr_s *e, const char *file, int line, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); +#define debug(e, fmt...) _debug(e, __FILE__, __LINE__, fmt) + +void _bug (struct expr_s *e, const char *file, int line, const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); +#define bug(e, fmt...) _bug(e, __FILE__, __LINE__, fmt) + +///@} #endif//__diagnostic_h diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 5b1c6d1e7..79fd77f99 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -36,7 +36,7 @@ /** \defgroup qfcc_expr Expressions \ingroup qfcc */ -//@{ +///@{ /** Type of the exression node in an expression tree. */ @@ -49,12 +49,15 @@ typedef enum { ex_block, ///< statement block expression (::ex_block_t) ex_expr, ///< binary expression (::ex_expr_t) ex_uexpr, ///< unary expression (::ex_expr_t) + ex_def, ///< non-temporary variable (::def_t) ex_symbol, ///< non-temporary variable (::symbol_t) ex_temp, ///< temporary variable (::ex_temp_t) ex_vector, ///< "vector" expression (::ex_vector_t) ex_nil, ///< umm, nil, null. nuff said (0 of any type) ex_value, ///< constant value (::ex_value_t) + ex_compound, ///< compound initializer + ex_memset, ///< memset needs three params... } expr_type; /** Binary and unary expressions. @@ -75,6 +78,7 @@ typedef struct ex_label_s { struct reloc_s *refs; ///< relocations associated with this label struct sblock_s *dest; ///< the location of this label if known const char *name; ///< the name of this label + struct symbol_s *symbol; ///< symbol used to define this label (maybe 0) int used; ///< label is used as a target struct daglabel_s *daglabel; } ex_label_t; @@ -83,15 +87,28 @@ typedef struct { ex_label_t *label; } ex_labelref_t; +typedef struct element_s { + struct element_s *next; ///< next in chain + int offset; + struct type_s *type; + struct expr_s *expr; ///< initializer expression + struct symbol_s *symbol; ///< for labeled initializers +} element_t; + +typedef struct element_chain_s { + element_t *head; + element_t **tail; +} element_chain_t; + typedef struct { struct expr_s *head; ///< the first expression in the block struct expr_s **tail; ///< last expression in the block, for appending struct expr_s *result; ///< the result of this block if non-void int is_call; ///< this block exprssion forms a function call + void *return_addr;///< who allocated this } ex_block_t; typedef struct { - struct expr_s *expr; struct operand_s *op; ///< The operand for the temporary variable, if ///< allocated struct type_s *type; ///< The type of the temporary variable. @@ -110,6 +127,7 @@ typedef struct ex_pointer_s { int val; struct type_s *type; struct def_s *def; + struct operand_s *tempop; } ex_pointer_t; typedef struct ex_func_s { @@ -128,6 +146,13 @@ typedef struct { struct expr_s *e; } ex_bool_t; +typedef struct ex_memset_s { + struct expr_s *dst; + struct expr_s *val; + struct expr_s *count; + struct type_s *type; +} ex_memset_t; + /** State expression used for think function state-machines. State expressions are of the form [framenum, nextthink] @@ -171,9 +196,11 @@ typedef struct { typedef struct ex_value_s { struct ex_value_s *next; struct daglabel_s *daglabel;///< dag label for this value - etype_t type; + struct type_s *type; + etype_t lltype; union { const char *string_val; ///< string constant + double double_val; ///< double constant float float_val; ///< float constant float vector_val[3]; ///< vector constant int entity_val; ///< entity constant @@ -190,12 +217,13 @@ typedef struct ex_value_s { typedef struct expr_s { struct expr_s *next; ///< the next expression in a block expression - expr_type type; ///< the type of the result of this expression - int line; ///< source line that generated this expression - string_t file; ///< source file that generated this expression + expr_type type; ///< the type of the result of this expression + int line; ///< source line that generated this expression + string_t file; ///< source file that generated this expression int printid; ///< avoid duplicate output when printing - unsigned paren:1; ///< the expression is enclosed in () - unsigned rvalue:1; ///< the expression is on the right side of = + unsigned paren:1; ///< the expression is enclosed in () + unsigned rvalue:1; ///< the expression is on the right side of = + unsigned implicit:1; ///< don't warn for implicit casts union { ex_label_t label; ///< label expression ex_labelref_t labelref; ///< label reference expression (&) @@ -203,14 +231,18 @@ typedef struct expr_s { ex_bool_t bool; ///< boolean logic expression ex_block_t block; ///< statement block expression ex_expr_t expr; ///< binary or unary expression + struct def_s *def; ///< def reference expression struct symbol_s *symbol; ///< symbol reference expression ex_temp_t temp; ///< temporary variable expression ex_vector_t vector; ///< vector expression list ex_value_t *value; ///< constant value + element_chain_t compound; ///< compound initializer + ex_memset_t memset; ///< memset expr params + struct type_s *nil; ///< type for nil if known } e; } expr_t; -extern struct type_s *ev_types[]; +extern const char *expr_names[]; /** Report a type mismatch error. @@ -262,11 +294,19 @@ expr_t *new_expr (void); */ expr_t *copy_expr (expr_t *e); +/** Copy source expression's file and line to the destination expression + + \param dst The expression to receive the file and line + \param src The expression from which the file and line will be taken + \return \a dst +*/ +expr_t *expr_file_line (expr_t *dst, const expr_t *src); + /** Create a new label name. - The label name is guaranteed to to the compilation. It is made up of the - name of the current function plus an incrementing number. The number is - not reset between functions. + The label name is guaranteed to be unique to the compilation. It is made + up of the name of the current function plus an incrementing number. The + number is not reset between functions. \return The string representing the label name. */ @@ -280,6 +320,19 @@ const char *new_label_name (void); */ expr_t *new_label_expr (void); +/** Create a named label expression node. + + The label name is set using new_label_name(), but the symbol is used to add + the label to the function's label scope symbol table. If the label already + exists in the function's label scope, then the existing label is returned, + allowing for forward label declarations. + + \param label The name symbol to use for adding the label to the function + label scope. + \return The new label expression (::ex_label_t) node. +*/ +expr_t *named_label_expr (struct symbol_s *label); + /** Create a new label reference expression node. Used for taking the address of a label (eg. jump tables). @@ -313,6 +366,28 @@ expr_t *new_bool_expr (ex_list_t *true_list, ex_list_t *false_list, expr_t *e); */ expr_t *new_block_expr (void); +/** Create a new statement block expression node from an expression list + + The returned block holds the expression list in reverse order. This makes + it easy to build the list in a parser. + + \param expr_list The expression list to convert to an expression block. + Note that the evaluation order will be reversed. + \return The new block expression (::ex_block_t) node. +*/ +expr_t *build_block_expr (expr_t *expr_list); + +element_t *new_element (expr_t *expr, struct symbol_s *symbol); +expr_t *new_compound_init (void); +expr_t *append_element (expr_t *compound, element_t *element); +expr_t *initialized_temp_expr (const struct type_s *type, expr_t *compound); +void assign_elements (expr_t *local_expr, expr_t *ptr, + element_chain_t *element_chain); +void build_element_chain (element_chain_t *element_chain, + const struct type_s *type, + expr_t *eles, int base_offset); +void free_element_chain (element_chain_t *element_chain); + /** Create a new binary expression node node. If either \a e1 or \a e2 are error expressions, then that expression will @@ -330,7 +405,7 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); /** Create a new unary expression node node. If \a e1 is an error expression, then it will be returned instead of a - new binary expression. + new unary expression. \param op The op-code of the unary expression. \param e1 The "right" side of the expression. @@ -339,6 +414,12 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); */ expr_t *new_unary_expr (int op, expr_t *e1); +/** Create a new def reference (non-temporary variable) expression node. + + \return The new def reference expression node (::def_t). +*/ +expr_t *new_def_expr (struct def_s *def); + /** Create a new symbol reference (non-temporary variable) expression node. \return The new symbol reference expression node (::symbol_t). @@ -353,7 +434,7 @@ expr_t *new_symbol_expr (struct symbol_s *symbol); \param type The type of the temporary variable. \return The new temporary variable expression node (ex_temp_t). */ -expr_t *new_temp_def_expr (struct type_s *type); +expr_t *new_temp_def_expr (const struct type_s *type); /** Create a new nil expression node. @@ -384,7 +465,16 @@ expr_t *new_name_expr (const char *name); (expr_t::e::string_val). */ expr_t *new_string_expr (const char *string_val); -const char *expr_string (expr_t *e); +const char *expr_string (expr_t *e) __attribute__((pure)); + +/** Create a new double constant expression node. + + \param double_val The double constant being represented. + \return The new double constant expression node + (expr_t::e::double_val). +*/ +expr_t *new_double_expr (double double_val); +double expr_double (expr_t *e) __attribute__((pure)); /** Create a new float constant expression node. @@ -393,7 +483,7 @@ const char *expr_string (expr_t *e); (expr_t::e::float_val). */ expr_t *new_float_expr (float float_val); -float expr_float (expr_t *e); +float expr_float (expr_t *e) __attribute__((pure)); /** Create a new vector constant expression node. @@ -402,7 +492,7 @@ float expr_float (expr_t *e); (expr_t::e::vector_val). */ expr_t *new_vector_expr (const float *vector_val); -const float *expr_vector (expr_t *e); +const float *expr_vector (expr_t *e) __attribute__((pure)); expr_t *new_vector_list (expr_t *e); /** Create a new entity constant expression node. @@ -415,7 +505,7 @@ expr_t *new_entity_expr (int entity_val); /** Create a new field constant expression node. - \param field_val XXX + \param field_val offset? XXX \param type The type of the field. \param def \return The new field constant expression node @@ -449,7 +539,7 @@ expr_t *new_pointer_expr (int val, struct type_s *type, struct def_s *def); (expr_t::e::quaternion_val). */ expr_t *new_quaternion_expr (const float *quaternion_val); -const float *expr_quaternion (expr_t *e); +const float *expr_quaternion (expr_t *e) __attribute__((pure)); /** Create a new integer constant expression node. @@ -458,7 +548,7 @@ const float *expr_quaternion (expr_t *e); (expr_t::e::integer_val). */ expr_t *new_integer_expr (int integer_val); -int expr_integer (expr_t *e); +int expr_integer (expr_t *e) __attribute__((pure)); /** Create a new integer constant expression node. @@ -467,7 +557,7 @@ int expr_integer (expr_t *e); (expr_t::e::integer_val). */ expr_t *new_uinteger_expr (unsigned uinteger_val); -unsigned expr_uinteger (expr_t *e); +unsigned expr_uinteger (expr_t *e) __attribute__((pure)); /** Create a new short constant expression node. @@ -476,14 +566,16 @@ unsigned expr_uinteger (expr_t *e); (expr_t::e::short_val). */ expr_t *new_short_expr (short short_val); -short expr_short (expr_t *e); +short expr_short (expr_t *e) __attribute__((pure)); + +int expr_integral (expr_t *e) __attribute__((pure)); /** Check of the expression refers to a constant value. \param e The expression to check. \return True if the expression is constant. */ -int is_constant (expr_t *e); +int is_constant (expr_t *e) __attribute__((pure)); /** Return a value expression representing the constant stored in \a e. @@ -500,30 +592,34 @@ expr_t *constant_expr (expr_t *e); \param op The op-code to check. \return True if the op-code is a comparison operator. */ -int is_compare (int op); +int is_compare (int op) __attribute__((const)); /** Check if the op-code is a math operator. \param op The op-code to check. \return True if the op-code is a math operator. */ -int is_math_op (int op); +int is_math_op (int op) __attribute__((const)); /** Check if the op-code is a logic operator. \param op The op-code to check. \return True if the op-code is a logic operator. */ -int is_logic (int op); +int is_logic (int op) __attribute__((const)); -int has_function_call (expr_t *e); +int has_function_call (expr_t *e) __attribute__((pure)); -int is_string_val (expr_t *e); -int is_float_val (expr_t *e); -int is_vector_val (expr_t *e); -int is_quaternion_val (expr_t *e); -int is_integer_val (expr_t *e); -int is_short_val (expr_t *e); +int is_nil (expr_t *e) __attribute__((pure)); +int is_string_val (expr_t *e) __attribute__((pure)); +int is_float_val (expr_t *e) __attribute__((pure)); +int is_vector_val (expr_t *e) __attribute__((pure)); +int is_quaternion_val (expr_t *e) __attribute__((pure)); +int is_integer_val (expr_t *e) __attribute__((pure)); +int is_uinteger_val (expr_t *e) __attribute__((pure)); +int is_short_val (expr_t *e) __attribute__((pure)); +int is_integral_val (expr_t *e) __attribute__((pure)); +int is_pointer_val (expr_t *e) __attribute__((pure)); /** Create a reference to the global .self entity variable. @@ -547,6 +643,7 @@ expr_t *new_this_expr (void); expr_t *new_ret_expr (struct type_s *type); expr_t *new_alias_expr (struct type_s *type, expr_t *expr); +expr_t *new_offset_alias_expr (struct type_s *type, expr_t *expr, int offset); /** Create an expression of the correct type that references the specified parameter slot. @@ -570,6 +667,9 @@ expr_t *new_param_expr (struct type_s *type, int num); expr_t *new_move_expr (expr_t *e1, expr_t *e2, struct type_s *type, int indirect); +expr_t *new_memset_expr (expr_t *dst, expr_t *val, struct type_s *type); + + /** Convert a name to an expression of the appropriate type. Converts the expression in-place. If the exprssion is not a name @@ -590,7 +690,8 @@ void dump_dot_expr (void *e, const char *filename); void convert_int (expr_t *e); void convert_short (expr_t *e); void convert_short_int (expr_t *e); -void convert_nil (expr_t *e, struct type_s *t); +void convert_double (expr_t *e); +expr_t *convert_nil (expr_t *e, struct type_s *t); expr_t *test_expr (expr_t *e); void backpatch (ex_list_t *list, expr_t *label); @@ -601,7 +702,7 @@ expr_t *binary_expr (int op, expr_t *e1, expr_t *e2); expr_t *field_expr (expr_t *e1, expr_t *e2); expr_t *asx_expr (int op, expr_t *e1, expr_t *e2); expr_t *unary_expr (int op, expr_t *e); -expr_t *build_function_call (expr_t *fexpr, struct type_s *ftype, +expr_t *build_function_call (expr_t *fexpr, const struct type_s *ftype, expr_t *params); expr_t *function_expr (expr_t *e1, expr_t *e2); struct function_s; @@ -624,10 +725,11 @@ expr_t *build_for_statement (expr_t *init, expr_t *test, expr_t *next, expr_t *break_label, expr_t *continue_label); expr_t *build_state_expr (expr_t *e); expr_t *think_expr (struct symbol_s *think_sym); -expr_t *assign_expr (expr_t *e1, expr_t *e2); +int is_lvalue (const expr_t *expr) __attribute__((pure)); +expr_t *assign_expr (expr_t *dst, expr_t *src); expr_t *cast_expr (struct type_s *t, expr_t *e); -const char *get_op_string (int op); +const char *get_op_string (int op) __attribute__((const)); struct keywordarg_s; struct class_type_s; @@ -640,6 +742,6 @@ expr_t *sizeof_expr (expr_t *expr, struct type_s *type); expr_t *fold_constants (expr_t *e); -//@} +///@} #endif//__expr_h diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index c605b1d22..f68c5d5cf 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -33,7 +33,7 @@ /** \defgroup qfcc_flow Flow graph analysis \ingroup qfcc */ -//@{ +///@{ struct function_s; struct sblock_s; @@ -46,6 +46,7 @@ typedef struct flowvar_s { struct set_s *define; ///< set of statements that define this var struct operand_s *op; ///< an operand using this var int number; ///< number of variable in func's ref list + int flowaddr; ///< psuedo address for local and temp vars } flowvar_t; typedef struct flowloop_s { @@ -83,12 +84,6 @@ typedef struct flownode_s { struct set_s *in; struct set_s *out; } live_vars; - struct { - struct set_s *use; - struct set_s *def; - struct set_s *in; - struct set_s *out; - } init_vars; struct sblock_s *sblock; ///< original statement block struct dag_s *dag; ///< dag for this node } flownode_t; @@ -101,15 +96,16 @@ typedef struct flowgraph_s { flowedge_t *edges; ///< array of all edges in the graph int num_edges; struct set_s *dfst; ///< edges in the depth-first search tree - int *dfo; ///< depth-first order of nodes + int *depth_first; ///< depth-first order of nodes flowloop_t *loops; ///< linked list of natural loops } flowgraph_t; flowvar_t *flow_get_var (struct operand_s *op); +#define FLOW_OPERANDS 5 void flow_analyze_statement (struct statement_s *s, struct set_s *use, struct set_s *def, struct set_s *kill, - struct operand_s *operands[4]); + struct operand_s *operands[FLOW_OPERANDS]); void flow_data_flow (struct function_s *func); @@ -119,6 +115,6 @@ void dump_dot_flow_live (void *g, const char *filename); void dump_dot_flow_reaching (void *g, const char *filename); void dump_dot_flow_statements (void *g, const char *filename); -//@} +///@} #endif//flow_h diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index a1a5c19bf..3ae7c845f 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -34,7 +34,7 @@ /** \defgroup qfcc_function Internal function structures. \ingroup qfcc */ -//@{ +///@{ #include "QF/pr_comp.h" #include "QF/pr_debug.h" @@ -51,7 +51,7 @@ typedef struct overloaded_function_s { const char *name; ///< source level name of function const char *full_name; ///< progs name of function, with type ///< encoding - struct type_s *type; ///< type of this function + const struct type_s *type; ///< type of this function int overloaded; ///< is this function overloaded string_t file; ///< source file of the function int line; ///< source line of this function @@ -68,6 +68,7 @@ typedef struct function_s { int local_defs; string_t s_file; ///< source file with definition string_t s_name; ///< name of function in output + const struct type_s *type; ///< function's type without aliases int temp_num; ///< number for next temp var struct def_s *temp_defs[4]; ///< freed temp vars (by size) struct def_s *def; ///< output def holding function number @@ -79,6 +80,7 @@ typedef struct function_s { scope symbol table's defspace. */ struct symtab_s *symtab; + struct symtab_s *label_scope; struct reloc_s *refs; ///< relocation targets for this function struct expr_s *var_init; const char *name; ///< nice name for __PRETTY_FUNCTION__ @@ -94,6 +96,7 @@ typedef struct function_s { struct set_s *global_vars;///< set indicating which vars are global struct statement_s **statements; int num_statements; + int tmpaddr; ///< tmp var "address" for flow analysis } function_t; extern function_t *current_func; @@ -105,9 +108,9 @@ extern function_t *current_func; typedef struct param_s { struct param_s *next; const char *selector; - struct type_s *type; //FIXME redundant - const char *name; //FIXME redundant - struct symbol_s *symbol; + struct type_s *type; + const char *name; + struct symbol_s *symbol; //FIXME what is this for? } param_t; struct expr_s; @@ -118,8 +121,8 @@ param_t *new_param (const char *selector, struct type_s *type, const char *name); param_t *param_append_identifiers (param_t *params, struct symbol_s *idents, struct type_s *type); -param_t *_reverse_params (param_t *params, param_t *next); param_t *reverse_params (param_t *params); +param_t *append_params (param_t *params, param_t *more_params); param_t *copy_params (param_t *params); struct type_s *parse_params (struct type_s *type, param_t *params); param_t *check_params (param_t *params); @@ -140,12 +143,11 @@ function_t *build_code_function (struct symbol_s *fsym, struct expr_s *statements); function_t *build_builtin_function (struct symbol_s *sym, struct expr_s *bi_val, int far); -void build_function (function_t *f); void finish_function (function_t *f); void emit_function (function_t *f, struct expr_s *e); int function_parms (function_t *f, byte *parm_size); void clear_functions (void); -//@} +///@} #endif//__function_h diff --git a/tools/qfcc/include/method.h b/tools/qfcc/include/method.h index ef51e1579..598e151ee 100644 --- a/tools/qfcc/include/method.h +++ b/tools/qfcc/include/method.h @@ -58,6 +58,10 @@ typedef struct methodlist_s { int instance; ///< used only for emitting } methodlist_t; +typedef struct methodset_s { + struct hashtab_s *tab; +} methodset_t; + typedef struct keywordarg_s { // the first two fields match the first two fields of param_t in // functionl.h @@ -80,7 +84,12 @@ struct symbol_s *method_symbol (struct class_type_s *class_type, void method_set_param_names (method_t *dst, method_t *src); methodlist_t *new_methodlist (void); -void copy_methods (methodlist_t *dst, methodlist_t *src); +methodset_t *new_methodset (void); +void methodset_add_methods (methodset_t *methodset, methodlist_t *methods); +int methodset_contains_method (methodset_t *methodset, method_t *method); +//NOTE frees the source list and any methods not copied +void merge_method_lists (methodlist_t *dst, methodlist_t *src); +void copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except); int method_compare (method_t *m1, method_t *m2); keywordarg_t *new_keywordarg (const char *selector, struct expr_s *expr); @@ -89,6 +98,9 @@ keywordarg_t *copy_keywordargs (const keywordarg_t *kwargs); struct expr_s *send_message (int super); method_t *find_method (const char *sel_name); +method_t *methodlist_find_method (methodlist_t *methodlist, + selector_t *selector, int instance) + __attribute__((pure)); void selector_name (struct dstring_s *sel_id, keywordarg_t *selector); void method_types (struct dstring_s *sel_types, method_t *method); diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index cd9cd45f6..55a93542b 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -34,7 +34,7 @@ /** \defgroup qfcc_qfo Object file functions \ingroup qfcc */ -//@{ +///@{ #include "QF/pr_comp.h" #include "QF/pr_debug.h" @@ -60,13 +60,13 @@ */ typedef struct qfo_header_s { int8_t qfo[4]; ///< identifier string (includes nul) (#QFO) - pr_int_t version; ///< QFO format version (#QFO_VERSION) - pr_int_t num_spaces; - pr_int_t num_relocs; ///< number of relocation records - pr_int_t num_defs; ///< number of def records - pr_int_t num_funcs; ///< number of function records - pr_int_t num_lines; ///< number of line records - pr_int_t num_loose_relocs; ///< number of loose relocation records + pr_uint_t version; ///< QFO format version (#QFO_VERSION) + pr_uint_t num_spaces; + pr_uint_t num_relocs; ///< number of relocation records + pr_uint_t num_defs; ///< number of def records + pr_uint_t num_funcs; ///< number of function records + pr_uint_t num_lines; ///< number of line records + pr_uint_t num_loose_relocs; ///< number of loose relocation records ///< (included in num_relocs) } qfo_header_t; @@ -77,17 +77,18 @@ typedef enum qfos_type_e { qfos_string, ///< strings. char data qfos_entity, ///< entity field defs. no data qfos_type, ///< type encodings + qfos_debug, ///< debug data } qfos_type_t; /** Representation of a space in the object file. */ typedef struct qfo_space_s { pr_int_t type; ///< code, string, data, entity... - pr_int_t defs; ///< index of first def - pr_int_t num_defs; ///< zero for code or string spaces - pr_int_t data; ///< byte offset in qfo + pr_uint_t defs; ///< index of first def + pr_uint_t num_defs; ///< zero for code or string spaces + pr_uint_t data; ///< byte offset in qfo pr_uint_t data_size; ///< in elements. zero for entity spaces - pr_int_t id; + pr_uint_t id; pr_int_t reserved[2]; } qfo_space_t; @@ -98,20 +99,20 @@ typedef struct qfo_def_s { string_t name; ///< def name pointer_t offset; ///< def offset (address) - pr_int_t relocs; ///< index of first reloc record - pr_int_t num_relocs; ///< number of reloc records + pr_uint_t relocs; ///< index of first reloc record + pr_uint_t num_relocs; ///< number of reloc records pr_uint_t flags; ///< \ref qfcc_qfo_QFOD "QFOD flags" string_t file; ///< source file name - pr_int_t line; ///< source line number + pr_uint_t line; ///< source line number } qfo_def_t; -//@} +///@} /** \defgroup qfcc_qfo_QFOD QFOD flags \ingroup qfcc_qfo */ -//@{ +///@{ /** The def has been initialized. @@ -168,11 +169,11 @@ typedef struct qfo_def_s { \hideinitializer */ #define QFOD_PARAM (1u<<8) -//@} +///@} /** \addtogroup qfcc_qfo */ -//@{ +///@{ /** Representation of a function in the object file. */ @@ -180,7 +181,7 @@ typedef struct qfo_func_s { string_t name; ///< function name pointer_t type; ///< function type (in type data space) string_t file; ///< source file name - pr_int_t line; ///< source line number + pr_uint_t line; ///< source line number /** \name Function code location. If #code is negative, then the function is a VM builtin function. @@ -191,22 +192,22 @@ typedef struct qfo_func_s { */ pr_int_t code; - pr_int_t def; ///< def that references this function. Index + pr_uint_t def; ///< def that references this function. Index ///< to ::qfo_def_t. The data word pointed to ///< by the def stores the index of this ///< function. - pr_int_t locals_space; ///< space holding the function's local data + pr_uint_t locals_space; ///< space holding the function's local data - pr_int_t line_info; ///< Index to first ::pr_lineno_t line record. + pr_uint_t line_info; ///< Index to first ::pr_lineno_t line record. ///< Zero if there are no records. /** \name Function relocation records. XXX not sure how these work */ //@{ - pr_int_t relocs; ///< Index to first ::qfo_reloc_t reloc record. - pr_int_t num_relocs; ///< Number of reloc records. + pr_uint_t relocs; ///< Index to first ::qfo_reloc_t reloc record. + pr_uint_t num_relocs; ///< Number of reloc records. //@} pr_int_t reserved[2]; } qfo_func_t; @@ -237,8 +238,8 @@ typedef struct qfo_func_s { the referenced field def. */ typedef struct qfo_reloc_s { - pr_int_t space; ///< index of space holding data to be adjusted - pr_int_t offset; ///< offset of the relocation + pr_uint_t space; ///< index of space holding data to be adjusted + pr_uint_t offset; ///< offset of the relocation pr_int_t type; ///< type of the relocation (::reloc_type) pr_uint_t target; ///< def/func/etc this relocation is for } qfo_reloc_t; @@ -248,14 +249,14 @@ typedef struct qfo_reloc_s { typedef struct qfo_mspace_s { qfos_type_t type; qfo_def_t *defs; - int num_defs; + unsigned num_defs; union { dstatement_t *code; pr_type_t *data; char *strings; } d; unsigned data_size; - int id; + unsigned id; } qfo_mspace_t; /** In-memory representation of a QFO object file. @@ -263,16 +264,16 @@ typedef struct qfo_mspace_s { typedef struct qfo_s { void *data; ///< data buffer holding qfo file when read qfo_mspace_t *spaces; - int num_spaces; + unsigned num_spaces; qfo_reloc_t *relocs; - int num_relocs; // includes num_loose_relocs + unsigned num_relocs; // includes num_loose_relocs qfo_def_t *defs; - int num_defs; + unsigned num_defs; qfo_func_t *funcs; - int num_funcs; + unsigned num_funcs; pr_lineno_t *lines; - int num_lines; - int num_loose_relocs; // included in num_relocs + unsigned num_lines; + unsigned num_loose_relocs; // included in num_relocs } qfo_t; enum { @@ -283,16 +284,17 @@ enum { qfo_far_data_space, qfo_entity_space, qfo_type_space, + qfo_debug_space, qfo_num_spaces }; -//@} +///@} /** \defgroup qfcc_qfo_data_access QFO Data Acess \ingroup qfcc_qfo Macros for accessing data in the QFO address space */ -//@{ +///@{ /** \internal \param q pointer to ::qfo_t struct @@ -305,6 +307,19 @@ enum { */ #define QFO_var(q, s, t, o) ((q)->spaces[s].d.data[o].t##_var) +/** Access a double variable in the object file. Can be assigned to. + + \par QC type: + \c double + \param q pointer to ::qfo_t struct + \param s space index + \param o offset into object file data space + \return double lvalue + + \hideinitializer +*/ +#define QFO_DOUBLE(q, s, o) (*(double *) ((q)->spaces[s].d.data + o)) + /** Access a float variable in the object file. Can be assigned to. \par QC type: @@ -361,7 +376,6 @@ enum { \param q pointer to ::qfo_t struct \param s space index - \param s offset into object file string space \return (char *) \hideinitializer @@ -439,11 +453,11 @@ enum { */ #define QFO_STRUCT(q, s, t, o) (*QFO_POINTER (q, s, t, o)) -//@} +///@} /** \addtogroup qfcc_qfo */ -//@{ +///@{ struct pr_info_s; @@ -485,6 +499,8 @@ qfo_t *qfo_new (void); */ void qfo_delete (qfo_t *qfo); -//@} +__attribute__((const)) int qfo_log2 (unsigned x); + +///@} #endif//__obj_file_h diff --git a/tools/qfcc/include/obj_type.h b/tools/qfcc/include/obj_type.h index 1e559f45e..a8c546703 100644 --- a/tools/qfcc/include/obj_type.h +++ b/tools/qfcc/include/obj_type.h @@ -31,82 +31,12 @@ #ifndef __obj_type_h #define __obj_type_h -/** \defgroup qfcc_qfo_type Object file type encoding - \ingroup qfcc_qfo - - All \c pointer_t \c type fields are pointers within the type qfo_space. -*/ -//@{ - -#include "QF/pr_comp.h" +#include "QF/pr_type.h" #include "type.h" -typedef struct qfot_fldptr_s { - pr_int_t type; ///< ev_field or ev_pointer - pointer_t aux_type; ///< referenced type -} qfot_fldptr_t; - -typedef struct qfot_func_s { - pr_int_t type; ///< always ev_func - pointer_t return_type; ///< return type of the function - pr_int_t num_params; ///< ones compliment count of the - ///< parameters. -ve values indicate the - ///< number of real parameters before the - ///< ellipsis - pointer_t param_types[1]; ///< variable length list of parameter - ///< types -} qfot_func_t; - -typedef struct qfot_var_s { - pointer_t type; ///< type of field or self reference for - ///< enum - string_t name; ///< name of field/enumerator - pr_int_t offset; ///< value for enum, 0 for union -} qfot_var_t; - -typedef struct qfot_struct_s { - string_t tag; ///< struct/union/enum tag - pr_int_t num_fields; ///< number of fields/enumerators - qfot_var_t fields[1]; ///< variable length list of - ///< fields/enumerators -} qfot_struct_t; - -typedef struct qfot_array_s { - pointer_t type; ///< element type - pr_int_t base; ///< start index of array - pr_int_t size; ///< number of elements in array -} qfot_array_t; - -/** QFO type encoding. - - \note As this holds a union of all type representations, and those - representations may contain variable arrays, sizeof() will return only - one, rather useless, value. It is also not suitable for direct use in - arrays. -*/ -typedef struct qfot_type_s { - pr_int_t ty; ///< meta type: ty_meta_e - pr_int_t size; ///< total word size of this encoding - string_t encoding; ///< Objective-QC encoding - union { - pr_int_t type; ///< basic type: etype_t - qfot_fldptr_t fldptr; ///< ty_none, ev_pointer/ev_field - qfot_func_t func; ///< ty_none, ev_func - qfot_struct_t strct; ///< ty_struct/ty_union/ty_enum - qfot_array_t array; ///< ty_array - pointer_t class; ///< ty_class - } t; -} qfot_type_t; - -typedef struct qfot_type_encodings_s { - pointer_t types; - pr_int_t size; -} qfot_type_encodings_t; - +struct defspace_s; struct type_s; -struct def_s *qfo_encode_type (struct type_s *type); - -//@} +struct def_s *qfo_encode_type (struct type_s *type, struct defspace_s *space); #endif//__obj_type_h diff --git a/tools/qfcc/include/options.h b/tools/qfcc/include/options.h index 4377dab97..580f97370 100644 --- a/tools/qfcc/include/options.h +++ b/tools/qfcc/include/options.h @@ -45,6 +45,8 @@ typedef struct { unsigned progsversion; // Progs version to generate code for qboolean vector_components; // add *_[xyz] symbols for vectors qboolean ifstring; // expand if (str) to if (str != "") + qboolean const_initializers; // initialied globals are constant + qboolean promote_float; // promote float through ... } code_options_t; typedef struct { @@ -70,6 +72,11 @@ typedef struct { qboolean silent; // don't even bother (overrides promote) } notice_options_t; +typedef struct { + qboolean promote; // Promote bugs to internal errors + qboolean silent; // don't even bother (overrides promote) +} bug_options_t; + typedef struct { qboolean initial; qboolean thread; @@ -77,6 +84,7 @@ typedef struct { qboolean final; qboolean dags; qboolean expr; + qboolean statements; qboolean reaching; qboolean live; qboolean flow; @@ -87,6 +95,7 @@ typedef struct { code_options_t code; // Code generation options warn_options_t warnings; // Warning options notice_options_t notices; // Notice options + bug_options_t bug; // Bug options blockdot_options_t block_dot; // Statement block flow diagrams int verbosity; // 0=silent, goes up to 2 currently @@ -105,8 +114,6 @@ typedef struct { qboolean partial_link; // partial linking qboolean preprocess_only;// run only cpp, don't compile qboolean gzip; // compress qfo files when writing - int strip_path; // number of leading path elements to strip - // from source file names const char *output_file; const char *debug_file; } options_t; diff --git a/tools/qfcc/include/pragma.h b/tools/qfcc/include/pragma.h index 1f6726f28..2fad5a357 100644 --- a/tools/qfcc/include/pragma.h +++ b/tools/qfcc/include/pragma.h @@ -33,10 +33,11 @@ /** \defgroup qfcc_pragma pragma handling \ingroup qfcc */ -//@{ +///@{ -void pragma (const char *id); +void pragma_process (void); +void pragma_add_arg (const char *id); -//@} +///@} #endif//pragma_h diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 3aa464185..9d552ab3e 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -34,12 +34,13 @@ */ #include +#include "QF/darray.h" #include "QF/pr_comp.h" /** \defgroup qfcc_general General functions \ingroup qfcc */ -//@{ +///@{ typedef struct srcline_s srcline_t; struct srcline_s { @@ -68,6 +69,11 @@ typedef struct pr_info_s { struct defspace_s *entity_data; ///< entity field address space. no ///< data is stored in the progs file struct defspace_s *type_data; ///< encoded type information. + struct defspace_s *debug_data; ///< additional debug data. + struct strpool_s *comp_file_set; + struct DARRAY_TYPE (const char *) comp_files; + const char *comp_dir; + const char *unit_name; struct symtab_s *symtab; struct symtab_s *entity_fields; @@ -92,10 +98,11 @@ extern pr_info_t pr; #define GETSTR(s) (pr.strings->strings + (s)) #define D_var(t, d) ((d)->space->data[(d)->offset].t##_var) +#define D_DOUBLE(d) (*(double *) ((d)->space->data + (d)->offset)) #define D_FLOAT(d) D_var (float, d) #define D_INT(d) D_var (integer, d) -#define D_VECTOR(d) D_var (vector, d) -#define D_QUAT(d) D_var (quat, d) +#define D_VECTOR(d) (&D_var (vector, d)) +#define D_QUAT(d) (&D_var (quat, d)) #define D_STRING(d) D_var (string, d) #define D_GETSTR(d) GETSTR (D_STRING (d)) #define D_FUNCTION(d) D_var (func, d) @@ -107,7 +114,7 @@ extern pr_info_t pr; #define POINTER_OFS(s,p) ((pr_type_t *) (p) - (s)->data) -const char *strip_path (const char *filename); +const char *file_basename (const char *filename, int keepdot) __attribute__((pure)); extern FILE *qc_yyin; extern FILE *qp_yyin; @@ -132,6 +139,6 @@ char *fix_backslash (char *path); */ #define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1)) -//@} +///@} #endif//__qfcc_h diff --git a/tools/qfcc/include/qfprogs.h b/tools/qfcc/include/qfprogs.h index 09fade09d..731a61194 100644 --- a/tools/qfcc/include/qfprogs.h +++ b/tools/qfcc/include/qfprogs.h @@ -55,8 +55,11 @@ struct dfunction_s *func_find (int st_num); void dump_strings (struct progs_s *pr); void qfo_globals (struct qfo_s *qfo); +void qfo_fields (struct qfo_s *qfo); void qfo_functions (struct qfo_s *qfo); +void qfo_lines (struct qfo_s *qfo); void qfo_relocs (struct qfo_s *qfo); +void qfo_strings (struct qfo_s *qfo); void qfo_types (struct qfo_s *qfo); #endif//__qfprogs_h diff --git a/tools/qfcc/include/reloc.h b/tools/qfcc/include/reloc.h index 2272dab5d..dc6e802c8 100644 --- a/tools/qfcc/include/reloc.h +++ b/tools/qfcc/include/reloc.h @@ -68,7 +68,7 @@ typedef enum { */ typedef struct reloc_s { struct reloc_s *next; ///< next reloc in reloc chain - struct ex_label_s *label; ///< instruction label for *_op relocs + const struct ex_label_s *label; ///< instruction label for *_op relocs struct defspace_s *space; ///< the space containing the location in ///< need of adjustment for def_* relocations ///< (op_* relocations always use the code @@ -78,7 +78,7 @@ typedef struct reloc_s { reloc_type type; ///< type type of relocation to perform int line; ///< current source line when creating reloc string_t file; ///< current source file when creating reloc - void *return_address; ///< for debugging + const void *return_address; ///< for debugging } reloc_t; struct statement_s; @@ -147,7 +147,7 @@ void reloc_op_def_ofs (struct def_s *def, int offset, int field); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_def (struct def_s *def, struct def_s *location); +void reloc_def_def (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a def. @@ -162,7 +162,7 @@ void reloc_def_def (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_def_ofs (struct def_s *def, struct def_s *location); +void reloc_def_def_ofs (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a function. @@ -177,7 +177,7 @@ void reloc_def_def_ofs (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_func (struct function_s *func, struct def_s *location); +void reloc_def_func (struct function_s *func, const struct def_s *location); /** Create a relocation record for a data location referencing a string. @@ -191,7 +191,7 @@ void reloc_def_func (struct function_s *func, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_string (struct def_s *location); +void reloc_def_string (const struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -206,7 +206,7 @@ void reloc_def_string (struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_field (struct def_s *def, struct def_s *location); +void reloc_def_field (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -221,7 +221,7 @@ void reloc_def_field (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_field_ofs (struct def_s *def, struct def_s *location); +void reloc_def_field_ofs (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing an instruction. @@ -237,7 +237,8 @@ void reloc_def_field_ofs (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_op (struct ex_label_s *label, struct def_s *location); +void reloc_def_op (const struct ex_label_s *label, + const struct def_s *location); void reloc_attach_relocs (reloc_t *relocs, reloc_t **location); diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index 75be49d79..829723729 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -38,23 +38,28 @@ typedef enum { op_label, op_temp, op_alias, + op_nil, } op_type_e; -typedef struct { +typedef struct tempop_s { struct def_s *def; + int offset; struct type_s *type; struct flowvar_s *flowvar; struct daglabel_s *daglabel; struct operand_s *alias; struct operand_s *alias_ops; int users; + int flowaddr; ///< "address" of temp in flow analysis, != 0 } tempop_t; typedef struct operand_s { struct operand_s *next; op_type_e op_type; - etype_t type; ///< possibly override def's type + struct type_s *type; ///< possibly override def's/nil's type int size; ///< for structures + struct expr_s *expr; ///< expression generating this operand + void *return_addr; ///< who created this operand union { struct def_s *def; struct ex_value_s *value; @@ -68,17 +73,20 @@ typedef struct operand_s { Statement types are broken down into expressions (binary and unary, includes address and pointer dereferencing (read)), assignment, pointer - assignment (write to dereference pointer), move (special case of pointer - assignment), state, function related (call, rcall, return and done), and - flow control (conditional branches, goto, jump (single pointer and jump - table)). + assignment (write to dereference pointer), move (special case of + assignment), pointer move (special case of pointer assignment), state, + function related (call, rcall, return and done), and flow control + (conditional branches, goto, jump (single pointer and jump table)). */ typedef enum { st_none, ///< not a (valid) statement. Used in dags. st_expr, ///< c = a op b; or c = op a; st_assign, ///< b = a st_ptrassign, ///< *b = a; or *(b + c) = a; - st_move, ///< memcpy (c, a, b); + st_move, ///< memcpy (c, a, b); c and a are direct def references + st_ptrmove, ///< memcpy (c, a, b); c and a are pointers + st_memset, ///< memset (c, a, b); c is direct def reference + st_ptrmemset, ///< memset (c, a, b); c is pointer st_state, ///< state (a, b); or state (a, b, c) st_func, ///< call, rcall or return/done st_flow, ///< if/ifa/ifae/ifb/ifbe/ifnot or goto or jump/jumpb @@ -111,28 +119,40 @@ struct expr_s; struct type_s; struct dstring_s; -const char *optype_str (op_type_e type); +extern const char *op_type_names[]; +extern const char *st_type_names[]; -operand_t *def_operand (struct def_s *def, struct type_s *type); -operand_t *value_operand (struct ex_value_s *value); -operand_t *temp_operand (struct type_s *type); -operand_t *alias_operand (etype_t type, operand_t *op); +const char *optype_str (op_type_e type) __attribute__((const)); + +operand_t *nil_operand (struct type_s *type, struct expr_s *expr); +operand_t *def_operand (struct def_s *def, struct type_s *type, + struct expr_s *expr); +operand_t *return_operand (struct type_s *type, struct expr_s *expr); +operand_t *value_operand (struct ex_value_s *value, struct expr_s *expr); +int tempop_overlap (tempop_t *t1, tempop_t *t2) __attribute__((pure)); +operand_t *temp_operand (struct type_s *type, struct expr_s *expr); +int tempop_visit_all (tempop_t *tempop, int overlap, + int (*visit) (tempop_t *, void *), void *data); +operand_t *alias_operand (struct type_s *type, operand_t *op, + struct expr_s *expr); +operand_t *label_operand (struct expr_s *label); void free_operand (operand_t *op); sblock_t *new_sblock (void); statement_t *new_statement (st_type_t type, const char *opcode, struct expr_s *expr); -int statement_is_cond (statement_t *s); -int statement_is_goto (statement_t *s); -int statement_is_jumpb (statement_t *s); -int statement_is_call (statement_t *s); -int statement_is_return (statement_t *s); -sblock_t *statement_get_target (statement_t *s); +int statement_is_cond (statement_t *s) __attribute__((pure)); +int statement_is_goto (statement_t *s) __attribute__((pure)); +int statement_is_jumpb (statement_t *s) __attribute__((pure)); +int statement_is_call (statement_t *s) __attribute__((pure)); +int statement_is_return (statement_t *s) __attribute__((pure)); +sblock_t *statement_get_target (statement_t *s) __attribute__((pure)); sblock_t **statement_get_targetlist (statement_t *s); void sblock_add_statement (sblock_t *sblock, statement_t *statement); sblock_t *make_statements (struct expr_s *expr); void statements_count_temps (sblock_t *sblock); +void print_operand (operand_t *op); void print_statement (statement_t *s); void dump_dot_sblock (void *data, const char *fname); void dot_sblock (struct dstring_s *dstr, sblock_t *sblock, int blockno); diff --git a/tools/qfcc/include/strpool.h b/tools/qfcc/include/strpool.h index e6e065cb8..fbb4bc049 100644 --- a/tools/qfcc/include/strpool.h +++ b/tools/qfcc/include/strpool.h @@ -42,6 +42,7 @@ strpool_t *strpool_new (void); strpool_t *strpool_build (const char *strings, int size); void strpool_delete (strpool_t *strpool); int strpool_addstr (strpool_t *strpool, const char *str); +int strpool_findstr (strpool_t *strpool, const char *str); /** Smart strdup. @@ -53,6 +54,8 @@ int strpool_addstr (strpool_t *strpool, const char *str); */ const char *save_string (const char *str); +const char *save_cwd (void); + const char *make_string (char *token, char **end); const char *html_string (const char *str); diff --git a/tools/qfcc/include/struct.h b/tools/qfcc/include/struct.h index 8f50845cf..4438ec600 100644 --- a/tools/qfcc/include/struct.h +++ b/tools/qfcc/include/struct.h @@ -59,6 +59,7 @@ struct symbol_s *make_structure (const char *name, int su, struct_def_t *defs, struct type_s *type); struct def_s * emit_structure (const char *name, int su, struct_def_t *defs, struct type_s *type, void *data, + struct defspace_s *space, enum storage_class_e storage); #endif//__struct_h diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h index 0a89a39e7..7a6904f1a 100644 --- a/tools/qfcc/include/symtab.h +++ b/tools/qfcc/include/symtab.h @@ -39,23 +39,31 @@ enum storage_class_e; /** \defgroup qfcc_symtab Symbol Table Management \ingroup qfcc */ -//@{ +///@{ typedef enum vis_e { vis_public, vis_protected, vis_private, + vis_anonymous, } vis_t; typedef enum { + sy_name, ///< just a name (referent tbd) sy_var, ///< symbol refers to a variable sy_const, ///< symbol refers to a constant sy_type, ///< symbol refers to a type sy_expr, ///< symbol refers to an expression sy_func, ///< symbol refers to a function sy_class, ///< symbol refers to a class + sy_convert, ///< symbol refers to a conversion function } sy_type_e; +typedef struct symconv_s { + struct expr_s *(*conv) (struct symbol_s *symbol, void *data); + void *data; +} symconv_t; + typedef struct symbol_s { struct symbol_s *next; ///< chain of symbols in symbol table struct symtab_s *table; ///< symbol table that owns this symbol @@ -70,6 +78,7 @@ typedef struct symbol_s { struct ex_value_s *value; ///< sy_const struct expr_s *expr; ///< sy_expr struct function_s *func; ///< sy_func + symconv_t convert; ///< sy_convert } s; } symbol_t; @@ -90,9 +99,10 @@ typedef struct symtab_s { symbol_t *symbols; ///< chain of symbols in this table symbol_t **symtail; ///< keep chain in declaration order struct defspace_s *space; ///< storage for vars in scope symtabs + struct class_s *class; ///< owning class if ivar scope } symtab_t; -const char *symtype_str (sy_type_e type); +const char *symtype_str (sy_type_e type) __attribute__((const)); /** Create a new, empty named symbol. @@ -234,6 +244,6 @@ symtab_t *symtab_flat_copy (symtab_t *symtab, symtab_t *parent); symbol_t *make_symbol (const char *name, struct type_s *type, struct defspace_s *space, enum storage_class_e storage); -//@} +///@} #endif//__symtab_h diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 2020e8a95..686e864e1 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -31,14 +31,14 @@ #ifndef __type_h #define __type_h -#include "QF/pr_comp.h" +#include "QF/pr_type.h" #include "def.h" typedef struct ty_func_s { struct type_s *type; int num_params; - struct type_s *param_types[MAX_PARMS]; + struct type_s **param_types; } ty_func_t; typedef struct ty_fldptr_s { @@ -51,30 +51,30 @@ typedef struct ty_array_s { int size; } ty_array_t; -typedef enum { - ty_none, ///< func/field/pointer or not used - ty_struct, - ty_union, - ty_enum, - ty_array, - ty_class, -} ty_meta_e; +typedef struct ty_alias_s { + struct type_s *aux_type; ///< other aliases stripped + struct type_s *full_type; ///< full alias chain +} ty_alias_t; typedef struct type_s { etype_t type; ///< ev_invalid means structure/array etc const char *name; + int alignment; ///< required alignment for instances /// function/pointer/array/struct types are more complex ty_meta_e meta; union { + // no data for ty_basic when not a func, field or pointer ty_func_t func; ty_fldptr_t fldptr; ty_array_t array; struct symtab_s *symtab; struct class_s *class; + ty_alias_t alias; } t; struct type_s *next; int freeable; int allocated; + int printid; ///< for dot output struct protocollist_s *protos; const char *encoding; ///< Objective-QC encoding struct def_s *type_def; ///< offset of qfo encodoing @@ -83,6 +83,7 @@ typedef struct type_s { typedef struct { type_t *type; struct param_s *params; + struct symbol_s *sym; ///< for dealing with "int id" etc storage_class_t storage; unsigned multi_type:1; unsigned multi_store:1; @@ -98,6 +99,7 @@ typedef struct { extern type_t type_invalid; extern type_t type_void; extern type_t type_string; +extern type_t type_double; extern type_t type_float; extern type_t type_vector; extern type_t type_entity; @@ -117,21 +119,24 @@ extern type_t type_va_list; extern type_t type_param; extern type_t type_zero; extern type_t type_type_encodings; +extern type_t type_xdef; +extern type_t type_xdef_pointer; +extern type_t type_xdefs; extern struct symtab_s *vector_struct; extern struct symtab_s *quaternion_struct; struct dstring_s; -etype_t low_level_type (type_t *type); +etype_t low_level_type (type_t *type) __attribute__((pure)); type_t *new_type (void); void free_type (type_t *type); void chain_type (type_t *type); /** Append a type to the end of a type chain. - The type chain must be made up of only field, pointer, function and array - types, as other types do not have auxiliary type fields. + The type chain must be made up of only field, pointer, function, and + array types, as other types do not have auxiliary type fields. \param type The type chain to which the type will be appended. \param new The type to be appended. May be any type. @@ -145,26 +150,43 @@ type_t *field_type (type_t *aux); type_t *pointer_type (type_t *aux); type_t *array_type (type_t *aux, int size); type_t *based_array_type (type_t *aux, int base, int top); +type_t *alias_type (type_t *type, type_t *alias_chain, const char *name); +const type_t *unalias_type (const type_t *type) __attribute__((pure)); void print_type_str (struct dstring_s *str, const type_t *type); void print_type (const type_t *type); +void dump_dot_type (void *t, const char *filename); const char *encode_params (const type_t *type); void encode_type (struct dstring_s *encoding, const type_t *type); const char *type_get_encoding (const type_t *type); -int is_void (const type_t *type); -int is_enum (const type_t *type); -int is_integral (const type_t *type); -int is_float (const type_t *type); -int is_scalar (const type_t *type); -int is_math (const type_t *type); -int is_pointer (const type_t *type); -int is_struct (const type_t *type); -int is_array (const type_t *type); +int is_void (const type_t *type) __attribute__((pure)); +int is_enum (const type_t *type) __attribute__((pure)); +int is_integer (const type_t *type) __attribute__((pure)); +int is_uinteger (const type_t *type) __attribute__((pure)); +int is_short (const type_t *type) __attribute__((pure)); +int is_integral (const type_t *type) __attribute__((pure)); +int is_double (const type_t *type) __attribute__((pure)); +int is_float (const type_t *type) __attribute__((pure)); +int is_scalar (const type_t *type) __attribute__((pure)); +int is_vector (const type_t *type) __attribute__((pure)); +int is_quaternion (const type_t *type) __attribute__((pure)); +int is_math (const type_t *type) __attribute__((pure)); +int is_pointer (const type_t *type) __attribute__((pure)); +int is_field (const type_t *type) __attribute__((pure)); +int is_entity (const type_t *type) __attribute__((pure)); +int is_struct (const type_t *type) __attribute__((pure)); +int is_array (const type_t *type) __attribute__((pure)); +int is_structural (const type_t *type) __attribute__((pure)); +int is_func (const type_t *type) __attribute__((pure)); +int is_string (const type_t *type) __attribute__((pure)); +int type_compatible (const type_t *dst, const type_t *src) __attribute__((pure)); int type_assignable (const type_t *dst, const type_t *src); -int type_size (const type_t *type); +int type_size (const type_t *type) __attribute__((pure)); void init_types (void); void chain_initial_types (void); void clear_typedefs (void); +extern type_t *ev_types[]; + #endif//__type_h diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 11bee26e6..a2f13dd67 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -34,12 +34,15 @@ /** \defgroup qfcc_value Constant values. \ingroup qfcc_expr */ -//@{ +///@{ +struct def_s; struct ex_value_s; +struct tempop_s; struct type_s; struct ex_value_s *new_string_val (const char *string_val); +struct ex_value_s *new_double_val (double double_val); struct ex_value_s *new_float_val (float float_val); struct ex_value_s *new_vector_val (const float *vector_val); struct ex_value_s *new_entity_val (int entity_val); @@ -47,7 +50,8 @@ struct ex_value_s *new_field_val (int field_val, struct type_s *type, struct def_s *def); struct ex_value_s *new_func_val (int func_val, struct type_s *type); struct ex_value_s *new_pointer_val (int val, struct type_s *type, - struct def_s *def); + struct def_s *def, + struct operand_s *tempop); struct ex_value_s *new_quaternion_val (const float *quaternion_val); struct ex_value_s *new_integer_val (int integer_val); struct ex_value_s *new_uinteger_val (int uinteger_val); @@ -63,6 +67,6 @@ int ReuseString (const char *str); void clear_immediates (void); -//@} +///@} #endif//__value_h diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am deleted file mode 100644 index 58011ea08..000000000 --- a/tools/qfcc/source/Makefile.am +++ /dev/null @@ -1,71 +0,0 @@ -## Process this file with automake to produce Makefile.in -# -# Makefile.am -# -# Automake-using build system for QuakeForge -# -# Copyright (C) 2000 Jeff Teunissen -# -# This Makefile 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: -# -# Free Software Foundation, Inc. -# 59 Temple Place - Suite 330 -# Boston, MA 02111-1307, USA -# -# $Id$ -# -AUTOMAKE_OPTIONS= foreign - -QFCC_LIBS=@QFCC_LIBS@ -QFCC_DEPS=@QFCC_DEPS@ -QFCC_INCS=@QFCC_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFCC_INCS) -YFLAGS = -v -d - -bin_PROGRAMS= qfcc qfprogs -bin_SCRIPTS= qfpreqcc - -common_src=\ - class.c codespace.c constfold.c cpp.c dags.c debug.c def.c defspace.c \ - diagnostic.c dot.c dot_dag.c dot_expr.c dot_flow.c dot_sblock.c emit.c \ - expr.c expr_binary.c flow.c function.c grab.c idstuff.c linker.c method.c \ - obj_file.c \ - obj_type.c opcodes.c options.c pragma.c qfcc.c reloc.c shared.c \ - statements.c strpool.c struct.c switch.c symtab.c type.c value.c - -qfcc_SOURCES= qc-lex.l qc-parse.y qp-lex.l qp-parse.y $(common_src) -qfcc_LDADD= $(QFCC_LIBS) -qfcc_DEPENDENCIES= $(QFCC_DEPS) - -qfprogs_SOURCES= \ - disassemble.c dump_globals.c dump_lines.c dump_modules.c dump_strings.c \ - obj_file.c qfprogs.c strpool.c stub.c -qfprogs_LDADD= $(QFCC_LIBS) -qfprogs_DEPENDENCIES= $(QFCC_DEPS) - -BUILT_SOURCES=qc-parse.c qc-parse.h qc-lex.c qp-parse.c qp-parse.h qp-lex.c - -qc-parse.c: qc-parse.y - $(YACC) $(YFLAGS) -Dapi.prefix=qc_yy $< -o $@ -qc-lex.c: qc-lex.l - $(LEX) $(LFLAGS) $(AM_LFLAGS) -Pqc_yy -o$@ $< -qp-parse.c: qp-parse.y - $(YACC) $(YFLAGS) -Dapi.prefix=qp_yy $< -o $@ -qp-lex.c: qp-lex.l - $(LEX) $(LFLAGS) $(AM_LFLAGS) -Pqp_yy -o$@ $< - -EXTRA_DIST=qc-lex.c qc-parse.c qc-parse.h qfpreqcc \ - qp-parse.c qp-parse.h qp-lex.c diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am new file mode 100644 index 000000000..dacfd3448 --- /dev/null +++ b/tools/qfcc/source/Makemodule.am @@ -0,0 +1,92 @@ +QFCC_LIBS=@QFCC_LIBS@ +QFCC_DEPS=@QFCC_DEPS@ +QFCC_INCS=@QFCC_INCS@ + +bin_PROGRAMS += qfcc qfprogs +bin_SCRIPTS += tools/qfcc/source/qfpreqcc + +qfcc_SOURCES = \ + tools/qfcc/source/class.c \ + tools/qfcc/source/codespace.c \ + tools/qfcc/source/constfold.c \ + tools/qfcc/source/cpp.c \ + tools/qfcc/source/dags.c \ + tools/qfcc/source/debug.c \ + tools/qfcc/source/def.c \ + tools/qfcc/source/defspace.c \ + tools/qfcc/source/diagnostic.c \ + tools/qfcc/source/dot.c \ + tools/qfcc/source/dot_dag.c \ + tools/qfcc/source/dot_expr.c \ + tools/qfcc/source/dot_flow.c \ + tools/qfcc/source/dot_sblock.c \ + tools/qfcc/source/dot_type.c \ + tools/qfcc/source/emit.c \ + tools/qfcc/source/expr.c \ + tools/qfcc/source/expr_assign.c \ + tools/qfcc/source/expr_binary.c \ + tools/qfcc/source/expr_bool.c \ + tools/qfcc/source/expr_compound.c \ + tools/qfcc/source/expr_obj.c \ + tools/qfcc/source/flow.c \ + tools/qfcc/source/function.c \ + tools/qfcc/source/grab.c \ + tools/qfcc/source/idstuff.c \ + tools/qfcc/source/linker.c \ + tools/qfcc/source/method.c \ + tools/qfcc/source/obj_file.c \ + tools/qfcc/source/obj_type.c \ + tools/qfcc/source/opcodes.c \ + tools/qfcc/source/options.c \ + tools/qfcc/source/pragma.c \ + tools/qfcc/source/qc-lex.l \ + tools/qfcc/source/qc-parse.y \ + tools/qfcc/source/qfcc.c \ + tools/qfcc/source/qp-lex.l \ + tools/qfcc/source/qp-parse.y \ + tools/qfcc/source/reloc.c \ + tools/qfcc/source/shared.c \ + tools/qfcc/source/statements.c \ + tools/qfcc/source/strpool.c \ + tools/qfcc/source/struct.c \ + tools/qfcc/source/switch.c \ + tools/qfcc/source/symtab.c \ + tools/qfcc/source/type.c \ + tools/qfcc/source/value.c + +qfcc_LDADD= $(QFCC_LIBS) +qfcc_DEPENDENCIES= $(QFCC_DEPS) + +qfprogs_SOURCES= \ + tools/qfcc/source/disassemble.c \ + tools/qfcc/source/dump_globals.c \ + tools/qfcc/source/dump_lines.c \ + tools/qfcc/source/dump_modules.c \ + tools/qfcc/source/dump_strings.c \ + tools/qfcc/source/obj_file.c \ + tools/qfcc/source/qfprogs.c \ + tools/qfcc/source/strpool.c \ + tools/qfcc/source/stub.c \ + tools/qfcc/source/type.c +qfprogs_LDADD= $(QFCC_LIBS) +qfprogs_DEPENDENCIES= $(QFCC_DEPS) + +BUILT_SOURCES += \ + tools/qfcc/source/qc-parse.c \ + tools/qfcc/source/qc-parse.h \ + tools/qfcc/source/qc-lex.c \ + tools/qfcc/source/qp-parse.c \ + tools/qfcc/source/qp-parse.h \ + tools/qfcc/source/qp-lex.c + +tools/qfcc/source/qc-parse.c: tools/qfcc/source/qc-parse.y + $(AM_V_YACC)$(YACCCOMPILE) -Dapi.prefix={qc_yy} $< -o $@ +tools/qfcc/source/qc-lex.c: tools/qfcc/source/qc-lex.l tools/qfcc/source/qc-parse.h + $(AM_V_LEX)$(LEXCOMPILE) -Pqc_yy -o$@ $< +tools/qfcc/source/qp-parse.c: tools/qfcc/source/qp-parse.y + $(AM_V_YACC)$(YACCCOMPILE) -Dapi.prefix={qp_yy} $< -o $@ +tools/qfcc/source/qp-lex.c: tools/qfcc/source/qp-lex.l tools/qfcc/source/qp-parse.h + $(AM_V_LEX)$(LEXCOMPILE) -Pqp_yy -o$@ $< + +EXTRA_DIST += \ + tools/qfcc/source/qfpreqcc diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index a7898e5db..ddef199fa 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -44,52 +44,59 @@ #include "QF/pr_obj.h" #include "QF/va.h" -#include "qfcc.h" +#include "tools/qfcc/include/qfcc.h" -#include "codespace.h" -#include "class.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "method.h" -#include "options.h" -#include "reloc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static hashtab_t *class_hash; static hashtab_t *category_hash; static hashtab_t *protocol_hash; +static hashtab_t *static_instances; +static hashtab_t *static_instance_classes; // these will be built up further -type_t type_obj_selector = { ev_invalid, 0, ty_struct}; -type_t type_SEL = { ev_pointer, "SEL", ty_none, {{&type_obj_selector}}}; -type_t type_IMP = { ev_func, "IMP", ty_none, - {{&type_id, -3, {&type_id, &type_SEL}}}}; -type_t type_obj_super = { ev_invalid, 0 }; -type_t type_SuperPtr = { ev_pointer, 0, ty_none, {{&type_obj_super}}}; -type_t type_supermsg = { ev_func, ".supermsg", ty_none, - {{&type_id, -3, {&type_SuperPtr, &type_SEL}}}}; -type_t type_obj_method = { ev_invalid, 0, ty_struct }; -type_t type_obj_method_description = { ev_invalid, 0, ty_struct }; -type_t type_obj_category = { ev_invalid, 0, ty_struct}; -type_t type_obj_ivar = { ev_invalid, 0, ty_struct}; -type_t type_obj_module = { ev_invalid, 0, ty_struct}; -type_t type_moduleptr = { ev_pointer, 0, ty_none, {{&type_obj_module}}}; -type_t type_obj_exec_class = { ev_func, 0, ty_none, - {{&type_void, 1, { &type_moduleptr }}}}; - -type_t type_obj_object = {ev_invalid, 0, ty_struct}; -type_t type_id = { ev_pointer, "id", ty_none, {{&type_obj_object}}}; -type_t type_obj_class = { ev_invalid, 0, ty_struct}; -type_t type_Class = { ev_pointer, 0, ty_none, {{&type_obj_class}}}; -type_t type_obj_protocol = { ev_invalid, 0, ty_struct}; +type_t type_selector = { ev_invalid, 0, 0, ty_struct}; +type_t type_SEL = { ev_pointer, "SEL", 1, ty_basic, {{&type_selector}}}; +type_t *IMP_params[] = {&type_id, &type_SEL}; +type_t type_IMP = { ev_func, "IMP", 1, ty_basic, + {{&type_id, -3, IMP_params}}}; +type_t type_super = { ev_invalid, 0, 0 }; +type_t type_SuperPtr = { ev_pointer, 0, 1, ty_basic, {{&type_super}}}; +type_t *supermsg_params[] = {&type_SuperPtr, &type_SEL}; +type_t type_supermsg = { ev_func, ".supermsg", 1, ty_basic, + {{&type_id, -3, supermsg_params}}}; +type_t type_method = { ev_invalid, 0, 0, ty_struct }; +type_t type_method_description = { ev_invalid, 0, 0, ty_struct }; +type_t type_category = { ev_invalid, 0, 0, ty_struct}; +type_t type_ivar = { ev_invalid, 0, 0, ty_struct}; +type_t type_module = { ev_invalid, 0, 0, ty_struct}; +type_t type_moduleptr = { ev_pointer, 0, 1, ty_basic, {{&type_module}}}; +type_t *obj_exec_class_params[] = { &type_moduleptr }; +type_t type_exec_class = { ev_func, 0, 1, ty_basic, + {{&type_void, 1, obj_exec_class_params}}}; +// the cast of 1 in the init is to ensure pointers to incomplete types +// are never misidentified as id. It will be set to the correct value +// when the obj system is initialized. +type_t type_object = {ev_invalid, 0, 0, ty_struct, {{(type_t *)1}}}; +type_t type_id = { ev_pointer, "id", 1, ty_basic, {{&type_object}}}; +type_t type_class = { ev_invalid, 0, 0, ty_struct}; +type_t type_Class = { ev_pointer, 0, 1, ty_basic, {{&type_class}}}; +type_t type_protocol = { ev_invalid, 0, 0, ty_struct}; int obj_initialized = 0; @@ -173,8 +180,145 @@ static struct_def_t object_struct[] = { {0, 0} }; +static const char * +static_instance_get_key (const void *instance, void *unused) +{ + return ((static_instance_t *) instance)->class; +} + +static void +add_static_instance (const char *class, def_t *instance_def) +{ + static_instance_t *instance = malloc (sizeof (*instance)); + + if (!static_instances) { + static_instances = Hash_NewTable (1021, static_instance_get_key, + 0, 0, 0); + static_instance_classes = Hash_NewTable (1021, static_instance_get_key, + 0, 0, 0); + } + + instance->class = save_string (class); + instance->instance = instance_def; + Hash_Add (static_instances, instance); + + // uniqued set of class names for all static instances + if (!Hash_Find (static_instance_classes, class)) { + Hash_Add (static_instance_classes, instance); + } +} +typedef struct { + const char *class_name; + int num_instances; + static_instance_t **instances; +} obj_static_instances_data_t; + +static void +emit_instance_classname (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (!is_string(def->type)) + internal_error (0, "%s: expected string def", __FUNCTION__); + EMIT_STRING (def->space, D_STRING (def), da->class_name); +} + +static void +emit_instance_defs (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) + internal_error (0, "%s: expected array of pointers def", __FUNCTION__); + if (index < 0 || index >= da->num_instances + 1) + internal_error (0, "%s: out of bounds index: %d %d", + __FUNCTION__, index, da->num_instances + 1); + D_INT (def) = 0; + if (index < da->num_instances) { + EMIT_DEF (def->space, D_INT (def), da->instances[index]->instance); + } +} + +static def_t * +emit_static_instances (const char *classname) +{ + static struct_def_t instances_struct[] = { + {"class_name", &type_string, emit_instance_classname}, + {"instances", 0, emit_instance_defs}, + {0, 0} + }; + obj_static_instances_data_t data = {}; + def_t *instances_def; + + data.class_name = classname; + data.instances = (static_instance_t **) Hash_FindList (static_instances, + classname); + for (static_instance_t **inst = data.instances; *inst; inst++) { + data.num_instances++; + } + instances_struct[1].type = array_type (&type_pointer, + data.num_instances + 1); + instances_def = emit_structure (va (0, "_OBJ_STATIC_INSTANCES_%s", + classname), + 's', instances_struct, 0, &data, + 0, sc_static); + free (data.instances); + return instances_def; +} + +static def_t * +emit_static_instances_list (void) +{ + static_instance_t **classes; + int num_classes = 0; + def_t **instance_lists; + type_t *instance_lists_type; + symbol_t *instance_lists_sym; + def_t *instance_lists_def; + pointer_t *list; + defspace_t *space; + + if (!static_instance_classes || !static_instances) { + return 0; + } + + classes = (static_instance_t **) Hash_GetList (static_instance_classes); + for (static_instance_t **c = classes; *c; c++) { + num_classes++; + } + if (!num_classes) { + free (classes); + return 0; + } + instance_lists = alloca (num_classes * sizeof (*instance_lists)); + for (int i = 0; i < num_classes; i++) { + instance_lists[i] = emit_static_instances (classes[i]->class); + } + free (classes); + + // +1 for terminating null + instance_lists_type = array_type (&type_pointer, num_classes + 1); + instance_lists_sym = make_symbol ("_OBJ_STATIC_INSTANCES", + instance_lists_type, + pr.far_data, sc_static); + if (!instance_lists_sym->table) { + symtab_addsymbol (pr.symtab, instance_lists_sym); + } + instance_lists_def = instance_lists_sym->s.def; + instance_lists_def->initialized = instance_lists_def->constant = 1; + instance_lists_def->nosave = 1; + + list = D_POINTER (pointer_t, instance_lists_def); + space = instance_lists_def->space; + for (int i = 0; i < num_classes; i++, list++) { + EMIT_DEF (space, *list, instance_lists[i]); + } + *list = 0; + return instance_lists_def; +} + int -obj_is_id (const type_t *type) +is_id (const type_t *type) { if (type == &type_id) return 1; @@ -185,13 +329,13 @@ obj_is_id (const type_t *type) if (!is_struct (type->t.fldptr.type)) return 0; // if the the symtabs match, then type is id in disguise - if (type->t.fldptr.type->t.symtab == type_obj_object.t.symtab) + if (type->t.fldptr.type->t.symtab == type_object.t.symtab) return 1; return 0; } int -obj_is_class (const type_t *type) +is_class (const type_t *type) { if (type->type == ev_invalid && type->meta == ty_class) return 1; @@ -199,42 +343,57 @@ obj_is_class (const type_t *type) } int -obj_is_Class (const type_t *type) +is_Class (const type_t *type) { if (type == &type_Class) return 1; - // type may be a qualified Class, in which case it will be a pointer to - // a qualified obj_class struct - if (type->type != ev_pointer) - return 0; - if (!is_struct (type->t.fldptr.type)) - return 0; - // if the the symtabs match, then type is Class in disguise - if (type->t.fldptr.type->t.symtab == type_obj_class.t.symtab) - return 1; return 0; } int -obj_is_classptr (const type_t *type) +is_classptr (const type_t *type) { // easy cases first :) - if (obj_is_id (type) || obj_is_Class (type)) + if (is_id (type) || is_Class (type)) return 1; if (type->type != ev_pointer) return 0; type = type->t.fldptr.type; - if (obj_is_class (type)) + if (is_class (type)) return 1; return 0; } +int +is_SEL (const type_t *type) +{ + return type == &type_SEL; +} + +int +is_object (const type_t *type) +{ + return type == &type_object; +} + +int +is_method (const type_t *type) +{ + return type == &type_method; +} + +int +is_method_description (const type_t *type) +{ + return type == &type_method_description; +} + static protocollist_t * obj_get_class_protos (const type_t *type) { if (is_pointer (type)) type = type->t.fldptr.type; - if (obj_is_class (type)) + if (is_class (type)) return type->t.class->protocols; return 0; } @@ -252,7 +411,7 @@ obj_get_categories (const type_t *type) { if (is_pointer (type)) type = type->t.fldptr.type; - if (obj_is_class (type)) + if (is_class (type)) return type->t.class->categories; return 0; } @@ -266,14 +425,14 @@ obj_classname (const type_t *type) if (!str) str = dstring_new (); dstring_clearstr (str); - if (obj_is_id (type)) { + if (is_id (type)) { dstring_copystr (str, "id"); - } else if (obj_is_Class (type)) { + } else if (is_Class (type)) { dstring_copystr (str, "Class"); } else { if (is_pointer (type)) type = type->t.fldptr.type; - if (obj_is_class (type)) + if (is_class (type)) dstring_copystr (str, type->t.class->name); } if ((protos = obj_get_protos (type))) @@ -281,7 +440,7 @@ obj_classname (const type_t *type) return str->str; } -static int +static __attribute__((pure)) int category_implements (category_t *cat, protocol_t *protocol) { for (; cat; cat = cat->next) { @@ -303,11 +462,17 @@ obj_types_assignable (const type_t *dst, const type_t *src) int i; //puts ("%$$\"$#%"); - if (!obj_is_classptr (dst) || !obj_is_classptr (src)) + if (!is_classptr (src)) { + // if dst is a class pointer, then the types are not compatible, + // otherwise unknown + return is_classptr (dst) - 1; + } + if (!is_classptr (dst)) { return -1; + } - dst_is_proto = obj_is_id (dst) && (dst_protos = obj_get_protos (dst)); - src_is_proto = obj_is_id (src) && (src_protos = obj_get_protos (src)); + dst_is_proto = is_id (dst) && (dst_protos = obj_get_protos (dst)); + src_is_proto = is_id (src) && (src_protos = obj_get_protos (src)); if (dst_is_proto) { if (src_is_proto) { @@ -320,7 +485,7 @@ obj_types_assignable (const type_t *dst, const type_t *src) return 1; } } - } else if (!obj_is_id (src)) { + } else if (!is_id (src)) { src_protos = obj_get_class_protos (src); for (i = 0; i < dst_protos->count; i++) { if (procollist_find_protocol (src_protos, dst_protos->list[i])) @@ -337,7 +502,7 @@ obj_types_assignable (const type_t *dst, const type_t *src) } else if (src_is_proto) { } else { } - if (obj_is_id (dst) || obj_is_id (src)) + if (is_id (dst) || is_id (src)) return 1; // check dst is a base class of src @@ -374,16 +539,16 @@ get_class_name (class_type_t *class_type, int pretty) if (pretty) return class_type->c.class->name; else - return va ("%s_", class_type->c.class->name); + return va (0, "%s_", class_type->c.class->name); case ct_category: if (pretty) - return va ("%s (%s)", class_type->c.category->class->name, + return va (0, "%s (%s)", class_type->c.category->class->name, class_type->c.category->name); else - return va ("%s_%s", class_type->c.category->class->name, + return va (0, "%s_%s", class_type->c.category->class->name, class_type->c.category->name); case ct_protocol: - return va ("<%s>", class_type->c.protocol->name); + return va (0, "<%s>", class_type->c.protocol->name); } return "???"; } @@ -397,14 +562,14 @@ class_symbol (class_type_t *class_type, int external) switch (class_type->type) { case ct_category: - name = va ("_OBJ_CATEGORY_%s_%s", + name = va (0, "_OBJ_CATEGORY_%s_%s", class_type->c.category->class->name, class_type->c.category->name); - type = &type_obj_category; + type = &type_category; break; case ct_class: - name = va ("_OBJ_CLASS_%s", class_type->c.class->name); - type = &type_obj_class; + name = va (0, "_OBJ_CLASS_%s", class_type->c.class->name); + type = &type_class; break; case ct_protocol: return 0; // probably in error recovery @@ -422,7 +587,7 @@ _get_class (symbol_t *sym, int create) class_t *c; if (!class_hash) - class_hash = Hash_NewTable (1021, class_get_key, 0, 0); + class_hash = Hash_NewTable (1021, class_get_key, 0, 0, 0); if (sym) { c = Hash_Find (class_hash, sym->name); if (c || !create) @@ -489,9 +654,7 @@ class_add_methods (class_t *class, methodlist_t *methods) if (!methods) return; - *class->methods->tail = methods->head; - class->methods->tail = methods->tail; - free (methods); + merge_method_lists (class->methods, methods); methods_set_self_type (class, class->methods); } @@ -502,15 +665,26 @@ class_add_protocols (class_t *class, protocollist_t *protocols) int i; protocol_t *p; methodlist_t *methods; + methodset_t *except; + class_t *super; if (!protocols) return; methods = class->methods; + except = new_methodset (); + for (super = class->super_class; super; super = super->super_class) { + methodset_add_methods (except, super->methods); + } + for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; - copy_methods (methods, p->methods); + if (p->methods) { + copy_methods (methods, p->methods, except); + } else { + warning (0, "definition of protocol `%s' not found", p->name); + } if (p->protocols) class_add_protocols (class, p->protocols); } @@ -537,7 +711,8 @@ begin_category (category_t *category) EMIT_STRING (space, pr_category->class_name, class->name); EMIT_DEF (space, pr_category->protocols, emit_protocol_list (category->protocols, - va ("%s_%s", class->name, category->name))); + va (0, "%s_%s", class->name, + category->name))); } typedef struct { @@ -551,7 +726,7 @@ emit_ivar_count (def_t *def, void *data, int index) { ivar_data_t *ivar_data = (ivar_data_t *) data; - if (def->type != &type_integer) + if (!is_integer(def->type)) internal_error (0, "%s: expected integer def", __FUNCTION__); D_INT (def) = ivar_data->count; } @@ -565,7 +740,7 @@ emit_ivar_list_item (def_t *def, void *data, int index) defspace_t *space; #if 0 - //FIXME the type is dynamic, so need a way to pass it before it cn be + //FIXME the type is dynamic, so need a way to pass it before it can be //checked if (def->type != &XXX) internal_error (0, "%s: expected XXX def", @@ -611,10 +786,10 @@ emit_ivars (symtab_t *ivars, const char *name) if (s->sy_type == sy_var) ivar_data.count++; } - ivar_list_struct[1].type = array_type (&type_obj_ivar, ivar_data.count); + ivar_list_struct[1].type = array_type (&type_ivar, ivar_data.count); - def = emit_structure (va ("_OBJ_INSTANCE_VARIABLES_%s", name), 's', - ivar_list_struct, 0, &ivar_data, sc_static); + def = emit_structure (va (0, "_OBJ_INSTANCE_VARIABLES_%s", name), 's', + ivar_list_struct, 0, &ivar_data, 0, sc_static); dstring_delete (ivar_data.encoding); return def; @@ -630,8 +805,8 @@ begin_class (class_t *class) def_t *def; defspace_t *space; - sym = make_symbol (va ("_OBJ_METACLASS_%s", class->name), - &type_obj_class, pr.far_data, sc_static); + sym = make_symbol (va (0, "_OBJ_METACLASS_%s", class->name), + &type_class, pr.far_data, sc_static); meta_def = sym->s.def; meta_def->initialized = meta_def->constant = meta_def->nosave = 1; space = meta_def->space; @@ -641,13 +816,13 @@ begin_class (class_t *class) EMIT_STRING (space, meta->super_class, class->super_class->name); EMIT_STRING (space, meta->name, class->name); meta->info = _PR_CLS_META; - meta->instance_size = type_size (&type_obj_class); + meta->instance_size = type_size (&type_class); if (!class->super_class) { // The ivars list for the meta class struct get emitted only for the // root class of the hierachy. - // NOTE: type_obj_class is not actually a class + // NOTE: type_class is not actually a class EMIT_DEF (space, meta->ivars, - emit_ivars (type_obj_class.t.symtab, "Class")); + emit_ivars (type_class.t.symtab, "Class")); } else { meta->ivars = 0; } @@ -699,15 +874,15 @@ emit_class_ref (const char *class_name) def_t *ref_def; def_t *name_def; - ref_sym = make_symbol (va (".obj_class_ref_%s", class_name), &type_pointer, - pr.far_data, sc_static); + ref_sym = make_symbol (va (0, ".obj_class_ref_%s", class_name), + &type_pointer, pr.far_data, sc_static); if (!ref_sym->table) symtab_addsymbol (pr.symtab, ref_sym); ref_def = ref_sym->s.def; if (ref_def->initialized) return; ref_def->initialized = ref_def->constant = ref_def->nosave = 1; - name_sym = make_symbol (va (".obj_class_name_%s", class_name), + name_sym = make_symbol (va (0, ".obj_class_name_%s", class_name), &type_pointer, pr.far_data, sc_extern); if (!name_sym->table) symtab_addsymbol (pr.symtab, name_sym); @@ -723,7 +898,7 @@ emit_class_name (const char *class_name) symbol_t *name_sym; def_t *name_def; - name_sym = make_symbol (va (".obj_class_name_%s", class_name), + name_sym = make_symbol (va (0, ".obj_class_name_%s", class_name), &type_pointer, pr.far_data, sc_global); if (!name_sym->table) symtab_addsymbol (pr.symtab, name_sym); @@ -743,9 +918,9 @@ emit_category_ref (const char *class_name, const char *category_name) def_t *ref_def; def_t *name_def; - ref_sym = make_symbol (va (".obj_category_ref_%s_%s", - class_name, category_name), - &type_pointer, pr.far_data, sc_static); + ref_sym = make_symbol (va (0, ".obj_category_ref_%s_%s", + class_name, category_name), + &type_pointer, pr.far_data, sc_static); if (!ref_sym->table) symtab_addsymbol (pr.symtab, ref_sym); ref_def = ref_sym->s.def; @@ -753,9 +928,9 @@ emit_category_ref (const char *class_name, const char *category_name) return; ref_def->initialized = ref_def->constant = 1; ref_def->nosave = 1; - name_sym = make_symbol (va (".obj_category_name_%s_%s", - class_name, category_name), - &type_pointer, pr.far_data, sc_extern); + name_sym = make_symbol (va (0, ".obj_category_name_%s_%s", + class_name, category_name), + &type_pointer, pr.far_data, sc_extern); if (!name_sym->table) symtab_addsymbol (pr.symtab, name_sym); name_def = name_sym->s.def; @@ -770,7 +945,7 @@ emit_category_name (const char *class_name, const char *category_name) symbol_t *name_sym; def_t *name_def; - name_sym = make_symbol (va (".obj_category_name_%s_%s", + name_sym = make_symbol (va (0, ".obj_category_name_%s_%s", class_name, category_name), &type_pointer, pr.far_data, sc_global); if (!name_sym->table) @@ -884,10 +1059,20 @@ class_find_ivar (class_t *class, int vis, const char *name) { symbol_t *ivar; + if (!class->ivars) { + if (!class->interface_declared) { + class->interface_declared = 1; + error (0, "accessing incomplete type %s", class->name); + } + return 0; + } ivar = symtab_lookup (class->ivars, name); if (ivar) { - if (ivar->visibility > (vis_t) vis) + if (ivar->visibility > (vis_t) vis + || (ivar->table->class != class + && ivar->visibility > vis_protected)) { goto access_error; + } return ivar; } error (0, "%s.%s does not exist", class->name, name); @@ -920,7 +1105,7 @@ class_find_method (class_type_t *class_type, method_t *method) start_methods = methods; start_class = class; while (class) { - for (m = methods->head; m; m = m->next) + for (m = methods->head; m; m = m->next) { if (method_compare (method, m)) { if (m->type != method->type) error (0, "method type mismatch"); @@ -932,6 +1117,7 @@ class_find_method (class_type_t *class_type, method_t *method) method_set_param_names (m, method); return m; } + } if (class->methods == methods) class = class->super_class; else @@ -945,48 +1131,86 @@ class_find_method (class_type_t *class_type, method_t *method) return method; } +static method_t * +cls_find_method (methodlist_t *methodlist, selector_t *selector, + int class_msg, int is_root) +{ + method_t *m = 0; + m = methodlist_find_method (methodlist, selector, !class_msg); + if (!m && is_root && class_msg + && (m = methodlist_find_method (methodlist, selector, 1))) { + return m; + } + return m; +} + method_t * -class_message_response (class_t *class, int class_msg, expr_t *sel) +class_message_response (type_t *clstype, int class_msg, expr_t *sel) { selector_t *selector; method_t *m; - class_t *c = class; + class_t *c; + class_t *class = 0; category_t *cat; + dstring_t *dstr; selector = get_selector (sel); if (!selector) return 0; - if (class && class->type != &type_obj_object) { - while (c) { - for (cat = c->categories; cat; cat = cat->next) { - for (m = cat->methods->head; m; m = m->next) { - if (((!c->super_class && class_msg) - || class_msg != m->instance) - && strcmp (selector->name, m->name) == 0) - return m; - } + + if (!is_classptr (clstype) && !is_class (clstype)) { + error (0, "neither class nor object"); + return 0; + } + if (is_id (clstype)) { + protocollist_t *protos = clstype->t.fldptr.type->protos; + if (protos) { + if ((m = protocollist_find_method (protos, selector, !class_msg))) { + return m; } - for (m = c->methods->head; m; m = m->next) { - if (((!c->super_class && class_msg) - || class_msg != m->instance) - && strcmp (selector->name, m->name) == 0) - return m; - } - c = c->super_class; + dstr = dstring_new (); + print_protocollist (dstr, protos); + warning (sel, "id%s may not respond to %c%s", dstr->str, + class_msg ? '+' : '-', selector->name); + dstring_delete (dstr); } - //FIXME right option? - if (options.warnings.interface_check) + } else { + if (is_class (clstype)) { + class = clstype->t.class; + } else if (is_class (clstype->t.fldptr.type)) { + class = clstype->t.fldptr.type->t.class; + } + if (class && !is_object(class->type)) { + if (!class->interface_declared) { + class->interface_declared = 1; + warning (0, "cannot find interface declaration for `%s'", + class->name); + } + c = class; + while (c) { + for (cat = c->categories; cat; cat = cat->next) { + if ((m = cls_find_method (cat->methods, selector, + class_msg, + !c->super_class))) { + return m; + } + } + if ((m = cls_find_method (c->methods, selector, class_msg, + !c->super_class))) { + return m; + } + c = c->super_class; + } warning (sel, "%s may not respond to %c%s", class->name, class_msg ? '+' : '-', selector->name); + } } m = find_method (selector->name); - if (m) - return m; - //FIXME right option? - if (options.warnings.interface_check) + if (!m && (!class || is_object(class->type))) { warning (sel, "could not find method for %c%s", class_msg ? '+' : '-', selector->name); - return 0; + } + return m; } static uintptr_t @@ -1014,6 +1238,7 @@ class_new_ivars (class_t *class) if (class->super_class) super_ivars = class->super_class->ivars; ivars = new_symtab (super_ivars, stab_local); + ivars->class = class; return ivars; } @@ -1074,7 +1299,7 @@ get_category (symbol_t *class_name, const char *category_name, int create) class_t *class; if (!category_hash) { - category_hash = Hash_NewTable (1021, 0, 0, 0); + category_hash = Hash_NewTable (1021, 0, 0, 0, 0); Hash_SetHashCompare (category_hash, category_get_hash, category_compare); } @@ -1109,9 +1334,7 @@ category_add_methods (category_t *category, methodlist_t *methods) { if (!methods) return; - *category->methods->tail = methods->head; - category->methods->tail = methods->tail; - free (methods); + merge_method_lists (category->methods, methods); methods_set_self_type (category->class, category->methods); } @@ -1122,15 +1345,22 @@ category_add_protocols (category_t *category, protocollist_t *protocols) int i; protocol_t *p; methodlist_t *methods; + methodset_t *except; + class_t *class; if (!protocols) return; methods = category->methods; + except = new_methodset (); + for (class = category->class; class; class = class->super_class) { + methodset_add_methods (except, class->methods); + } + for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; - copy_methods (methods, p->methods); + copy_methods (methods, p->methods, except); if (p->protocols) category_add_protocols (category, p->protocols); } @@ -1146,9 +1376,8 @@ class_pointer_symbol (class_t *class) class_type.c.class = class; - sym = make_symbol (va ("_OBJ_CLASS_POINTER_%s", class->name), - &type_Class, - pr.near_data, sc_static); + sym = make_symbol (va (0, "_OBJ_CLASS_POINTER_%s", class->name), + &type_Class, pr.near_data, sc_static); if (!sym->table) symtab_addsymbol (pr.symtab, sym); def = sym->s.def; @@ -1171,6 +1400,7 @@ typedef struct { int cls_def_cnt; category_t **categories; int cat_def_cnt; + def_t *instances_list; } obj_symtab_data_t; static void @@ -1178,7 +1408,7 @@ emit_symtab_ref_cnt (def_t *def, void *data, int index) { obj_symtab_data_t *da = (obj_symtab_data_t *)data; - if (def->type != &type_integer) + if (!is_integer(def->type)) internal_error (0, "%s: expected integer def", __FUNCTION__); D_INT (def) = 0; if (da->refs) @@ -1190,7 +1420,7 @@ emit_symtab_refs (def_t *def, void *data, int index) { obj_symtab_data_t *da = (obj_symtab_data_t *)data; - if (def->type != &type_SEL) + if (!is_SEL(def->type)) internal_error (0, "%s: expected SEL def", __FUNCTION__); D_INT (def) = 0; if (da->refs) @@ -1202,7 +1432,7 @@ emit_symtab_cls_def_cnt (def_t *def, void *data, int index) { obj_symtab_data_t *da = (obj_symtab_data_t *)data; - if (def->type != &type_integer) + if (!is_integer(def->type)) internal_error (0, "%s: expected integer def", __FUNCTION__); D_INT (def) = da->cls_def_cnt; } @@ -1212,7 +1442,7 @@ emit_symtab_cat_def_cnt (def_t *def, void *data, int index) { obj_symtab_data_t *da = (obj_symtab_data_t *)data; - if (def->type != &type_integer) + if (!is_integer(def->type)) internal_error (0, "%s: expected integer def", __FUNCTION__); D_INT (def) = da->cat_def_cnt; } @@ -1224,10 +1454,10 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) internal_error (0, "%s: expected array of pointers def", __FUNCTION__); - if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt) + if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt + 1) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, - da->cls_def_cnt + da->cat_def_cnt); + da->cls_def_cnt + da->cat_def_cnt + 1); if (index < da->cls_def_cnt) { class_t **cl; @@ -1236,7 +1466,7 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*cl)->def); - } else { + } else if (index < da->cls_def_cnt + da->cat_def_cnt) { category_t **ca; index -= da->cls_def_cnt; for (ca = da->categories; *ca; ca++) @@ -1244,6 +1474,11 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*ca)->def); + } else { + D_INT (def) = 0; + if (da->instances_list) { + EMIT_DEF (def->space, D_INT (def), da->instances_list); + } } } @@ -1259,12 +1494,13 @@ class_finish_module (void) {0, 0} }; - obj_symtab_data_t data = {0, 0, 0, 0, 0}; + obj_symtab_data_t data = {}; class_t **cl; category_t **ca; def_t *symtab_def; symbol_t *module_sym; + expr_t *module_expr; pr_module_t *module; symbol_t *exec_class_sym; symbol_t *init_sym; @@ -1284,20 +1520,24 @@ class_finish_module (void) if ((*ca)->def && !(*ca)->def->external) data.cat_def_cnt++; } - if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt) + data.instances_list = emit_static_instances_list (); + if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt + && !data.instances_list) return; symtab_struct[4].type = array_type (&type_pointer, - data.cls_def_cnt + data.cat_def_cnt); + data.cls_def_cnt + + data.cat_def_cnt + + 1); symtab_def = emit_structure ("_OBJ_SYMTAB", 's', symtab_struct, 0, &data, - sc_static); + 0, sc_static); free (data.classes); free (data.categories); - module_sym = make_symbol ("_OBJ_MODULE", &type_obj_module, pr.far_data, + module_sym = make_symbol ("_OBJ_MODULE", &type_module, pr.far_data, sc_static); symtab_addsymbol (current_symtab, module_sym); module = &D_STRUCT (pr_module_t, module_sym->s.def); - module->size = type_size (&type_obj_module); + module->size = type_size (&type_module); EMIT_STRING (module_sym->s.def->space, module->name, GETSTR (pr.source_file)); EMIT_DEF (module_sym->s.def->space, module->symtab, symtab_def); @@ -1305,7 +1545,7 @@ class_finish_module (void) exec_class_sym = symtab_lookup (pr.symtab, "__obj_exec_class"); if (!exec_class_sym) { exec_class_sym = new_symbol_type ("__obj_exec_class", - &type_obj_exec_class); + &type_exec_class); exec_class_sym = function_symbol (exec_class_sym, 0, 1); make_function (exec_class_sym, 0, exec_class_sym->table->space, sc_extern); @@ -1314,17 +1554,17 @@ class_finish_module (void) init_sym = new_symbol_type (".ctor", &type_function); init_sym = function_symbol (init_sym, 0, 1); + module_expr = address_expr (new_symbol_expr (module_sym), 0, 0); + init_expr = new_block_expr (); append_expr (init_expr, - build_function_call (new_symbol_expr (exec_class_sym), - exec_class_sym->type, - address_expr (new_symbol_expr (module_sym), - 0, 0))); + build_function_call (new_symbol_expr (exec_class_sym), + exec_class_sym->type, module_expr)); save_storage = current_storage; current_storage = sc_static; current_func = begin_function (init_sym, 0, current_symtab, 1); - build_code_function (init_sym, 0, init_expr);; + build_code_function (init_sym, 0, init_expr); current_func = 0; current_storage = save_storage; } @@ -1335,7 +1575,7 @@ get_protocol (const char *name, int create) protocol_t *p; if (!protocol_hash) - protocol_hash = Hash_NewTable (1021, protocol_get_key, 0, 0); + protocol_hash = Hash_NewTable (1021, protocol_get_key, 0, 0, 0); if (name) { p = Hash_Find (protocol_hash, name); @@ -1345,7 +1585,7 @@ get_protocol (const char *name, int create) p = calloc (sizeof (protocol_t), 1); p->name = name; - p->methods = new_methodlist (); + p->methods = 0; p->class_type.type = ct_protocol; p->class_type.c.protocol = p; if (name) @@ -1358,9 +1598,7 @@ protocol_add_methods (protocol_t *protocol, methodlist_t *methods) { if (!methods) return; - *protocol->methods->tail = methods->head; - protocol->methods->tail = methods->tail; - free (methods); + merge_method_lists (protocol->methods, methods); } void @@ -1372,8 +1610,11 @@ protocol_add_protocols (protocol_t *protocol, protocollist_t *protocols) def_t * protocol_def (protocol_t *protocol) { - return make_symbol (protocol->name, &type_obj_protocol, - pr.far_data, sc_static)->s.def; + if (!protocol->def) { + protocol->def = emit_protocol (protocol); + add_static_instance ("Protocol", protocol->def); + } + return protocol->def; } protocollist_t * @@ -1397,7 +1638,7 @@ add_protocol (protocollist_t *protocollist, const char *name) } protocollist->count++; protocollist->list = realloc (protocollist->list, - sizeof (protocol_t) * protocollist->count); + sizeof (protocol_t *) * protocollist->count); protocollist->list[protocollist->count - 1] = protocol; return protocollist; } @@ -1414,6 +1655,34 @@ procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto) return 0; } +static method_t * +protocol_find_method (protocol_t *protocol, selector_t *selector, int instance) +{ + method_t *m = 0; + if (protocol->methods) { + m = methodlist_find_method (protocol->methods, selector, instance); + } + if (!m && protocol->protocols) { + return protocollist_find_method (protocol->protocols, selector, + instance); + } + return m; +} + +method_t * +protocollist_find_method (protocollist_t *protocollist, selector_t *selector, + int instance) +{ + method_t *m; + for (int i = 0; i < protocollist->count; i++) { + if ((m = protocol_find_method (protocollist->list[i], selector, + instance))) { + return m; + } + } + return 0; +} + int compare_protocols (protocollist_t *protos1, protocollist_t *protos2) { @@ -1448,8 +1717,8 @@ emit_protocol (protocol_t *protocol) pr_protocol_t *proto; defspace_t *space; - proto_def = make_symbol (va ("_OBJ_PROTOCOL_%s", protocol->name), - &type_obj_protocol, pr.far_data, sc_static)->s.def; + proto_def = make_symbol (va (0, "_OBJ_PROTOCOL_%s", protocol->name), + &type_protocol, pr.far_data, sc_static)->s.def; if (proto_def->initialized) return proto_def; proto_def->initialized = proto_def->constant = 1; @@ -1460,7 +1729,7 @@ emit_protocol (protocol_t *protocol) EMIT_STRING (space, proto->protocol_name, protocol->name); EMIT_DEF (space, proto->protocol_list, emit_protocol_list (protocol->protocols, - va ("PROTOCOL_%s", protocol->name))); + va (0, "PROTOCOL_%s", protocol->name))); EMIT_DEF (space, proto->instance_methods, emit_method_descriptions (protocol->methods, protocol->name, 1)); EMIT_DEF (space, proto->class_methods, @@ -1469,39 +1738,57 @@ emit_protocol (protocol_t *protocol) return proto_def; } +static void +emit_protocol_next (def_t *def, void *data, int index) +{ + if (!is_pointer(def->type)) { + internal_error (0, "%s: expected pointer def", __FUNCTION__); + } + D_INT (def) = 0; +} + +static void +emit_protocol_count (def_t *def, void *data, int index) +{ + protocollist_t *protocols = (protocollist_t *) data; + + if (!is_integer(def->type)) { + internal_error (0, "%s: expected integer def", __FUNCTION__); + } + D_INT (def) = protocols->count; +} + +static void +emit_protocol_list_item (def_t *def, void *data, int index) +{ + protocollist_t *protocols = (protocollist_t *) data; + protocol_t *protocol = protocols->list[index]; + + if (!is_array (def->type) || !is_pointer(def->type->t.array.type)) { + internal_error (0, "%s: expected array of pointer def", __FUNCTION__); + } + if (index < 0 || index >= protocols->count) { + internal_error (0, "%s: out of bounds index: %d %d", + __FUNCTION__, index, protocols->count); + } + EMIT_DEF (def->space, D_INT(def), protocol_def (protocol)); +} + def_t * emit_protocol_list (protocollist_t *protocols, const char *name) { - //FIXME use emit_struct static struct_def_t proto_list_struct[] = { - {"next", &type_pointer}, - {"count", &type_integer}, - {"list", 0}, // type will be filled in at run time + {"next", &type_pointer, emit_protocol_next}, + {"count", &type_integer, emit_protocol_count}, + {"list", 0, emit_protocol_list_item}, {0, 0}, }; - type_t *proto_list_type; - def_t *proto_list_def; - defspace_t *space; - pr_protocol_list_t *proto_list; - int i; if (!protocols) return 0; proto_list_struct[2].type = array_type (&type_pointer, protocols->count); - proto_list_type = make_structure (0, 's', proto_list_struct, 0)->type; - proto_list_def = make_symbol (va ("_OBJ_PROTOCOLS_%s", name), - proto_list_type, - pr.far_data, sc_static)->s.def; - proto_list_def->initialized = proto_list_def->constant = 1; - proto_list_def->nosave = 1; - space = proto_list_def->space; - proto_list = &D_STRUCT (pr_protocol_list_t, proto_list_def); - proto_list->next = 0; - proto_list->count = protocols->count; - for (i = 0; i < protocols->count; i++) - EMIT_DEF (space, proto_list->list[i], - emit_protocol (protocols->list[i])); - return proto_list_def; + return emit_structure (va (0, "_OBJ_PROTOCOLS_%s", name), 's', + proto_list_struct, 0, protocols, 0, sc_static); } void @@ -1513,6 +1800,10 @@ clear_classes (void) Hash_FlushTable (protocol_hash); if (category_hash) Hash_FlushTable (category_hash); + if (static_instances) + Hash_FlushTable (static_instances); + if (static_instance_classes) + Hash_FlushTable (static_instance_classes); obj_initialized = 0; } @@ -1551,6 +1842,15 @@ class_ivar_scope (class_type_t *class_type, symtab_t *parent) return symtab_flat_copy (class->ivars, parent); } +static expr_t * +class_dereference_ivar (symbol_t *sym, void *_self) +{ + expr_t *self = (expr_t *) _self; + + return field_expr (copy_expr (self), + new_symbol_expr (new_symbol (sym->name))); +} + void class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, symtab_t *param_scope) @@ -1564,8 +1864,9 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, if (!ivar_scope) return; self = symtab_lookup (param_scope, "self"); - if (!self) + if (!self) { internal_error (0, "I've lost my self!"); + } self_expr = new_symbol_expr (self); if (self->type != class_ptr) { debug (0, "class method scope"); @@ -1575,35 +1876,35 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, for (sym = ivar_scope->symbols; sym; sym = sym->next) { if (sym->sy_type != sy_var) continue; - sym->sy_type = sy_expr; - sym->s.expr = field_expr (copy_expr (self_expr), - new_symbol_expr (new_symbol (sym->name))); + sym->sy_type = sy_convert; + sym->s.convert.conv = class_dereference_ivar; + sym->s.convert.data = self_expr; } } static void init_objective_structs (void) { - make_structure ("obj_selector", 's', sel_struct, &type_obj_selector); - chain_type (&type_obj_selector); + make_structure ("obj_selector", 's', sel_struct, &type_selector); + chain_type (&type_selector); chain_type (&type_SEL); chain_type (&type_IMP); - make_structure ("obj_method", 's', method_struct, &type_obj_method); - chain_type (&type_obj_method); + make_structure ("obj_method", 's', method_struct, &type_method); + chain_type (&type_method); make_structure ("obj_method_description", 's', method_desc_struct, - &type_obj_method_description); - chain_type (&type_obj_method_description); + &type_method_description); + chain_type (&type_method_description); - make_structure ("obj_category", 's', category_struct, &type_obj_category); - chain_type (&type_obj_category); + make_structure ("obj_category", 's', category_struct, &type_category); + chain_type (&type_category); - make_structure ("obj_ivar", 's', ivar_struct, &type_obj_ivar); - chain_type (&type_obj_ivar); + make_structure ("obj_ivar", 's', ivar_struct, &type_ivar); + chain_type (&type_ivar); - make_structure ("obj_super", 's', super_struct, &type_obj_super); - chain_type (&type_obj_super); + make_structure ("obj_super", 's', super_struct, &type_super); + chain_type (&type_super); chain_type (&type_SuperPtr); chain_type (&type_supermsg); @@ -1613,24 +1914,24 @@ init_objective_structs (void) static void init_classes (void) { - make_structure ("obj_class", 's', class_struct, &type_obj_class); - chain_type (&type_obj_class); + make_structure ("obj_class", 's', class_struct, &type_class); + chain_type (&type_class); chain_type (&type_Class); - make_structure ("obj_object", 's', object_struct, &type_obj_object); - chain_type (&type_obj_object); + make_structure ("obj_object", 's', object_struct, &type_object); + chain_type (&type_object); chain_type (&type_id); - make_structure ("obj_protocol", 's', protocol_struct, &type_obj_protocol); - chain_type (&type_obj_protocol); + make_structure ("obj_protocol", 's', protocol_struct, &type_protocol); + chain_type (&type_protocol); } static void class_init_obj_module (void) { - make_structure ("obj_module", 's', module_struct, &type_obj_module); + make_structure ("obj_module", 's', module_struct, &type_module); - chain_type (&type_obj_module); + chain_type (&type_module); chain_type (&type_moduleptr); - chain_type (&type_obj_exec_class); + chain_type (&type_exec_class); } void diff --git a/tools/qfcc/source/codespace.c b/tools/qfcc/source/codespace.c index 797bc5707..b7cd56bcc 100644 --- a/tools/qfcc/source/codespace.c +++ b/tools/qfcc/source/codespace.c @@ -41,7 +41,7 @@ #include "QF/pr_comp.h" -#include "codespace.h" +#include "tools/qfcc/include/codespace.h" codespace_t * codespace_new (void) diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 799b2ff0f..2d2c1400d 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -42,13 +42,15 @@ #include #include -#include "diagnostic.h" -#include "expr.h" -#include "options.h" -#include "qfcc.h" -#include "strpool.h" -#include "type.h" -#include "qc-parse.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +#include "tools/qfcc/source/qc-parse.h" typedef expr_t *(*operation_t) (int op, expr_t *e, expr_t *e1, expr_t *e2); typedef expr_t *(*unaryop_t) (int op, expr_t *e, expr_t *e1); @@ -60,7 +62,7 @@ cf_cast_expr (type_t *type, expr_t *e) return e; } -static int +static __attribute__((pure)) int valid_op (int op, int *valid_ops) { while (*valid_ops && op != *valid_ops) @@ -68,6 +70,16 @@ valid_op (int op, int *valid_ops) return *valid_ops == op; } +static expr_t * +cmp_result_expr (int result) +{ + if (is_float (type_default)) { + return new_float_expr (result); + } else { + return new_integer_expr(result); + } +} + static expr_t * do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2) { @@ -107,22 +119,22 @@ do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_string_expr (save_string (temp_str->str)); break; case LT: - e = new_integer_expr (strcmp (s1, s2) < 0); + e = cmp_result_expr (strcmp (s1, s2) < 0); break; case GT: - e = new_integer_expr (strcmp (s1, s2) > 0); + e = cmp_result_expr (strcmp (s1, s2) > 0); break; case LE: - e = new_integer_expr (strcmp (s1, s2) <= 0); + e = cmp_result_expr (strcmp (s1, s2) <= 0); break; case GE: - e = new_integer_expr (strcmp (s1, s2) >= 0); + e = cmp_result_expr (strcmp (s1, s2) >= 0); break; case EQ: - e = new_integer_expr (strcmp (s1, s2) == 0); + e = cmp_result_expr (strcmp (s1, s2) == 0); break; case NE: - e = new_integer_expr (strcmp (s1, s2)); + e = cmp_result_expr (strcmp (s1, s2)); break; default: internal_error (e1, 0); @@ -135,18 +147,56 @@ do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2) static expr_t * convert_to_float (expr_t *e) { - if (get_type (e) == &type_float) + if (is_float(get_type (e))) return e; switch (e->type) { case ex_value: - switch (e->e.value->type) { + switch (e->e.value->lltype) { case ev_integer: convert_int (e); return e; case ev_short: convert_short (e); return e; + case ev_double: + convert_double (e); + return e; + default: + internal_error (e, "bad conversion to float: %d", + e->e.value->lltype); + } + break; + case ex_symbol: + case ex_expr: + case ex_uexpr: + case ex_temp: + case ex_block: + e = cf_cast_expr (&type_float, e); + return e; + default: + internal_error (e, 0); + } +} + +static expr_t * +convert_to_double (expr_t *e) +{ + if (is_double(get_type (e))) + return e; + + switch (e->type) { + case ex_value: + switch (e->e.value->lltype) { + case ev_integer: + e->e.value = new_double_val (expr_integer (e)); + return e; + case ev_short: + e->e.value = new_double_val (expr_short (e)); + return e; + case ev_float: + e->e.value = new_double_val (expr_float (e)); + return e; default: internal_error (e, 0); } @@ -177,8 +227,8 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for float"); - if (op == '=' || op == PAS) { - if ((type = get_type (e1)) != &type_float) { + if (op == '=') { + if (!is_float(type = get_type (e1))) { //FIXME optimize casting a constant e->e.expr.e2 = e2 = cf_cast_expr (type, e2); } else if ((conv = convert_to_float (e2)) != e2) { @@ -261,28 +311,133 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_float_expr ((int)f1 >> (int)f2); break; case AND: - e = new_integer_expr (f1 && f2); + e = cmp_result_expr (f1 && f2); break; case OR: - e = new_integer_expr (f1 || f2); + e = cmp_result_expr (f1 || f2); break; case LT: - e = new_integer_expr (f1 < f2); + e = cmp_result_expr (f1 < f2); break; case GT: - e = new_integer_expr (f1 > f2); + e = cmp_result_expr (f1 > f2); break; case LE: - e = new_integer_expr (f1 <= f2); + e = cmp_result_expr (f1 <= f2); break; case GE: - e = new_integer_expr (f1 >= f2); + e = cmp_result_expr (f1 >= f2); break; case EQ: - e = new_integer_expr (f1 == f2); + e = cmp_result_expr (f1 == f2); break; case NE: - e = new_integer_expr (f1 != f2); + e = cmp_result_expr (f1 != f2); + break; + default: + internal_error (e1, 0); + } + e->file = e1->file; + e->line = e1->line; + return e; +} + +static expr_t * +do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2) +{ + double d1, d2; + expr_t *conv; + type_t *type = &type_double; + static int valid[] = { + '=', '+', '-', '*', '/', '%', + LT, GT, LE, GE, EQ, NE, 0 + }; + + if (!valid_op (op, valid)) + return error (e1, "invalid operator for double"); + + if (op == '=') { + if (!is_double(type = get_type (e1))) { + //FIXME optimize casting a constant + e->e.expr.e2 = e2 = cf_cast_expr (type, e2); + } else if ((conv = convert_to_double (e2)) != e2) { + e->e.expr.e2 = e2 = conv; + } + } else { + if ((conv = convert_to_double (e1)) != e1) { + e->e.expr.e1 = e1 = conv; + } + if ((conv = convert_to_double (e2)) != e2) { + e->e.expr.e2 = e2 = conv; + } + } + if (is_compare (op) || is_logic (op)) { + type = &type_integer; + } + e->e.expr.type = type; + + if (op == '*' && is_constant (e1) && expr_double (e1) == 1) + return e2; + if (op == '*' && is_constant (e2) && expr_double (e2) == 1) + return e1; + if (op == '*' && is_constant (e1) && expr_double (e1) == 0) + return e1; + if (op == '*' && is_constant (e2) && expr_double (e2) == 0) + return e2; + if (op == '/' && is_constant (e2) && expr_double (e2) == 1) + return e1; + if (op == '/' && is_constant (e2) && expr_double (e2) == 0) + return error (e, "division by zero"); + if (op == '/' && is_constant (e1) && expr_double (e1) == 0) + return e1; + if (op == '+' && is_constant (e1) && expr_double (e1) == 0) + return e2; + if (op == '+' && is_constant (e2) && expr_double (e2) == 0) + return e1; + if (op == '-' && is_constant (e2) && expr_double (e2) == 0) + return e1; + + if (op == '=' || !is_constant (e1) || !is_constant (e2)) + return e; + + d1 = expr_double (e1); + d2 = expr_double (e2); + + switch (op) { + case '+': + e = new_double_expr (d1 + d2); + break; + case '-': + e = new_double_expr (d1 - d2); + break; + case '*': + e = new_double_expr (d1 * d2); + break; + case '/': + if (!d2) + return error (e1, "divide by zero"); + e = new_double_expr (d1 / d2); + break; + case '%': + e = new_double_expr ((int)d1 % (int)d2); + break; + case LT: + e = cmp_result_expr (d1 < d2); + break; + case GT: + e = cmp_result_expr (d1 > d2); + break; + case LE: + e = cmp_result_expr (d1 <= d2); + break; + case GE: + e = cmp_result_expr (d1 >= d2); + break; + case EQ: + e = cmp_result_expr (d1 == d2); + break; + case NE: + e = cmp_result_expr (d1 != d2); break; default: internal_error (e1, 0); @@ -300,7 +455,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) static int valid[] = {'=', '+', '-', '*', EQ, NE, 0}; expr_t *t; - if (get_type (e1) != &type_vector) { + if (!is_vector(get_type (e1))) { if (op != '*') return error (e1, "invalid operator for vector"); @@ -309,7 +464,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) e->e.expr.e1 = e1 = e2; e2 = t; } - if (get_type (e2) != &type_vector) { + if (!is_vector(get_type (e2))) { e->e.expr.e2 = e2 = convert_to_float (e2); if (op != '*' && op != '/') return error (e1, "invalid operator for vector"); @@ -322,7 +477,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) e->e.expr.type = &type_integer; else e->e.expr.type = &type_float; - } else if (op == '*' && get_type (e2) == &type_vector) { + } else if (op == '*' && is_vector(get_type (e2))) { e->e.expr.type = &type_float; } else if (op == '/' && !is_constant (e1)) { e2 = fold_constants (binary_expr ('/', new_float_expr (1), e2)); @@ -387,7 +542,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_vector_expr (v); break; case '*': - if (get_type (e2) == &type_vector) { + if (is_vector(get_type (e2))) { e = new_float_expr (DotProduct (v1, v2)); } else { VectorScale (v1, v2[0], v); @@ -395,10 +550,10 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) } break; case EQ: - e = new_integer_expr (VectorCompare (v1, v2)); + e = cmp_result_expr (VectorCompare (v1, v2)); break; case NE: - e = new_integer_expr (!VectorCompare (v1, v2)); + e = cmp_result_expr (!VectorCompare (v1, v2)); break; default: internal_error (e1, 0); @@ -423,7 +578,7 @@ do_op_entity (int op, expr_t *e, expr_t *e1, expr_t *e2) e->e.expr.type = &type_float; return e; } - if (op != '=' || type != &type_entity) + if (op != '=' || !is_entity(type)) return error (e1, "invalid operator for entity"); e->e.expr.type = &type_entity; return e; @@ -462,7 +617,7 @@ static expr_t * do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2) { type_t *type; - static int valid[] = {'=', PAS, '-', '&', 'M', '.', EQ, NE, 0}; + static int valid[] = {'=', '-', '&', 'M', '.', EQ, NE, 0}; if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) { // pointer arithmetic @@ -486,29 +641,16 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2) e = binary_expr ('/', e, new_integer_expr (type_size (type))); return e; } - if (op == PAS && (type = get_type (e1)->t.fldptr.type) != get_type (e2)) { - // make sure auto-convertions happen - expr_t *tmp = new_temp_def_expr (type); - expr_t *ass = new_binary_expr ('=', tmp, e2); - - tmp->file = e1->file; - ass->line = e2->line; - ass->file = e2->file; - ass = fold_constants (ass); - if (e->e.expr.e2 == tmp) - internal_error (e2, 0); - e->e.expr.e2 = ass->e.expr.e2; - } if (op == EQ || op == NE) { if (options.code.progsversion > PROG_ID_VERSION) e->e.expr.type = &type_integer; else e->e.expr.type = &type_float; } - if (op != PAS && op != '.' && op != '&' && op != 'M' + if (op != '.' && op != '&' && op != 'M' && extract_type (e1) != extract_type (e2)) return type_mismatch (e1, e2, op); - if ((op == '.' || op == '&') && get_type (e2) == &type_uinteger) + if ((op == '.' || op == '&') && is_uinteger(get_type (e2))) e->e.expr.e2 = cf_cast_expr (&type_integer, e2); return e; } @@ -543,7 +685,7 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) static int valid[] = {'=', '+', '-', '*', EQ, NE, 0}; expr_t *t; - if (get_type (e1) != &type_quaternion) { + if (!is_quaternion(get_type (e1))) { if (op != '*' && op != '/') return error (e1, "invalid operator for quaternion"); @@ -554,7 +696,7 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) e2 = t; } } - if (get_type (e2) != &type_quaternion) { + if (!is_quaternion(get_type (e2))) { e->e.expr.e2 = e2 = convert_to_float (e2); if (op != '*' && op != '/') return error (e1, "invalid operator for quaternion"); @@ -593,11 +735,11 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) return e; if (is_float_val (e1)) { - float_quat[0] = expr_float (e1); + QuatSet (0, 0, 0, expr_float (e1), float_quat); q2 = float_quat; q1 = expr_quaternion (e2); } else if (is_float_val (e2)) { - float_quat[0] = expr_float (e2); + QuatSet (0, 0, 0, expr_float (e2), float_quat); q2 = float_quat; q1 = expr_quaternion (e1); } else { @@ -624,18 +766,18 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_quaternion_expr (q); break; case '*': - if (get_type (e2) == &type_quaternion) { + if (is_quaternion(get_type (e2))) { QuatMult (q1, q2, q); } else { - QuatScale (q1, q2[0], q); + QuatScale (q1, q2[3], q); } e = new_quaternion_expr (q); break; case EQ: - e = new_integer_expr (QuatCompare (q1, q2)); + e = cmp_result_expr (QuatCompare (q1, q2)); break; case NE: - e = new_integer_expr (!QuatCompare (q1, q2)); + e = cmp_result_expr (!QuatCompare (q1, q2)); break; default: internal_error (e1, 0); @@ -648,7 +790,8 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) static expr_t * do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) { - int i1, i2; + int isval1 = 0, isval2 = 0; + int val1 = 0, val2 = 0; static int valid[] = { '=', '+', '-', '*', '/', '&', '|', '^', '%', SHL, SHR, AND, OR, LT, GT, LE, GE, EQ, NE, 0 @@ -657,11 +800,23 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for integer"); - if (is_short_val (e1)) - convert_short_int (e1); + if (is_short_val (e1)) { + isval1 = 1; + val1 = expr_short (e1); + } + if (is_integer_val (e1)) { + isval1 = 1; + val1 = expr_integer (e1); + } - if (is_short_val (e2)) - convert_short_int (e2); + if (is_short_val (e2)) { + isval2 = 1; + val2 = expr_short (e2); + } + if (is_integer_val (e2)) { + isval2 = 1; + val2 = expr_integer (e2); + } if (is_compare (op) || is_logic (op)) { if (options.code.progsversion > PROG_ID_VERSION) @@ -672,89 +827,86 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) e->e.expr.type = &type_integer; } - if (op == '*' && is_constant (e1) && expr_integer (e1) == 1) + if (op == '*' && isval1 && val1 == 1) return e2; - if (op == '*' && is_constant (e2) && expr_integer (e2) == 1) + if (op == '*' && isval2 && val2 == 1) return e1; - if (op == '*' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '*' && isval1 && val1 == 0) return e1; - if (op == '*' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '*' && isval2 && val2 == 0) return e2; - if (op == '/' && is_constant (e2) && expr_integer (e2) == 1) + if (op == '/' && isval2 && val2 == 1) return e1; - if (op == '/' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '/' && isval2 && val2 == 0) return error (e, "division by zero"); - if (op == '/' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '/' && isval1 && val1 == 0) return e1; - if (op == '+' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '+' && isval1 && val1 == 0) return e2; - if (op == '+' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '+' && isval2 && val2 == 0) return e1; - if (op == '-' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '-' && isval2 && val2 == 0) return e1; - if (op == '=' || !is_constant (e1) || !is_constant (e2)) + if (op == '=' || !isval1 || !isval2) return e; - i1 = expr_integer (e1); - i2 = expr_integer (e2); - switch (op) { case '+': - e = new_integer_expr (i1 + i2); + e = new_integer_expr (val1 + val2); break; case '-': - e = new_integer_expr (i1 - i2); + e = new_integer_expr (val1 - val2); break; case '*': - e = new_integer_expr (i1 * i2); + e = new_integer_expr (val1 * val2); break; case '/': if (options.warnings.integer_divide) - warning (e2, "%d / %d == %d", i1, i2, i1 / i2); - e = new_integer_expr (i1 / i2); + warning (e2, "%d / %d == %d", val1, val2, val1 / val2); + e = new_integer_expr (val1 / val2); break; case '&': - e = new_integer_expr (i1 & i2); + e = new_integer_expr (val1 & val2); break; case '|': - e = new_integer_expr (i1 | i2); + e = new_integer_expr (val1 | val2); break; case '^': - e = new_integer_expr (i1 ^ i2); + e = new_integer_expr (val1 ^ val2); break; case '%': - e = new_integer_expr (i1 % i2); + e = new_integer_expr (val1 % val2); break; case SHL: - e = new_integer_expr (i1 << i2); + e = new_integer_expr (val1 << val2); break; case SHR: - e = new_integer_expr (i1 >> i2); + e = new_integer_expr (val1 >> val2); break; case AND: - e = new_integer_expr (i1 && i2); + e = cmp_result_expr (val1 && val2); break; case OR: - e = new_integer_expr (i1 || i2); + e = cmp_result_expr (val1 || val2); break; case LT: - e = new_integer_expr (i1 < i2); + e = cmp_result_expr (val1 < val2); break; case GT: - e = new_integer_expr (i1 > i2); + e = cmp_result_expr (val1 > val2); break; case LE: - e = new_integer_expr (i1 <= i2); + e = cmp_result_expr (val1 <= val2); break; case GE: - e = new_integer_expr (i1 >= i2); + e = cmp_result_expr (val1 >= val2); break; case EQ: - e = new_integer_expr (i1 == i2); + e = cmp_result_expr (val1 == val2); break; case NE: - e = new_integer_expr (i1 != i2); + e = cmp_result_expr (val1 != val2); break; default: internal_error (e1, 0); @@ -837,22 +989,22 @@ do_op_short (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_short_expr (i1 || i2); break; case LT: - e = new_integer_expr (i1 < i2); + e = cmp_result_expr (i1 < i2); break; case GT: - e = new_integer_expr (i1 > i2); + e = cmp_result_expr (i1 > i2); break; case LE: - e = new_integer_expr (i1 <= i2); + e = cmp_result_expr (i1 <= i2); break; case GE: - e = new_integer_expr (i1 >= i2); + e = cmp_result_expr (i1 >= i2); break; case EQ: - e = new_integer_expr (i1 == i2); + e = cmp_result_expr (i1 == i2); break; case NE: - e = new_integer_expr (i1 != i2); + e = cmp_result_expr (i1 != i2); break; default: internal_error (e1, 0); @@ -884,11 +1036,15 @@ do_op_compound (int op, expr_t *e, expr_t *e1, expr_t *e2) return do_op_struct (op, e, e1, e2); if (is_scalar (t1) && is_scalar (t2)) { if (is_enum (t1)) { - if (t2->type == ev_float) + if (t2->type == ev_double) + return do_op_float (op, e, e1, e2); + if (t2->type == ev_double) return do_op_float (op, e, e1, e2); return do_op_integer (op, e, e1, e2); } if (is_enum (t2)) { + if (t1->type == ev_double) + return do_op_double (op, e, e1, e2); if (t1->type == ev_float) return do_op_float (op, e, e1, e2); return do_op_integer (op, e, e1, e2); @@ -947,6 +1103,7 @@ static operation_t op_void[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -963,6 +1120,7 @@ static operation_t op_string[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -979,6 +1137,7 @@ static operation_t op_float[ev_type_count] = { do_op_float, // ev_integer do_op_float, // ev_uinteger do_op_float, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -995,6 +1154,7 @@ static operation_t op_vector[ev_type_count] = { do_op_vector, // ev_integer do_op_vector, // ev_uinteger do_op_vector, // ev_short + do_op_vector, // ev_double do_op_invalid, // ev_invalid }; @@ -1011,6 +1171,7 @@ static operation_t op_entity[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -1027,6 +1188,7 @@ static operation_t op_field[ev_type_count] = { do_op_invalid, // ev_integer do_op_invalid, // ev_uinteger do_op_invalid, // ev_short + do_op_invalid, // ev_double do_op_invalid, // ev_invalid }; @@ -1043,6 +1205,7 @@ static operation_t op_func[ev_type_count] = { do_op_func, // ev_integer do_op_func, // ev_uinteger do_op_func, // ev_short + do_op_func, // ev_double do_op_func, // ev_invalid }; @@ -1059,6 +1222,7 @@ static operation_t op_pointer[ev_type_count] = { do_op_pointer, // ev_integer do_op_pointer, // ev_uinteger do_op_pointer, // ev_short + do_op_pointer, // ev_double do_op_pointer, // ev_invalid }; @@ -1075,6 +1239,7 @@ static operation_t op_quaternion[ev_type_count] = { do_op_quaternion, // ev_integer do_op_quaternion, // ev_uinteger do_op_quaternion, // ev_short + do_op_quaternion, // ev_double do_op_invalid, // ev_invalid }; @@ -1091,6 +1256,7 @@ static operation_t op_integer[ev_type_count] = { do_op_integer, // ev_integer do_op_uinteger, // ev_uinteger do_op_integer, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -1107,6 +1273,7 @@ static operation_t op_uinteger[ev_type_count] = { do_op_uinteger, // ev_integer do_op_uinteger, // ev_uinteger do_op_uinteger, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -1123,6 +1290,24 @@ static operation_t op_short[ev_type_count] = { do_op_integer, // ev_integer do_op_uinteger, // ev_uinteger do_op_short, // ev_short + do_op_double, // ev_double + do_op_invalid, // ev_invalid +}; + +static operation_t op_double[ev_type_count] = { + do_op_invalid, // ev_void + do_op_invalid, // ev_string + do_op_float, // ev_float + do_op_vector, // ev_vector + do_op_invalid, // ev_entity + do_op_invalid, // ev_field + do_op_invalid, // ev_func + do_op_invalid, // ev_pointer + do_op_quaternion, // ev_quaternion + do_op_integer, // ev_integer + do_op_uinteger, // ev_uinteger + do_op_short, // ev_short + do_op_double, // ev_double do_op_invalid, // ev_invalid }; @@ -1139,6 +1324,7 @@ static operation_t op_compound[ev_type_count] = { do_op_compound, // ev_integer do_op_compound, // ev_uinteger do_op_compound, // ev_short + do_op_compound, // ev_double do_op_compound, // ev_invalid }; @@ -1155,6 +1341,7 @@ static operation_t *do_op[ev_type_count] = { op_integer, // ev_integer op_uinteger, // ev_uinteger op_short, // ev_short + op_double, // ev_double op_compound, // ev_invalid }; @@ -1196,20 +1383,22 @@ uop_string (int op, expr_t *e, expr_t *e1) return e; s = expr_string (e1); - return new_integer_expr (!s || !s[0]); + return cmp_result_expr (!s || !s[0]); } static expr_t * uop_float (int op, expr_t *e, expr_t *e1) { static int valid[] = { '+', '-', '!', '~', 'C', 0 }; + type_t *type; if (!valid_op (op, valid)) return error (e1, "invalid unary operator for float: %s", get_op_string (op)); if (op == '+') return e1; - if (op == 'C' && get_type (e) != &type_integer) + type = get_type (e); + if (op == 'C' && !is_integer(type) && !is_double(type)) return error (e1, "invalid cast of float"); if (!is_constant (e1)) return e; @@ -1218,11 +1407,15 @@ uop_float (int op, expr_t *e, expr_t *e1) return new_float_expr (-expr_float (e1)); case '!': print_type (get_type (e)); - return new_integer_expr (!expr_float (e1)); + return cmp_result_expr (!expr_float (e1)); case '~': return new_float_expr (~(int) expr_float (e1)); case 'C': - return new_integer_expr (expr_float (e1)); + if (is_integer(type)) { + return new_integer_expr (expr_float (e1)); + } else { + return new_double_expr (expr_float (e1)); + } } internal_error (e, "float unary op blew up"); } @@ -1245,7 +1438,7 @@ uop_vector (int op, expr_t *e, expr_t *e1) VectorNegate (expr_vector (e), v); return new_vector_expr (v); case '!': - return new_integer_expr (!VectorIsZero (expr_vector (e1))); + return cmp_result_expr (!VectorIsZero (expr_vector (e1))); } internal_error (e, "vector unary op blew up"); } @@ -1339,7 +1532,7 @@ uop_quaternion (int op, expr_t *e, expr_t *e1) QuatNegate (expr_vector (e), q); return new_quaternion_expr (q); case '!': - return new_integer_expr (!QuatIsZero (expr_quaternion (e1))); + return cmp_result_expr (!QuatIsZero (expr_quaternion (e1))); case '~': QuatConj (expr_vector (e), q); return new_quaternion_expr (q); @@ -1357,7 +1550,7 @@ uop_integer (int op, expr_t *e, expr_t *e1) get_op_string (op)); if (op == '+') return e1; - if (op == 'C' && get_type (e) != &type_float) + if (op == 'C' && !is_float(get_type (e))) return error (e1, "invalid cast of int"); if (!is_constant (e1)) return e; @@ -1365,7 +1558,7 @@ uop_integer (int op, expr_t *e, expr_t *e1) case '-': return new_integer_expr (-expr_integer (e1)); case '!': - return new_integer_expr (!expr_integer (e1)); + return cmp_result_expr (!expr_integer (e1)); case '~': return new_integer_expr (~expr_integer (e1)); case 'C': @@ -1390,7 +1583,7 @@ uop_uinteger (int op, expr_t *e, expr_t *e1) case '-': return new_uinteger_expr (-expr_uinteger (e1)); case '!': - return new_integer_expr (!expr_uinteger (e1)); + return cmp_result_expr (!expr_uinteger (e1)); case '~': return new_uinteger_expr (~expr_uinteger (e1)); } @@ -1413,13 +1606,45 @@ uop_short (int op, expr_t *e, expr_t *e1) case '-': return new_short_expr (-expr_short (e1)); case '!': - return new_integer_expr (!expr_short (e1)); + return cmp_result_expr (!expr_short (e1)); case '~': return new_short_expr (~expr_short (e1)); } internal_error (e, "short unary op blew up"); } +static expr_t * +uop_double (int op, expr_t *e, expr_t *e1) +{ + static int valid[] = { '+', '-', '!', 'C', 0 }; + type_t *type; + + if (!valid_op (op, valid)) + return error (e1, "invalid unary operator for double: %s", + get_op_string (op)); + if (op == '+') + return e1; + type = get_type (e); + if (op == 'C' && !is_integer(type) && !is_float(type)) + return error (e1, "invalid cast of double"); + if (!is_constant (e1)) + return e; + switch (op) { + case '-': + return new_double_expr (-expr_double (e1)); + case '!': + print_type (get_type (e)); + return cmp_result_expr (!expr_double (e1)); + case 'C': + if (is_integer(type)) { + return new_integer_expr (expr_double (e1)); + } else { + return new_float_expr (expr_double (e1)); + } + } + internal_error (e, "float unary op blew up"); +} + static expr_t * uop_compound (int op, expr_t *e, expr_t *e1) { @@ -1446,6 +1671,7 @@ static unaryop_t do_unary_op[ev_type_count] = { uop_integer, // ev_integer uop_uinteger, // ev_uinteger uop_short, // ev_short + uop_double, // ev_double uop_compound, // ev_invalid }; @@ -1456,34 +1682,12 @@ fold_constants (expr_t *e) expr_t *e1, *e2; etype_t t1, t2; - if (e->type == ex_block) { - expr_t *block = new_block_expr (); - expr_t *next; - - block->e.block.result = e->e.block.result; - block->line = e->line; - block->file = e->file; - - for (e = e->e.block.head; e; e = next) { - next = e->next; - e = fold_constants (e); - e->next = 0; - append_expr (block, e); - } - - return block; - } - if (e->type == ex_bool) { - e->e.bool.e = fold_constants (e->e.bool.e); - return e; - } if (e->type == ex_uexpr) { - if (!e->e.expr.e1) + e1 = e->e.expr.e1; + if (!e1) { return e; + } op = e->e.expr.op; - e->e.expr.e1 = e1 = fold_constants (e->e.expr.e1); - if (e1->type == ex_error) - return e1; if (op == 'A' || op == 'g' || op == 'r') return e; t1 = extract_type (e1); @@ -1492,35 +1696,25 @@ fold_constants (expr_t *e) internal_error (e, "invalid type: %d", t1); } return do_unary_op[t1] (op, e, e1); + } else if (e->type == ex_expr) { + e1 = e->e.expr.e1; + e2 = e->e.expr.e2; + if (!is_constant (e1) && !is_constant (e2)) { + return e; + } + + op = e->e.expr.op; + if (op == 'A' || op == 'i' || op == 'n' || op == 'c' || op == 's') { + return e; + } + + t1 = extract_type (e1); + t2 = extract_type (e2); + + if (t1 >= ev_type_count || t2 >= ev_type_count + || !do_op[t1] || !do_op[t1][t2]) + internal_error (e, "invalid type %d %d", t1, t2); + return do_op[t1][t2] (op, e, e1, e2); } - - if (e->type != ex_expr) - return e; - - op = e->e.expr.op; - - e->e.expr.e1 = e1 = fold_constants (e->e.expr.e1); - if (e1->type == ex_error) - return e1; - t1 = extract_type (e1); - - if (op == 'i' || op == 'n' || op == 'c') - return e; - - e->e.expr.e2 = e2 = fold_constants (e->e.expr.e2); - if (e2->type == ex_error) - return e2; - - if (e2->type == ex_label || e2->type == ex_labelref) - return e; - - t2 = extract_type (e2); - - if (op == 's') - return e; - - if (t1 >= ev_type_count || t2 >= ev_type_count - || !do_op[t1] || !do_op[t1][t2]) - internal_error (e, "invalid type"); - return do_op[t1][t2] (op, e, e1, e2); + return e; } diff --git a/tools/qfcc/source/cpp.c b/tools/qfcc/source/cpp.c index cfc5de81d..1adb1301b 100644 --- a/tools/qfcc/source/cpp.c +++ b/tools/qfcc/source/cpp.c @@ -54,8 +54,9 @@ #include "QF/dstring.h" -#include "cpp.h" -#include "options.h" +#include "tools/qfcc/include/cpp.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/options.h" typedef struct cpp_arg_s { struct cpp_arg_s *next; @@ -66,11 +67,25 @@ cpp_arg_t *cpp_arg_list; cpp_arg_t **cpp_arg_tail = &cpp_arg_list; cpp_arg_t *cpp_def_list; cpp_arg_t **cpp_def_tail = &cpp_def_list; +cpp_arg_t *cpp_undef_list; +cpp_arg_t **cpp_undef_tail = &cpp_undef_list; +cpp_arg_t *cpp_sysinc_list; +cpp_arg_t **cpp_sysinc_tail = &cpp_sysinc_list; const char **cpp_argv; const char *cpp_name = CPP_NAME; static int cpp_argc = 0; dstring_t *tempname; +static const char ** +append_cpp_args (const char **arg, cpp_arg_t *arg_list) +{ + cpp_arg_t *cpp_arg; + + for (cpp_arg = arg_list; cpp_arg; cpp_arg = cpp_arg->next) + *arg++ = cpp_arg->arg; + return arg; +} + static void add_cpp_arg (const char *arg) { @@ -82,6 +97,28 @@ add_cpp_arg (const char *arg) cpp_argc++; } +void +add_cpp_sysinc (const char *arg) +{ + cpp_arg_t *cpp_arg = malloc (sizeof (cpp_arg_t)); + cpp_arg->next = 0; + cpp_arg->arg = arg; + *cpp_sysinc_tail = cpp_arg; + cpp_sysinc_tail = &(*cpp_sysinc_tail)->next; + cpp_argc++; +} + +void +add_cpp_undef (const char *arg) +{ + cpp_arg_t *cpp_arg = malloc (sizeof (cpp_arg_t)); + cpp_arg->next = 0; + cpp_arg->arg = arg; + *cpp_undef_tail = cpp_arg; + cpp_undef_tail = &(*cpp_undef_tail)->next; + cpp_argc++; +} + void add_cpp_def (const char *arg) { @@ -116,18 +153,20 @@ static void build_cpp_args (const char *in_name, const char *out_name) { cpp_arg_t *cpp_arg; - cpp_arg_t *cpp_def; const char **arg; if (cpp_argv) free (cpp_argv); - cpp_argv = (const char **)malloc ((cpp_argc + 1) * sizeof (char**)); + cpp_argv = (const char **)malloc ((cpp_argc + 1) * sizeof (char *)); for (arg = cpp_argv, cpp_arg = cpp_arg_list; cpp_arg; cpp_arg = cpp_arg->next) { - if (!strcmp (cpp_arg->arg, "%d")) { - for (cpp_def = cpp_def_list; cpp_def; cpp_def = cpp_def->next) - *arg++ = cpp_def->arg; + if (!strcmp (cpp_arg->arg, "%u")) { + arg = append_cpp_args (arg, cpp_undef_list); + } else if (!strcmp (cpp_arg->arg, "%s")) { + arg = append_cpp_args (arg, cpp_sysinc_list); + } else if (!strcmp (cpp_arg->arg, "%d")) { + arg = append_cpp_args (arg, cpp_def_list); } else if (!strcmp (cpp_arg->arg, "%i")) { *arg++ = in_name; } else if (!strcmp (cpp_arg->arg, "%o")) { @@ -140,9 +179,6 @@ build_cpp_args (const char *in_name, const char *out_name) } } *arg = 0; - //for (arg = cpp_argv; *arg; arg++) - // printf ("%s ", *arg); - //puts (""); } //============================================================================ @@ -205,6 +241,9 @@ preprocess_file (const char *filename, const char *ext) if (cpp_name) { intermediate_file (tempname, filename, ext ? ext : "p", 0); build_cpp_args (filename, tempname->str); + if (!cpp_argv[0]) { + internal_error(0, "cpp_argv[0] is null"); + } #ifdef _WIN32 if (!options.save_temps && !options.preprocess_only) diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 95c99d10a..1d98df411 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -47,16 +47,18 @@ #include "QF/mathlib.h" #include "QF/set.h" -#include "dags.h" -#include "diagnostic.h" -#include "flow.h" -#include "function.h" -#include "qfcc.h" -#include "statements.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/dags.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/dot.h" +#include "tools/qfcc/include/flow.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static daglabel_t *labels_freelist; static dagnode_t *nodes_freelist; @@ -80,7 +82,7 @@ flush_daglabels (void) else if (op->op_type == op_label) op->o.label->daglabel = 0; else - internal_error (0, "unexpected operand type"); + internal_error (op->expr, "unexpected operand type"); } daglabel_chain = daglabel_chain->daglabel_chain; } @@ -133,6 +135,11 @@ daglabel_string (daglabel_t *label) // operand_string might use quote_string, which returns a pointer to // a static variable. dstring_copystr (str, operand_string (label->op)); +#if 0 + if (label->op->type) { + dstring_appendstr (str, label->op->type->encoding); + } +#endif return quote_string (str->str); } @@ -158,8 +165,8 @@ operand_label (dag_t *dag, operand_t *op) return 0; if (op->op_type == op_temp) { - while (op->o.tempop.alias) - op = op->o.tempop.alias; + //while (op->o.tempop.alias) + // op = op->o.tempop.alias; if (op->o.tempop.daglabel) return op->o.tempop.daglabel; label = new_label (dag); @@ -186,7 +193,7 @@ operand_label (dag_t *dag, operand_t *op) label->op = op; op->o.label->daglabel = label; } else { - internal_error (0, "unexpected operand type: %d", op->op_type); + internal_error (op->expr, "unexpected operand type: %d", op->op_type); } return label; } @@ -208,7 +215,7 @@ leaf_node (dag_t *dag, operand_t *op, expr_t *expr) return node; } -static dagnode_t * +static __attribute__((pure)) dagnode_t * dag_node (operand_t *op) { def_t *def; @@ -232,21 +239,44 @@ dag_node (operand_t *op) if (op->o.label->daglabel) node = op->o.label->daglabel->dagnode; } - if (node && node->killed) - node = 0; return node; } static void -dag_make_children (dag_t *dag, statement_t *s, operand_t *operands[4], +dag_make_leafs (dag_t *dag, statement_t *s, operand_t *operands[FLOW_OPERANDS]) +{ + int i; + + flow_analyze_statement (s, 0, 0, 0, operands); + for (i = 1; i < FLOW_OPERANDS; i++) { + if (!dag_node (operands[i])) { + leaf_node (dag, operands[i], s->expr); + } + } +} + +static void +dag_make_children (dag_t *dag, statement_t *s, + operand_t *operands[FLOW_OPERANDS], dagnode_t *children[3]) { int i; flow_analyze_statement (s, 0, 0, 0, operands); for (i = 0; i < 3; i++) { - if (!(children[i] = dag_node (operands[i + 1]))) - children[i] = leaf_node (dag, operands[i + 1], s->expr); + dagnode_t *node = dag_node (operands[i + 1]); + dagnode_t *killer = 0; + if (node && node->killed) { + killer = node->killed; + node = 0; + } + if (!node) { + node = leaf_node (dag, operands[i + 1], s->expr); + } + if (killer) { + set_add (node->edges, killer->number); + } + children[i] = node; } } @@ -311,7 +341,21 @@ dagnode_add_children (dag_t *dag, dagnode_t *n, operand_t *operands[4], } static int -dagnode_set_edges_visit (def_t *def, void *_node) +dagnode_tempop_set_edges_visit (tempop_t *tempop, void *_node) +{ + dagnode_t *node = (dagnode_t *) _node; + daglabel_t *label; + + label = tempop->daglabel; + if (label && label->dagnode) { + set_add (node->edges, label->dagnode->number); + label->live = 1; + } + return 0; +} + +static int +dagnode_def_set_edges_visit (def_t *def, void *_node) { dagnode_t *node = (dagnode_t *) _node; daglabel_t *label; @@ -353,16 +397,25 @@ dagnode_set_edges (dag_t *dag, dagnode_t *n) if (child->label->op) { dagnode_t *node = child->label->dagnode; operand_t *op = child->label->op; - if (node != child && node != n) + if (node != child && node != n) { set_add (node->edges, n->number); + } if (op->op_type == op_value - && op->o.value->type == ev_pointer - && op->o.value->v.pointer.def) + && op->o.value->lltype == ev_pointer + && op->o.value->v.pointer.def) { def_visit_all (op->o.value->v.pointer.def, 1, - dagnode_set_edges_visit, n); + dagnode_def_set_edges_visit, n); + } if (op->op_type == op_def - && (op->o.def->alias || op->o.def->alias_defs)) - def_visit_all (op->o.def, 1, dagnode_set_edges_visit, n); + && (op->o.def->alias || op->o.def->alias_defs)) { + def_visit_all (op->o.def, 1, + dagnode_def_set_edges_visit, n); + } + if (op->op_type == op_temp + && (op->o.tempop.alias || op->o.tempop.alias_ops)) { + tempop_visit_all (&op->o.tempop, 1, + dagnode_tempop_set_edges_visit, n); + } } if (n != child) set_add (n->edges, child->number); @@ -400,7 +453,8 @@ dagnode_set_edges (dag_t *dag, dagnode_t *n) param_node = def_visit_all (param_def, 0, dag_find_node, &daglabel); if (!param_node) { - bug (0, ".param_%d not set for %s", i, n->label->opcode); + bug (n->label->expr, ".param_%d not set for %s", i, + n->label->opcode); continue; } daglabel->live = 1; @@ -425,10 +479,28 @@ op_is_identifier (operand_t *op) } static int -dag_kill_aliases_visit (def_t *def, void *_l) +dag_tempop_kill_aliases_visit (tempop_t *tempop, void *_l) { daglabel_t *l = (daglabel_t *) _l; - dagnode_t *node = l->dagnode;; + dagnode_t *node = l->dagnode; + daglabel_t *label; + + if (tempop == &l->op->o.tempop) + return 0; + label = tempop->daglabel; + if (label && label->dagnode) { + set_add (node->edges, label->dagnode->number); + set_remove (node->edges, node->number); + label->dagnode->killed = node; + } + return 0; +} + +static int +dag_def_kill_aliases_visit (def_t *def, void *_l) +{ + daglabel_t *l = (daglabel_t *) _l; + dagnode_t *node = l->dagnode; daglabel_t *label; if (def == l->op->o.def) @@ -437,7 +509,7 @@ dag_kill_aliases_visit (def_t *def, void *_l) if (label && label->dagnode) { set_add (node->edges, label->dagnode->number); set_remove (node->edges, node->number); - label->dagnode->killed = 1; + label->dagnode->killed = node; } return 0; } @@ -448,16 +520,30 @@ dag_kill_aliases (daglabel_t *l) operand_t *op = l->op; if (op->op_type == op_temp) { + if (op->o.tempop.alias || op->o.tempop.alias_ops) { + tempop_visit_all (&op->o.tempop, 1, + dag_tempop_kill_aliases_visit, l); + } } else if (op->op_type == op_def) { - if (op->o.def->alias || op->o.def->alias_defs) - def_visit_all (op->o.def, 1, dag_kill_aliases_visit, l); + if (op->o.def->alias || op->o.def->alias_defs) { + def_visit_all (op->o.def, 1, dag_def_kill_aliases_visit, l); + } } else { - internal_error (0, "rvalue assignment?"); + internal_error (op->expr, "rvalue assignment?"); } } static int -dag_live_aliases (def_t *def, void *_d) +dag_tempop_live_aliases (tempop_t *tempop, void *_t) +{ + + if (tempop != _t && tempop->daglabel) + tempop->daglabel->live = 1; + return 0; +} + +static int +dag_def_live_aliases (def_t *def, void *_d) { if (def != _d && def->daglabel) @@ -465,6 +551,34 @@ dag_live_aliases (def_t *def, void *_d) return 0; } +static void +dag_live_aliases(operand_t *op) +{ + // FIXME it would be better to propogate the aliasing + if (op->op_type == op_temp + && (op->o.tempop.alias || op->o.tempop.alias_ops)) { + tempop_visit_all (&op->o.tempop, 1, dag_tempop_live_aliases, + &op->o.tempop); + } + if (op->op_type == op_def + && (op->o.def->alias || op->o.def->alias_defs)) { + def_visit_all (op->o.def, 1, dag_def_live_aliases, op->o.def); + } +} + +static void +dag_make_var_live (set_t *live_vars, operand_t *op) +{ + flowvar_t *var = 0; + + if (op) { + dag_live_aliases (op); + var = flow_get_var (op); + } + if (var) + set_add (live_vars, var->number); +} + static void dagnode_attach_label (dagnode_t *n, daglabel_t *l) { @@ -472,9 +586,15 @@ dagnode_attach_label (dagnode_t *n, daglabel_t *l) internal_error (0, "attempt to attach operator label to dagnode " "identifiers"); if (!op_is_identifier (l->op)) - internal_error (0, "attempt to attach non-identifer label to dagnode " + internal_error (l->op->expr, + "attempt to attach non-identifer label to dagnode " "identifiers"); if (l->dagnode) { + // if the node is a leaf, then kill its value so no attempt is made + // to reuse it. + if (l->dagnode->type == st_none) { + l->dagnode->killed = n; + } dagnode_t *node = l->dagnode; set_union (n->edges, node->parents); set_remove (n->edges, n->number); @@ -485,18 +605,21 @@ dagnode_attach_label (dagnode_t *n, daglabel_t *l) set_add (n->identifiers, l->number); dag_kill_aliases (l); if (n->label->op) { - // FIXME temps - // FIXME it would be better to propogate the aliasing - if (n->label->op->op_type == op_def - && (n->label->op->o.def->alias - || n->label->op->o.def->alias_defs)) - def_visit_all (n->label->op->o.def, 1, dag_live_aliases, - n->label->op->o.def); + dag_live_aliases (n->label->op); } } static int -dag_alias_live (def_t *def, void *_live_vars) +dag_tempop_alias_live (tempop_t *tempop, void *_live_vars) +{ + set_t *live_vars = (set_t *) _live_vars; + if (!tempop->flowvar) + return 0; + return set_is_member (live_vars, tempop->flowvar->number); +} + +static int +dag_def_alias_live (def_t *def, void *_live_vars) { set_t *live_vars = (set_t *) _live_vars; if (!def->flowvar) @@ -523,7 +646,11 @@ dag_remove_dead_vars (dag_t *dag, set_t *live_vars) if (set_is_member (dag->flownode->global_vars, var->number)) continue; if (l->op->op_type == op_def - && def_visit_all (l->op->o.def, 1, dag_alias_live, live_vars)) + && def_visit_all (l->op->o.def, 1, dag_def_alias_live, live_vars)) + continue; + if (l->op->op_type == op_temp + && tempop_visit_all (&l->op->o.tempop, 1, dag_tempop_alias_live, + live_vars)) continue; if (!set_is_member (live_vars, var->number)) set_remove (l->dagnode->identifiers, l->number); @@ -568,17 +695,6 @@ dag_sort_nodes (dag_t *dag) dag->num_topo = topo; } -static void -dag_make_var_live (set_t *live_vars, operand_t *op) -{ - flowvar_t *var = 0; - - if (op) - var = flow_get_var (op); - if (var) - set_add (live_vars, var->number); -} - static void dag_kill_nodes (dag_t *dag, dagnode_t *n) { @@ -600,7 +716,7 @@ dag_kill_nodes (dag_t *dag, dagnode_t *n) // operations. continue; } - node->killed = 1; + node->killed = n; } n->killed = 0; } @@ -614,6 +730,8 @@ dag_create (flownode_t *flownode) dagnode_t **nodes; daglabel_t **labels; int num_statements = 0; + int num_nodes; + int num_lables; set_t *live_vars = set_new (); flush_daglabels (); @@ -627,32 +745,50 @@ dag_create (flownode_t *flownode) dag = new_dag (); dag->flownode = flownode; - // at most 4 per statement - dag->nodes = alloca (num_statements * 4 * sizeof (dagnode_t)); - // at most 4 per statement, + return + params - dag->labels = alloca (num_statements * (4 + 1 + 8) * sizeof (daglabel_t)); + // at most FLOW_OPERANDS per statement + num_nodes = num_statements * FLOW_OPERANDS; + dag->nodes = alloca (num_nodes * sizeof (dagnode_t)); + // at most FLOW_OPERANDS per statement, + return + params + num_lables = num_statements * (FLOW_OPERANDS + 1 + 8); + dag->labels = alloca (num_lables * sizeof (daglabel_t)); dag->roots = set_new (); + // do a first pass to ensure all operands have an "x_0" leaf node + // prior do actual dag creation for (s = block->statements; s; s = s->next) { - operand_t *operands[4]; + operand_t *operands[FLOW_OPERANDS]; + dag_make_leafs (dag, s, operands); + } + // actual dag creation + for (s = block->statements; s; s = s->next) { + operand_t *operands[FLOW_OPERANDS]; dagnode_t *n = 0, *children[3] = {0, 0, 0}; daglabel_t *op, *lx; int i; dag_make_children (dag, s, operands, children); - if (s->type == st_flow) - for (i = 0; i < 3; i++) - if (children[i]) - dag_make_var_live (live_vars, operands[i]); + if (s->type == st_flow || s->type == st_func) { + for (i = 0; i < 3; i++) { + if (children[i]) { + dag_make_var_live (live_vars, operands[i + 1]); + } + } + } + if (operands[4]) { + // a movep instruction knew what it was reading, so mark that + // as live + dag_make_var_live (live_vars, operands[4]); + } op = opcode_label (dag, s->opcode, s->expr); n = children[0]; - if (s->type != st_assign - && !(n = dagnode_search (dag, op, children))) { - n = new_node (dag); - n->type = s->type; - n->label = op; - dagnode_add_children (dag, n, operands, children); - dagnode_set_edges (dag, n); + if (s->type != st_assign) { + if (!(n = dagnode_search (dag, op, children))) { + n = new_node (dag); + n->type = s->type; + n->label = op; + dagnode_add_children (dag, n, operands, children); + dagnode_set_edges (dag, n); + } } lx = operand_label (dag, operands[0]); if (lx && lx->dagnode != n) { @@ -669,7 +805,12 @@ dag_create (flownode_t *flownode) labels = malloc (dag->num_labels * sizeof (daglabel_t *)); memcpy (labels, dag->labels, dag->num_labels * sizeof (daglabel_t *)); dag->labels = labels; - +#if 0 + if (options.block_dot.dags) { + flownode->dag = dag; + dump_dot ("raw-dags", flownode->graph, dump_dot_flow_dags); + } +#endif dag_remove_dead_vars (dag, live_vars); dag_sort_nodes (dag); set_delete (live_vars); @@ -734,10 +875,10 @@ dag_calc_node_costs (dagnode_t *dagnode) } #endif static operand_t * -fix_op_type (operand_t *op, etype_t type) +fix_op_type (operand_t *op, type_t *type) { if (op && op->op_type != op_label && op->type != type) - op = alias_operand (type, op); + op = alias_operand (type, op, op->expr); return op; } @@ -782,23 +923,105 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) operand_t *operands[3] = {0, 0, 0}; statement_t *st; operand_t *dst = 0; + type_t *type; + int offset = 0; + def_t *dstDef; operands[0] = make_operand (dag, block, dagnode, 0); operands[1] = make_operand (dag, block, dagnode, 1); + if (dagnode->children[2]) { + operands[2] = make_operand (dag, block, dagnode, 2); + st = build_statement ("", operands, dagnode->label->expr); + sblock_add_statement (block, st); + if ((var_iter = set_first (dagnode->identifiers))) { + var = dag->labels[var_iter->element]; + dst = var->op; + set_del_iter (var_iter); + } + } else { + for (var_iter = set_first (dagnode->identifiers); var_iter; + var_iter = set_next (var_iter)) { + var = dag->labels[var_iter->element]; + dst = var->op; + type = dst->o.def->type; + dstDef = dst->o.def; + if (dstDef->alias) { + offset = dstDef->offset; + dstDef = dstDef->alias; + } + operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), + operands[1]->expr); + st = build_statement ("", operands, var->expr); + sblock_add_statement (block, st); + } + } + return dst; +} + +static operand_t * +generate_memsets (dag_t *dag, sblock_t *block, dagnode_t *dagnode) +{ + set_iter_t *var_iter; + daglabel_t *var; + operand_t *operands[3] = {0, 0, 0}; + statement_t *st; + operand_t *dst; + + operands[0] = make_operand (dag, block, dagnode, 0); + operands[1] = make_operand (dag, block, dagnode, 1); + dst = operands[0]; for (var_iter = set_first (dagnode->identifiers); var_iter; var_iter = set_next (var_iter)) { var = dag->labels[var_iter->element]; - dst = var->op; - operands[2] = value_operand (new_pointer_val (0, 0, dst->o.def)); - st = build_statement ("", operands, var->expr); + operands[2] = var->op; + dst = operands[2]; + st = build_statement ("", operands, var->expr); sblock_add_statement (block, st); } return dst; } +static operand_t * +generate_memsetps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) +{ + set_iter_t *var_iter; + daglabel_t *var; + operand_t *operands[3] = {0, 0, 0}; + statement_t *st; + operand_t *dst = 0; + type_t *type; + int offset = 0; + def_t *dstDef; + + operands[0] = make_operand (dag, block, dagnode, 0); + operands[1] = make_operand (dag, block, dagnode, 1); + if (dagnode->children[2]) { + operands[2] = make_operand (dag, block, dagnode, 2); + st = build_statement ("", operands, dagnode->label->expr); + sblock_add_statement (block, st); + } else { + for (var_iter = set_first (dagnode->identifiers); var_iter; + var_iter = set_next (var_iter)) { + var = dag->labels[var_iter->element]; + dst = var->op; + type = dst->o.def->type; + dstDef = dst->o.def; + if (dstDef->alias) { + offset = dstDef->offset; + dstDef = dstDef->alias; + } + operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), + operands[1]->expr); + st = build_statement ("", operands, var->expr); + sblock_add_statement (block, st); + } + } + return dst; +} + static operand_t * generate_assignments (dag_t *dag, sblock_t *block, operand_t *src, - set_iter_t *var_iter, etype_t type) + set_iter_t *var_iter, type_t *type) { statement_t *st; operand_t *dst = 0; @@ -826,7 +1049,7 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) statement_t *st; set_iter_t *var_iter; int i; - etype_t type; + type_t *type; switch (dagnode->type) { case st_none: @@ -842,9 +1065,10 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) operands[0] = make_operand (dag, block, dagnode, 0); if (dagnode->children[1]) operands[1] = make_operand (dag, block, dagnode, 1); - type = low_level_type (get_type (dagnode->label->expr)); + type = get_type (dagnode->label->expr); if (!(var_iter = set_first (dagnode->identifiers))) { - operands[2] = temp_operand (get_type (dagnode->label->expr)); + operands[2] = temp_operand (get_type (dagnode->label->expr), + dagnode->label->expr); } else { daglabel_t *var = dag->labels[var_iter->element]; @@ -871,16 +1095,17 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) dst = operands[0]; break; case st_move: - if (!strcmp (dagnode->label->opcode, "")) { - dst = generate_moves (dag, block, dagnode); - break; - } - if (!strcmp (dagnode->label->opcode, "") - && !dagnode->children[2]) { - dst = generate_moveps (dag, block, dagnode); - break; - } - //fall through + dst = generate_moves (dag, block, dagnode); + break; + case st_ptrmove: + dst = generate_moveps (dag, block, dagnode); + break; + case st_memset: + dst = generate_memsets (dag, block, dagnode); + break; + case st_ptrmemset: + dst = generate_memsetps (dag, block, dagnode); + break; case st_state: case st_func: for (i = 0; i < 3; i++) @@ -938,6 +1163,19 @@ dag_remove_dead_nodes (dag_t *dag) } } } while (added_root); + + // clean up any stray edges that point to removed nodes + for (int i = 0; i < dag->num_nodes; i++) { + node = dag->nodes[i]; + for (child_i = set_first (node->edges); child_i; + child_i = set_next (child_i)) { + child = dag->nodes[child_i->element]; + if (!set_is_member (dag->roots, child->number) + && set_is_empty (child->parents)) { + set_remove (node->edges, child->number); + } + } + } dag_sort_nodes (dag); } diff --git a/tools/qfcc/source/debug.c b/tools/qfcc/source/debug.c index 5d6f1f5f5..ec0367fa0 100644 --- a/tools/qfcc/source/debug.c +++ b/tools/qfcc/source/debug.c @@ -43,12 +43,18 @@ #include "QF/alloc.h" #include "QF/pr_comp.h" -#include "debug.h" -#include "diagnostic.h" -#include "expr.h" -#include "qfcc.h" -#include "strpool.h" -#include "value.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" int lineno_base; @@ -79,6 +85,17 @@ pop_source_file (void) FREE (srclines, tmp); } +#define Sys_Error(fmt...) internal_error(0, fmt) +void +add_source_file (const char *file) +{ + pr.source_file = ReuseString (file); + if (!strpool_findstr (pr.comp_file_set, file)) { + strpool_addstr (pr.comp_file_set, file); + DARRAY_APPEND (&pr.comp_files, save_string (file)); + } +} + void line_info (char *text) { @@ -111,7 +128,7 @@ line_info (char *text) while (*p && *p != '\n') // ignore rest p++; pr.source_line = line - 1; - pr.source_file = ReuseString (strip_path (str)); + add_source_file (str); } pr_lineno_t * @@ -125,3 +142,67 @@ new_lineno (void) memset (&pr.linenos[pr.num_linenos], 0, sizeof (pr_lineno_t)); return &pr.linenos[pr.num_linenos++]; } + +static void +emit_unit_name (def_t *def, void *data, int index) +{ + if (!is_string (def->type)) { + internal_error (0, "%s: expected string def", __FUNCTION__); + } + EMIT_STRING (def->space, D_STRING (def), pr.unit_name); +} + +static void +emit_basedir (def_t *def, void *data, int index) +{ + if (!is_string (def->type)) { + internal_error (0, "%s: expected string def", __FUNCTION__); + } + EMIT_STRING (def->space, D_STRING (def), pr.comp_dir); +} + +static void +emit_num_files (def_t *def, void *data, int index) +{ + if (!is_integer (def->type)) { + internal_error (0, "%s: expected int def", __FUNCTION__); + } + D_INT (def) = pr.comp_files.size; +} + +static void +emit_files_item (def_t *def, void *data, int index) +{ + if (!is_array (def->type) || !is_string (def->type->t.array.type)) { + internal_error (0, "%s: expected array of string def", __FUNCTION__); + } + if ((unsigned) index >= pr.comp_files.size) { + internal_error (0, "%s: out of bounds index: %d %zd", + __FUNCTION__, index, pr.comp_files.size); + } + EMIT_STRING (def->space, D_STRING (def), pr.comp_files.a[index]); +} + +static def_t * +emit_compunit (const char *modname) +{ + static struct_def_t compunit_struct[] = { + {"unit_name", &type_string, emit_unit_name}, + {"basedir", &type_string, emit_basedir}, + {"num_files", &type_integer, emit_num_files}, + {"files", 0, emit_files_item}, + {0, 0} + }; + int count = pr.comp_files.size; + + pr.unit_name = modname; + compunit_struct[3].type = array_type (&type_string, count); + return emit_structure (".compile_unit", 's', compunit_struct, 0, &pr, + pr.debug_data, sc_static); +} + +void +debug_finish_module (const char *modname) +{ + emit_compunit (modname); +} diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index c16aa9912..7ac1d0822 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -45,22 +45,22 @@ #include "QF/sys.h" #include "QF/va.h" -#include "qfcc.h" -#include "class.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "function.h" -#include "options.h" -#include "reloc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static def_t *defs_freelist; @@ -140,7 +140,7 @@ new_def (const char *name, type_t *type, defspace_t *space, if (!space && storage != sc_extern) internal_error (0, "non-external def with no storage space"); - if (obj_is_class (type)) { + if (is_class (type) || (is_array (type) && is_class(type->t.array.type))) { error (0, "statically allocated instance of class %s", type->t.class->name); return def; @@ -148,11 +148,18 @@ new_def (const char *name, type_t *type, defspace_t *space, if (storage != sc_extern) { int size = type_size (type); + int alignment = type->alignment; + if (!size) { error (0, "%s has incomplete type", name); size = 1; + alignment = 1; } - def->offset = defspace_alloc_loc (space, size); + if (alignment < 1) { + print_type (type); + internal_error (0, "type has no alignment"); + } + def->offset = defspace_alloc_aligned_loc (space, size, alignment); } return def; @@ -180,7 +187,7 @@ alias_def (def_t *def, type_t *type, int offset) return alias; } ALLOC (16384, def_t, defs, alias); - alias->name = save_string (va ("[%s:%d]", def->name, offset)); + alias->name = save_string (va (0, "[%s:%d]", def->name, offset)); alias->return_addr = __builtin_return_address (0); alias->offset = offset; alias->offset_reloc = 1; @@ -194,23 +201,31 @@ alias_def (def_t *def, type_t *type, int offset) } def_t * -temp_def (etype_t type, int size) +temp_def (type_t *type) { def_t *temp; defspace_t *space = current_func->symtab->space; + int size = type_size (type); + int alignment = type->alignment; + if (size < 1 || size > 4) { + internal_error (0, "%d invalid size for temp def", size); + } + if (alignment < 1) { + internal_error (0, "temp type has no alignment"); + } if ((temp = current_func->temp_defs[size - 1])) { current_func->temp_defs[size - 1] = temp->temp_next; temp->temp_next = 0; } else { ALLOC (16384, def_t, defs, temp); - temp->offset = defspace_alloc_loc (space, size); + temp->offset = defspace_alloc_aligned_loc (space, size, alignment); *space->def_tail = temp; space->def_tail = &temp->next; - temp->name = save_string (va (".tmp%d", current_func->temp_num++)); + temp->name = save_string (va (0, ".tmp%d", current_func->temp_num++)); } temp->return_addr = __builtin_return_address (0); - temp->type = ev_types[type]; + temp->type = type; temp->file = pr.source_file; temp->line = pr.source_line; set_storage_bits (temp, sc_local); @@ -272,107 +287,119 @@ def_to_ddef (def_t *def, ddef_t *ddef, int aux) ddef->s_name = ReuseString (def->name); } +static int +zero_memory (expr_t *local_expr, def_t *def, type_t *zero_type, + int init_size, int init_offset) +{ + int zero_size = type_size (zero_type); + expr_t *zero = convert_nil (new_nil_expr (), zero_type); + expr_t *dst; + + for (; init_offset < init_size + 1 - zero_size; init_offset += zero_size) { + dst = new_def_expr (def); + dst = new_offset_alias_expr (zero_type, dst, init_offset); + append_expr (local_expr, assign_expr (dst, zero)); + } + return init_offset; +} + +static void +init_elements_nil (def_t *def) +{ + if (def->local && local_expr) { + // memset to 0 + int init_size = type_size (def->type); + int init_offset = 0; + + if (options.code.progsversion != PROG_ID_VERSION) { + init_offset = zero_memory (local_expr, def, &type_zero, + init_size, init_offset); + } + // probably won't happen any time soon, but who knows... + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_quaternion)) { + init_offset = zero_memory (local_expr, def, &type_quaternion, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (&type_vector)) { + init_offset = zero_memory (local_expr, def, &type_vector, + init_size, init_offset); + } + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_double)) { + init_offset = zero_memory (local_expr, def, &type_double, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (type_default)) { + zero_memory (local_expr, def, type_default, + init_size, init_offset); + } + } + // it's a global, so already initialized to 0 +} + static void init_elements (struct def_s *def, expr_t *eles) { - expr_t *e, *c; - int count, i, num_elements, base_offset; + expr_t *c; pr_type_t *g; - def_t *elements; + element_chain_t element_chain; + element_t *element; - base_offset = def->offset; - if (def->local && local_expr) - base_offset = 0; - if (is_array (def->type)) { - type_t *array_type = def->type->t.array.type; - int array_size = def->type->t.array.size; - elements = calloc (array_size, sizeof (def_t)); - for (i = 0; i < array_size; i++) { - elements[i].type = array_type; - elements[i].space = def->space; - elements[i].offset = base_offset + i * type_size (array_type); - } - num_elements = i; - } else if (is_struct (def->type) - || def->type == &type_vector - || def->type == &type_quaternion) { - symtab_t *symtab = def->type->t.symtab; - symbol_t *field; - - for (i = 0, field = symtab->symbols; field; field = field->next) { - if (field->sy_type != sy_var) - continue; - i++; - } - elements = calloc (i, sizeof (def_t)); - for (i = 0, field = symtab->symbols; field; field = field->next) { - if (field->sy_type != sy_var) - continue; - elements[i].type = field->type; - elements[i].space = def->space; - elements[i].offset = base_offset + field->s.offset; - i++; - } - num_elements = i; - } else { - error (eles, "invalid initializer"); + if (eles->type == ex_nil) { + init_elements_nil (def); return; } - for (count = 0, e = eles->e.block.head; e; count++, e = e->next) { - convert_name (e); - if (e->type == ex_nil && count < num_elements) - convert_nil (e, elements[count].type); - if (e->type == ex_error) { - free (elements); - return; - } - } - if (count > num_elements) { - if (options.warnings.initializer) - warning (eles, "excessive elements in initializer"); - count = num_elements; - } - for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) { - g = D_POINTER (pr_type_t, &elements[i]); - c = constant_expr (e); - if (c->type == ex_block) { - if (!is_array (elements[i].type) - && !is_struct (elements[i].type)) { - error (e, "type mismatch in initializer"); - continue; - } - init_elements (&elements[i], c); - continue; - } else if (c->type == ex_labelref) { - def_t loc; - loc.space = elements[i].space; - loc.offset = elements[i].offset; - reloc_def_op (c->e.labelref.label, &loc); - continue; - } else if (c->type == ex_value) { - if (c->e.value->type == ev_integer - && elements[i].type->type == ev_float) - convert_int (c); - if (get_type (c) != elements[i].type) { - error (e, "type mismatch in initializer"); - continue; - } - } else { - if (!def->local || !local_expr) { - error (e, "non-constant initializer"); - continue; - } - } - if (def->local && local_expr) { - int offset = elements[i].offset; - type_t *type = elements[i].type; - expr_t *ptr = new_pointer_expr (offset, type, def); - append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c)); - } else { - if (c->type != ex_value) + element_chain.head = 0; + element_chain.tail = &element_chain.head; + build_element_chain (&element_chain, def->type, eles, 0); + + if (def->local && local_expr) { + expr_t *dst = new_def_expr (def); + assign_elements (local_expr, dst, &element_chain); + } else { + def_t dummy = *def; + for (element = element_chain.head; element; element = element->next) { + if (!element->expr + || ((c = constant_expr (element->expr))->type == ex_nil)) { + // nil is type agnostic 0 and defspaces are initialized to + // 0 on creation + continue; + } + if (c->type == ex_nil) { + c = convert_nil (c, element->type); + } + dummy.offset = def->offset + element->offset; + g = D_POINTER (pr_type_t, &dummy); + if (c->type == ex_labelref) { + // reloc_def_* use only the def's offset and space, so dummy + // is ok + reloc_def_op (c->e.labelref.label, &dummy); + continue; + } else if (c->type == ex_value) { + if (c->e.value->lltype == ev_integer + && is_float (element->type)) { + convert_int (c); + } + if (is_double (get_type (c)) && is_float (element->type) + && c->implicit) { + convert_double (c); + } + if (get_type (c) != element->type) { + error (c, "type mismatch in initializer"); + continue; + } + } else { + if (!def->local || !local_expr) { + error (c, "non-constant initializer"); + continue; + } + } + if (c->type != ex_value) { internal_error (c, "bogus expression type in init_elements()"); - if (c->e.value->type == ev_string) { + } + if (c->e.value->lltype == ev_string) { EMIT_STRING (def->space, g->string_var, c->e.value->v.string_val); } else { @@ -380,7 +407,8 @@ init_elements (struct def_s *def, expr_t *eles) } } } - free (elements); + + free_element_chain (&element_chain); } static void @@ -396,7 +424,7 @@ init_vector_components (symbol_t *vector_sym, int is_field) symbol_t *sym; const char *name; - name = va ("%s_%s", vector_sym->name, fields[i]); + name = va (0, "%s_%s", vector_sym->name, fields[i]); sym = symtab_lookup (current_symtab, name); if (sym) { if (sym->table == current_symtab) { @@ -407,7 +435,7 @@ init_vector_components (symbol_t *vector_sym, int is_field) expr = sym->s.expr; if (is_field) { if (expr->type != ex_value - || expr->e.value->type != ev_field) { + || expr->e.value->lltype != ev_field) { error (0, "%s redefined", name); sym = 0; } else { @@ -470,7 +498,7 @@ init_field_def (def_t *def, expr_t *init, storage_class_t storage) def->nosave = 1; } // no support for initialized field vector componets (yet?) - if (type == &type_vector && options.code.vector_components) + if (is_vector(type) && options.code.vector_components) init_vector_components (field_sym, 1); } else if (init->type == ex_symbol) { symbol_t *sym = init->e.symbol; @@ -483,20 +511,25 @@ init_field_def (def_t *def, expr_t *init, storage_class_t storage) } } +static int +num_elements (expr_t *e) +{ + int count = 0; + for (e = e->e.block.head; e; e = e->next) { + count++; + } + return count; +} + void -initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space, +initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, storage_class_t storage) { symbol_t *check = symtab_lookup (current_symtab, sym->name); reloc_t *relocs = 0; - if (!type) { - warning (0, "type for %s defaults to %s", sym->name, - type_default->name); - type = type_default; - } if (check && check->table == current_symtab) { - if (check->sy_type != sy_var || check->type != type) { + if (check->sy_type != sy_var || check->type != sym->type) { error (0, "%s redefined", sym->name); } else { // is var and same type @@ -504,7 +537,7 @@ initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space, internal_error (0, "half defined var"); if (storage == sc_extern) { if (init) - warning (0, "initializing external variable"); + error (0, "initializing external variable"); return; } if (init && check->s.def->initialized) { @@ -514,20 +547,10 @@ initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space, sym = check; } } - sym->type = type; + sym->sy_type = sy_var; if (!sym->table) symtab_addsymbol (current_symtab, sym); -// if (storage == sc_global && init && is_scalar (type)) { -// sym->sy_type = sy_const; -// memset (&sym->s.value, 0, sizeof (&sym->s.value)); -// if (init->type != ex_value) { //FIXME arrays/structs -// error (0, "non-constant initializier"); -// } else { -// sym->s.value = init->e.value; -// convert_value (&sym->s.value, sym->type); -// } -// return; -// } + if (sym->s.def && sym->s.def->external) { //FIXME this really is not the right way relocs = sym->s.def->relocs; @@ -535,16 +558,22 @@ initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space, sym->s.def = 0; } if (!sym->s.def) { - sym->s.def = new_def (sym->name, type, space, storage); + if (is_array (sym->type) && !type_size (sym->type) + && init->type == ex_compound) { + sym->type = array_type (sym->type->t.array.type, + num_elements (init)); + } + sym->s.def = new_def (sym->name, sym->type, space, storage); reloc_attach_relocs (relocs, &sym->s.def->relocs); } - if (type == &type_vector && options.code.vector_components) + if (is_vector(sym->type) && options.code.vector_components) init_vector_components (sym, 0); - if (type->type == ev_field && storage != sc_local && storage != sc_param) + if (sym->type->type == ev_field && storage != sc_local + && storage != sc_param) init_field_def (sym->s.def, init, storage); if (storage == sc_extern) { if (init) - warning (0, "initializing external variable"); + error (0, "initializing external variable"); return; } if (!init) @@ -552,48 +581,73 @@ initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space, convert_name (init); if (init->type == ex_error) return; - if (init->type == ex_nil) - convert_nil (init, type); - if ((is_array (type) || is_struct (type) - || type == &type_vector || type == &type_quaternion) - && init->type == ex_block && !init->e.block.result) { + if ((is_array (sym->type) || is_struct (sym->type) + || is_vector(sym->type) || is_quaternion(sym->type)) + && ((init->type == ex_compound) + || init->type == ex_nil)) { init_elements (sym->s.def, init); sym->s.def->initialized = 1; } else { - if (!type_assignable (type, get_type (init))) { + type_t *init_type; + if (init->type == ex_nil) { + convert_nil (init, sym->type); + } + init_type = get_type (init); + if (!type_assignable (sym->type, init_type)) { error (init, "type mismatch in initializer"); return; } - if (local_expr) { + if (storage == sc_local && local_expr) { sym->s.def->initialized = 1; init = assign_expr (new_symbol_expr (sym), init); // fold_constants takes care of int/float conversions append_expr (local_expr, fold_constants (init)); } else { - if (init->type != ex_value) { //FIXME enum etc - error (0, "non-constant initializier"); + int offset = 0; + if (!is_constant (init)) { + error (init, "non-constant initializier"); return; } - if (init->e.value->type == ev_pointer - || init->e.value->type == ev_field) { + while ((init->type == ex_uexpr || init->type == ex_expr) + && init->e.expr.op == 'A') { + if (init->type == ex_expr) { + offset += expr_integer (init->e.expr.e2); + } + init = init->e.expr.e1; + } + if (init->type != ex_value) { //FIXME enum etc + internal_error (0, "initializier not a value"); + return; + } + if (init->e.value->lltype == ev_pointer + || init->e.value->lltype == ev_field) { // FIXME offset pointers D_INT (sym->s.def) = init->e.value->v.pointer.val; if (init->e.value->v.pointer.def) reloc_def_field (init->e.value->v.pointer.def, sym->s.def); } else { ex_value_t *v = init->e.value; + if (!init->implicit + && is_double (init_type) + && (is_integral (sym->type) || is_float (sym->type))) { + warning (init, "assigning double to %s in initializer " + "(use a cast)", sym->type->name); + } if (is_scalar (sym->type)) v = convert_value (v, sym->type); - if (v->type == ev_string) { + if (v->lltype == ev_string) { EMIT_STRING (sym->s.def->space, D_STRING (sym->s.def), v->v.string_val); } else { memcpy (D_POINTER (void, sym->s.def), &v->v, - type_size (type) * sizeof (pr_type_t)); + type_size (sym->type) * sizeof (pr_type_t)); } } - sym->s.def->initialized = sym->s.def->constant = 1; - sym->s.def->nosave = 1; + sym->s.def->initialized = 1; + if (options.code.const_initializers) { + sym->s.def->constant = 1; + sym->s.def->nosave = 1; + } } } sym->s.def->initializer = init; @@ -660,6 +714,8 @@ def_visit_all (def_t *def, int overlap, def = def->alias; if ((ret = visit (def, data))) return ret; + } else { + overlap = 0; } for (def = def->alias_defs; def; def = def->next) { if (def == start_def) diff --git a/tools/qfcc/source/defspace.c b/tools/qfcc/source/defspace.c index f227209d3..1cfe572c3 100644 --- a/tools/qfcc/source/defspace.c +++ b/tools/qfcc/source/defspace.c @@ -44,15 +44,9 @@ #include "QF/sys.h" #include "QF/va.h" -#include "qfcc.h" -#include "defspace.h" -#include "diagnostic.h" -#include "expr.h" -#include "options.h" -#include "reloc.h" -#include "strpool.h" -#include "struct.h" -#include "type.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" typedef struct locref_s { struct locref_s *next; @@ -63,6 +57,33 @@ typedef struct locref_s { static defspace_t *spaces_freelist; static locref_t *locrefs_freelist; +static locref_t * +new_locref (int ofs, int size, locref_t *next) +{ + locref_t *loc; + + ALLOC (1024, locref_t, locrefs, loc); + loc->ofs = ofs; + loc->size = size; + loc->next = next; + return loc; +} + +static void +del_locref (locref_t *loc) +{ + FREE (locrefs, loc); +} + +static defspace_t * +new_defspace (void) +{ + defspace_t *space; + + ALLOC (1024, defspace_t, spaces, space); + return space; +} + #define GROW 1024 static int @@ -98,9 +119,8 @@ grow_space_virtual (defspace_t *space) defspace_t * defspace_new (ds_type_t type) { - defspace_t *space; + defspace_t *space = new_defspace (); - ALLOC (1024, defspace_t, spaces, space); space->def_tail = &space->defs; space->type = type; if (type == ds_backed) { @@ -113,36 +133,84 @@ defspace_new (ds_type_t type) return space; } +void +defspace_delete (defspace_t *space) +{ + locref_t **lr; + + for (lr = &space->free_locs; *lr; lr = &(*lr)->next) { + } + *lr = locrefs_freelist; + locrefs_freelist = space->free_locs; + + if (space->data) { + free (space->data); + } + + while (space->defs) { + def_t *def = space->defs; + space->defs = def->next; + def->space = 0; + free_def (def); + } +} + int defspace_alloc_loc (defspace_t *space, int size) { - int ofs; + return defspace_alloc_aligned_loc (space, size, 1); +} + +int +defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment) +{ + int ofs, pad; locref_t *loc; locref_t **l = &space->free_locs; if (size <= 0) internal_error (0, "invalid number of words requested: %d", size); - while (*l && (*l)->size < size) - l = &(*l)->next; - if ((loc = *l)) { - ofs = (*l)->ofs; - if ((*l)->size == size) { - loc = *l; - *l = (*l)->next; - FREE (locrefs, loc); - } else { - (*l)->ofs += size; - (*l)->size -= size; + if (alignment <= 0) + internal_error (0, "invalid alignment requested: %d", alignment); + while ((loc = *l)) { + ofs = loc->ofs; + pad = alignment * ((ofs + alignment - 1) / alignment) - ofs; + // exact fit, so just shrink the block or remove it if there is no + // padding (any padding remains free) + if (size + pad == loc->size) { + if (!pad) { + *l = loc->next; + del_locref (loc); + } + return ofs + pad; } - return ofs; + // there's excess space in the block. If there's no padding, then + // just shrink it, otherwise split it into two, one on either side + // of the allocated block, such that the padding remains free + if (size + pad < loc->size) { + if (!pad) { + loc->ofs += size; + loc->size -= size; + } else { + loc->next = new_locref (ofs + pad + size, + loc->size - ofs - pad, loc->next); + loc->size = pad; + } + return ofs + pad; + } + l = &(*l)->next; } ofs = space->size; - space->size += size; + pad = alignment * ((ofs + alignment - 1) / alignment) - ofs; + space->size += size + pad; if (space->size > space->max_size) { if (!space->grow || !space->grow (space)) internal_error (0, "unable to allocate %d words", size); } - return ofs; + if (pad) { + *l = new_locref (ofs, pad, 0); + } + return ofs + pad; } void @@ -184,17 +252,13 @@ defspace_free_loc (defspace_t *space, int ofs, int size) loc->size += loc->next->size; loc = loc->next; *l = loc->next; - FREE (locrefs, loc); + del_locref (loc); } return; } } // insert a new free block for the location to be freed - ALLOC (1024, locref_t, locrefs, loc); - loc->ofs = ofs; - loc->size = size; - loc->next = *l; - *l = loc; + *l = new_locref (ofs, size, *l); } int diff --git a/tools/qfcc/source/diagnostic.c b/tools/qfcc/source/diagnostic.c index 2b2347cc2..d7f9fa1fb 100644 --- a/tools/qfcc/source/diagnostic.c +++ b/tools/qfcc/source/diagnostic.c @@ -33,13 +33,18 @@ #include -#include "qfcc.h" -#include "class.h" -#include "diagnostic.h" -#include "expr.h" -#include "function.h" -#include "options.h" -#include "strpool.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/strpool.h" + +diagnostic_hook bug_hook; +diagnostic_hook error_hook; +diagnostic_hook warning_hook; +diagnostic_hook notice_hook; static void report_function (expr_t *e) @@ -72,75 +77,122 @@ report_function (expr_t *e) last_func = current_func; } -static void -_warning (expr_t *e, const char *fmt, va_list args) +static __attribute__((format(printf, 4, 0))) void +format_message (dstring_t *message, const char *msg_type, expr_t *e, + const char *fmt, va_list args) { string_t file = pr.source_file; int line = pr.source_line; - - report_function (e); - if (options.warnings.promote) { - options.warnings.promote = 0; // want to do this only once - fprintf (stderr, "%s: warnings treated as errors\n", "qfcc"); - pr.error_count++; - } + const char *colon = fmt ? ": " : ""; if (e) { file = e->file; line = e->line; } - fprintf (stderr, "%s:%d: warning: ", GETSTR (file), line); - vfprintf (stderr, fmt, args); - fputs ("\n", stderr); + dsprintf (message, "%s:%d: %s%s", GETSTR (file), line, msg_type, colon); + if (fmt) { + davsprintf (message, fmt, args); + } +} + +static __attribute__((format(printf, 4, 0))) void +__warning (expr_t *e, const char *file, int line, + const char *fmt, va_list args) +{ + static int promoted = 0; + dstring_t *message = dstring_new (); + + report_function (e); + if (options.warnings.promote) { + if (!promoted) { + promoted = 1; // want to do this only once + fprintf (stderr, "%s: warnings treated as errors\n", "qfcc"); + } + pr.error_count++; + format_message (message, "error", e, fmt, args); + } else { + format_message (message, "warning", e, fmt, args); + } + + if (options.verbosity > 0) { + dasprintf (message, " (%s:%d)", file, line); + } + if (warning_hook) { + warning_hook (message->str); + } else { + fprintf (stderr, "%s\n", message->str); + } + dstring_delete (message); } void -debug (expr_t *e, const char *fmt, ...) +_debug (expr_t *e, const char *file, int line, const char *fmt, ...) { va_list args; - if (options.verbosity < 1) + if (options.verbosity < 2) return; + report_function (e); va_start (args, fmt); { - string_t file = pr.source_file; - int line = pr.source_line; + dstring_t *message = dstring_new (); - report_function (e); - if (e) { - file = e->file; - line = e->line; - } - fprintf (stderr, "%s:%d: debug: ", GETSTR (file), line); - vfprintf (stderr, fmt, args); - fputs ("\n", stderr); + format_message (message, "debug", e, fmt, args); + dasprintf (message, " (%s:%d)", file, line); + fprintf (stderr, "%s\n", message->str); + dstring_delete (message); } va_end (args); } -void -bug (expr_t *e, const char *fmt, ...) +static __attribute__((noreturn, format(printf, 4, 0))) void +__internal_error (expr_t *e, const char *file, int line, + const char *fmt, va_list args) { - va_list args; - string_t file = pr.source_file; - int line = pr.source_line; - - va_start (args, fmt); + dstring_t *message = dstring_new (); report_function (e); - if (e) { - file = e->file; - line = e->line; + + format_message (message, "internal error", e, fmt, args); + dasprintf (message, " (%s:%d)", file, line); + fprintf (stderr, "%s\n", message->str); + dstring_delete (message); + abort (); +} + +void +_bug (expr_t *e, const char *file, int line, const char *fmt, ...) +{ + va_list args; + + if (options.bug.silent) + return; + + va_start (args, fmt); + if (options.bug.promote) { + __internal_error (e, file, line, fmt, args); + } + + { + dstring_t *message = dstring_new (); + + report_function (e); + + format_message (message, "BUG", e, fmt, args); + dasprintf (message, " (%s:%d)", file, line); + if (bug_hook) { + bug_hook (message->str); + } else { + fprintf (stderr, "%s\n", message->str); + } + dstring_delete (message); } - fprintf (stderr, "%s:%d: BUG: ", GETSTR (file), line); - vfprintf (stderr, fmt, args); - fputs ("\n", stderr); va_end (args); } expr_t * -notice (expr_t *e, const char *fmt, ...) +_notice (expr_t *e, const char *file, int line, const char *fmt, ...) { va_list args; @@ -149,73 +201,72 @@ notice (expr_t *e, const char *fmt, ...) va_start (args, fmt); if (options.notices.promote) { - _warning (e, fmt, args); + __warning (e, file, line, fmt, args); } else { - string_t file = pr.source_file; - int line = pr.source_line; + dstring_t *message = dstring_new (); report_function (e); - if (e) { - file = e->file; - line = e->line; + + format_message (message, "notice", e, fmt, args); + if (options.verbosity > 0) { + dasprintf (message, " (%s:%d)", file, line); } - fprintf (stderr, "%s:%d: notice: ", GETSTR (file), line); - vfprintf (stderr, fmt, args); - fputs ("\n", stderr); + if (notice_hook) { + notice_hook (message->str); + } else { + fprintf (stderr, "%s\n", message->str); + } + dstring_delete (message); } va_end (args); return e; } expr_t * -warning (expr_t *e, const char *fmt, ...) +_warning (expr_t *e, const char *file, int line, const char *fmt, ...) { va_list args; va_start (args, fmt); - _warning (e, fmt, args); + __warning (e, file, line, fmt, args); va_end (args); return e; } -static void -_error (expr_t *e, const char *err, const char *fmt, va_list args) -{ - string_t file = pr.source_file; - int line = pr.source_line; - - report_function (e); - - if (e) { - file = e->file; - line = e->line; - } - fprintf (stderr, "%s:%d: %s%s", GETSTR (file), line, err, - fmt ? ": " : ""); - if (fmt) - vfprintf (stderr, fmt, args); - fputs ("\n", stderr); - pr.error_count++; -} - void -internal_error (expr_t *e, const char *fmt, ...) +_internal_error (expr_t *e, const char *file, int line, const char *fmt, ...) { va_list args; va_start (args, fmt); - _error (e, "internal error", fmt, args); + __internal_error (e, file, line, fmt, args); va_end (args); - abort (); } expr_t * -error (expr_t *e, const char *fmt, ...) +_error (expr_t *e, const char *file, int line, const char *fmt, ...) { va_list args; + pr.error_count++; + + report_function (e); + va_start (args, fmt); - _error (e, "error", fmt, args); + { + dstring_t *message = dstring_new (); + + format_message (message, "error", e, fmt, args); + if (options.verbosity > 0) { + dasprintf (message, " (%s:%d)", file, line); + } + if (error_hook) { + error_hook (message->str); + } else { + fprintf (stderr, "%s\n", message->str); + } + dstring_delete (message); + } va_end (args); if (!e) diff --git a/tools/qfcc/source/disassemble.c b/tools/qfcc/source/disassemble.c index 06624013c..7002510bc 100644 --- a/tools/qfcc/source/disassemble.c +++ b/tools/qfcc/source/disassemble.c @@ -56,7 +56,7 @@ #include "QF/progs.h" #include "QF/sys.h" -#include "qfprogs.h" +#include "tools/qfcc/include/qfprogs.h" void disassemble_progs (progs_t *pr) diff --git a/tools/qfcc/source/dot.c b/tools/qfcc/source/dot.c index 1844a1fe9..333104dad 100644 --- a/tools/qfcc/source/dot.c +++ b/tools/qfcc/source/dot.c @@ -35,10 +35,13 @@ #include "QF/va.h" -#include "dot.h" -#include "function.h" -#include "qfcc.h" -#include "strpool.h" +#include "tools/qfcc/include/dot.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/strpool.h" + +static function_t *last_func; +static int dot_index; void dump_dot (const char *stage, void *data, @@ -46,8 +49,18 @@ dump_dot (const char *stage, void *data, { char *fname; - fname = nva ("%s.%s.%s.dot", GETSTR (pr.source_file), current_func->name, - stage); + if (last_func != current_func) { + last_func = current_func; + dot_index = 0; + } else { + dot_index++; + } + if (current_func) { + fname = nva ("%s.%s.%03d.%s.dot", options.output_file, + current_func->name, dot_index, stage); + } else { + fname = nva ("%s.%03d.%s.dot", options.output_file, dot_index, stage); + } dump_func (data, fname); free (fname); } diff --git a/tools/qfcc/source/dot_dag.c b/tools/qfcc/source/dot_dag.c index bf0e26c63..541993735 100644 --- a/tools/qfcc/source/dot_dag.c +++ b/tools/qfcc/source/dot_dag.c @@ -44,11 +44,11 @@ #include "QF/set.h" #include "QF/va.h" -#include "dags.h" -#include "statements.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/dags.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" static void print_node_def (dstring_t *dstr, dag_t *dag, dagnode_t *node) @@ -176,6 +176,7 @@ dot_dump_dag (void *_dag, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph dag_%p {\n", dag); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot;\n"); dasprintf (dstr, " clusterrank=local;\n"); dasprintf (dstr, " rankdir=TB;\n"); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index accd8485a..84bae7aa2 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -46,13 +46,14 @@ #include "qfalloca.h" -#include "expr.h" -#include "symtab.h" -#include "type.h" -#include "qc-parse.h" -#include "strpool.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/strpool.h" -static const char *expr_names[] = +#include "tools/qfcc/source/qc-parse.h" + +const char *expr_names[] = { "error", "state", @@ -62,18 +63,20 @@ static const char *expr_names[] = "block", "expr", "uexpr", + "def", "symbol", "temp", "vector", "nil", "value", + "compound", + "memset", }; const char * get_op_string (int op) { switch (op) { - case PAS: return ".="; case OR: return "||"; case AND: return "&&"; case EQ: return "=="; @@ -88,6 +91,7 @@ get_op_string (int op) case '*': return "*"; case '/': return "/"; case '%': return "%"; + case MOD: return "%%"; case '&': return "&"; case '|': return "|"; case '^': return "^"; @@ -176,13 +180,13 @@ print_bool (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) for ( ; i < tl_count; i++) dasprintf (dstr, "%*st%s\n", indent, "", i, - i == count ? va ("", + i == count ? va (0, "", bool->true_list->size - count) : ""); for ( ; i < fl_count; i++) dasprintf (dstr, "%*s%sf\n", indent, "", - i == count ? va ("", + i == count ? va (0, "", bool->false_list->size - count) : "", i); @@ -246,7 +250,7 @@ print_block (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) "\n", indent + 4, ""); for (se = e->e.block.head, i = 0; se; se = se->next, i++) dasprintf (dstr, "%*s%d%s\n", - indent + 4, "", i, i, expr_names[se->type]); + indent + 4, "", se->line, i, expr_names[se->type]); dasprintf (dstr, "%*s\n", indent + 2, ""); dasprintf (dstr, "%*s>];\n", indent, ""); @@ -320,8 +324,16 @@ print_subexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"r\"];\n", indent, "", e, e->e.expr.e2); } - dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e, - get_op_string (e->e.expr.op), e->line); + if (e->e.expr.op == 'A') { + dstring_t *typestr = dstring_newstr(); + print_type_str (typestr, e->e.expr.type); + dasprintf (dstr, "%*se_%p [label=\"%s (%s)\\n%d\"];\n", indent, "", e, + get_op_string (e->e.expr.op), typestr->str, e->line); + dstring_delete (typestr); + } else { + dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e, + get_op_string (e->e.expr.op), e->line); + } } static void @@ -344,6 +356,15 @@ print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) dstring_delete (typestr); } +static void +print_def (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + + dasprintf (dstr, "%*se_%p [label=\"d %s\\n%d\"];\n", indent, "", e, + e->e.def->name, e->line); +} + static void print_symbol (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -367,7 +388,42 @@ print_vector (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { int indent = level * 2 + 2; - dasprintf (dstr, "%*se_%p [label=\"vector FIXME\"];\n", indent, "", e); + if (is_vector(e->e.vector.type)) { + expr_t *x = e->e.vector.list; + expr_t *y = x->next; + expr_t *z = y->next; + _print_expr (dstr, x, level, id, next); + _print_expr (dstr, y, level, id, next); + _print_expr (dstr, z, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, x); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, y); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, z); + } + if (is_quaternion(e->e.vector.type)) { + if (e->e.vector.list->next->next) { + expr_t *x = e->e.vector.list; + expr_t *y = x->next; + expr_t *z = y->next; + expr_t *w = z->next; + _print_expr (dstr, x, level, id, next); + _print_expr (dstr, y, level, id, next); + _print_expr (dstr, z, level, id, next); + _print_expr (dstr, w, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, x); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, y); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, z); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, w); + } else { + expr_t *v = e->e.vector.list; + expr_t *s = v->next; + _print_expr (dstr, v, level, id, next); + _print_expr (dstr, s, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, v); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, s); + } + } + dasprintf (dstr, "%*se_%p [label=\"vector %d\"];\n", indent, "", e, + e->line); } static void @@ -385,22 +441,31 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) int indent = level * 2 + 2; type_t *type; const char *label = "?!?"; + static dstring_t *type_str; - switch (e->e.value->type) { + if (!type_str) { + type_str = dstring_newstr (); + } + + switch (e->e.value->lltype) { case ev_string: - label = va ("\\\"%s\\\"", quote_string (e->e.value->v.string_val)); + label = va (0, "\\\"%s\\\"", + quote_string (e->e.value->v.string_val)); + break; + case ev_double: + label = va (0, "f %g", e->e.value->v.double_val); break; case ev_float: - label = va ("f %g", e->e.value->v.float_val); + label = va (0, "f %g", e->e.value->v.float_val); break; case ev_vector: - label = va ("'%g %g %g'", + label = va (0, "'%g %g %g'", e->e.value->v.vector_val[0], e->e.value->v.vector_val[1], e->e.value->v.vector_val[2]); break; case ev_quat: - label = va ("'%g %g %g %g'", + label = va (0, "'%g %g %g %g'", e->e.value->v.quaternion_val[0], e->e.value->v.quaternion_val[1], e->e.value->v.quaternion_val[2], @@ -408,33 +473,37 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) break; case ev_pointer: type = e->e.value->v.pointer.type; + dstring_clearstr(type_str); + if (type) { + print_type_str (type_str, type); + } if (e->e.value->v.pointer.def) - label = va ("(%s)[%d]<%s>", - type ? pr_type_name[type->type] : "???", + label = va (0, "(*%s)[%d]<%s>", + type ? type_str->str : "???", e->e.value->v.pointer.val, e->e.value->v.pointer.def->name); else - label = va ("(%s)[%d]", - type ? pr_type_name[type->type] : "???", + label = va (0, "(*%s)[%d]", + type ? type_str->str : "???", e->e.value->v.pointer.val); break; case ev_field: - label = va ("field %d", e->e.value->v.pointer.val); + label = va (0, "field %d", e->e.value->v.pointer.val); break; case ev_entity: - label = va ("ent %d", e->e.value->v.integer_val); + label = va (0, "ent %d", e->e.value->v.integer_val); break; case ev_func: - label = va ("func %d", e->e.value->v.integer_val); + label = va (0, "func %d", e->e.value->v.integer_val); break; case ev_integer: - label = va ("i %d", e->e.value->v.integer_val); + label = va (0, "i %d", e->e.value->v.integer_val); break; case ev_uinteger: - label = va ("u %u", e->e.value->v.uinteger_val); + label = va (0, "u %u", e->e.value->v.uinteger_val); break; case ev_short: - label = va ("s %d", e->e.value->v.short_val); + label = va (0, "s %d", e->e.value->v.short_val); break; case ev_void: label = ""; @@ -450,6 +519,29 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) e->line); } +static void +print_compound (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + dasprintf (dstr, "%*se_%p [label=\"compound init\"];\n", indent, "", e); +} + +static void +print_memset (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + expr_t *dst = e->e.memset.dst; + expr_t *val = e->e.memset.val; + expr_t *count = e->e.memset.count; + _print_expr (dstr, dst, level, id, next); + _print_expr (dstr, val, level, id, next); + _print_expr (dstr, count, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, dst); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, val); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, count); + dasprintf (dstr, "%*se_%p [label=\"memset\"];\n", indent, "", e); +} + static void _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -462,11 +554,14 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) print_block, print_subexpr, print_uexpr, + print_def, print_symbol, print_temp, print_vector, print_nil, print_value, + print_compound, + print_memset, }; int indent = level * 2 + 2; @@ -478,7 +573,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) return; e->printid = id; - if ((int) e->type < 0 || e->type > ex_value) { + if ((int) e->type < 0 || e->type > ex_memset) { dasprintf (dstr, "%*se_%p [label=\"(bad expr type)\\n%d\"];\n", indent, "", e, e->line); return; @@ -495,6 +590,7 @@ dump_dot_expr (void *_e, const char *filename) expr_t *e = (expr_t *) _e; dasprintf (dstr, "digraph expr_%p {\n", e); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot; rankdir=TB; compound=true;\n"); _print_expr (dstr, e, 0, ++id, 0); dasprintf (dstr, "}\n"); diff --git a/tools/qfcc/source/dot_flow.c b/tools/qfcc/source/dot_flow.c index 7c8357611..ecfbcc01f 100644 --- a/tools/qfcc/source/dot_flow.c +++ b/tools/qfcc/source/dot_flow.c @@ -44,18 +44,22 @@ #include "QF/set.h" #include "QF/va.h" -#include "dags.h" -#include "flow.h" -#include "function.h" -#include "expr.h" -#include "statements.h" -#include "strpool.h" +#include "tools/qfcc/include/dags.h" +#include "tools/qfcc/include/flow.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/strpool.h" + +typedef struct { + void (*node) (dstring_t *, flowgraph_t *, flownode_t *, int); + void (*edge) (dstring_t *, flowgraph_t *, flowedge_t *, int); + void (*extra) (dstring_t *, flowgraph_t *, int); +} flow_print_t; typedef struct { const char *type; - void (*print_node) (dstring_t *, flowgraph_t *, flownode_t *, int); - void (*print_edge) (dstring_t *, flowgraph_t *, flowedge_t *, int); - void (*print_extra) (dstring_t *, flowgraph_t *, int); + flow_print_t *print; } flow_dot_t; static void @@ -110,7 +114,7 @@ print_flow_node_dag (dstring_t *dstr, flowgraph_t *graph, flownode_t *node, int level) { if (node->dag) - print_dag (dstr, node->dag, va ("%d (%d)", node->id, node->dfn)); + print_dag (dstr, node->dag, va (0, "%d (%d)", node->id, node->dfn)); else print_flow_node (dstr, graph, node, level); } @@ -177,27 +181,21 @@ print_flow_node_live (dstring_t *dstr, flowgraph_t *graph, flownode_t *node, int level) { int indent = level * 2 + 2; - int live; set_t *use = node->live_vars.use; set_t *def = node->live_vars.def; set_t *in = node->live_vars.in; set_t *out = node->live_vars.out; - live = node->live_vars.out && !set_is_empty (node->live_vars.out); - - if (live) { - dasprintf (dstr, "%*sfn_%p [label=\"", indent, "", node); - dasprintf (dstr, "use: %s\\n", set_as_string (use)); - dasprintf (dstr, "def: %s\\n", set_as_string (def)); - dasprintf (dstr, "in: %s\\n", set_as_string (in)); - dasprintf (dstr, "out: %s\"];\n", set_as_string (out)); - } else { - print_flow_node (dstr, graph, node, level); - } + dasprintf (dstr, "%*sfn_%p [label=\"", indent, "", node); + dasprintf (dstr, "use: %s\\n", set_as_string (use)); + dasprintf (dstr, "def: %s\\n", set_as_string (def)); + dasprintf (dstr, "in: %s\\n", set_as_string (in)); + dasprintf (dstr, "out: %s", set_as_string (out)); + dasprintf (dstr, "\"];\n"); } static void -print_extra_live (dstring_t *dstr, flowgraph_t *graph, int level) +print_flow_vars (dstring_t *dstr, flowgraph_t *graph, int level) { int indent = level * 2 + 2; int i; @@ -208,8 +206,9 @@ print_extra_live (dstring_t *dstr, flowgraph_t *graph, int level) "cellspacing=\"0\">\n", indent + 2, ""); for (i = 0; i < graph->func->num_vars; i++) { var = graph->func->vars[i]; - dasprintf (dstr, "%*s(%d) %s\n", indent + 4, "", - var->number, html_string(operand_string (var->op))); + dasprintf (dstr, "%*s(%d) %s %s\n", indent + 4, "", + var->number, html_string(operand_string (var->op)), + set_as_string (var->define)); } dasprintf (dstr, "%*s>];\n", indent + 2, ""); } @@ -296,12 +295,34 @@ print_flow_edge_statements (dstring_t *dstr, flowgraph_t *graph, dasprintf (dstr, "];\n"); } +static flow_print_t null_print[] = { + { print_flow_node, print_flow_edge }, + { 0 } +}; +static flow_print_t dag_print[] = { + { print_flow_node_dag, print_flow_edge_dag}, + { 0 } +}; +static flow_print_t live_print[] = { + { print_flow_node_live, print_flow_edge, print_flow_vars}, + { print_flow_node_statements, print_flow_edge_statements}, + { 0 } +}; +static flow_print_t reaching_print[] = { + { print_flow_node_reaching, print_flow_edge}, + { 0 } +}; +static flow_print_t statements_print[] = { + { print_flow_node_statements, print_flow_edge_statements}, + { 0 } +}; + static flow_dot_t flow_dot_methods[] = { - {"", print_flow_node, print_flow_edge}, - {"dag", print_flow_node_dag, print_flow_edge_dag}, - {"live", print_flow_node_live, print_flow_edge, print_extra_live}, - {"reaching", print_flow_node_reaching, print_flow_edge}, - {"statements", print_flow_node_statements, print_flow_edge_statements}, + {"", null_print}, + {"dag", dag_print}, + {"live", live_print}, + {"reaching", reaching_print}, + {"statements", statements_print}, }; static void @@ -311,21 +332,24 @@ print_flowgraph (flow_dot_t *method, flowgraph_t *graph, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph flowgraph_%s_%p {\n", method->type, graph); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot;\n"); dasprintf (dstr, " clusterrank=local;\n"); dasprintf (dstr, " rankdir=TB;\n"); dasprintf (dstr, " compound=true;\n"); - for (i = 0; i < graph->num_nodes; i++) { - method->print_node (dstr, graph, graph->nodes[i], 0); + for (flow_print_t *print = method->print; print->node; print++) { + for (i = 0; i < graph->num_nodes; i++) { + print->node (dstr, graph, graph->nodes[i], 0); + } + for (i = 0; i < graph->num_edges; i++) { + if ((int) graph->edges[i].head >= graph->num_nodes + || (int) graph->edges[i].tail >= graph->num_nodes) + continue; // dummy node + print->edge (dstr, graph, &graph->edges[i], 0); + } + if (print->extra) + print->extra (dstr, graph, 0); } - for (i = 0; i < graph->num_edges; i++) { - if ((int) graph->edges[i].head >= graph->num_nodes - || (int) graph->edges[i].tail >= graph->num_nodes) - continue; // dummy node - method->print_edge (dstr, graph, &graph->edges[i], 0); - } - if (method->print_extra) - method->print_extra (dstr, graph, 0); dasprintf (dstr, "}\n"); if (filename) { diff --git a/tools/qfcc/source/dot_sblock.c b/tools/qfcc/source/dot_sblock.c index 72b245efe..18089681c 100644 --- a/tools/qfcc/source/dot_sblock.c +++ b/tools/qfcc/source/dot_sblock.c @@ -41,17 +41,18 @@ #include #include +#include #include -#include "dags.h" -#include "flow.h" -#include "expr.h" -#include "qfcc.h" -#include "function.h" -#include "statements.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/dags.h" +#include "tools/qfcc/include/flow.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" static void flow_statement (dstring_t *dstr, statement_t *s) @@ -62,6 +63,30 @@ flow_statement (dstring_t *dstr, statement_t *s) dasprintf (dstr, "%s", html_string(operand_string (s->opa))); dasprintf (dstr, "%s", html_string(operand_string (s->opb))); dasprintf (dstr, "%s", html_string(operand_string (s->opc))); +#if 0 + if (s->number >= 0) { + set_t *use = set_new (); + set_t *def = set_new (); + set_t *kill = set_new (); + set_t *ops = set_new (); + operand_t *operands[FLOW_OPERANDS]; + + flow_analyze_statement (s, use, def, kill, operands); + for (int i = 0; i < FLOW_OPERANDS; i++) { + if (operands[i]) { + set_add (ops, i); + } + } + dasprintf (dstr, "%s", html_string(set_as_string (use))); + dasprintf (dstr, "%s", html_string(set_as_string (def))); + dasprintf (dstr, "%s", html_string(set_as_string (kill))); + dasprintf (dstr, "%s", html_string(set_as_string (ops))); + + set_delete (use); + set_delete (def); + set_delete (kill); + } +#endif dasprintf (dstr, "\n"); } @@ -77,11 +102,10 @@ dot_sblock (dstring_t *dstr, sblock_t *sblock, int blockno) dasprintf (dstr, " \n"); dasprintf (dstr, " %p(%d)\n", sblock, blockno); - dasprintf (dstr, " \n"); + dasprintf (dstr, " \n"); for (l = sblock->labels; l; l = l->next) dasprintf (dstr, " %s(%d)\n", l->name, l->used); dasprintf (dstr, " \n"); - dasprintf (dstr, " \n"); dasprintf (dstr, " \n"); for (s = sblock->statements; s; s = s->next) flow_statement (dstr, s); @@ -128,6 +152,7 @@ print_sblock (sblock_t *sblock, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph sblock_%p {\n", sblock); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot; rankdir=TB;\n"); for (i = 0; sblock; sblock = sblock->next, i++) flow_sblock (dstr, sblock, i); diff --git a/tools/qfcc/source/dot_type.c b/tools/qfcc/source/dot_type.c new file mode 100644 index 000000000..522fa91fb --- /dev/null +++ b/tools/qfcc/source/dot_type.c @@ -0,0 +1,282 @@ +/* + dot_type.c + + "emit" types to dot (graphvis). + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/03/28 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include +#include +#include +#include + +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/strpool.h" + +typedef void (*print_f) (dstring_t *dstr, type_t *, int, int); +static void dot_print_type (dstring_t *dstr, type_t *t, int level, int id); + +static void +print_pointer (dstring_t *dstr, type_t *t, int level, int id) +{ + int indent = level * 2 + 2; + type_t *aux = t->t.fldptr.type; + + dot_print_type (dstr, aux, level, id); + dasprintf (dstr, "%*st_%p -> \"t_%p\";\n", indent, "", t, aux); + dasprintf (dstr, "%*st_%p [label=\"%c\"];\n", indent, "", t, + t->type == ev_pointer ? '*' : '.'); +} + +static void +print_ellipsis (dstring_t *dstr, int level, int id) +{ + static int ellipsis_id; + int indent = level * 2 + 2; + + if (ellipsis_id == id) { + return; + } + ellipsis_id = id; + dasprintf (dstr, "%*st_ellipsis [label=\"...\"];\n", indent, ""); +} + +static void +print_function (dstring_t *dstr, type_t *t, int level, int id) +{ + int indent = level * 2 + 2; + const ty_func_t *func = &t->t.func; + type_t *ret = func->type; + type_t *param; + + dot_print_type (dstr, ret, level + 1, id); + if (func->num_params < 0) { + for (int i = 0; i < ~func->num_params; i++) { + param = func->param_types[i]; + dot_print_type (dstr, param, level + 1, id); + } + print_ellipsis (dstr, level, id); + } else { + for (int i = 0; i < func->num_params; i++) { + param = func->param_types[i]; + dot_print_type (dstr, param, level + 1, id); + } + } + dasprintf (dstr, "%*st_%p -> \"t_%p\" [label=\"r\"];\n", indent, "", + t, ret); + if (func->num_params < 0) { + for (int i = 0; i < ~func->num_params; i++) { + param = func->param_types[i]; + dasprintf (dstr, "%*st_%p -> \"t_%p\";\n", indent, "", t, param); + } + dasprintf (dstr, "%*st_%p -> \"t_ellipsis\";\n", indent, "", t); + } else { + for (int i = 0; i < func->num_params; i++) { + param = func->param_types[i]; + dasprintf (dstr, "%*st_%p -> \"t_%p\";\n", indent, "", t, param); + } + } + dasprintf (dstr, "%*st_%p [label=\"( )\"];\n", indent, "", t); +} + +static void +print_basic (dstring_t *dstr, type_t *t, int level, int id) +{ + if (t->type == ev_pointer || t->type == ev_field) { + print_pointer (dstr, t, level, id); + } else if (t->type == ev_func) { + print_function (dstr, t, level, id); + } else { + int indent = level * 2 + 2; + dasprintf (dstr, "%*st_%p [label=\"%s\"];\n", indent, "", t, t->name); + } +} + +static void +print_struct (dstring_t *dstr, type_t *t, int level, int id) +{ + int indent = level * 2 + 2; + const symtab_t *symtab = t->t.symtab; + const symbol_t *sym; + int pnum; + static const char *struct_type_names[3] = {"struct", "union", "enum"}; + const char *struct_type = struct_type_names[t->meta - ty_struct]; + + if (!symtab) { + dasprintf (dstr, "%*st_%p [label=\"%s %s\"];\n", indent, "", t, + struct_type, quote_string (t->name)); + return; + } + if (t->meta != ty_enum) { + for (sym = symtab->symbols; sym; sym = sym->next) { + if (sym->sy_type != sy_var) { + continue; + } + dot_print_type (dstr, sym->type, level, id); + } + for (pnum = 0, sym = symtab->symbols; sym; sym = sym->next) { + if (sym->sy_type != sy_var) { + continue; + } + dasprintf (dstr, "%*st_%p:f%d -> \"t_%p\";\n", indent, "", + t, pnum++, sym->type); + } + } + dasprintf (dstr, "%*st_%p [shape=none,label=<\n", indent, "", t); + dasprintf (dstr, "%*s\n", + indent + 2, ""); + dasprintf (dstr, "%*s\n", + indent + 4, "", + struct_type, quote_string (t->name)); + for (pnum = 0, sym = symtab->symbols; sym; sym = sym->next) { + int val; + const char *port = ""; + if (sym->sy_type == sy_const) { + val = sym->s.value->v.integer_val; + } else { + if (sym->sy_type != sy_var) { + continue; + } + val = sym->s.offset; + port = va (0, " port=\"f%d\"", pnum++); + } + dasprintf (dstr, "%*s%d\n", + indent + 4, "", + quote_string (sym->name), port, val); + } + dasprintf (dstr, "%*s
%s %s
%s
\n", indent + 2, ""); + dasprintf (dstr, "%*s>];\n", indent, ""); +} + +static void +print_array (dstring_t *dstr, type_t *t, int level, int id) +{ + int indent = level * 2 + 2; + type_t *type = t->t.array.type; + + dot_print_type (dstr, type, level, id); + dasprintf (dstr, "%*st_%p -> \"t_%p\";\n", indent, "", t, type); + if (t->t.array.base) { + dasprintf (dstr, "%*st_%p [label=\"[%d..%d]\"];\n", indent, "", t, + t->t.array.base, + t->t.array.base + t->t.array.size - 1); + } else { + dasprintf (dstr, "%*st_%p [label=\"[%d]\"];\n", indent, "", t, + t->t.array.size); + } +} + +static void +print_class (dstring_t *dstr, type_t *t, int level, int id) +{ + int indent = level * 2 + 2; + dasprintf (dstr, "%*st_%p [label=\"class '%s'\"];\n", indent, "", t, + t->t.class->name); +} + +static void +print_alias (dstring_t *dstr, type_t *t, int level, int id) +{ + int indent = level * 2 + 2; + type_t *aux = t->t.alias.aux_type; + type_t *full = t->t.alias.full_type; + + dot_print_type (dstr, aux, level, id); + dot_print_type (dstr, full, level, id); + dasprintf (dstr, "%*st_%p -> \"t_%p\";\n", indent, "", t, aux); + dasprintf (dstr, "%*st_%p -> \"t_%p\";\n", indent, "", t, full); + dasprintf (dstr, "%*st_%p [label=\"alias '%s'\"];\n", indent, "", t, + t->name); +} + +static void +dot_print_type (dstring_t *dstr, type_t *t, int level, int id) +{ + static print_f print_funcs[] = { + print_basic, + print_struct, + print_struct, + print_struct, + print_array, + print_class, + print_alias, + }; + int indent = level * 2 + 2; + + if (!t) { + dasprintf (dstr, "%*s\"e_%p\" [label=\"(null)\"];\n", indent, "", t); + return; + } + if (t->printid == id) // already printed this type + return; + t->printid = id; + + if ((unsigned) t->meta >= sizeof (print_funcs) / sizeof (print_funcs[0])) { + dasprintf (dstr, "%*se_%p [label=\"(bad type meta)\\n%d\"];\n", + indent, "", t, t->meta); + return; + } + print_funcs [t->meta] (dstr, t, level, id); +} + +void +dump_dot_type (void *_t, const char *filename) +{ + static int id = 0; + dstring_t *dstr = dstring_newstr (); + type_t *t = (type_t *) _t; + + dasprintf (dstr, "digraph type_%p {\n", t); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); + dasprintf (dstr, " layout=dot; rankdir=TB; compound=true;\n"); + dot_print_type (dstr, t, 0, ++id); + dasprintf (dstr, "}\n"); + + if (filename) { + QFile *file; + + file = Qopen (filename, "wt"); + Qwrite (file, dstr->str, dstr->size - 1); + Qclose (file); + } else { + fputs (dstr->str, stdout); + } + dstring_delete (dstr); +} diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index dce3bd265..317e70c03 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -43,23 +43,23 @@ #include "QF/progs.h" #include "QF/va.h" -#include "obj_file.h" -#include "obj_type.h" -#include "qfprogs.h" -#include "reloc.h" -#include "strpool.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/qfprogs.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/strpool.h" static int cmp (const void *_a, const void *_b) { - const ddef_t *a = (const ddef_t *)_a; - const ddef_t *b = (const ddef_t *)_b; + const pr_def_t *a = (const pr_def_t *)_a; + const pr_def_t *b = (const pr_def_t *)_b; return a->ofs - b->ofs; } static void -dump_def (progs_t *pr, ddef_t *def, int indent) +dump_def (progs_t *pr, pr_def_t *def, int indent) { const char *name; const char *type; @@ -69,10 +69,10 @@ dump_def (progs_t *pr, ddef_t *def, int indent) const char *str; int saveglobal; - if (!def->type && !def->ofs && !def->s_name) + if (!def->type && !def->ofs && !def->name) return; - name = PR_GetString (pr, def->s_name); + name = PR_GetString (pr, def->name); type = pr_type_name[def->type & ~DEF_SAVEGLOBAL]; saveglobal = (def->type & DEF_SAVEGLOBAL) != 0; offset = def->ofs; @@ -86,19 +86,27 @@ dump_def (progs_t *pr, ddef_t *def, int indent) break; case ev_string: string = G_INT (pr, offset); - if (string < 0 || string >= pr->progs->numstrings) { + // at runtime, strings can be negative (thus string_t is + // signed), but negative strings means they have been + // dynamically allocated, thus a negative string index should + // never appear in compiled code + if (string < 0 + || (pr_uint_t) string >= pr->progs->numstrings) { str = "invalid string offset"; - comment = va (" %d %s", string, str); + comment = va (0, " %d %s", string, str); } else { str = quote_string (pr->pr_strings + G_INT (pr, offset)); - comment = va (" %d \"%s\"", string, str); + comment = va (0, " %d \"%s\"", string, str); } break; case ev_float: - comment = va (" %g", G_FLOAT (pr, offset)); + comment = va (0, " %g", G_FLOAT (pr, offset)); + break; + case ev_double: + comment = va (0, " %.17g", G_DOUBLE (pr, offset)); break; case ev_vector: - comment = va (" '%g %g %g'", + comment = va (0, " '%g %g %g'", G_VECTOR (pr, offset)[0], G_VECTOR (pr, offset)[1], G_VECTOR (pr, offset)[2]); @@ -106,35 +114,35 @@ dump_def (progs_t *pr, ddef_t *def, int indent) case ev_entity: break; case ev_field: - comment = va (" %x", G_INT (pr, offset)); + comment = va (0, " %x", G_INT (pr, offset)); break; case ev_func: { func_t func = G_FUNCTION (pr, offset); int start; - if (func >= 0 && func < pr->progs->numfunctions) { + if (func < pr->progs->numfunctions) { start = pr->pr_functions[func].first_statement; if (start > 0) - comment = va (" %d @ %x", func, start); + comment = va (0, " %d @ %x", func, start); else - comment = va (" %d = #%d", func, -start); + comment = va (0, " %d = #%d", func, -start); } else { - comment = va (" %d = illegal function", func); + comment = va (0, " %d = illegal function", func); } } break; case ev_pointer: - comment = va (" %x", G_INT (pr, offset)); + comment = va (0, " %x", G_INT (pr, offset)); break; case ev_quat: - comment = va (" '%g %g %g %g'", + comment = va (0, " '%g %g %g %g'", G_QUAT (pr, offset)[0], G_QUAT (pr, offset)[1], G_QUAT (pr, offset)[2], G_QUAT (pr, offset)[3]); break; case ev_integer: - comment = va (" %d", G_INT (pr, offset)); + comment = va (0, " %d", G_INT (pr, offset)); break; case ev_short: break; @@ -145,15 +153,16 @@ dump_def (progs_t *pr, ddef_t *def, int indent) break; } } - printf ("%*s %x %d %s %s%s\n", indent * 12, "", - offset, saveglobal, name, type, comment); + printf ("%*s %x:%d %d %s %s:%x %s\n", indent * 12, "", + offset, def->size, saveglobal, name, type, def->type_encoding, + comment); } void dump_globals (progs_t *pr) { unsigned int i; - ddef_t *global_defs = pr->pr_globaldefs; + pr_def_t *global_defs = pr->pr_globaldefs; if (sorted) { global_defs = malloc (pr->progs->numglobaldefs * sizeof (ddef_t)); @@ -162,7 +171,7 @@ dump_globals (progs_t *pr) qsort (global_defs, pr->progs->numglobaldefs, sizeof (ddef_t), cmp); } for (i = 0; i < pr->progs->numglobaldefs; i++) { - ddef_t *def = &global_defs[i]; + pr_def_t *def = &global_defs[i]; dump_def (pr, def, 0); } } @@ -177,9 +186,9 @@ dump_fields (progs_t *pr) const char *comment; for (i = 0; i < pr->progs->numfielddefs; i++) { - ddef_t *def = &pr->pr_fielddefs[i]; + pr_def_t *def = &pr->pr_fielddefs[i]; - name = PR_GetString (pr, def->s_name); + name = PR_GetString (pr, def->name); type = pr_type_name[def->type & ~DEF_SAVEGLOBAL]; offset = def->ofs; @@ -189,26 +198,66 @@ dump_fields (progs_t *pr) } } +void +qfo_fields (qfo_t *qfo) +{ + unsigned int i; + const char *name; + const char *typestr; + qfot_type_t *type; + int offset; + const char *comment; + qfo_mspace_t *space = &qfo->spaces[qfo_entity_space]; + + if (qfo_entity_space >= qfo->num_spaces) { + printf ("no entity space\n"); + return; + } + if (!space->num_defs) { + printf ("no fields\n"); + return; + } + + for (i = 0; i < space->num_defs; i++) { + qfo_def_t *def = space->defs + i; + + name = QFO_GETSTR (qfo, def->name); + //FIXME check type + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, def->type); + typestr = QFO_GETSTR (qfo, type->encoding); + offset = def->offset; + + comment = ""; + + printf ("%d %s %s%s\n", offset, name, typestr, comment); + } +} + void dump_functions (progs_t *pr) { - int i, j; + pr_uint_t i, j, count; const char *name; - int start, count; + int start; const char *comment; + pr_def_t *encodings_def; + pointer_t type_encodings = 0; + + encodings_def = PR_FindGlobal (pr, ".type_encodings"); + if (encodings_def) { + type_encodings = encodings_def->ofs; + } for (i = 0; i < pr->progs->numfunctions; i++) { dfunction_t *func = &pr->pr_functions[i]; name = PR_GetString (pr, func->s_name); - comment = ""; - start = func->first_statement; if (start > 0) - comment = va (" @ %x", start); + comment = va (0, " @ %x", start); else - comment = va (" = #%d", -start); + comment = va (0, " = #%d", -start); printf ("%-5d %s%s: %d (", i, name, comment, func->numparms); if (func->numparms < 0) @@ -216,20 +265,27 @@ dump_functions (progs_t *pr) else count = func->numparms; for (j = 0; j < count; j++) - printf (" %d", func->parm_size[j]); + printf (" %d:%d", func->parm_size[j].alignment, + func->parm_size[j].size); printf (") %d @ %x", func->locals, func->parm_start); puts (""); - if (pr->debug) { - pr_auxfunction_t *aux = pr->auxfunction_map[i]; - if (!aux) + if (type_encodings) { + pr_auxfunction_t *aux = PR_Debug_MappedAuxFunction (pr, i); + if (!aux) { continue; + } printf (" %d %s:%d %d %d %d %x\n", aux->function, PR_GetString (pr, func->s_file), aux->source_line, aux->line_info, aux->local_defs, aux->num_locals, aux->return_type); - for (j = 0; j < (int)aux->num_locals; j++) - dump_def (pr, pr->local_defs + aux->local_defs + j, 1); + pr_def_t *local_defs = PR_Debug_LocalDefs (pr, aux); + if (!local_defs) { + continue; + } + for (j = 0; j < aux->num_locals; j++) { + dump_def (pr, local_defs + j, 1); + } } } } @@ -257,16 +313,17 @@ void qfo_globals (qfo_t *qfo) { qfo_def_t *def; - int i; - int space; + unsigned i; + unsigned space; int count = 0; for (space = 0; space < qfo->num_spaces; space++) { for (i = 0; i < qfo->spaces[space].num_defs; i++, count++) { def = &qfo->spaces[space].defs[i]; - printf ("%-5d %2d:%-5x %s %s %s", count, space, def->offset, + printf ("%-5d %2d:%-5x %s %s %x %s", count, space, def->offset, flags_string (def->flags), QFO_GETSTR (qfo, def->name), + def->type, QFO_TYPESTR (qfo, def->type)); if (!(def->flags & QFOD_EXTERNAL) && qfo->spaces[space].d.data) printf (" %d", @@ -282,9 +339,14 @@ qfo_relocs (qfo_t *qfo) qfo_reloc_t *reloc; qfo_def_t *def; qfo_func_t *func; - int i; + int opind; + dstatement_t *statement; + unsigned i; for (i = 0; i < qfo->num_relocs; i++) { + if (i == qfo->num_relocs - qfo->num_loose_relocs) { + printf ("---- unbound relocs ----\n"); + } reloc = qfo->relocs + i; if ((unsigned) reloc->type > rel_def_field_ofs) { printf ("%d unknown reloc: %d\n", i, reloc->type); @@ -344,10 +406,13 @@ qfo_relocs (qfo_t *qfo) case rel_op_b_def_ofs: case rel_op_c_def_ofs: def = qfo->defs + reloc->target; - printf (" op.%c@%x def#%d %s", - reloc->type - rel_op_a_def_ofs + 'a', + opind = reloc->type - rel_op_a_def_ofs; + statement = QFO_STATEMENT (qfo, reloc->offset); + printf (" op.%c@%x def#%d %s+%d", + opind + 'a', reloc->offset, reloc->target, - QFO_GETSTR (qfo, def->name)); + QFO_GETSTR (qfo, def->name), + ((pr_ushort_t *)statement)[opind + 1]); break; case rel_def_def_ofs: def = qfo->defs + reloc->target; @@ -385,8 +450,9 @@ qfo_functions (qfo_t *qfo) { qfo_def_t *def; qfo_func_t *func; - int i, d; - int space; + unsigned i, j, d; + unsigned space; + qfo_mspace_t *locals; for (i = 0; i < qfo->num_funcs; i++) { func = &qfo->funcs[i]; @@ -410,17 +476,40 @@ qfo_functions (qfo_t *qfo) printf (" @ %x", func->code); else printf (" = #%d", -func->code); - puts (""); + printf (" loc: %d\n", func->locals_space); + if (func->locals_space) { + locals = &qfo->spaces[func->locals_space]; + printf ("%*s%d %p %d %p %d %d\n", 16, "", locals->type, + locals->defs, locals->num_defs, + locals->d.data, locals->data_size, locals->id); + for (j = 0; j < locals->num_defs; j++) { + qfo_def_t *def = locals->defs + j; + int offset; + const char *typestr; + const char *name; + qfot_type_t *type; + + name = QFO_GETSTR (qfo, def->name); + //FIXME check type + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, + def->type); + typestr = QFO_GETSTR (qfo, type->encoding); + offset = def->offset; + + printf ("%*s%d %s %s\n", 20, "", offset, name, typestr); + } + } } } static const char *ty_meta_names[] = { - "ty_none", + "ty_basic", "ty_struct", "ty_union", "ty_enum", "ty_array", "ty_class", + "ty_alias", }; #define NUM_META ((int)(sizeof (ty_meta_names) / sizeof (ty_meta_names[0]))) @@ -447,52 +536,58 @@ dump_qfo_types (qfo_t *qfo, int base_address) qfo->spaces[qfo_type_space].data_size); continue; } - if (type->ty < 0 || type->ty >= NUM_META) - meta = va ("invalid meta: %d", type->ty); + if (type->meta < 0 || type->meta >= NUM_META) + meta = va (0, "invalid meta: %d", type->meta); else - meta = ty_meta_names[type->ty]; + meta = ty_meta_names[type->meta]; printf ("%-5x %-9s %-20s", type_ptr + base_address, meta, QFO_TYPESTR (qfo, type_ptr)); - if (type->ty < 0 || type->ty >= NUM_META) { + if (type->meta < 0 || type->meta >= NUM_META) { puts (""); break; } - switch ((ty_meta_e) type->ty) { - case ty_none: - printf (" %-10s", (type->t.type < 0 - || type->t.type >= ev_type_count) + switch ((ty_meta_e) type->meta) { + case ty_basic: + printf (" %-10s", (type->type < 0 + || type->type >= ev_type_count) ? "invalid type" - : pr_type_name[type->t.type]); - if (type->t.type == ev_func) { - printf (" %4x %d", type->t.func.return_type, - count = type->t.func.num_params); + : pr_type_name[type->type]); + if (type->type == ev_func) { + printf (" %4x %d", type->func.return_type, + count = type->func.num_params); if (count < 0) count = ~count; //ones complement for (i = 0; i < count; i++) - printf (" %x", type->t.func.param_types[i]); - } else if (type->t.type == ev_pointer - || type->t.type == ev_field) { - printf (" %4x", type->t.fldptr.aux_type); + printf (" %x", type->func.param_types[i]); + } else if (type->type == ev_pointer + || type->type == ev_field) { + printf (" %4x", type->fldptr.aux_type); } printf ("\n"); break; case ty_struct: case ty_union: case ty_enum: - printf (" %s\n", QFO_GETSTR (qfo, type->t.strct.tag)); - for (i = 0; i < type->t.strct.num_fields; i++) { + printf (" %s\n", QFO_GETSTR (qfo, type->strct.tag)); + for (i = 0; i < type->strct.num_fields; i++) { printf (" %-5x %4x %s\n", - type->t.strct.fields[i].type, - type->t.strct.fields[i].offset, - QFO_GETSTR (qfo, type->t.strct.fields[i].name)); + type->strct.fields[i].type, + type->strct.fields[i].offset, + QFO_GETSTR (qfo, type->strct.fields[i].name)); } break; case ty_array: - printf (" %-5x %d %d\n", type->t.array.type, - type->t.array.base, type->t.array.size); + printf (" %-5x %d %d\n", type->array.type, + type->array.base, type->array.size); break; case ty_class: - printf (" %-5x\n", type->t.class); + printf (" %-5x\n", type->class); + break; + case ty_alias: + printf (" %s %d %5x %5x\n", + QFO_GETSTR (qfo, type->alias.name), + type->alias.type, type->alias.aux_type, + type->alias.full_type); break; } } @@ -509,7 +604,7 @@ dump_types (progs_t *pr) { qfo_mspace_t spaces[qfo_num_spaces]; qfo_t qfo; - ddef_t *encodings_def; + pr_def_t *encodings_def; qfot_type_encodings_t *encodings; encodings_def = PR_FindGlobal (pr, ".type_encodings"); diff --git a/tools/qfcc/source/dump_lines.c b/tools/qfcc/source/dump_lines.c index 847bdb5c2..46382cf11 100644 --- a/tools/qfcc/source/dump_lines.c +++ b/tools/qfcc/source/dump_lines.c @@ -41,49 +41,152 @@ #include #include "QF/progs.h" +#include "QF/pr_type.h" -#include "qfprogs.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/qfprogs.h" -void -dump_lines (progs_t *pr) +typedef struct { + const char *source_name; + const char *source_file; + pr_uint_t source_line; + pr_int_t first_statement; + pointer_t return_type; + pr_uint_t local_defs; + pr_uint_t num_locals; + pr_uint_t line_info; + pr_uint_t function; +} func_data_t; + +typedef func_data_t *(*get_func_data_t)(unsigned func, void *data); + +static func_data_t * +progs_get_func_data (unsigned func_index, void *data) { - unsigned int i, line, addr; - pr_lineno_t *lineno; - pr_auxfunction_t *aux_func = 0; - dfunction_t *func = 0; + static func_data_t func_data; + progs_t *pr = (progs_t *) data; + pr_auxfunction_t *aux_func; + dfunction_t *func; - if (!pr->debug) - return; - for (i = 0; i < pr->debug->num_linenos; i++) { - lineno = &pr->linenos[i]; + memset (&func_data, 0, sizeof (func_data)); + aux_func = PR_Debug_AuxFunction (pr, func_index); + if (aux_func) { + func_data.source_line = aux_func->source_line; + func_data.return_type = aux_func->return_type; + func_data.num_locals = aux_func->num_locals; + func_data.local_defs = aux_func->local_defs; + func_data.line_info = aux_func->line_info; + func_data.function = aux_func->function; + if (aux_func->function < (unsigned int) pr->progs->numfunctions) { + func = pr->pr_functions + aux_func->function; + func_data.source_file = pr->pr_strings + func->s_file; + func_data.source_name = pr->pr_strings + func->s_name; + func_data.first_statement = func->first_statement; + } + return &func_data; + } + return 0; +} +static void +dump_line_set (pr_lineno_t *lineno, unsigned count, + get_func_data_t get_func_data, void *data) +{ + unsigned int line, addr; + func_data_t *func_data = 0; + + for (; count-- > 0; lineno++) { if (!lineno->line) { - aux_func = 0; - func = 0; - if (lineno->fa.func < pr->debug->num_auxfunctions) - aux_func = pr->auxfunctions + lineno->fa.func; - if (aux_func - && aux_func->function < (unsigned int) pr->progs->numfunctions) - func = pr->pr_functions + aux_func->function; + func_data = get_func_data(lineno->fa.func, data); } printf ("%5u %5u", lineno->fa.addr, lineno->line); line = addr = -1; - if (aux_func) - line = aux_func->source_line + lineno->line; - if (func) - addr = lineno->line ? lineno->fa.addr - : (unsigned int) func->first_statement; - if (aux_func && func) - printf (" %05x %s:%u %s+%u %d", addr, pr->pr_strings + func->s_file, - line, pr->pr_strings + func->s_name, - addr - func->first_statement, aux_func->return_type); - else if (aux_func) - printf ("%u %u %u %u %u %d", aux_func->function, line, - aux_func->line_info, aux_func->local_defs, - aux_func->num_locals, aux_func->return_type); - else if (lineno->line) + if (func_data) { + line = func_data->source_line + lineno->line; + if (func_data->source_name) { + addr = lineno->line ? (pr_int_t) lineno->fa.addr + : func_data->first_statement; + printf (" %05x %s:%u %s+%u %d", addr, func_data->source_file, + line, func_data->source_name, + addr - func_data->first_statement, + func_data->return_type); + } else { + printf ("%u %u %u %u %u %d", func_data->function, line, + func_data->line_info, func_data->local_defs, + func_data->num_locals, func_data->return_type); + } + } else if (lineno->line) { printf ("%5x", lineno->fa.addr); + } printf ("\n"); } } + +void +dump_lines (progs_t *pr) +{ + pr_lineno_t *linenos; + pr_uint_t num_linenos; + if (!(linenos = PR_Debug_Linenos (pr, 0, &num_linenos))) + return; + dump_line_set (linenos, num_linenos, progs_get_func_data, pr); +} + +static func_data_t * +qfo_get_func_data (unsigned func_index, void *data) +{ + return (func_data_t *) data; +} + +static void +qfo_set_func_data (qfo_t *qfo, qfo_func_t *func, func_data_t *func_data) +{ + qfot_type_t *type; + + func_data->source_line = func->line; + //FIXME check type + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type); + func_data->return_type = type->func.return_type; + func_data->num_locals = -1; + if (func->locals_space < qfo->num_spaces) { + func_data->num_locals = qfo->spaces[func->locals_space].num_defs; + } + func_data->local_defs = func->locals_space; + func_data->line_info = func->line_info; + func_data->function = func - qfo->funcs; + func_data->source_file = QFO_GETSTR (qfo, func->file); + func_data->source_name = QFO_GETSTR (qfo, func->name); + func_data->first_statement = func->code; +} + +void +qfo_lines (qfo_t *qfo) +{ + static func_data_t func_data; + pr_lineno_t *start_lineno = 0; + pr_lineno_t *lineno; + qfo_func_t *func = 0; + + for (func = qfo->funcs; func - qfo->funcs < qfo->num_funcs; func++) { + if (!func->line_info) { + // builtin + continue; + } + if (func->line_info >= qfo->num_lines) { + printf ("%s: bad line info: %u >= %u\n", + QFO_GETSTR (qfo, func->name), + func->line_info, qfo->num_lines); + continue; + } + qfo_set_func_data(qfo, func, &func_data); + start_lineno = qfo->lines + func->line_info; + for (lineno = start_lineno + 1; + lineno - qfo->lines < qfo->num_lines && lineno->line; + lineno++) + { + } + dump_line_set (start_lineno, lineno-start_lineno, + qfo_get_func_data, &func_data); + } +} diff --git a/tools/qfcc/source/dump_modules.c b/tools/qfcc/source/dump_modules.c index d55195aaa..7516f323b 100644 --- a/tools/qfcc/source/dump_modules.c +++ b/tools/qfcc/source/dump_modules.c @@ -44,7 +44,7 @@ #include "QF/progs.h" #include "QF/va.h" -#include "qfprogs.h" +#include "tools/qfcc/include/qfprogs.h" static void dump_methods (progs_t *pr, pr_method_list_t *methods, int class) @@ -89,22 +89,41 @@ dump_selector (progs_t *pr, pr_sel_t *sel) printf (" %s\n", sel_types); } +static void +dump_method_description_list (progs_t *pr, char c, + pr_method_description_list_t *list) +{ + if (list) { + for (int i = 0; i < list->count; i++) { + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].name)); + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].types)); + } + } +} + static void dump_protocol (progs_t *pr, pr_protocol_t *proto) { const char *protocol_name = ""; - printf (" %d ", proto->class_pointer); + printf (" %x %x ", + (pointer_t) ((pr_int_t *) proto - (pr_int_t *) pr->pr_globals), + proto->class_pointer); if (PR_StringValid (pr, proto->protocol_name)) protocol_name = PR_GetString (pr, proto->protocol_name); printf ("<%s>\n", protocol_name); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->instance_methods)); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->class_methods)); } static void dump_protocol_list (progs_t *pr, pr_protocol_list_t *list) { int i; - printf (" %d\n", list->next); - printf (" %d\n", list->count); + printf (" %x %d\n", list->next, list->count); for (i = 0; i < list->count; i++) { if (list->list[i] <= 0 || list->list[i] >= pr->globals_size) { printf ("invalid pointer\n"); @@ -171,6 +190,32 @@ dump_category (progs_t *pr, pr_category_t *category) category->protocols)); } +static void +dump_static_instance_lists (progs_t *pr, pointer_t instance_lists) +{ + pointer_t *ptr = &G_STRUCT (pr, pointer_t, instance_lists); + + printf (" static instance lists @ %x\n", instance_lists); + while (*ptr) { + __auto_type list = &G_STRUCT (pr, pr_static_instances_t, *ptr); + const char *class_name = "*** INVALID ***"; + + if (PR_StringValid (pr, list->class_name)) { + class_name = PR_GetString (pr, list->class_name); + } + printf (" %x %s\n", *ptr, class_name); + for (int i = 0; list->instances[i]; i++) { + if (!strcmp (class_name, "Protocol")) { + dump_protocol (pr, &G_STRUCT (pr, pr_protocol_t, + list->instances[i])); + } else { + printf (" %x\n", list->instances[i]); + } + } + ptr++; + } +} + static void dump_module (progs_t *pr, pr_module_t *module) { @@ -197,6 +242,9 @@ dump_module (progs_t *pr, pr_module_t *module) dump_class (pr, &G_STRUCT (pr, pr_class_t, *ptr++)); for (i = 0; i < symtab->cat_def_cnt; i++) dump_category (pr, &G_STRUCT (pr, pr_category_t, *ptr++)); + if (*ptr) { + dump_static_instance_lists (pr, *ptr); + } } void @@ -205,11 +253,11 @@ dump_modules (progs_t *pr) unsigned int i; for (i = 0; i < pr->progs->numglobaldefs; i++) { - ddef_t *def = &pr->pr_globaldefs[i]; + pr_def_t *def = &pr->pr_globaldefs[i]; const char *name = ""; - if (PR_StringValid (pr, def->s_name)) - name = PR_GetString (pr, def->s_name); + if (PR_StringValid (pr, def->name)) + name = PR_GetString (pr, def->name); if (strcmp (name, "_OBJ_MODULE") == 0) { printf ("module @ %x\n", def->ofs); dump_module (pr, &G_STRUCT (pr, pr_module_t, def->ofs)); diff --git a/tools/qfcc/source/dump_strings.c b/tools/qfcc/source/dump_strings.c index 91d6ca2ba..ce9627f32 100644 --- a/tools/qfcc/source/dump_strings.c +++ b/tools/qfcc/source/dump_strings.c @@ -36,21 +36,22 @@ #include "QF/progs.h" #include "QF/sys.h" -#include "qfprogs.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/qfprogs.h" -void -dump_strings (progs_t *pr) +static void +dump_string_block (const char *strblock, unsigned size) { - int i = 0; - char *s = pr->pr_strings; + const char *s = strblock; - printf ("%d ", 0); - while (i++ < pr->progs->numstrings) { - switch (*s) { + printf ("%x \"", 0); + while (s - strblock < size) { + char c = *s++; + switch (c) { case 0: - fputs ("\n", stdout); - if (i < pr->progs->numstrings) - printf ("%d ", i); + fputs ("\"\n", stdout); + if (s - strblock < size) + printf ("%lx \"", s - strblock); break; case 9: fputs ("\\t", stdout); @@ -61,10 +62,37 @@ dump_strings (progs_t *pr) case 13: fputs ("\\r", stdout); break; + case '\"': + fputs ("\\\"", stdout); + break; + case '\\': + fputs ("\\\\", stdout); + break; default: - fputc (sys_char_map[(unsigned char)*s], stdout); + fputc (sys_char_map[(unsigned char)c], stdout); break; } - s++; } } + +void +dump_strings (progs_t *pr) +{ + dump_string_block (pr->pr_strings, pr->progs->numstrings); +} + +void +qfo_strings (qfo_t *qfo) +{ + qfo_mspace_t *space = &qfo->spaces[qfo_strings_space]; + + if (qfo_strings_space >= qfo->num_spaces) { + printf ("no strings space\n"); + return; + } + if (!space->data_size) { + printf ("no strings\n"); + return; + } + dump_string_block (space->d.strings, space->data_size); +} diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 34a5de3f2..f61151da3 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -42,37 +42,62 @@ #include #include -#include "codespace.h" -#include "def.h" -#include "defspace.h" -#include "debug.h" -#include "diagnostic.h" -#include "emit.h" -#include "function.h" -#include "opcodes.h" -#include "options.h" -#include "qfcc.h" -#include "reloc.h" -#include "statements.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/opcodes.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static def_t zero_def; +static def_t *get_operand_def (expr_t *expr, operand_t *op); + static def_t * -get_value_def (ex_value_t *value, etype_t type) +get_tempop_def (expr_t *expr, operand_t *tmpop, type_t *type) +{ + tempop_t *tempop = &tmpop->o.tempop; + if (tempop->def) { + return tempop->def; + } + if (tempop->alias) { + def_t *tdef = get_operand_def (expr, tempop->alias); + int offset = tempop->offset; + tempop->def = alias_def (tdef, type, offset); + } + if (!tempop->def) { + tempop->def = temp_def (type); + } + return tempop->def; +} + +static def_t * +get_value_def (expr_t *expr, ex_value_t *value, type_t *type) { def_t *def; - if (type == ev_short) { + if (is_short (type)) { def = new_def (0, &type_short, 0, sc_extern); def->offset = value->v.short_val; return def; } + if (is_pointer (type) && value->v.pointer.tempop + && !value->v.pointer.def) { + value->v.pointer.def = get_tempop_def (expr, value->v.pointer.tempop, + type->t.fldptr.type); + } def = emit_value (value, 0); - if (type != def->type->type) - return alias_def (def, ev_types[type], 0); + if (type != def->type) + return alias_def (def, type, 0); return def; } @@ -85,20 +110,19 @@ get_operand_def (expr_t *expr, operand_t *op) case op_def: return op->o.def; case op_value: - return get_value_def (op->o.value, op->type); + return get_value_def (expr, op->o.value, op->type); case op_label: - op->type = ev_short; + op->type = &type_short; zero_def.type = &type_short; return &zero_def; //FIXME case op_temp: - while (op->o.tempop.alias) - op = op->o.tempop.alias; - if (!op->o.tempop.def) - op->o.tempop.def = temp_def (op->type, op->size); - return op->o.tempop.def; + return get_tempop_def (expr, op, op->type); case op_alias: return get_operand_def (expr, op->o.alias); + case op_nil: + internal_error (expr, "unexpected nil operand"); } + internal_error (expr, "unexpected operand"); return 0; } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 36627517f..f86e9dece 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -45,44 +45,29 @@ #include "QF/sys.h" #include "QF/va.h" -#include "qfcc.h" -#include "class.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "function.h" -#include "idstuff.h" -#include "method.h" -#include "options.h" -#include "reloc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" -#include "value.h" -#include "qc-parse.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/idstuff.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +#include "tools/qfcc/source/qc-parse.h" static expr_t *exprs_freelist; -type_t *ev_types[ev_type_count] = { - &type_void, - &type_string, - &type_float, - &type_vector, - &type_entity, - &type_field, - &type_function, - &type_pointer, - &type_quaternion, - &type_integer, - &type_uinteger, - &type_short, - &type_invalid, -}; - void convert_name (expr_t *e) { @@ -125,6 +110,10 @@ convert_name (expr_t *e) //FIXME need a def return; } + if (sym->sy_type == sy_convert) { + new = sym->s.convert.conv (sym, sym->s.convert.data); + goto convert; + } if (sym->sy_type == sy_expr) { new = copy_expr (sym->s.expr); goto convert; @@ -145,7 +134,7 @@ convert_vector (expr_t *e) if (e->type != ex_vector) return e; - if (e->e.vector.type == &type_vector) { + if (is_vector(e->e.vector.type)) { // guaranteed to have three elements expr_t *x = e->e.vector.list; expr_t *y = x->next; @@ -159,39 +148,62 @@ convert_vector (expr_t *e) val[2] = expr_float(z); return new_vector_expr (val); } + // at least one of x, y, z is not constant, so rebuild the + // list incase any of them are new expressions + z->next = 0; + y->next = z; + x->next = y; + e->e.vector.list = x; + return e; } - if (e->e.vector.type == &type_quaternion) { + if (is_quaternion(e->e.vector.type)) { // guaranteed to have two or four elements if (e->e.vector.list->next->next) { - // four vals: w, x, y, z - expr_t *w = e->e.vector.list; - expr_t *x = w->next; + // four vals: x, y, z, w + expr_t *x = e->e.vector.list; expr_t *y = x->next; expr_t *z = y->next; - w = fold_constants (cast_expr (&type_float, w)); + expr_t *w = z->next; x = fold_constants (cast_expr (&type_float, x)); y = fold_constants (cast_expr (&type_float, y)); z = fold_constants (cast_expr (&type_float, z)); - if (is_constant (w) && is_constant (x) && is_constant (y) - && is_constant (z)) { - val[0] = expr_float(w); - val[1] = expr_float(x); - val[2] = expr_float(y); - val[3] = expr_float(z); + w = fold_constants (cast_expr (&type_float, w)); + if (is_constant (x) && is_constant (y) && is_constant (z) + && is_constant (w)) { + val[0] = expr_float(x); + val[1] = expr_float(y); + val[2] = expr_float(z); + val[3] = expr_float(w); return new_quaternion_expr (val); } + // at least one of x, y, z, w is not constant, so rebuild the + // list incase any of them are new expressions + w->next = 0; + z->next = w; + y->next = z; + x->next = y; + e->e.vector.list = x; + return e; } else { - // s, v - expr_t *s = e->e.vector.list; - expr_t *v = s->next; + // v, s + expr_t *v = e->e.vector.list; + expr_t *s = v->next; - s = fold_constants (cast_expr (&type_float, s)); v = convert_vector (v); - if (is_constant (s) && is_constant (v)) { - val[0] = expr_float (s); - memcpy (val + 1, expr_vector (v), 3 * sizeof (float)); + s = fold_constants (cast_expr (&type_float, s)); + if (is_constant (v) && is_constant (s)) { + memcpy (val, expr_vector (v), 3 * sizeof (float)); + val[3] = expr_float (s); return new_quaternion_expr (val); } + // Either v or s is not constant, so can't convert to a quaternion + // constant. + // Rebuild the list in case v or s is a new expression + // the list will always be v, s + s->next = 0; + v->next = s; + e->e.vector.list = v; + return e; } } internal_error (e, "bogus vector expression"); @@ -200,18 +212,26 @@ convert_vector (expr_t *e) type_t * get_type (expr_t *e) { + const type_t *type = 0; convert_name (e); switch (e->type) { case ex_labelref: return &type_void; + case ex_memset: + return e->e.memset.type; case ex_label: case ex_error: + case ex_compound: return 0; // something went very wrong case ex_bool: if (options.code.progsversion == PROG_ID_VERSION) return &type_float; return &type_integer; case ex_nil: + if (e->e.nil) { + return e->e.nil; + } + // fall through case ex_state: return &type_void; case ex_block: @@ -220,27 +240,24 @@ get_type (expr_t *e) return &type_void; case ex_expr: case ex_uexpr: - return e->e.expr.type; + type = e->e.expr.type; + break; + case ex_def: + type = e->e.def->type; + break; case ex_symbol: - return e->e.symbol->type; + type = e->e.symbol->type; + break; case ex_temp: - return e->e.temp.type; + type = e->e.temp.type; + break; case ex_value: - if (e->e.value->type == ev_func) - return e->e.value->v.func_val.type; - if (e->e.value->type == ev_pointer) - return pointer_type (e->e.value->v.pointer.type); - if (e->e.value->type == ev_field) - return field_type (e->e.value->v.pointer.type); - if (e->e.value->type == ev_integer - && options.code.progsversion == PROG_ID_VERSION) { - convert_int (e); - } - return ev_types[e->e.value->type]; + type = e->e.value->type; + break; case ex_vector: return e->e.vector.type; } - return 0; + return (type_t *) unalias_type (type);//FIXME cast } etype_t @@ -294,7 +311,7 @@ cast_error (expr_t *e, type_t *t1, type_t *t2) print_type_str (s1, t1); print_type_str (s2, t2); - e = error (e, "can not cast from %s to %s", s1->str, s2->str); + e = error (e, "cannot cast from %s to %s", s1->str, s2->str); dstring_delete (s1); dstring_delete (s2); return e; @@ -334,6 +351,7 @@ copy_expr (expr_t *e) return 0; switch (e->type) { case ex_error: + case ex_def: case ex_symbol: case ex_nil: case ex_value: @@ -414,34 +432,54 @@ copy_expr (expr_t *e) *n = *e; n->line = pr.source_line; n->file = pr.source_file; - n->e.temp.expr = copy_expr (e->e.temp.expr); return n; case ex_vector: n = new_expr (); n->e.vector.type = e->e.vector.type; n->e.vector.list = copy_expr (e->e.vector.list); - n = n->e.vector.list; t = e->e.vector.list; + e = n->e.vector.list; while (t->next) { - n->next = copy_expr (t->next); - n = n->next; + e->next = copy_expr (t->next); + e = e->next; t = t->next; } return n; + case ex_compound: + n = new_expr (); + *n = *e; + for (element_t *i = e->e.compound.head; i; i = i->next) { + append_element (n, new_element (i->expr, i->symbol)); + } + return n; + case ex_memset: + n = new_expr (); + *n = *e; + n->e.memset.dst = copy_expr (e->e.memset.dst); + n->e.memset.val = copy_expr (e->e.memset.val); + n->e.memset.count = copy_expr (e->e.memset.count); + return n; } internal_error (e, "invalid expression"); } +expr_t * +expr_file_line (expr_t *dst, const expr_t *src) +{ + dst->file = src->file; + dst->line = src->line; + return dst; +} + const char * new_label_name (void) { static int label = 0; int lnum = ++label; const char *fname = current_func->sym->name; - char *lname; + const char *lname; - lname = nva ("$%s_%d", fname, lnum); - SYS_CHECKMEM (lname); + lname = save_string (va (0, "$%s_%d", fname, lnum)); return lname; } @@ -488,6 +526,32 @@ new_label_expr (void) return l; } +expr_t * +named_label_expr (symbol_t *label) +{ + symbol_t *sym; + expr_t *l; + + if (!current_func) { + // XXX this might be only an error + internal_error (0, "label defined outside of function scope"); + } + + sym = symtab_lookup (current_func->label_scope, label->name); + + if (sym) { + return sym->s.expr; + } + l = new_label_expr (); + l->e.label.name = save_string (va (0, "%s_%s", l->e.label.name, + label->name)); + l->e.label.symbol = label; + label->sy_type = sy_expr; + label->s.expr = l; + symtab_addsymbol (current_func->label_scope, label); + return label->s.expr; +} + expr_t * new_label_ref (ex_label_t *label) { @@ -508,6 +572,7 @@ new_block_expr (void) b->type = ex_block; b->e.block.head = 0; b->e.block.tail = &b->e.block.head; + b->e.block.return_addr = __builtin_return_address (0); return b; } @@ -528,6 +593,20 @@ new_binary_expr (int op, expr_t *e1, expr_t *e2) return e; } +expr_t * +build_block_expr (expr_t *expr_list) +{ + expr_t *b = new_block_expr (); + + while (expr_list) { + expr_t *e = expr_list; + expr_list = e->next; + e->next = 0; + append_expr (b, e); + } + return b; +} + expr_t * new_unary_expr (int op, expr_t *e1) { @@ -542,6 +621,15 @@ new_unary_expr (int op, expr_t *e1) return e; } +expr_t * +new_def_expr (def_t *def) +{ + expr_t *e = new_expr (); + e->type = ex_def; + e->e.def = def; + return e; +} + expr_t * new_symbol_expr (symbol_t *symbol) { @@ -552,12 +640,12 @@ new_symbol_expr (symbol_t *symbol) } expr_t * -new_temp_def_expr (type_t *type) +new_temp_def_expr (const type_t *type) { expr_t *e = new_expr (); e->type = ex_temp; - e->e.temp.type = type; + e->e.temp.type = (type_t *) unalias_type (type); // FIXME cast return e; } @@ -601,6 +689,15 @@ new_string_expr (const char *string_val) return e; } +expr_t * +new_double_expr (double double_val) +{ + expr_t *e = new_expr (); + e->type = ex_value; + e->e.value = new_double_val (double_val); + return e; +} + expr_t * new_float_expr (float float_val) { @@ -635,23 +732,51 @@ new_vector_list (expr_t *e) type = &type_quaternion; case 3: // quaternion or vector. all expressions must be compatible with - // a float - for (t = e; t; t = t->next) - if (!type_assignable (&type_float, get_type (t))) + // a float (ie, a scalar) + for (t = e; t; t = t->next) { + if (t->type == ex_error) { + return t; + } + if (!is_scalar (get_type (t))) { return error (t, "invalid type for vector element"); + } + } vec = new_expr (); vec->type = ex_vector; vec->e.vector.type = type; vec->e.vector.list = e; break; case 2: - // quaternion. first expression must be compatible with a float, - // the other must be a vector - if (!type_assignable (&type_float, get_type (e)) - || !type_assignable (&type_vector, get_type(e->next))) { + if (e->type == ex_error || e->next->type == ex_error) { + return e; + } + if (is_scalar (get_type (e)) && is_scalar (get_type (e->next))) { + // scalar, scalar + // expand [x, y] to [x, y, 0] + e->next->next = new_float_expr (0); + vec = new_expr (); + vec->type = ex_vector; + vec->e.vector.type = type; + vec->e.vector.list = e; + break; + } + // quaternion. either scalar, vector or vector, scalar + if (is_scalar (get_type (e)) + && is_vector (get_type (e->next))) { + // scalar, vector + // swap expressions + t = e; + e = e->next; + e->next = t; + t->next = 0; + } else if (is_vector (get_type (e)) + && is_scalar (get_type (e->next))) { + // vector, scalar + // do nothing + } else { return error (t, "invalid types for vector elements"); } - // s, v + // v, s vec = new_expr (); vec->type = ex_vector; vec->e.vector.type = &type_quaternion; @@ -695,7 +820,7 @@ new_pointer_expr (int val, type_t *type, def_t *def) { expr_t *e = new_expr (); e->type = ex_value; - e->e.value = new_pointer_val (val, type, def); + e->e.value = new_pointer_val (val, type, def, 0); return e; } @@ -738,6 +863,10 @@ new_short_expr (short short_val) int is_constant (expr_t *e) { + while ((e->type == ex_uexpr || e->type == ex_expr) + && e->e.expr.op == 'A') { + e = e->e.expr.e1; + } if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref || (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) || (e->type == ex_symbol && e->e.symbol->sy_type == sy_var @@ -779,12 +908,18 @@ constant_expr (expr_t *e) return new; } +int +is_nil (expr_t *e) +{ + return e->type == ex_nil; +} + int is_string_val (expr_t *e) { if (e->type == ex_nil) return 1; - if (e->type == ex_value && e->e.value->type == ev_string) + if (e->type == ex_value && e->e.value->lltype == ev_string) return 1; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && e->e.symbol->type->type == ev_string) @@ -797,7 +932,7 @@ expr_string (expr_t *e) { if (e->type == ex_nil) return 0; - if (e->type == ex_value && e->e.value->type == ev_string) + if (e->type == ex_value && e->e.value->lltype == ev_string) return e->e.value->v.string_val; internal_error (e, "not a string constant"); } @@ -807,7 +942,7 @@ is_float_val (expr_t *e) { if (e->type == ex_nil) return 1; - if (e->type == ex_value && e->e.value->type == ev_float) + if (e->type == ex_value && e->e.value->lltype == ev_float) return 1; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && e->e.symbol->type->type == ev_float) @@ -815,12 +950,29 @@ is_float_val (expr_t *e) return 0; } +double +expr_double (expr_t *e) +{ + if (e->type == ex_nil) + return 0; + if (e->type == ex_value && e->e.value->lltype == ev_double) + return e->e.value->v.double_val; + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const + && e->e.symbol->type->type == ev_double) + return e->e.symbol->s.value->v.double_val; + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var + && e->e.symbol->s.def->constant + && is_double (e->e.symbol->s.def->type)) + return D_DOUBLE (e->e.symbol->s.def); + internal_error (e, "not a double constant"); +} + float expr_float (expr_t *e) { if (e->type == ex_nil) return 0; - if (e->type == ex_value && e->e.value->type == ev_float) + if (e->type == ex_value && e->e.value->lltype == ev_float) return e->e.value->v.float_val; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && e->e.symbol->type->type == ev_float) @@ -837,7 +989,7 @@ is_vector_val (expr_t *e) { if (e->type == ex_nil) return 1; - if (e->type == ex_value && e->e.value->type == ev_vector) + if (e->type == ex_value && e->e.value->lltype == ev_vector) return 1; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && e->e.symbol->type->type == ev_vector) @@ -850,7 +1002,7 @@ expr_vector (expr_t *e) { if (e->type == ex_nil) return vec3_origin; - if (e->type == ex_value && e->e.value->type == ev_vector) + if (e->type == ex_value && e->e.value->lltype == ev_vector) return e->e.value->v.vector_val; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && e->e.symbol->type->type == ev_vector) @@ -867,7 +1019,7 @@ is_quaternion_val (expr_t *e) { if (e->type == ex_nil) return 1; - if (e->type == ex_value && e->e.value->type == ev_quat) + if (e->type == ex_value && e->e.value->lltype == ev_quat) return 1; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && e->e.symbol->type->type == ev_quat) @@ -880,7 +1032,7 @@ expr_quaternion (expr_t *e) { if (e->type == ex_nil) return quat_origin; - if (e->type == ex_value && e->e.value->type == ev_quat) + if (e->type == ex_value && e->e.value->lltype == ev_quat) return e->e.value->v.quaternion_val; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && e->e.symbol->type->type == ev_quat) @@ -895,98 +1047,167 @@ expr_quaternion (expr_t *e) int is_integer_val (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 1; - if (e->type == ex_value && e->e.value->type == ev_integer) + } + if (e->type == ex_value && e->e.value->lltype == ev_integer) { return 1; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && (e->e.symbol->type->type == ev_integer - || is_enum (e->e.symbol->type))) + && is_integral (e->e.symbol->type)) { return 1; + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return 1; + } return 0; } int expr_integer (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->type == ev_integer) + } + if (e->type == ex_value && e->e.value->lltype == ev_integer) { return e->e.value->v.integer_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && (e->e.symbol->type->type == ev_integer - || is_enum (e->e.symbol->type))) + || is_enum (e->e.symbol->type))) { return e->e.symbol->s.value->v.integer_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var && e->e.symbol->s.def->constant - && is_integral (e->e.symbol->s.def->type)) + && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return D_INT (e->e.def); + } internal_error (e, "not an integer constant"); } +int +is_uinteger_val (expr_t *e) +{ + if (e->type == ex_nil) { + return 1; + } + if (e->type == ex_value && e->e.value->lltype == ev_uinteger) { + return 1; + } + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const + && is_integral (e->e.symbol->type)) { + return 1; + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return 1; + } + return 0; +} + unsigned expr_uinteger (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->type == ev_uinteger) + } + if (e->type == ex_value && e->e.value->lltype == ev_uinteger) { return e->e.value->v.uinteger_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_uinteger) + && e->e.symbol->type->type == ev_uinteger) { return e->e.symbol->s.value->v.uinteger_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var && e->e.symbol->s.def->constant - && is_integral (e->e.symbol->s.def->type)) + && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return D_INT (e->e.def); + } internal_error (e, "not an unsigned constant"); } int is_short_val (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 1; - if (e->type == ex_value && e->e.value->type == ev_short) + } + if (e->type == ex_value && e->e.value->lltype == ev_short) { return 1; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_short) + && e->e.symbol->type->type == ev_short) { return 1; + } return 0; } short expr_short (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->type == ev_short) + } + if (e->type == ex_value && e->e.value->lltype == ev_short) { return e->e.value->v.short_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_short) + && e->e.symbol->type->type == ev_short) { return e->e.symbol->s.value->v.short_val; + } internal_error (e, "not a short constant"); } -expr_t * -new_self_expr (void) +int +is_integral_val (expr_t *e) { - symbol_t *sym; - - sym = make_symbol (".self", &type_entity, pr.near_data, sc_extern); - if (!sym->table) - symtab_addsymbol (pr.symtab, sym); - return new_symbol_expr (sym); + if (is_constant (e)) { + if (is_integer_val (e)) { + return 1; + } + if (is_uinteger_val (e)) { + return 1; + } + if (is_short_val (e)) { + return 1; + } + } + return 0; } -expr_t * -new_this_expr (void) +int +expr_integral (expr_t *e) { - symbol_t *sym; + if (is_constant (e)) { + if (is_integer_val (e)) { + return expr_integer (e); + } + if (is_uinteger_val (e)) { + return expr_uinteger (e); + } + if (is_short_val (e)) { + return expr_short (e); + } + } + internal_error (e, "not an integral constant"); +} - sym = make_symbol (".this", field_type (&type_id), pr.near_data, sc_extern); - if (!sym->table) - symtab_addsymbol (pr.symtab, sym); - return new_symbol_expr (sym); +int +is_pointer_val (expr_t *e) +{ + if (e->type == ex_value && e->e.value->lltype == ev_pointer) { + return 1; + } + return 0; } expr_t * @@ -994,12 +1215,33 @@ new_alias_expr (type_t *type, expr_t *expr) { expr_t *alias; - if (expr->type == ex_value) - return new_value_expr (alias_value (expr->e.value, type)); alias = new_unary_expr ('A', expr); alias->e.expr.type = type; //if (expr->type == ex_uexpr && expr->e.expr.op == 'A') // bug (alias, "aliasing an alias expression"); + if (expr->type == ex_expr && expr->e.expr.op == 'A') { + return new_offset_alias_expr (type, expr, 0); + } + alias->file = expr->file; + alias->line = expr->line; + return alias; +} + +expr_t * +new_offset_alias_expr (type_t *type, expr_t *expr, int offset) +{ + expr_t *alias; + + if (expr->type == ex_expr && expr->e.expr.op == 'A') { + expr_t *ofs_expr = expr->e.expr.e2; + expr = expr->e.expr.e1; + if (!is_constant (ofs_expr)) { + internal_error (ofs_expr, "non-constant offset for alias expr"); + } + offset += expr_integer (ofs_expr); + } + alias = new_binary_expr ('A', expr, new_integer_expr (offset)); + alias->e.expr.type = type; alias->file = expr->file; alias->line = expr->line; return alias; @@ -1027,7 +1269,7 @@ new_ret_expr (type_t *type) expr_t * new_param_expr (type_t *type, int num) { - return param_expr (va (".param_%d", num), type); + return param_expr (va (0, ".param_%d", num), type); } expr_t * @@ -1038,6 +1280,25 @@ new_move_expr (expr_t *e1, expr_t *e2, type_t *type, int indirect) return e; } +expr_t * +new_memset_expr (expr_t *dst, expr_t *val, type_t *type) +{ + expr_t *e; + if (!is_pointer (get_type (dst))) { + return error (dst, "incorrect destination type for memset"); + } + if (!is_scalar (get_type (val))) { + return error (val, "memset value must be a scalar"); + } + e = new_expr (); + e->type = ex_memset; + e->e.memset.dst = dst; + e->e.memset.val = val; + e->e.memset.count = new_integer_expr (type_size (type)); + e->e.memset.type = type; + return e; +} + expr_t * append_expr (expr_t *block, expr_t *e) { @@ -1057,7 +1318,7 @@ append_expr (expr_t *block, expr_t *e) } static symbol_t * -get_struct_field (type_t *t1, expr_t *e1, expr_t *e2) +get_struct_field (const type_t *t1, expr_t *e1, expr_t *e2) { symtab_t *strct = t1->t.symtab; symbol_t *sym = e2->e.symbol;//FIXME need to check @@ -1068,7 +1329,7 @@ get_struct_field (type_t *t1, expr_t *e1, expr_t *e2) return 0; } field = symtab_lookup (strct, sym->name); - if (!field && t1 != &type_entity) { + if (!field && !is_entity(t1)) { error (e2, "'%s' has no member named '%s'", t1->name + 4, sym->name); e1->type = ex_error; } @@ -1078,12 +1339,12 @@ get_struct_field (type_t *t1, expr_t *e1, expr_t *e2) expr_t * field_expr (expr_t *e1, expr_t *e2) { - type_t *t1, *t2; + const type_t *t1, *t2; expr_t *e; + t1 = get_type (e1); if (e1->type == ex_error) return e1; - t1 = get_type (e1); if (t1->type == ev_entity) { symbol_t *field = 0; @@ -1117,12 +1378,13 @@ field_expr (expr_t *e1, expr_t *e2) e = new_binary_expr ('&', e1, e2); e->e.expr.type = pointer_type (field->type); return unary_expr ('.', e); - } else if (obj_is_class (t1->t.fldptr.type)) { + } else if (is_class (t1->t.fldptr.type)) { class_t *class = t1->t.fldptr.type->t.class; symbol_t *sym = e2->e.symbol;//FIXME need to check symbol_t *ivar; + int protected = class_access (current_class, class); - ivar = class_find_ivar (class, vis_protected, sym->name); + ivar = class_find_ivar (class, protected, sym->name); if (!ivar) return new_error_expr (); e2->type = ex_value; @@ -1140,7 +1402,7 @@ field_expr (expr_t *e1, expr_t *e2) return e1; if (e1->type == ex_expr && e1->e.expr.op == '.' - && get_type (e1->e.expr.e1) == &type_entity) { + && is_entity(get_type (e1->e.expr.e1))) { // undo the . expression e2 = e1->e.expr.e2; e1 = e1->e.expr.e1; @@ -1155,19 +1417,24 @@ field_expr (expr_t *e1, expr_t *e2) } def = sym->s.def; e2 = new_field_expr (0, field->type, def); - } else if (e2->type != ex_value || e2->e.value->type != ev_field) { + } else if (e2->type != ex_value + || e2->e.value->lltype != ev_field) { internal_error (e2, "unexpected field exression"); } e2->e.value = new_field_val (e2->e.value->v.pointer.val + field->s.offset, field->type, e2->e.value->v.pointer.def); // create a new . expression return field_expr (e1, e2); } else { - e2->type = ex_value; - e2->e.value = new_short_val (field->s.offset); - e = address_expr (e1, e2, field->type); - return unary_expr ('.', e); + if (e1->type == ex_uexpr && e1->e.expr.op == '.') { + e2->type = ex_value; + e2->e.value = new_short_val (field->s.offset); + e = address_expr (e1, e2, field->type); + return unary_expr ('.', e); + } else { + return new_offset_alias_expr (field->type, e1, field->s.offset); + } } - } else if (obj_is_class (t1)) { + } else if (is_class (t1)) { //Class instance variables aren't allowed and thus declaring one //is treated as an error, so this is a follow-on error. return error (e1, "class instance access"); @@ -1175,194 +1442,6 @@ field_expr (expr_t *e1, expr_t *e2) return type_mismatch (e1, e2, '.'); } -expr_t * -test_expr (expr_t *e) -{ - static float zero[4] = {0, 0, 0, 0}; - expr_t *new = 0; - type_t *type; - - if (e->type == ex_error) - return e; - - type = get_type (e); - if (e->type == ex_error) - return e; - switch (type->type) { - case ev_type_count: - internal_error (e, 0); - case ev_void: - if (options.traditional) { - if (options.warnings.traditional) - warning (e, "void has no value"); - return e; - } - return error (e, "void has no value"); - case ev_string: - if (!options.code.ifstring) - return new_alias_expr (type_default, e); - new = new_string_expr (0); - break; - case ev_uinteger: - case ev_integer: - case ev_short: - if (type_default != &type_integer) - return new_alias_expr (type_default, e); - return e; - case ev_float: - if (options.code.fast_float - || options.code.progsversion == PROG_ID_VERSION) { - if (type_default != &type_float) - return new_alias_expr (type_default, e); - return e; - } - new = new_float_expr (0); - break; - case ev_vector: - new = new_vector_expr (zero); - break; - case ev_entity: - return new_alias_expr (type_default, e); - case ev_field: - return new_alias_expr (type_default, e); - case ev_func: - return new_alias_expr (type_default, e); - case ev_pointer: - return new_alias_expr (type_default, e); - case ev_quat: - new = new_quaternion_expr (zero); - break; - case ev_invalid: - if (is_enum (type)) { - new = new_nil_expr (); - break; - } - return test_error (e, get_type (e)); - } - new->line = e->line; - new->file = e->file; - new = binary_expr (NE, e, new); - new->line = e->line; - new->file = e->file; - return fold_constants (new); -} - -void -backpatch (ex_list_t *list, expr_t *label) -{ - int i; - expr_t *e; - - if (!list) - return; - if (!label || label->type != ex_label) - internal_error (label, "not a label"); - - for (i = 0; i < list->size; i++) { - e = list->e[i]; - if (e->type == ex_uexpr && e->e.expr.op == 'g') - e->e.expr.e1 = label; - else if (e->type == ex_expr && (e->e.expr.op == 'i' - || e->e.expr.op == 'n')) - e->e.expr.e2 = label; - else { - internal_error (e, 0); - } - label->e.label.used++; - } -} - -static ex_list_t * -merge (ex_list_t *l1, ex_list_t *l2) -{ - ex_list_t *m; - - if (!l1 && !l2) - internal_error (0, 0); - if (!l2) - return l1; - if (!l1) - return l2; - m = malloc ((size_t)&((ex_list_t *)0)->e[l1->size + l2->size]); - m->size = l1->size + l2->size; - memcpy (m->e, l1->e, l1->size * sizeof (expr_t *)); - memcpy (m->e + l1->size, l2->e, l2->size * sizeof (expr_t *)); - return m; -} - -static ex_list_t * -make_list (expr_t *e) -{ - ex_list_t *m; - - m = malloc ((size_t)&((ex_list_t *) 0)->e[1]); - m->size = 1; - m->e[0] = e; - return m; -} - -expr_t * -convert_bool (expr_t *e, int block) -{ - expr_t *b; - - if (e->type == ex_expr && (e->e.expr.op == '=' || e->e.expr.op == PAS)) { - expr_t *src; - if (!e->paren && options.warnings.precedence) - warning (e, "suggest parentheses around assignment " - "used as truth value"); - src = e->e.expr.e2; - if (src->type == ex_block) { - src = new_temp_def_expr (get_type (src)); - e = new_binary_expr (e->e.expr.op, e->e.expr.e1, - assign_expr (src, e->e.expr.e2)); - } - b = convert_bool (src, 1); - if (b->type == ex_error) - return b; - // insert the assignment into the bool's block - e->next = b->e.bool.e->e.block.head; - b->e.bool.e->e.block.head = e; - if (b->e.bool.e->e.block.tail == &b->e.bool.e->e.block.head) { - // shouldn't happen, but just in case - b->e.bool.e->e.block.tail = &e->next; - } - return b; - } - - if (e->type == ex_uexpr && e->e.expr.op == '!' - && get_type (e->e.expr.e1) != &type_string) { - e = convert_bool (e->e.expr.e1, 0); - if (e->type == ex_error) - return e; - e = unary_expr ('!', e); - } - if (e->type != ex_bool) { - e = test_expr (e); - if (e->type == ex_error) - return e; - if (is_integer_val (e)) { - b = goto_expr (0); - if (expr_integer (e)) - e = new_bool_expr (make_list (b), 0, b); - else - e = new_bool_expr (0, make_list (b), b); - } else { - b = new_block_expr (); - append_expr (b, branch_expr ('i', e, 0)); - append_expr (b, goto_expr (0)); - e = new_bool_expr (make_list (b->e.block.head), - make_list (b->e.block.head->next), b); - } - } - if (block && e->e.bool.e->type != ex_block) { - expr_t *block = new_block_expr (); - append_expr (block, e->e.bool.e); - e->e.bool.e = block; - } - return e; -} - expr_t * convert_from_bool (expr_t *e, type_t *type) { @@ -1370,15 +1449,15 @@ convert_from_bool (expr_t *e, type_t *type) expr_t *one; expr_t *cond; - if (type == &type_float) { + if (is_float (type)) { one = new_float_expr (1); zero = new_float_expr (0); - } else if (type == &type_integer) { + } else if (is_integer (type)) { one = new_integer_expr (1); zero = new_integer_expr (0); } else if (is_enum (type) && enum_as_bool (type, &zero, &one)) { // don't need to do anything - } else if (type == &type_uinteger) { + } else if (is_uinteger (type)) { one = new_uinteger_expr (1); zero = new_uinteger_expr (0); } else { @@ -1394,44 +1473,6 @@ convert_from_bool (expr_t *e, type_t *type) return e; } -expr_t * -bool_expr (int op, expr_t *label, expr_t *e1, expr_t *e2) -{ - expr_t *block; - - if (!options.code.short_circuit) - return binary_expr (op, e1, e2); - - e1 = convert_bool (e1, 0); - if (e1->type == ex_error) - return e1; - - e2 = convert_bool (e2, 0); - if (e2->type == ex_error) - return e2; - - block = new_block_expr (); - append_expr (block, e1); - append_expr (block, label); - append_expr (block, e2); - - switch (op) { - case OR: - backpatch (e1->e.bool.false_list, label); - return new_bool_expr (merge (e1->e.bool.true_list, - e2->e.bool.true_list), - e2->e.bool.false_list, block); - break; - case AND: - backpatch (e1->e.bool.true_list, label); - return new_bool_expr (e2->e.bool.true_list, - merge (e1->e.bool.false_list, - e2->e.bool.false_list), block); - break; - } - internal_error (e1, 0); -} - void convert_int (expr_t *e) { @@ -1457,10 +1498,18 @@ convert_short_int (expr_t *e) } void +convert_double (expr_t *e) +{ + float float_val = expr_double (e); + e->type = ex_value; + e->e.value = new_float_val (float_val); +} + +expr_t * convert_nil (expr_t *e, type_t *t) { - e->type = ex_value; - e->e.value = new_nil_val (t); + e->e.nil = t; + return e; } int @@ -1536,6 +1585,8 @@ unary_expr (int op, expr_t *e) vec3_t v; quat_t q; const char *s; + expr_t *new; + type_t *t; convert_name (e); if (e->type == ex_error) @@ -1552,6 +1603,10 @@ unary_expr (int op, expr_t *e) case ev_func: case ev_pointer: internal_error (e, "type check failed!"); + case ev_double: + new = new_double_expr (-expr_double (e)); + new->implicit = e->implicit; + return new; case ev_float: return new_float_expr (-expr_float (e)); case ev_vector: @@ -1579,13 +1634,29 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: + case ex_memset: internal_error (e, 0); case ex_uexpr: - if (e->e.expr.op == '-') + if (e->e.expr.op == '-') { return e->e.expr.e1; + } + { + expr_t *n = new_unary_expr (op, e); + + n->e.expr.type = get_type (e); + return n; + } case ex_block: - if (!e->e.block.result) + if (!e->e.block.result) { return error (e, "invalid type for unary -"); + } + { + expr_t *n = new_unary_expr (op, e); + + n->e.expr.type = get_type (e); + return n; + } case ex_expr: case ex_bool: case ex_temp: @@ -1593,7 +1664,14 @@ unary_expr (int op, expr_t *e) { expr_t *n = new_unary_expr (op, e); - n->e.expr.type = e->e.expr.type; + n->e.expr.type = get_type (e); + return n; + } + case ex_def: + { + expr_t *n = new_unary_expr (op, e); + + n->e.expr.type = e->e.def->type; return n; } case ex_symbol: @@ -1618,6 +1696,8 @@ unary_expr (int op, expr_t *e) case ev_string: s = expr_string (e); return new_integer_expr (!s || !s[0]); + case ev_double: + return new_integer_expr (!expr_double (e)); case ev_float: return new_integer_expr (!expr_float (e)); case ev_vector: @@ -1643,6 +1723,8 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: + case ex_memset: internal_error (e, 0); case ex_bool: return new_bool_expr (e->e.bool.false_list, @@ -1652,6 +1734,7 @@ unary_expr (int op, expr_t *e) return error (e, "invalid type for unary !"); case ex_uexpr: case ex_expr: + case ex_def: case ex_symbol: case ex_temp: case ex_vector: @@ -1677,6 +1760,7 @@ unary_expr (int op, expr_t *e) case ev_func: case ev_pointer: case ev_vector: + case ev_double: return error (e, "invalid type for unary ~"); case ev_float: return new_float_expr (~(int) expr_float (e)); @@ -1690,6 +1774,11 @@ unary_expr (int op, expr_t *e) case ev_short: return new_short_expr (~expr_short (e)); case ev_invalid: + t = get_type (e); + if (t->meta == ty_enum) { + return new_integer_expr (~expr_integer (e)); + } + break; case ev_type_count: case ev_void: break; @@ -1702,6 +1791,8 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: + case ex_memset: internal_error (e, 0); case ex_uexpr: if (e->e.expr.op == '~') @@ -1713,6 +1804,7 @@ unary_expr (int op, expr_t *e) goto bitnot_expr; case ex_expr: case ex_bool: + case ex_def: case ex_symbol: case ex_temp: case ex_vector: @@ -1724,8 +1816,8 @@ bitnot_expr: expr_t *n = new_unary_expr (op, e); type_t *t = get_type (e); - if (t != &type_integer && t != &type_float - && t != &type_quaternion) + if (!is_integer(t) && !is_float(t) + && !is_quaternion(t)) return error (e, "invalid type for unary ~"); n->e.expr.type = t; return n; @@ -1749,15 +1841,17 @@ bitnot_expr: } expr_t * -build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) +build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) { expr_t *e; + expr_t *p; int arg_count = 0, parm_count = 0; int i; expr_t *args = 0, **a = &args; type_t *arg_types[MAX_PARMS]; expr_t *arg_exprs[MAX_PARMS][2]; int arg_expr_count = 0; + expr_t *assign; expr_t *call; expr_t *err = 0; @@ -1790,7 +1884,21 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) parm_count = ftype->t.func.num_params; } for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) { - type_t *t = get_type (e); + type_t *t; + + if (e->type == ex_compound) { + if (i < parm_count) { + t = ftype->t.func.param_types[i]; + } else { + return error (e, "cannot pass compound initializer " + "through ..."); + } + } else { + t = get_type (e); + } + if (!t) { + return e; + } if (!type_size (t)) err = error (e, "type of formal parameter %d is incomplete", @@ -1798,11 +1906,6 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) if (type_size (t) > type_size (&type_param)) err = error (e, "formal parameter %d is too large to be passed by" " value", i + 1); - if (ftype->t.func.param_types[i] == &type_float - && is_integer_val (e)) { - convert_int (e); - t = &type_float; - } if (i < parm_count) { if (e->type == ex_nil) convert_nil (e, t = ftype->t.func.param_types[i]); @@ -1823,6 +1926,21 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) if (is_integer_val (e) && options.code.progsversion == PROG_ID_VERSION) convert_int (e); + if (options.code.promote_float) { + if (is_float (get_type (e))) { + t = &type_double; + } + } else { + if (is_double (get_type (e))) { + if (!e->implicit) { + warning (e, "passing double into ... function"); + } + if (is_constant (e)) { + // don't auto-demote non-constant doubles + t = &type_float; + } + } + } if (is_integer_val (e) && options.warnings.vararg_integer) warning (e, "passing integer constant into ... function"); } @@ -1831,31 +1949,43 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) if (err) return err; - call = new_block_expr (); + call = expr_file_line (new_block_expr (), fexpr); call->e.block.is_call = 1; - for (e = params, i = 0; e; e = e->next, i++) { + for (p = params, i = 0; p; p = p->next, i++) { + expr_t *e = p; + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (arg_types[i], e), e); + } + // FIXME this is target-specific info and should not be in the + // expression tree + // That, or always use a temp, since it should get optimized out if (has_function_call (e)) { - *a = new_temp_def_expr (arg_types[i]); - arg_exprs[arg_expr_count][0] = cast_expr (arg_types[i], convert_vector (e)); + expr_t *cast = cast_expr (arg_types[i], convert_vector (e)); + expr_t *tmp = new_temp_def_expr (arg_types[i]); + *a = expr_file_line (tmp, e); + arg_exprs[arg_expr_count][0] = expr_file_line (cast, e); arg_exprs[arg_expr_count][1] = *a; arg_expr_count++; } else { - *a = cast_expr (arg_types[i], convert_vector (e)); + *a = expr_file_line (cast_expr (arg_types[i], convert_vector (e)), + e); } a = &(*a)->next; } for (i = 0; i < arg_expr_count - 1; i++) { - append_expr (call, assign_expr (arg_exprs[i][1], arg_exprs[i][0])); + assign = assign_expr (arg_exprs[i][1], arg_exprs[i][0]); + append_expr (call, expr_file_line (assign, arg_exprs[i][0])); } if (arg_expr_count) { e = assign_expr (arg_exprs[arg_expr_count - 1][1], arg_exprs[arg_expr_count - 1][0]); + e = expr_file_line (e, arg_exprs[arg_expr_count - 1][0]); append_expr (call, e); } - e = new_binary_expr ('c', fexpr, args); + e = expr_file_line (new_binary_expr ('c', fexpr, args), fexpr); e->e.expr.type = ftype->t.func.type; append_expr (call, e); - if (ftype->t.func.type != &type_void) { + if (!is_void(ftype->t.func.type)) { call->e.block.result = new_ret_expr (ftype->t.func.type); } else if (options.traditional) { call->e.block.result = new_ret_expr (&type_float); @@ -1918,45 +2048,54 @@ goto_expr (expr_t *label) expr_t * return_expr (function_t *f, expr_t *e) { - type_t *t; + const type_t *t; + const type_t *ret_type = unalias_type (f->type->t.func.type); if (!e) { - if (f->sym->type->t.func.type != &type_void) { + if (!is_void(ret_type)) { if (options.traditional) { if (options.warnings.traditional) warning (e, "return from non-void function without a value"); + // force a nil return value in case qf code is being generated e = new_nil_expr (); } else { e = error (e, "return from non-void function without a value"); return e; } } - return new_unary_expr ('r', 0); + // the traditional check above may have set e + if (!e) { + return new_unary_expr ('r', 0); + } + } + + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (ret_type, e), e); } t = get_type (e); - if (e->type == ex_error) + if (!t) { return e; - if (f->sym->type->t.func.type == &type_void) { + } + if (is_void(ret_type)) { if (!options.traditional) return error (e, "returning a value for a void function"); if (options.warnings.traditional) warning (e, "returning a value for a void function"); } - if (e->type == ex_bool) - e = convert_from_bool (e, f->sym->type->t.func.type); - if (f->sym->type->t.func.type == &type_float && is_integer_val (e)) { + if (e->type == ex_bool) { + e = convert_from_bool (e, (type_t *) ret_type); //FIXME cast + } + if (is_float(ret_type) && is_integer_val (e)) { convert_int (e); t = &type_float; } - if (t == &type_void) { + if (is_void(t)) { if (e->type == ex_nil) { - t = f->sym->type->t.func.type; - convert_nil (e, t); - if (e->type == ex_nil) - return error (e, "invalid return type for NIL"); + t = ret_type; + convert_nil (e, (type_t *) t);//FIXME cast } else { if (!options.traditional) return error (e, "void value not ignored as it ought to be"); @@ -1965,7 +2104,7 @@ return_expr (function_t *f, expr_t *e) //FIXME does anything need to be done here? } } - if (!type_assignable (f->sym->type->t.func.type, t)) { + if (!type_assignable (ret_type, t)) { if (!options.traditional) return error (e, "type mismatch for return value of %s", f->sym->name); @@ -1973,8 +2112,16 @@ return_expr (function_t *f, expr_t *e) warning (e, "type mismatch for return value of %s", f->sym->name); } else { - if (f->sym->type->t.func.type != t) - e = cast_expr (f->sym->type->t.func.type, e); + if (ret_type != t) { + e = cast_expr ((type_t *) ret_type, e);//FIXME cast + t = f->sym->type->t.func.type; + } + } + if (e->type == ex_vector) { + e = assign_expr (new_temp_def_expr (t), e); + } + if (e->type == ex_block) { + e->e.block.result->rvalue = 1; } return new_unary_expr ('r', e); } @@ -2058,6 +2205,8 @@ array_expr (expr_t *array, expr_t *index) type_t *array_type = get_type (array); type_t *index_type = get_type (index); expr_t *scale; + expr_t *offset; + expr_t *base; expr_t *e; int ind = 0; @@ -2081,11 +2230,9 @@ array_expr (expr_t *array, expr_t *index) return error (index, "array index out of bounds"); scale = new_integer_expr (type_size (array_type->t.array.type)); index = binary_expr ('*', index, scale); - index = binary_expr ('-', index, - binary_expr ('*', - new_integer_expr (array_type->t.array.base), - scale)); - index = fold_constants (index); + base = new_integer_expr (array_type->t.array.base); + offset = binary_expr ('*', base, scale); + index = binary_expr ('-', index, offset); if (is_short_val (index)) ind = expr_short (index); if (is_integer_val (index)) @@ -2131,6 +2278,22 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) t = get_type (e1); switch (e1->type) { + case ex_def: + { + def_t *def = e1->e.def; + type_t *type = def->type; + + if (is_array (type)) { + e = e1; + e->type = ex_value; + e->e.value = new_pointer_val (0, t, def, 0); + } else { + e = new_pointer_expr (0, t, def); + e->line = e1->line; + e->file = e1->file; + } + } + break; case ex_symbol: if (e1->e.symbol->sy_type == sy_var) { def_t *def = e1->e.symbol->s.def; @@ -2139,7 +2302,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) if (is_array (type)) { e = e1; e->type = ex_value; - e->e.value = new_pointer_val (0, t, def); + e->e.value = new_pointer_val (0, t, def, 0); } else { e = new_pointer_expr (0, t, def); e->line = e1->line; @@ -2165,6 +2328,16 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) e = e1->e.expr.e2; break; } + if (e1->e.expr.op == 'A') { + if (!t) + t = e1->e.expr.type; + if (e2) { + e2 = binary_expr ('+', e1->e.expr.e2, e2); + } else { + e2 = e1->e.expr.e2; + } + return address_expr (e1->e.expr.e1, e2, t); + } return error (e1, "invalid type for unary &"); case ex_uexpr: if (e1->e.expr.op == '.') { @@ -2181,22 +2354,23 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) return address_expr (e1->e.expr.e1, e2, t); } return error (e1, "invalid type for unary &"); - case ex_block: - if (!e1->e.block.result) - return error (e1, "invalid type for unary &"); - e1->e.block.result = address_expr (e1->e.block.result, e2, t); - return e1; case ex_label: return new_label_ref (&e1->e.label); + case ex_temp: + e = new_unary_expr ('&', e1); + e->e.expr.type = pointer_type (t); + break; default: return error (e1, "invalid type for unary &"); } if (e2) { if (e2->type == ex_error) return e2; - if (e->type == ex_value && e->e.value->type == ev_pointer - && is_short_val (e2)) { - e->e.value = new_pointer_val (e->e.value->v.pointer.val + expr_short (e2), t, e->e.value->v.pointer.def); + if (is_pointer_val (e) && is_integral_val (e2)) { + int base = e->e.value->v.pointer.val; + int offset = expr_integral (e2); + def_t *def = e->e.value->v.pointer.def; + e->e.value = new_pointer_val (base + offset, t, def, 0); } else { if (!is_short_val (e2) || expr_short (e2)) { if (e->type == ex_expr && e->e.expr.op == '&') { @@ -2458,293 +2632,84 @@ think_expr (symbol_t *think_sym) return new_symbol_expr (think_sym); } -static int -is_indirect (expr_t *e) -{ - if (e->type == ex_block && e->e.block.result) - return is_indirect (e->e.block.result); - if (e->type == ex_expr && e->e.expr.op == '.') - return 1; - if (!(e->type == ex_uexpr && e->e.expr.op == '.')) - return 0; - e = e->e.expr.e1; - if (e->type != ex_value || e->e.value->type != ev_pointer - || !(POINTER_VAL (e->e.value->v.pointer) >= 0 - && POINTER_VAL (e->e.value->v.pointer) < 65536)) { - return 1; - } - return 0; -} - -static inline int -is_lvalue (expr_t *e) -{ - if (e->type == ex_symbol) { - switch (e->e.symbol->sy_type) { - case sy_var: - return 1; - case sy_const: - return 0; - case sy_type: - return 0; - case sy_expr: - return 0; - case sy_func: - return 0; - case sy_class: - return 0; - } - } - if (e->type == ex_temp) - return 1; - if (e->type == ex_expr && e->e.expr.op == '.') - return 1; - if (e->type == ex_uexpr && e->e.expr.op == '.') - return 1; - if (e->type == ex_uexpr && e->e.expr.op == 'A') - return is_lvalue (e->e.expr.e1); - return 0; -} - expr_t * -assign_expr (expr_t *e1, expr_t *e2) -{ - int op = '='; - type_t *t1, *t2, *type; - expr_t *e; - - convert_name (e1); - convert_name (e2); - e2 = convert_vector (e2); - - if (e1->type == ex_error) - return e1; - if (e2->type == ex_error) - return e2; - - e1 = fold_constants (e1); - e2 = fold_constants (e2); - - if (options.traditional) { - if (e2->type == ex_expr && !e2->paren - && (e2->e.expr.op == AND || e2->e.expr.op == OR)) { - notice (e2, "precedence of `%s' and `%s' inverted for " - "traditional code", get_op_string (op), - get_op_string (e2->e.expr.op)); - e1 = assign_expr (e1, e2->e.expr.e1); - e1->paren = 1; - return binary_expr (e2->e.expr.op, e1, e2->e.expr.e2); - } - } - - if (!is_lvalue (e1)) { - if (options.traditional) - warning (e1, "invalid lvalue in assignment"); - else - return error (e1, "invalid lvalue in assignment"); - } - t1 = get_type (e1); - t2 = get_type (e2); - if (!t1 || !t2) - internal_error (e1, 0); - //XXX func = func ??? - if (t1->type == ev_pointer && is_array (t2)) { - e2 = address_expr (e2, 0, t2->t.fldptr.type); - t2 = get_type (e2); - } - if (e2->type == ex_bool) - e2 = convert_from_bool (e2, t1); - - if (t1->type != ev_void && e2->type == ex_nil) { - t2 = t1; - convert_nil (e2, t2); - } - - e2->rvalue = 1; - - if (!type_assignable (t1, t2)) { - if (options.traditional) { - if (t1->type == ev_func && t2->type == ev_func) { - warning (e1, "assignment between disparate function types"); - } else if (t1->type == ev_float && t2->type == ev_vector) { - warning (e1, "assignment of vector to float"); - e2 = field_expr (e2, new_name_expr ("x")); - } else if (t1->type == ev_vector && t2->type == ev_float) { - warning (e1, "assignment of float to vector"); - e1 = field_expr (e1, new_name_expr ("x")); - } else { - return type_mismatch (e1, e2, op); - } - } else { - return type_mismatch (e1, e2, op); - } - } - type = t1; - if (is_indirect (e1) && is_indirect (e2)) { - if (is_struct (get_type (e2))) { - e1 = address_expr (e1, 0, 0); - e2 = address_expr (e2, 0, 0); - e = new_move_expr (e1, e2, t2, 1); - } else { - expr_t *temp = new_temp_def_expr (t1); - - e = new_block_expr (); - append_expr (e, assign_expr (temp, e2)); - append_expr (e, assign_expr (e1, temp)); - e->e.block.result = temp; - } - return e; - } else if (is_indirect (e1)) { - if (is_struct (get_type (e1))) { - e1 = address_expr (e1, 0, 0); - e2 = address_expr (e2, 0, 0); - return new_move_expr (e1, e2, t1, 1); - } - if (e1->type == ex_expr) { - if (get_type (e1->e.expr.e1) == &type_entity) { - type = e1->e.expr.type; - e1->e.expr.type = pointer_type (type); - e1->e.expr.op = '&'; - } - op = PAS; - } else { - e = e1->e.expr.e1; - if ((e->type != ex_value || e->e.value->type != ev_pointer) - || !(POINTER_VAL (e->e.value->v.pointer) > 0 - && POINTER_VAL (e->e.value->v.pointer) < 65536)) { - e1 = e; - op = PAS; - } - } - } else if (is_indirect (e2)) { - if (is_struct (get_type (e1))) { - e1 = address_expr (e1, 0, 0); - e2 = address_expr (e2, 0, 0); - e2->rvalue = 1; - return new_move_expr (e1, e2, t2, 1); - } - if (e2->type == ex_uexpr) { - e = e2->e.expr.e1; - if ((e->type != ex_value || e->e.value->type != ev_pointer) - || !(POINTER_VAL (e->e.value->v.pointer) > 0 - && POINTER_VAL (e->e.value->v.pointer) < 65536)) { - if (e->type == ex_expr && e->e.expr.op == '&' - && e->e.expr.type->type == ev_pointer - && !is_constant (e)) { - e2 = e; - e2->e.expr.op = '.'; - e2->e.expr.type = t2; - e2->rvalue = 1; - } - } - } - } - if (is_struct (get_type (e1))) { - return new_move_expr (e1, e2, get_type (e1), 0); - } - if (!type) - internal_error (e1, 0); - - e = new_binary_expr (op, e1, e2); - e->e.expr.type = type; - return e; -} - -expr_t * -cast_expr (type_t *type, expr_t *e) +cast_expr (type_t *dstType, expr_t *e) { expr_t *c; - type_t *e_type; + type_t *srcType; convert_name (e); if (e->type == ex_error) return e; - e_type = get_type (e); + dstType = (type_t *) unalias_type (dstType); //FIXME cast + srcType = get_type (e); - if (type == e_type) + if (dstType == srcType) return e; - if ((type == type_default && is_enum (e_type)) - || (is_enum (type) && e_type == type_default)) + if ((dstType == type_default && is_enum (srcType)) + || (is_enum (dstType) && srcType == type_default)) return e; - if (!(type->type == ev_pointer - && (e_type->type == ev_pointer || is_integral (e_type) - || is_array (e_type))) - && !(is_integral (type) && e_type->type == ev_pointer) - && !(type->type == ev_func && e_type->type == ev_func) - && !(is_scalar (type) && is_scalar (e_type))) { - return cast_error (e, e_type, type); + if ((is_pointer (dstType) && is_string (srcType)) + || (is_string (dstType) && is_pointer (srcType))) { + c = new_alias_expr (dstType, e); + return c; } - if (is_array (e_type)) - return address_expr (e, 0, 0); - if (is_constant (e) && is_scalar (type) && is_scalar (e_type)) { + if (!(is_pointer (dstType) + && (is_pointer (srcType) || is_integral (srcType) + || is_array (srcType))) + && !(is_integral (dstType) && is_pointer (srcType)) + && !(is_func (dstType) && is_func (srcType)) + && !(is_scalar (dstType) && is_scalar (srcType))) { + return cast_error (e, srcType, dstType); + } + if (is_array (srcType)) { + return address_expr (e, 0, dstType->t.fldptr.type); + } + if (is_constant (e) && is_scalar (dstType) && is_scalar (srcType)) { ex_value_t *val = 0; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) { val = e->e.symbol->s.value; + } else if (e->type == ex_symbol + && e->e.symbol->sy_type == sy_var) { + // initialized global def treated as a constant + // from the tests above, the def is known to be constant + // and of one of the three storable scalar types + def_t *def = e->e.symbol->s.def; + if (is_float (def->type)) { + val = new_float_val (D_FLOAT (def)); + } else if (is_double (def->type)) { + val = new_double_val (D_DOUBLE (def)); + } else if (is_integral (def->type)) { + val = new_integer_val (D_INT (def)); + } } else if (e->type == ex_value) { val = e->e.value; } else if (e->type == ex_nil) { - convert_nil (e, type); + convert_nil (e, dstType); return e; } if (!val) internal_error (e, "unexpected constant expression type"); - e->e.value = convert_value (val, type); + e->e.value = convert_value (val, dstType); e->type = ex_value; c = e; - } else if ((is_float (type) && is_integral (e_type)) - || (is_integral (type) && is_float (e_type))) { + } else if (is_integral (dstType) && is_integral (srcType)) { + c = new_alias_expr (dstType, e); + } else if (is_scalar (dstType) && is_scalar (srcType)) { c = new_unary_expr ('C', e); - c->e.expr.type = type; + c->e.expr.type = dstType; } else if (e->type == ex_uexpr && e->e.expr.op == '.') { - e->e.expr.type = type; + e->e.expr.type = dstType; c = e; } else { - c = new_alias_expr (type, e); + c = new_alias_expr (dstType, e); } return c; } -expr_t * -selector_expr (keywordarg_t *selector) -{ - dstring_t *sel_id = dstring_newstr (); - expr_t *sel; - symbol_t *sel_sym; - symbol_t *sel_table; - int index; - - selector = copy_keywordargs (selector); - selector = (keywordarg_t *) reverse_params ((param_t *) selector); - selector_name (sel_id, selector); - index = selector_index (sel_id->str); - index *= type_size (type_SEL.t.fldptr.type); - sel_sym = make_symbol ("_OBJ_SELECTOR_TABLE_PTR", &type_SEL, - pr.near_data, sc_static); - if (!sel_sym->table) { - symtab_addsymbol (pr.symtab, sel_sym); - sel_table = make_symbol ("_OBJ_SELECTOR_TABLE", - array_type (type_SEL.t.fldptr.type, 0), - pr.far_data, sc_extern); - if (!sel_table->table) - symtab_addsymbol (pr.symtab, sel_table); - reloc_def_def (sel_table->s.def, sel_sym->s.def); - } - sel = new_symbol_expr (sel_sym); - dstring_delete (sel_id); - sel = new_binary_expr ('&', sel, new_short_expr (index)); - sel->e.expr.type = &type_SEL; - return sel; -} - -expr_t * -protocol_expr (const char *protocol) -{ - return error (0, "not implemented"); -} - expr_t * encode_expr (type_t *type) { @@ -2757,139 +2722,6 @@ encode_expr (type_t *type) return e; } -expr_t * -super_expr (class_type_t *class_type) -{ - symbol_t *sym; - expr_t *super; - expr_t *e; - expr_t *super_block; - class_t *class; - - if (!class_type) - return error (0, "`super' used outside of class implementation"); - - class = extract_class (class_type); - - if (!class->super_class) - return error (0, "%s has no super class", class->name); - - sym = symtab_lookup (current_symtab, ".super"); - if (!sym || sym->table != current_symtab) { - sym = new_symbol (".super"); - initialize_def (sym, &type_obj_super, 0, current_symtab->space, - sc_local); - } - super = new_symbol_expr (sym); - - super_block = new_block_expr (); - - e = assign_expr (field_expr (super, new_name_expr ("self")), - new_name_expr ("self")); - append_expr (super_block, e); - - e = new_symbol_expr (class_pointer_symbol (class)); - e = assign_expr (field_expr (super, new_name_expr ("class")), - field_expr (e, new_name_expr ("super_class"))); - append_expr (super_block, e); - - e = address_expr (super, 0, 0); - super_block->e.block.result = e; - return super_block; -} - -expr_t * -message_expr (expr_t *receiver, keywordarg_t *message) -{ - expr_t *args = 0, **a = &args; - expr_t *selector = selector_expr (message); - expr_t *call; - keywordarg_t *m; - int self = 0, super = 0, class_msg = 0; - type_t *rec_type; - type_t *return_type; - type_t *method_type = &type_IMP; - class_t *class = 0; - method_t *method; - expr_t *send_msg; - - if (receiver->type == ex_symbol - && strcmp (receiver->e.symbol->name, "super") == 0) { - super = 1; - - receiver = super_expr (current_class); - - if (receiver->type == ex_error) - return receiver; - receiver = cast_expr (&type_id, receiver); //FIXME better way? - class = extract_class (current_class); - rec_type = class->type; - } else { - if (receiver->type == ex_symbol) { - if (strcmp (receiver->e.symbol->name, "self") == 0) - self = 1; - if (receiver->e.symbol->sy_type == sy_class) { - class = receiver->e.symbol->type->t.class; - class_msg = 1; - receiver = new_symbol_expr (class_pointer_symbol (class)); - } - } else if (receiver->type == ex_nil) { - convert_nil (receiver, &type_id); - } - rec_type = get_type (receiver); - - if (receiver->type == ex_error) - return receiver; - - if (rec_type == &type_id || rec_type == &type_Class) { - } else { - if (rec_type->type == ev_pointer) - rec_type = rec_type->t.fldptr.type; - if (!obj_is_class (rec_type)) - return error (receiver, "not a class/object"); - - if (self) { - if (!class) - class = extract_class (current_class); - if (rec_type == &type_obj_class) - class_msg = 1; - } else { - if (!class) - class = rec_type->t.class; - } - } - } - - return_type = &type_id; - method = class_message_response (class, class_msg, selector); - if (method) - return_type = method->type->t.func.type; - - for (m = message; m; m = m->next) { - *a = m->expr; - while ((*a)) - a = &(*a)->next; - } - *a = selector; - a = &(*a)->next; - *a = receiver; - - send_msg = send_message (super); - if (method) { - expr_t *err; - if ((err = method_check_params (method, args))) - return err; - method_type = method->type; - } - call = build_function_call (send_msg, method_type, args); - - if (call->type == ex_error) - return receiver; - - call->e.block.result = new_ret_expr (return_type); - return call; -} - expr_t * sizeof_expr (expr_t *expr, struct type_s *type) { diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c new file mode 100644 index 000000000..472c1f1a5 --- /dev/null +++ b/tools/qfcc/source/expr_assign.c @@ -0,0 +1,360 @@ +/* + expr_assign.c + + assignment expression construction and manipulations + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/15 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/idstuff.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +static expr_t * +check_assign_logic_precedence (expr_t *dst, expr_t *src) +{ + if (src->type == ex_expr && !src->paren && is_logic (src->e.expr.op)) { + // traditional QuakeC gives = higher precedence than && and || + expr_t *assignment; + notice (src, "precedence of `=' and `%s' inverted for " + "traditional code", get_op_string (src->e.expr.op)); + // change {a = (b logic c)} to {(a = b) logic c} + assignment = assign_expr (dst, src->e.expr.e1); + assignment->paren = 1; // protect assignment from binary_expr + return binary_expr (src->e.expr.op, assignment, src->e.expr.e2); + } + return 0; +} + +int +is_lvalue (const expr_t *expr) +{ + switch (expr->type) { + case ex_def: + return !expr->e.def->constant; + case ex_symbol: + switch (expr->e.symbol->sy_type) { + case sy_name: + break; + case sy_var: + return 1; + case sy_const: + break; + case sy_type: + break; + case sy_expr: + break; + case sy_func: + break; + case sy_class: + break; + case sy_convert: + break; + } + break; + case ex_temp: + return 1; + case ex_expr: + if (expr->e.expr.op == '.') { + return 1; + } + if (expr->e.expr.op == 'A') { + return is_lvalue (expr->e.expr.e1); + } + break; + case ex_uexpr: + if (expr->e.expr.op == '.') { + return 1; + } + if (expr->e.expr.op == 'A') { + return is_lvalue (expr->e.expr.e1); + } + break; + case ex_memset: + case ex_compound: + case ex_state: + case ex_bool: + case ex_label: + case ex_labelref: + case ex_block: + case ex_vector: + case ex_nil: + case ex_value: + case ex_error: + break; + } + return 0; +} + +static expr_t * +check_valid_lvalue (expr_t *expr) +{ + if (!is_lvalue (expr)) { + if (options.traditional) { + warning (expr, "invalid lvalue in assignment"); + return 0; + } + return error (expr, "invalid lvalue in assignment"); + } + return 0; +} + +static expr_t * +check_types_compatible (expr_t *dst, expr_t *src) +{ + type_t *dst_type = get_type (dst); + type_t *src_type = get_type (src); + + if (dst_type == src_type) { + return 0; + } + + if (type_assignable (dst_type, src_type)) { + if (is_scalar (dst_type) && is_scalar (src_type)) { + if (!src->implicit) { + if (is_double (src_type)) { + warning (dst, "assignment of double to %s (use a cast)\n", + dst_type->name); + } + } + // the types are different but cast-compatible + expr_t *new = cast_expr (dst_type, src); + // the cast was a no-op, so the types are compatible at the + // low level (very true for default type <-> enum) + if (new != src) { + return assign_expr (dst, new); + } + } + return 0; + } + // traditional qcc is a little sloppy + if (!options.traditional) { + return type_mismatch (dst, src, '='); + } + if (is_func (dst_type) && is_func (src_type)) { + warning (dst, "assignment between disparate function types"); + return 0; + } + if (is_float (dst_type) && is_vector (src_type)) { + warning (dst, "assignment of vector to float"); + src = field_expr (src, new_name_expr ("x")); + return assign_expr (dst, src); + } + if (is_vector (dst_type) && is_float (src_type)) { + warning (dst, "assignment of float to vector"); + dst = field_expr (dst, new_name_expr ("x")); + return assign_expr (dst, src); + } + return type_mismatch (dst, src, '='); +} + +static expr_t * +assign_vector_expr (expr_t *dst, expr_t *src) +{ + expr_t *dx, *sx; + expr_t *dy, *sy; + expr_t *dz, *sz; + expr_t *dw, *sw; + expr_t *ds, *ss; + expr_t *dv, *sv; + expr_t *block; + + if (src->type == ex_vector) { + src = convert_vector (src); + if (src->type != ex_vector) { + // src was constant and thus converted + return assign_expr (dst, src); + } + } + if (src->type == ex_vector && dst->type != ex_vector) { + if (is_vector(src->e.vector.type)) { + // guaranteed to have three elements + sx = src->e.vector.list; + sy = sx->next; + sz = sy->next; + dx = field_expr (dst, new_name_expr ("x")); + dy = field_expr (dst, new_name_expr ("y")); + dz = field_expr (dst, new_name_expr ("z")); + block = new_block_expr (); + append_expr (block, assign_expr (dx, sx)); + append_expr (block, assign_expr (dy, sy)); + append_expr (block, assign_expr (dz, sz)); + block->e.block.result = dst; + return block; + } + if (is_quaternion(src->e.vector.type)) { + // guaranteed to have two or four elements + if (src->e.vector.list->next->next) { + // four vals: x, y, z, w + sx = src->e.vector.list; + sy = sx->next; + sz = sy->next; + sw = sz->next; + dx = field_expr (dst, new_name_expr ("x")); + dy = field_expr (dst, new_name_expr ("y")); + dz = field_expr (dst, new_name_expr ("z")); + dw = field_expr (dst, new_name_expr ("w")); + block = new_block_expr (); + append_expr (block, assign_expr (dx, sx)); + append_expr (block, assign_expr (dy, sy)); + append_expr (block, assign_expr (dz, sz)); + append_expr (block, assign_expr (dw, sw)); + block->e.block.result = dst; + return block; + } else { + // v, s + sv = src->e.vector.list; + ss = sv->next; + dv = field_expr (dst, new_name_expr ("v")); + ds = field_expr (dst, new_name_expr ("s")); + block = new_block_expr (); + append_expr (block, assign_expr (dv, sv)); + append_expr (block, assign_expr (ds, ss)); + block->e.block.result = dst; + return block; + } + } + internal_error (src, "bogus vector expression"); + } + return 0; +} + +static __attribute__((pure)) int +is_memset (expr_t *e) +{ + return e->type == ex_memset; +} + +expr_t * +assign_expr (expr_t *dst, expr_t *src) +{ + int op = '='; + expr_t *expr; + type_t *dst_type, *src_type; + + convert_name (dst); + if (dst->type == ex_error) { + return dst; + } + if ((expr = check_valid_lvalue (dst))) { + return expr; + } + dst_type = get_type (dst); + if (!dst_type) { + internal_error (dst, "dst_type broke in assign_expr"); + } + + if (src && !is_memset (src)) { + convert_name (src); + if (src->type == ex_error) { + return src; + } + + if (options.traditional + && (expr = check_assign_logic_precedence (dst, src))) { + return expr; + } + } else { + if (!src && is_scalar (dst_type)) { + return error (dst, "empty scalar initializer"); + } + src = new_nil_expr (); + } + if (src->type == ex_compound) { + src = initialized_temp_expr (dst_type, src); + if (src->type == ex_error) { + return src; + } + } + src_type = get_type (src); + if (!src_type) { + internal_error (src, "src_type broke in assign_expr"); + } + + if (is_pointer (dst_type) && is_array (src_type)) { + // assigning an array to a pointer is the same as taking the address of + // the array but using the type of the array elements + src = address_expr (src, 0, src_type->t.fldptr.type); + src_type = get_type (src); + } + if (src->type == ex_bool) { + // boolean expressions are chains of tests, so extract the result + // of the tests + src = convert_from_bool (src, dst_type); + if (src->type == ex_error) { + return src; + } + src_type = get_type (src); + } + + if (!is_nil (src)) { + if ((expr = check_types_compatible (dst, src))) { + // expr might be a valid expression, but if so, + // check_types_compatible will take care of everything + return expr; + } + if ((expr = assign_vector_expr (dst, src))) { + return expr; + } + } else { + convert_nil (src, dst_type); + } + + expr = new_binary_expr (op, dst, src); + expr->e.expr.type = dst_type; + return expr; +} diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 2aa963b3a..616dc7ac4 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -31,19 +31,26 @@ # include "config.h" #endif -#include "diagnostic.h" -#include "expr.h" -#include "options.h" -#include "type.h" -#include "qc-parse.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/type.h" + +#include "tools/qfcc/source/qc-parse.h" typedef struct { int op; type_t *type; type_t *a_cast; type_t *b_cast; + expr_t *(*process)(int op, expr_t *e1, expr_t *e2); } expr_type_t; +static expr_t *pointer_arithmetic (int op, expr_t *e1, expr_t *e2); +static expr_t *pointer_compare (int op, expr_t *e1, expr_t *e2); +static expr_t *inverse_multiply (int op, expr_t *e1, expr_t *e2); +static expr_t *double_compare (int op, expr_t *e1, expr_t *e2); + static expr_type_t string_string[] = { {'+', &type_string}, {EQ, &type_integer}, @@ -64,8 +71,11 @@ static expr_type_t float_float[] = { {'|', &type_float}, {'^', &type_float}, {'%', &type_float}, + {MOD, &type_float}, {SHL, &type_float}, {SHR, &type_float}, + {AND, &type_integer}, + {OR, &type_integer}, {EQ, &type_integer}, {NE, &type_integer}, {LE, &type_integer}, @@ -82,7 +92,6 @@ static expr_type_t float_vector[] = { static expr_type_t float_quat[] = { {'*', &type_quaternion}, - {'/', &type_quaternion}, {0, 0} }; @@ -95,6 +104,7 @@ static expr_type_t float_integer[] = { {'|', &type_float, 0, &type_float}, {'^', &type_float, 0, &type_float}, {'%', &type_float, 0, &type_float}, + {MOD, &type_float, 0, &type_float}, {SHL, &type_float, 0, &type_float}, {SHR, &type_float, 0, &type_float}, {EQ, &type_integer, 0, &type_float}, @@ -108,9 +118,25 @@ static expr_type_t float_integer[] = { #define float_uinteger float_integer #define float_short float_integer +static expr_type_t float_double[] = { + {'+', &type_double, &type_double, 0}, + {'-', &type_double, &type_double, 0}, + {'*', &type_double, &type_double, 0}, + {'/', &type_double, &type_double, 0}, + {'%', &type_double, &type_double, 0}, + {MOD, &type_double, &type_double, 0}, + {EQ, 0, 0, 0, double_compare}, + {NE, 0, 0, 0, double_compare}, + {LE, 0, 0, 0, double_compare}, + {GE, 0, 0, 0, double_compare}, + {LT, 0, 0, 0, double_compare}, + {GT, 0, 0, 0, double_compare}, + {0, 0} +}; + static expr_type_t vector_float[] = { {'*', &type_vector}, - {'/', &type_vector}, + {'/', 0, 0, 0, inverse_multiply}, {0, 0} }; @@ -127,6 +153,12 @@ static expr_type_t vector_vector[] = { #define vector_uinteger vector_float #define vector_short vector_float +static expr_type_t vector_double[] = { + {'*', &type_vector}, + {'/', 0, 0, 0, inverse_multiply}, + {0, 0} +}; + static expr_type_t entity_entity[] = { {EQ, &type_integer}, {NE, &type_integer}, @@ -146,19 +178,19 @@ static expr_type_t func_func[] = { }; static expr_type_t pointer_pointer[] = { - {'-', &type_integer, &type_integer, &type_integer}, - {EQ, &type_integer}, - {NE, &type_integer}, - {LE, &type_integer}, - {GE, &type_integer}, - {LT, &type_integer}, - {GT, &type_integer}, + {'-', 0, 0, 0, pointer_arithmetic}, + {EQ, 0, 0, 0, pointer_compare}, + {NE, 0, 0, 0, pointer_compare}, + {LE, 0, 0, 0, pointer_compare}, + {GE, 0, 0, 0, pointer_compare}, + {LT, 0, 0, 0, pointer_compare}, + {GT, 0, 0, 0, pointer_compare}, {0, 0} }; static expr_type_t pointer_integer[] = { - {'+', &type_pointer}, - {'-', &type_pointer}, + {'+', 0, 0, 0, pointer_arithmetic}, + {'-', 0, 0, 0, pointer_arithmetic}, {0, 0} }; #define pointer_uinteger pointer_integer @@ -166,7 +198,7 @@ static expr_type_t pointer_integer[] = { static expr_type_t quat_float[] = { {'*', &type_quaternion}, - {'/', &type_quaternion}, + {'/', 0, 0, 0, inverse_multiply}, {0, 0} }; @@ -186,12 +218,18 @@ static expr_type_t quat_quat[] = { static expr_type_t quat_integer[] = { {'*', &type_quaternion, 0, &type_float}, - {'/', &type_quaternion, 0, &type_float}, + {'/', 0, 0, 0, inverse_multiply}, {0, 0} }; #define quat_uinteger quat_integer #define quat_short quat_integer +static expr_type_t quat_double[] = { + {'*', &type_quaternion}, + {'/', 0, 0, 0, inverse_multiply}, + {0, 0} +}; + static expr_type_t integer_float[] = { {'+', &type_float, &type_float, 0}, {'-', &type_float, &type_float, 0}, @@ -201,6 +239,7 @@ static expr_type_t integer_float[] = { {'|', &type_float, &type_float, 0}, {'^', &type_float, &type_float, 0}, {'%', &type_float, &type_float, 0}, + {MOD, &type_float, &type_float, 0}, {SHL, &type_integer, 0, &type_integer}, //FIXME? {SHR, &type_integer, 0, &type_integer}, //FIXME? {EQ, &type_integer, &type_float, 0}, @@ -218,13 +257,12 @@ static expr_type_t integer_vector[] = { }; static expr_type_t integer_pointer[] = { - {'+', &type_pointer}, + {'+', 0, 0, 0, pointer_arithmetic}, {0, 0} }; static expr_type_t integer_quat[] = { {'*', &type_quaternion, &type_float, 0}, - {'/', &type_quaternion, &type_float, 0}, {0, 0} }; @@ -237,8 +275,11 @@ static expr_type_t integer_integer[] = { {'|', &type_integer}, {'^', &type_integer}, {'%', &type_integer}, + {MOD, &type_integer}, {SHL, &type_integer}, {SHR, &type_integer}, + {AND, &type_integer}, + {OR, &type_integer}, {EQ, &type_integer}, {NE, &type_integer}, {LE, &type_integer}, @@ -257,6 +298,7 @@ static expr_type_t integer_uinteger[] = { {'|', &type_integer}, {'^', &type_integer}, {'%', &type_integer}, + {MOD, &type_integer}, {SHL, &type_integer}, {SHR, &type_integer}, {EQ, &type_integer}, @@ -269,22 +311,39 @@ static expr_type_t integer_uinteger[] = { }; static expr_type_t integer_short[] = { - {'+', &type_integer}, - {'-', &type_integer}, - {'*', &type_integer}, - {'/', &type_integer}, - {'&', &type_integer}, - {'|', &type_integer}, - {'^', &type_integer}, - {'%', &type_integer}, - {SHL, &type_integer}, - {SHR, &type_integer}, - {EQ, &type_integer}, - {NE, &type_integer}, - {LE, &type_integer}, - {GE, &type_integer}, - {LT, &type_integer}, - {GT, &type_integer}, + {'+', &type_integer, 0, &type_integer}, + {'-', &type_integer, 0, &type_integer}, + {'*', &type_integer, 0, &type_integer}, + {'/', &type_integer, 0, &type_integer}, + {'&', &type_integer, 0, &type_integer}, + {'|', &type_integer, 0, &type_integer}, + {'^', &type_integer, 0, &type_integer}, + {'%', &type_integer, 0, &type_integer}, + {MOD, &type_integer, 0, &type_integer}, + {SHL, &type_integer, 0, &type_integer}, + {SHR, &type_integer, 0, &type_integer}, + {EQ, &type_integer, 0, &type_integer}, + {NE, &type_integer, 0, &type_integer}, + {LE, &type_integer, 0, &type_integer}, + {GE, &type_integer, 0, &type_integer}, + {LT, &type_integer, 0, &type_integer}, + {GT, &type_integer, 0, &type_integer}, + {0, 0} +}; + +static expr_type_t integer_double[] = { + {'+', &type_double, &type_double, 0}, + {'-', &type_double, &type_double, 0}, + {'*', &type_double, &type_double, 0}, + {'/', &type_double, &type_double, 0}, + {'%', &type_double, &type_double, 0}, + {MOD, &type_double, &type_double, 0}, + {EQ, &type_integer, &type_double, 0}, + {NE, &type_integer, &type_double, 0}, + {LE, &type_integer, &type_double, 0}, + {GE, &type_integer, &type_double, 0}, + {LT, &type_integer, &type_double, 0}, + {GT, &type_integer, &type_double, 0}, {0, 0} }; @@ -302,6 +361,7 @@ static expr_type_t uinteger_integer[] = { {'|', &type_integer}, {'^', &type_integer}, {'%', &type_integer}, + {MOD, &type_integer}, {SHL, &type_uinteger}, {SHR, &type_uinteger}, {EQ, &type_integer}, @@ -322,6 +382,7 @@ static expr_type_t uinteger_uinteger[] = { {'|', &type_uinteger}, {'^', &type_uinteger}, {'%', &type_uinteger}, + {MOD, &type_uinteger}, {SHL, &type_uinteger}, {SHR, &type_uinteger}, {EQ, &type_integer}, @@ -333,6 +394,7 @@ static expr_type_t uinteger_uinteger[] = { {0, 0} }; #define uinteger_short uinteger_integer +#define uinteger_double integer_double #define short_float integer_float #define short_vector integer_vector @@ -340,42 +402,44 @@ static expr_type_t uinteger_uinteger[] = { #define short_quat integer_quat static expr_type_t short_integer[] = { - {'+', &type_integer}, - {'-', &type_integer}, - {'*', &type_integer}, - {'/', &type_integer}, - {'&', &type_integer}, - {'|', &type_integer}, - {'^', &type_integer}, - {'%', &type_integer}, + {'+', &type_integer, &type_integer, 0}, + {'-', &type_integer, &type_integer, 0}, + {'*', &type_integer, &type_integer, 0}, + {'/', &type_integer, &type_integer, 0}, + {'&', &type_integer, &type_integer, 0}, + {'|', &type_integer, &type_integer, 0}, + {'^', &type_integer, &type_integer, 0}, + {'%', &type_integer, &type_integer, 0}, + {MOD, &type_integer, &type_integer, 0}, {SHL, &type_short}, {SHR, &type_short}, - {EQ, &type_integer}, - {NE, &type_integer}, - {LE, &type_integer}, - {GE, &type_integer}, - {LT, &type_integer}, - {GT, &type_integer}, + {EQ, &type_integer, &type_integer, 0}, + {NE, &type_integer, &type_integer, 0}, + {LE, &type_integer, &type_integer, 0}, + {GE, &type_integer, &type_integer, 0}, + {LT, &type_integer, &type_integer, 0}, + {GT, &type_integer, &type_integer, 0}, {0, 0} }; static expr_type_t short_uinteger[] = { - {'+', &type_uinteger}, - {'-', &type_uinteger}, - {'*', &type_uinteger}, - {'/', &type_uinteger}, - {'&', &type_uinteger}, - {'|', &type_uinteger}, - {'^', &type_uinteger}, - {'%', &type_uinteger}, + {'+', &type_uinteger, &type_uinteger, 0}, + {'-', &type_uinteger, &type_uinteger, 0}, + {'*', &type_uinteger, &type_uinteger, 0}, + {'/', &type_uinteger, &type_uinteger, 0}, + {'&', &type_uinteger, &type_uinteger, 0}, + {'|', &type_uinteger, &type_uinteger, 0}, + {'^', &type_uinteger, &type_uinteger, 0}, + {'%', &type_uinteger, &type_uinteger, 0}, + {MOD, &type_uinteger, &type_uinteger, 0}, {SHL, &type_short}, {SHR, &type_short}, - {EQ, &type_integer}, - {NE, &type_integer}, - {LE, &type_integer}, - {GE, &type_integer}, - {LT, &type_integer}, - {GT, &type_integer}, + {EQ, &type_integer, &type_uinteger, 0}, + {NE, &type_integer, &type_uinteger, 0}, + {LE, &type_integer, &type_uinteger, 0}, + {GE, &type_integer, &type_uinteger, 0}, + {LT, &type_integer, &type_uinteger, 0}, + {GT, &type_integer, &type_uinteger, 0}, {0, 0} }; @@ -388,6 +452,7 @@ static expr_type_t short_short[] = { {'|', &type_short}, {'^', &type_short}, {'%', &type_short}, + {MOD, &type_short}, {SHL, &type_short}, {SHR, &type_short}, {EQ, &type_integer}, @@ -398,8 +463,69 @@ static expr_type_t short_short[] = { {GT, &type_integer}, {0, 0} }; +#define short_double integer_double -static expr_type_t *string_x[] = { +static expr_type_t double_float[] = { + {'+', &type_double, 0, &type_double}, + {'-', &type_double, 0, &type_double}, + {'*', &type_double, 0, &type_double}, + {'/', &type_double, 0, &type_double}, + {'%', &type_double, 0, &type_double}, + {MOD, &type_double, 0, &type_double}, + {EQ, 0, 0, 0, double_compare}, + {NE, 0, 0, 0, double_compare}, + {LE, 0, 0, 0, double_compare}, + {GE, 0, 0, 0, double_compare}, + {LT, 0, 0, 0, double_compare}, + {GT, 0, 0, 0, double_compare}, + {0, 0} +}; + +static expr_type_t double_vector[] = { + {'*', &type_vector}, + {0, 0} +}; + +static expr_type_t double_quat[] = { + {'*', &type_quaternion}, + {0, 0} +}; + +static expr_type_t double_integer[] = { + {'+', &type_double, 0, &type_double}, + {'-', &type_double, 0, &type_double}, + {'*', &type_double, 0, &type_double}, + {'/', &type_double, 0, &type_double}, + {'%', &type_double, 0, &type_double}, + {MOD, &type_double, 0, &type_double}, + {EQ, 0, 0, 0, double_compare}, + {NE, 0, 0, 0, double_compare}, + {LE, 0, 0, 0, double_compare}, + {GE, 0, 0, 0, double_compare}, + {LT, 0, 0, 0, double_compare}, + {GT, 0, 0, 0, double_compare}, + {0, 0} +}; +#define double_uinteger double_integer +#define double_short double_integer + +static expr_type_t double_double[] = { + {'+', &type_double}, + {'-', &type_double}, + {'*', &type_double}, + {'/', &type_double}, + {'%', &type_double}, + {MOD, &type_double}, + {EQ, &type_integer}, + {NE, &type_integer}, + {LE, &type_integer}, + {GE, &type_integer}, + {LT, &type_integer}, + {GT, &type_integer}, + {0, 0} +}; + +static expr_type_t *string_x[ev_type_count] = { 0, // ev_void string_string, 0, // ev_float @@ -412,9 +538,10 @@ static expr_type_t *string_x[] = { 0, // ev_integer 0, // ev_uinteger 0, // ev_short + 0, // ev_double }; -static expr_type_t *float_x[] = { +static expr_type_t *float_x[ev_type_count] = { 0, // ev_void 0, // ev_string float_float, @@ -427,9 +554,10 @@ static expr_type_t *float_x[] = { float_integer, float_uinteger, float_short, + float_double, }; -static expr_type_t *vector_x[] = { +static expr_type_t *vector_x[ev_type_count] = { 0, // ev_void 0, // ev_string vector_float, @@ -442,9 +570,10 @@ static expr_type_t *vector_x[] = { vector_integer, vector_uinteger, vector_short, + vector_double, }; -static expr_type_t *entity_x[] = { +static expr_type_t *entity_x[ev_type_count] = { 0, // ev_void 0, // ev_string 0, // ev_float @@ -457,9 +586,10 @@ static expr_type_t *entity_x[] = { 0, // ev_integer 0, // ev_uinteger 0, // ev_short + 0, // ev_double }; -static expr_type_t *field_x[] = { +static expr_type_t *field_x[ev_type_count] = { 0, // ev_void 0, // ev_string 0, // ev_float @@ -472,9 +602,10 @@ static expr_type_t *field_x[] = { 0, // ev_integer 0, // ev_uinteger 0, // ev_short + 0, // ev_double }; -static expr_type_t *funcx[] = { +static expr_type_t *func_x[ev_type_count] = { 0, // ev_void 0, // ev_string 0, // ev_float @@ -487,9 +618,10 @@ static expr_type_t *funcx[] = { 0, // ev_integer 0, // ev_uinteger 0, // ev_short + 0, // ev_double }; -static expr_type_t *pointer_x[] = { +static expr_type_t *pointer_x[ev_type_count] = { 0, // ev_void 0, // ev_string 0, // ev_float @@ -502,9 +634,10 @@ static expr_type_t *pointer_x[] = { pointer_integer, pointer_uinteger, pointer_short, + 0, // ev_double }; -static expr_type_t *quat_x[] = { +static expr_type_t *quat_x[ev_type_count] = { 0, // ev_void 0, // ev_string quat_float, @@ -517,9 +650,10 @@ static expr_type_t *quat_x[] = { quat_integer, quat_uinteger, quat_short, + quat_double, }; -static expr_type_t *integer_x[] = { +static expr_type_t *integer_x[ev_type_count] = { 0, // ev_void 0, // ev_string integer_float, @@ -532,9 +666,10 @@ static expr_type_t *integer_x[] = { integer_integer, integer_uinteger, integer_short, + integer_double, }; -static expr_type_t *uinteger_x[] = { +static expr_type_t *uinteger_x[ev_type_count] = { 0, // ev_void 0, // ev_string uinteger_float, @@ -547,9 +682,10 @@ static expr_type_t *uinteger_x[] = { uinteger_integer, uinteger_uinteger, uinteger_short, + uinteger_double, }; -static expr_type_t *short_x[] = { +static expr_type_t *short_x[ev_type_count] = { 0, // ev_void 0, // ev_string short_float, @@ -562,23 +698,141 @@ static expr_type_t *short_x[] = { short_integer, short_uinteger, short_short, + short_double, }; -static expr_type_t **binary_expr_types[] = { +static expr_type_t *double_x[ev_type_count] = { + 0, // ev_void + 0, // ev_string + double_float, + double_vector, + 0, // ev_entity + 0, // ev_field + 0, // ev_func + 0, // ev_pointer + double_quat, + double_integer, + double_uinteger, + double_short, + double_double, +}; + +static expr_type_t **binary_expr_types[ev_type_count] = { 0, // ev_void string_x, float_x, vector_x, entity_x, field_x, - funcx, + func_x, pointer_x, quat_x, integer_x, uinteger_x, short_x, + double_x }; +static expr_t * +pointer_arithmetic (int op, expr_t *e1, expr_t *e2) +{ + expr_t *e; + type_t *t1 = get_type (e1); + type_t *t2 = get_type (e2); + expr_t *ptr; + expr_t *offset; + expr_t *psize; + type_t *ptype; + + if (!is_pointer (t1) && !is_pointer (t2)) { + internal_error (e1, "pointer arithmetic on non-pointers"); + } + if (is_pointer (t1) && is_pointer (t2)) { + if (op != '-') { + return error (e2, "invalid pointer operation"); + } + if (t1 != t2) { + return error (e2, "cannot use %c on pointers of different types", + op); + } + e1 = cast_expr (&type_integer, e1); + e2 = cast_expr (&type_integer, e2); + psize = new_integer_expr (type_size (t1->t.fldptr.type)); + return binary_expr ('/', binary_expr ('-', e1, e2), psize); + } else if (is_pointer (t1)) { + offset = cast_expr (&type_integer, e2); + ptr = cast_expr (&type_integer, e1); + ptype = t1; + } else if (is_pointer (t2)) { + offset = cast_expr (&type_integer, e1); + ptr = cast_expr (&type_integer, e2); + ptype = t2; + } + psize = new_integer_expr (type_size (ptype->t.fldptr.type)); + e = binary_expr (op, ptr, binary_expr ('*', offset, psize)); + return cast_expr (ptype, e); +} + +static expr_t * +pointer_compare (int op, expr_t *e1, expr_t *e2) +{ + type_t *t1 = get_type (e1); + type_t *t2 = get_type (e2); + expr_t *e; + + if (!type_assignable (t1, t2)) { + return error (e2, "cannot use %s on pointers of different types", + get_op_string (op)); + } + e = new_binary_expr (op, e1, e2); + e->e.expr.type = &type_integer; + return e; +} + +static expr_t * +inverse_multiply (int op, expr_t *e1, expr_t *e2) +{ + // There is no vector/float or quaternion/float instruction and adding + // one would mean the engine would have to do 1/f every time + expr_t *one = new_float_expr (1); + return binary_expr ('*', e1, binary_expr ('/', one, e2)); +} + +static expr_t * +double_compare (int op, expr_t *e1, expr_t *e2) +{ + type_t *t1 = get_type (e1); + type_t *t2 = get_type (e2); + expr_t *e; + + if (is_constant (e1) && e1->implicit && is_double (t1) && is_float (t2)) { + t1 = &type_float; + convert_double (e1); + } + if (is_float (t1) && is_constant (e2) && e2->implicit && is_double (t2)) { + t2 = &type_float; + convert_double (e2); + } + if (is_double (t1)) { + if (is_float (t2)) { + warning (e2, "comparison between double and float"); + } else if (!is_constant (e2)) { + warning (e2, "comparison between double and integer"); + } + e2 = cast_expr (&type_double, e2); + } else if (is_double (t2)) { + if (is_float (t1)) { + warning (e1, "comparison between float and double"); + } else if (!is_constant (e1)) { + warning (e1, "comparison between integer and double"); + } + e1 = cast_expr (&type_double, e1); + } + e = new_binary_expr (op, e1, e2); + e->e.expr.type = &type_integer; + return e; +} + static expr_t * invalid_binary_expr (int op, expr_t *e1, expr_t *e2) { @@ -598,32 +852,14 @@ reimplement_binary_expr (int op, expr_t *e1, expr_t *e2) switch (op) { case '%': { - expr_t *tmp1, *tmp2, *tmp3, *tmp4, *t1, *t2; + expr_t *tmp1, *tmp2; e = new_block_expr (); - t1 = new_temp_def_expr (&type_float); - t2 = new_temp_def_expr (&type_float); tmp1 = new_temp_def_expr (&type_float); tmp2 = new_temp_def_expr (&type_float); - tmp3 = new_temp_def_expr (&type_float); - tmp4 = new_temp_def_expr (&type_float); - append_expr (e, assign_expr (t1, e1)); - e1 = binary_expr ('&', t1, t1); - append_expr (e, assign_expr (tmp1, e1)); - - append_expr (e, assign_expr (t2, e2)); - e2 = binary_expr ('&', t2, t2); - append_expr (e, assign_expr (tmp2, e2)); - - e1 = binary_expr ('/', tmp1, tmp2); - append_expr (e, assign_expr (tmp3, e1)); - - e2 = binary_expr ('&', tmp3, tmp3); - append_expr (e, assign_expr (tmp4, e2)); - - e1 = binary_expr ('*', tmp2, tmp4); - e2 = binary_expr ('-', tmp1, e1); - e->e.block.result = e2; + append_expr (e, assign_expr (tmp1, binary_expr ('/', e1, e2))); + append_expr (e, assign_expr (tmp2, binary_expr ('&', tmp1, tmp1))); + e->e.block.result = binary_expr ('-', e1, binary_expr ('*', e2, tmp2)); return e; } break; @@ -717,6 +953,11 @@ check_precedence (int op, expr_t *e1, expr_t *e2) return 0; } +static int is_call (expr_t *e) +{ + return e->type == ex_block && e->e.block.is_call; +} + expr_t * binary_expr (int op, expr_t *e1, expr_t *e2) { @@ -726,15 +967,32 @@ binary_expr (int op, expr_t *e1, expr_t *e2) expr_type_t *expr_type; convert_name (e1); + e1 = convert_vector (e1); + // FIXME this is target-specific info and should not be in the + // expression tree + if ((e1->type == ex_expr || e1->type == ex_uexpr) && e1->e.expr.op == 'A' + && is_call (e1->e.expr.e1)) { + // move the alias expression inside the block so the following check + // can detect the call and move the temp assignment into the block + expr_t *block = e1->e.expr.e1; + e1->e.expr.e1 = block->e.block.result; + block->e.block.result = e1; + e1 = block; + } if (e1->type == ex_block && e1->e.block.is_call && has_function_call (e2) && e1->e.block.result) { - e = new_temp_def_expr (get_type (e1->e.block.result)); - e1 = assign_expr (e, e1); + // the temp assignment needs to be insided the block so assignment + // code generation doesn't see it when applying right-associativity + expr_t *tmp = new_temp_def_expr (get_type (e1->e.block.result)); + e = assign_expr (tmp, e1->e.block.result); + append_expr (e1, e); + e1->e.block.result = tmp; } if (e1->type == ex_error) return e1; convert_name (e2); + e2 = convert_vector (e2); if (e2->type == ex_error) return e2; @@ -761,12 +1019,21 @@ binary_expr (int op, expr_t *e1, expr_t *e2) } } + if (is_constant (e1) && is_double (t1) && e1->implicit && is_float (t2)) { + t1 = &type_float; + convert_double (e1); + } + if (is_constant (e2) && is_double (t2) && e2->implicit && is_float (t1)) { + t2 = &type_float; + convert_double (e2); + } + et1 = low_level_type (t1); et2 = low_level_type (t2); - if (et1 > ev_short || !binary_expr_types[et1]) + if (et1 >= ev_type_count || !binary_expr_types[et1]) return invalid_binary_expr(op, e1, e2); - if (et2 > ev_short || !binary_expr_types[et1][et2]) + if (et2 >= ev_type_count || !binary_expr_types[et1][et2]) return invalid_binary_expr(op, e1, e2); expr_type = binary_expr_types[et1][et2]; while (expr_type->op && expr_type->op != op) @@ -778,15 +1045,19 @@ binary_expr (int op, expr_t *e1, expr_t *e2) e1 = cast_expr (expr_type->a_cast, e1); if (expr_type->b_cast) e2 = cast_expr (expr_type->b_cast, e2); + if (expr_type->process) { + return fold_constants (expr_type->process (op, e1, e2)); + } if ((e = reimplement_binary_expr (op, e1, e2))) - return e; + return fold_constants (e); e = new_binary_expr (op, e1, e2); e->e.expr.type = expr_type->type; if (is_compare (op) || is_logic (op)) { - if (options.code.progsversion == PROG_ID_VERSION) + if (options.code.progsversion == PROG_ID_VERSION) { e->e.expr.type = &type_float; + } } - return e; + return fold_constants (e); } diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c new file mode 100644 index 000000000..fd21de053 --- /dev/null +++ b/tools/qfcc/source/expr_bool.c @@ -0,0 +1,311 @@ +/* + expr_bool.c + + short-circuit boolean expressions + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/15 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/idstuff.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +#include "tools/qfcc/source/qc-parse.h" + +expr_t * +test_expr (expr_t *e) +{ + static float zero[4] = {0, 0, 0, 0}; + expr_t *new = 0; + type_t *type; + + if (e->type == ex_error) + return e; + + type = get_type (e); + if (e->type == ex_error) + return e; + switch (type->type) { + case ev_type_count: + internal_error (e, 0); + case ev_void: + if (options.traditional) { + if (options.warnings.traditional) + warning (e, "void has no value"); + return e; + } + return error (e, "void has no value"); + case ev_string: + if (!options.code.ifstring) + return new_alias_expr (type_default, e); + new = new_string_expr (0); + break; + case ev_uinteger: + case ev_integer: + case ev_short: + if (!is_integer(type_default)) { + if (is_constant (e)) { + return cast_expr (type_default, e); + } + return new_alias_expr (type_default, e); + } + return e; + case ev_float: + if (options.code.fast_float + || options.code.progsversion == PROG_ID_VERSION) { + if (!is_float(type_default)) { + if (is_constant (e)) { + return cast_expr (type_default, e); + } + return new_alias_expr (type_default, e); + } + return e; + } + new = new_float_expr (0); + break; + case ev_double: + new = new_double_expr (0); + break; + case ev_vector: + new = new_vector_expr (zero); + break; + case ev_entity: + return new_alias_expr (type_default, e); + case ev_field: + return new_alias_expr (type_default, e); + case ev_func: + return new_alias_expr (type_default, e); + case ev_pointer: + return new_alias_expr (type_default, e); + case ev_quat: + new = new_quaternion_expr (zero); + break; + case ev_invalid: + if (is_enum (type)) { + new = new_nil_expr (); + break; + } + return test_error (e, get_type (e)); + } + new->line = e->line; + new->file = e->file; + new = binary_expr (NE, e, new); + new->line = e->line; + new->file = e->file; + return new; +} + +void +backpatch (ex_list_t *list, expr_t *label) +{ + int i; + expr_t *e; + + if (!list) + return; + if (!label || label->type != ex_label) + internal_error (label, "not a label"); + + for (i = 0; i < list->size; i++) { + e = list->e[i]; + if (e->type == ex_uexpr && e->e.expr.op == 'g') + e->e.expr.e1 = label; + else if (e->type == ex_expr && (e->e.expr.op == 'i' + || e->e.expr.op == 'n')) + e->e.expr.e2 = label; + else { + internal_error (e, 0); + } + label->e.label.used++; + } +} + +static ex_list_t * +merge (ex_list_t *l1, ex_list_t *l2) +{ + ex_list_t *m; + + if (!l1 && !l2) + internal_error (0, 0); + if (!l2) + return l1; + if (!l1) + return l2; + m = malloc ((size_t)&((ex_list_t *)0)->e[l1->size + l2->size]); + m->size = l1->size + l2->size; + memcpy (m->e, l1->e, l1->size * sizeof (expr_t *)); + memcpy (m->e + l1->size, l2->e, l2->size * sizeof (expr_t *)); + return m; +} + +static ex_list_t * +make_list (expr_t *e) +{ + ex_list_t *m; + + m = malloc ((size_t)&((ex_list_t *) 0)->e[1]); + m->size = 1; + m->e[0] = e; + return m; +} + +expr_t * +bool_expr (int op, expr_t *label, expr_t *e1, expr_t *e2) +{ + expr_t *block; + + if (!options.code.short_circuit) + return binary_expr (op, e1, e2); + + e1 = convert_bool (e1, 0); + if (e1->type == ex_error) + return e1; + + e2 = convert_bool (e2, 0); + if (e2->type == ex_error) + return e2; + + block = new_block_expr (); + append_expr (block, e1); + append_expr (block, label); + append_expr (block, e2); + + switch (op) { + case OR: + backpatch (e1->e.bool.false_list, label); + return new_bool_expr (merge (e1->e.bool.true_list, + e2->e.bool.true_list), + e2->e.bool.false_list, block); + break; + case AND: + backpatch (e1->e.bool.true_list, label); + return new_bool_expr (e2->e.bool.true_list, + merge (e1->e.bool.false_list, + e2->e.bool.false_list), block); + break; + } + internal_error (e1, 0); +} + +expr_t * +convert_bool (expr_t *e, int block) +{ + expr_t *b; + + if (e->type == ex_expr && e->e.expr.op == '=') { + expr_t *src; + if (!e->paren && options.warnings.precedence) + warning (e, "suggest parentheses around assignment " + "used as truth value"); + src = e->e.expr.e2; + if (src->type == ex_block) { + src = new_temp_def_expr (get_type (src)); + e = new_binary_expr (e->e.expr.op, e->e.expr.e1, + assign_expr (src, e->e.expr.e2)); + } + b = convert_bool (src, 1); + if (b->type == ex_error) + return b; + // insert the assignment into the bool's block + e->next = b->e.bool.e->e.block.head; + b->e.bool.e->e.block.head = e; + if (b->e.bool.e->e.block.tail == &b->e.bool.e->e.block.head) { + // shouldn't happen, but just in case + b->e.bool.e->e.block.tail = &e->next; + } + return b; + } + + if (e->type == ex_uexpr && e->e.expr.op == '!' + && !is_string(get_type (e->e.expr.e1))) { + e = convert_bool (e->e.expr.e1, 0); + if (e->type == ex_error) + return e; + e = unary_expr ('!', e); + } + if (e->type != ex_bool) { + e = test_expr (e); + if (e->type == ex_error) + return e; + if (is_constant (e)) { + int val; + + b = goto_expr (0); + if (is_integer_val (e)) { + val = expr_integer (e); + } else { + val = expr_float (e) != 0; + } + if (val) + e = new_bool_expr (make_list (b), 0, b); + else + e = new_bool_expr (0, make_list (b), b); + } else { + b = new_block_expr (); + append_expr (b, branch_expr ('i', e, 0)); + append_expr (b, goto_expr (0)); + e = new_bool_expr (make_list (b->e.block.head), + make_list (b->e.block.head->next), b); + } + } + if (block && e->e.bool.e->type != ex_block) { + expr_t *block = new_block_expr (); + append_expr (block, e->e.bool.e); + e->e.bool.e = block; + } + return e; +} diff --git a/tools/qfcc/source/expr_compound.c b/tools/qfcc/source/expr_compound.c new file mode 100644 index 000000000..e75bb5b70 --- /dev/null +++ b/tools/qfcc/source/expr_compound.c @@ -0,0 +1,212 @@ +/* + expr_compound.c + + compound intializer expression construction and manipulations + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/03/11 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" + +static element_t *elements_freelist; + +element_t * +new_element (expr_t *expr, symbol_t *symbol) +{ + element_t *element; + ALLOC (256, element_t, elements, element); + element->expr = expr; + element->symbol = symbol; + return element; +} + +static element_t * +append_init_element (element_chain_t *element_chain, element_t *element) +{ + element->next = 0; + *element_chain->tail = element; + element_chain->tail = &element->next; + return element; +} + +expr_t * +new_compound_init (void) +{ + expr_t *c = new_expr (); + c->type = ex_compound; + c->e.compound.head = 0; + c->e.compound.tail = &c->e.compound.head; + return c; +} + +void +build_element_chain (element_chain_t *element_chain, const type_t *type, + expr_t *eles, int base_offset) +{ + element_t *ele = eles->e.compound.head; + + type = unalias_type (type); + + if (is_array (type)) { + type_t *array_type = type->t.array.type; + int array_size = type->t.array.size; + int i; + + for (i = 0; i < array_size; i++) { + int offset = base_offset + i * type_size (array_type); + if (ele && ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, array_type, + ele->expr, offset); + } else { + element_t *element = new_element (0, 0); + element->type = array_type; + element->offset = offset; + element->expr = ele ? ele->expr : 0; // null -> nil + append_init_element (element_chain, element); + } + if (ele) { + ele = ele->next; + } + } + } else if (is_struct (type) || is_vector (type) || is_quaternion (type)) { + symtab_t *symtab = type->t.symtab; + symbol_t *field; + + for (field = symtab->symbols; field; field = field->next) { + int offset = base_offset + field->s.offset; + if (field->sy_type != sy_var + || field->visibility == vis_anonymous) { + continue; + } + if (ele && ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, field->type, + ele->expr, offset); + } else { + element_t *element = new_element (0, 0); + element->type = field->type; + element->offset = offset; + element->expr = ele ? ele->expr : 0; // null -> nil + append_init_element (element_chain, element); + } + if (ele) { + ele = ele->next; + } + } + } else { + error (eles, "invalid initializer"); + } + if (ele && ele->next && options.warnings.initializer) { + warning (eles, "excessive elements in initializer"); + } +} + +void free_element_chain (element_chain_t *element_chain) +{ + *element_chain->tail = elements_freelist; + elements_freelist = element_chain->head; + element_chain->head = 0; + element_chain->tail = &element_chain->head; +} + +expr_t * +append_element (expr_t *compound, element_t *element) +{ + if (compound->type != ex_compound) { + internal_error (compound, "not a compound expression"); + } + + if (!element || (element->expr && element->expr->type == ex_error)) { + return compound; + } + + if (element->next) { + internal_error (compound, "append_element: element loop detected"); + } + append_init_element (&compound->e.compound, element); + return compound; +} + +void +assign_elements (expr_t *local_expr, expr_t *init, + element_chain_t *element_chain) +{ + element_t *element; + + for (element = element_chain->head; element; element = element->next) { + int offset = element->offset; + type_t *type = element->type; + expr_t *alias = new_offset_alias_expr (type, init, offset); + + expr_t *c; + + if (element->expr) { + c = constant_expr (element->expr); + } else { + c = new_nil_expr (); + } + if (c->type == ex_nil) { + c = convert_nil (c, type); + } + append_expr (local_expr, assign_expr (alias, c)); + } +} + +expr_t * +initialized_temp_expr (const type_t *type, expr_t *compound) +{ + type = unalias_type (type); + element_chain_t element_chain; + expr_t *temp = new_temp_def_expr (type); + expr_t *block = new_block_expr (); + + element_chain.head = 0; + element_chain.tail = &element_chain.head; + build_element_chain (&element_chain, type, compound, 0); + assign_elements (block, temp, &element_chain); + block->e.block.result = temp; + free_element_chain (&element_chain); + return block; +} diff --git a/tools/qfcc/source/expr_obj.c b/tools/qfcc/source/expr_obj.c new file mode 100644 index 000000000..17d53dfdb --- /dev/null +++ b/tools/qfcc/source/expr_obj.c @@ -0,0 +1,248 @@ +/* + expr_obj.c + + Objective-QuakeC expression construction and manipulations + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/15 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/idstuff.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +expr_t * +new_self_expr (void) +{ + symbol_t *sym; + + sym = make_symbol (".self", &type_entity, pr.near_data, sc_extern); + if (!sym->table) + symtab_addsymbol (pr.symtab, sym); + return new_symbol_expr (sym); +} + +expr_t * +new_this_expr (void) +{ + symbol_t *sym; + + sym = make_symbol (".this", field_type (&type_id), pr.near_data, sc_extern); + if (!sym->table) + symtab_addsymbol (pr.symtab, sym); + return new_symbol_expr (sym); +} + +expr_t * +selector_expr (keywordarg_t *selector) +{ + dstring_t *sel_id = dstring_newstr (); + expr_t *sel; + symbol_t *sel_sym; + symbol_t *sel_table; + int index; + + selector = copy_keywordargs (selector); + selector = (keywordarg_t *) reverse_params ((param_t *) selector); + selector_name (sel_id, selector); + index = selector_index (sel_id->str); + index *= type_size (type_SEL.t.fldptr.type); + sel_sym = make_symbol ("_OBJ_SELECTOR_TABLE_PTR", &type_SEL, + pr.near_data, sc_static); + if (!sel_sym->table) { + symtab_addsymbol (pr.symtab, sel_sym); + sel_table = make_symbol ("_OBJ_SELECTOR_TABLE", + array_type (type_SEL.t.fldptr.type, 0), + pr.far_data, sc_extern); + if (!sel_table->table) + symtab_addsymbol (pr.symtab, sel_table); + reloc_def_def (sel_table->s.def, sel_sym->s.def); + } + sel = new_symbol_expr (sel_sym); + dstring_delete (sel_id); + sel = new_binary_expr ('&', sel, new_short_expr (index)); + sel->e.expr.type = &type_SEL; + return sel; +} + +expr_t * +protocol_expr (const char *protocol_name) +{ + protocol_t *protocol = get_protocol (protocol_name, 0); + + if (!protocol) { + return error (0, "cannot find protocol declaration for `%s'", + protocol_name); + } + class_t *proto_class = get_class (new_symbol ("Protocol"), 1); + return new_pointer_expr (0, proto_class->type, protocol_def (protocol)); +} + +expr_t * +super_expr (class_type_t *class_type) +{ + symbol_t *sym; + expr_t *super; + expr_t *e; + expr_t *super_block; + class_t *class; + + if (!class_type) + return error (0, "`super' used outside of class implementation"); + + class = extract_class (class_type); + + if (!class->super_class) + return error (0, "%s has no super class", class->name); + + sym = symtab_lookup (current_symtab, ".super"); + if (!sym || sym->table != current_symtab) { + sym = new_symbol_type (".super", &type_super); + initialize_def (sym, 0, current_symtab->space, sc_local); + } + super = new_symbol_expr (sym); + + super_block = new_block_expr (); + + e = assign_expr (field_expr (super, new_name_expr ("self")), + new_name_expr ("self")); + append_expr (super_block, e); + + e = new_symbol_expr (class_pointer_symbol (class)); + e = assign_expr (field_expr (super, new_name_expr ("class")), + field_expr (e, new_name_expr ("super_class"))); + append_expr (super_block, e); + + e = address_expr (super, 0, 0); + super_block->e.block.result = e; + return super_block; +} + +expr_t * +message_expr (expr_t *receiver, keywordarg_t *message) +{ + expr_t *args = 0, **a = &args; + expr_t *selector = selector_expr (message); + expr_t *call; + keywordarg_t *m; + int super = 0, class_msg = 0; + type_t *rec_type = 0; + type_t *return_type; + type_t *method_type = &type_IMP; + method_t *method; + expr_t *send_msg; + + if (receiver->type == ex_nil) { + rec_type = &type_id; + convert_nil (receiver, rec_type); + } else if (receiver->type == ex_symbol) { + if (strcmp (receiver->e.symbol->name, "self") == 0) { + rec_type = get_type (receiver); + } else if (strcmp (receiver->e.symbol->name, "super") == 0) { + super = 1; + + receiver = super_expr (current_class); + + if (receiver->type == ex_error) + return receiver; + receiver = cast_expr (&type_id, receiver); //FIXME better way? + rec_type = extract_class (current_class)->type; + } else if (receiver->e.symbol->sy_type == sy_class) { + class_t *class; + rec_type = receiver->e.symbol->type; + class = rec_type->t.class; + class_msg = 1; + receiver = new_symbol_expr (class_pointer_symbol (class)); + } + } + if (!rec_type) { + rec_type = get_type (receiver); + } + + if (receiver->type == ex_error) + return receiver; + + return_type = &type_id; + method = class_message_response (rec_type, class_msg, selector); + if (method) + return_type = method->type->t.func.type; + + for (m = message; m; m = m->next) { + *a = m->expr; + while ((*a)) { + expr_file_line (selector, *a); + a = &(*a)->next; + } + } + *a = selector; + a = &(*a)->next; + *a = receiver; + + send_msg = expr_file_line (send_message (super), receiver); + if (method) { + expr_t *err; + if ((err = method_check_params (method, args))) + return err; + method_type = method->type; + } + call = build_function_call (send_msg, method_type, args); + + if (call->type == ex_error) + return receiver; + + call->e.block.result = new_ret_expr (return_type); + return call; +} diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 2c6692f1d..3a1bb54c1 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -44,24 +44,24 @@ #include "QF/set.h" #include "QF/va.h" -#include "dags.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "dot.h" -#include "flow.h" -#include "function.h" -#include "options.h" -#include "qfcc.h" -#include "statements.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/dags.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/dot.h" +#include "tools/qfcc/include/flow.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" -static flowvar_t *vars_freelist; -static flowloop_t *loops_freelist; -static flownode_t *nodes_freelist; -static flowgraph_t *graphs_freelist; +/// \addtogroup qfcc_flow +///@{ +/** Static operand definitions for the ever present return and parameter slots. + */ static struct { const char *name; operand_t op; @@ -78,6 +78,17 @@ static struct { }; static const int num_flow_params = sizeof(flow_params)/sizeof(flow_params[0]); +/** \name Flow analysis memory management */ +///@{ +static flowvar_t *vars_freelist; ///< flowvar pool +static flowloop_t *loops_freelist; ///< flow loop pool +static flownode_t *nodes_freelist; ///< flow node pool +static flowgraph_t *graphs_freelist; ///< flow graph pool + +/** Allocate a new flow var. + * + * The var's use and define sets are initialized to empty. + */ static flowvar_t * new_flowvar (void) { @@ -88,6 +99,20 @@ new_flowvar (void) return var; } +/** Delete a flow var + */ +static void +delete_flowvar (flowvar_t *var) +{ + set_delete (var->use); + set_delete (var->define); + FREE (vars, var); +} + +/** Allocate a new flow loop. + * + * The loop's nodes set is initialized to the empty set. + */ static flowloop_t * new_loop (void) { @@ -97,6 +122,8 @@ new_loop (void) return loop; } +/** Free a flow loop and its nodes set. + */ static void delete_loop (flowloop_t *loop) { @@ -104,6 +131,10 @@ delete_loop (flowloop_t *loop) FREE (loops, loop); } +/** Allocate a new flow node. + * + * The node is completely empty. + */ static flownode_t * new_node (void) { @@ -112,6 +143,10 @@ new_node (void) return node; } +/** Free a flow node and its resources. + * + * \bug not global_vars or the vars and defs sets? + */ static void delete_node (flownode_t *node) { @@ -126,6 +161,10 @@ delete_node (flownode_t *node) FREE (nodes, node); } +/** Allocate a new flow graph. + * + * The graph is completely empty. + */ static flowgraph_t * new_graph (void) { @@ -134,6 +173,10 @@ new_graph (void) return graph; } +/** Return a flow graph and its resources to the pools. + * + * \bug except loops? + */ static void __attribute__((unused)) delete_graph (flowgraph_t *graph) { @@ -148,31 +191,23 @@ delete_graph (flowgraph_t *graph) free (graph->edges); if (graph->dfst) set_delete (graph->dfst); - if (graph->dfo) - free (graph->dfo); + if (graph->depth_first) + free (graph->depth_first); FREE (graphs, graph); } +///@} -static def_t * -flowvar_get_def (flowvar_t *var) -{ - operand_t *op = var->op; - - switch (op->op_type) { - case op_def: - return op->o.def; - case op_value: - case op_label: - return 0; - case op_temp: - return op->o.tempop.def; - case op_alias: - internal_error (0, "unexpected alias operand"); - } - internal_error (0, "oops, blue pill"); - return 0; -} - +/** \name Flowvar classification */ +///@{ +/** Check if the flowvar refers to a global variable. + * + * For the flowvar to refer to a global variable, the flowvar's operand + * must be a def operand (but the def itself may be an alias of the real def) + * and the rel def must not have its def_t::local flag set. This means that + * function-scope static variables are not considered local (ie, only + * non-static function-scope variables and function parameters are considered + * local (temp vars are local too, but are not represented by \a op_def)). + */ static int flowvar_is_global (flowvar_t *var) { @@ -188,6 +223,14 @@ flowvar_is_global (flowvar_t *var) return 1; } +/** Check if the flowvar refers to a function parameter. + * + * For the flowvar to refer to a function parameter, the flowvar's operand + * must be a def operand (but the def itself may be an alias of the real def) + * and the rel def must have both its def_t::local and def_t::param flags set. + * + * Temp vars are are not represented by op_def, so no mistake can be made. + */ static int flowvar_is_param (flowvar_t *var) { @@ -204,18 +247,54 @@ flowvar_is_param (flowvar_t *var) return 0; return 1; } -#if 0 -static int -flowvar_is_initialized (flowvar_t *var) -{ - def_t *def; - if (var->op->op_type != op_def) - return 0; - def = var->op->o.def; - return def->initialized; +/** Check if the flowvar refers to a function parameter. + * + * As this is simply "neither global nor pamam", all other flowvars are + * considered local, in particular actual non-staic function scope variables + * and temp vars. + */ +static int +flowvar_is_local (flowvar_t *var) +{ + return !(flowvar_is_global (var) || flowvar_is_param (var)); } -#endif +///@} + +/** Extract the def from a def or temp flowvar. + * + * It is an error for the operand referenced by the flowvar to be anything + * other than a real def or temp. + */ +static __attribute__((pure)) def_t * +flowvar_get_def (flowvar_t *var) +{ + operand_t *op = var->op; + + switch (op->op_type) { + case op_def: + return op->o.def; + case op_value: + case op_label: + return 0; + case op_temp: + return op->o.tempop.def; + case op_alias: + internal_error (op->expr, "unexpected alias operand"); + case op_nil: + internal_error (op->expr, "unexpected nil operand"); + } + internal_error (op->expr, "oops, blue pill"); + return 0; +} + +/** Get a def or temp var operand's flowvar. + * + * Other operand types never have a flowvar. + * + * If the operand does not yet have a flowvar, one is created and assigned + * to the operand. + */ flowvar_t * flow_get_var (operand_t *op) { @@ -235,6 +314,12 @@ flow_get_var (operand_t *op) return 0; } +/** Indicate whether the operand should be counted. + * + * If the operand is a def or temp var operand, and it has not already been + * counted, then it is counted, otherwise it is not. + * \return 1 if the operand should be counted, 0 if not + */ static int count_operand (operand_t *op) { @@ -246,14 +331,15 @@ count_operand (operand_t *op) return 0; var = flow_get_var (op); - // flowvars are initialized with number == 0, and any global flowvar - // used by a function will always have a number >= 0 after flow analysis, - // and local flowvars will always be 0 before flow analysis, so use -1 - // to indicate the variable has been counted. - // - // Also, since this is the beginning of flow analysis for this function, - // ensure the define/use sets for global vars are empty. However, as - // checking if a var is global is too much trouble, just clear them all. + /** Flowvars are initialized with number == 0, and any global flowvar + * used by a function will always have a number >= 0 after flow analysis, + * and local flowvars will always be 0 before flow analysis, so use -1 + * to indicate the variable has been counted. + * + * Also, since this is the beginning of flow analysis for this function, + * ensure the define/use sets for global vars are empty. However, since + * checking if a var is global is too much trouble, just clear them all. + */ if (var && var->number != -1) { set_empty (var->use); set_empty (var->define); @@ -263,6 +349,45 @@ count_operand (operand_t *op) return 0; } +/** Allocate flow analysis pseudo address space to a temporary variable. + * + * If the operand already has an address allocated (flowvar_t::flowaddr is + * not 0), then the already allocated address is returned. + * + * If the operand refers to an alias, the alias chain is followed to the + * actual temp var operand and the real temp var is allocated space if it + * has not allready been alloced. + * + * The operand is given the address of the real temp var operand plus whatever + * offset the operand has. + * + * Real temp var operands must have a zero offset. + * + * The operand address is set in \a op and returned. + */ +static int +get_temp_address (function_t *func, operand_t *op) +{ + operand_t *top = op; + if (op->o.tempop.flowaddr) { + return op->o.tempop.flowaddr; + } + while (top->o.tempop.alias) { + top = top->o.tempop.alias; + } + if (!top->o.tempop.flowaddr) { + top->o.tempop.flowaddr = func->tmpaddr; + func->tmpaddr += top->size; + } + if (top->o.tempop.offset) { + internal_error (top->expr, "real tempop with a non-zero offset"); + } + op->o.tempop.flowaddr = top->o.tempop.flowaddr + op->o.tempop.offset; + return op->o.tempop.flowaddr; +} + +/** Add an operand's flowvar to the function's list of variables. + */ static void add_operand (function_t *func, operand_t *op) { @@ -274,15 +399,29 @@ add_operand (function_t *func, operand_t *op) return; var = flow_get_var (op); - // If the flowvar number is still -1, then the flowvar has not yet been - // added to the list of variables referenced by the function. + /** If the flowvar number is still -1, then the flowvar has not yet been + * added to the list of variables referenced by the function. + * + * The flowvar's flowvar_t::number is set to its index in the function's + * list of flowvars. + * + * Also, temp and local flowvars are assigned addresses from the flow + * analysys pseudo address space so partial accesses can be analyzed. + */ if (var && var->number == -1) { var->number = func->num_vars++; var->op = op; func->vars[var->number] = var; + if (op->op_type == op_temp) { + var->flowaddr = get_temp_address (func, op); + } else if (flowvar_is_local (var)) { + var->flowaddr = func->num_statements + def_offset (var->op->o.def); + } } } +/** Create symbols and defs for params/return if not already available. + */ static symbol_t * param_symbol (const char *name) { @@ -293,6 +432,15 @@ param_symbol (const char *name) return sym; } +/** Build an array of all the statements in a function. + + The array exists so statements can be referenced by number and thus used + in sets. + + The statement references in the array (function_t::statements) are in the + same order as they are within the statement blocks (function_t::sblock) + and with the blocks in the same order as the linked list of blocks. +*/ static void flow_build_statements (function_t *func) { @@ -315,11 +463,62 @@ flow_build_statements (function_t *func) } } +static int flow_def_clear_flowvars (def_t *def, void *data) +{ + if (def->flowvar) { + delete_flowvar (def->flowvar); + } + def->flowvar = 0; + return 0; +} + +/** Build an array of all the variables used by a function + * + * The array exists so variables can be referenced by number and thus used + * in sets. However, because larger variables may be aliased by smaller types, + * their representation is more complicated. + * + * # Local variable representation + * Defined local vars add their address in local space to the number of + * statements in the function. Thus their flow analysis address in in the + * range: + * + * ([num_statements ... num_statements+localsize]) + * + * with a set element in flowvar_t::define for each word used by the var. + * That is, single word types (int, float, pointer, etc) have one element, + * doubles have two adjacant elements, and vectors and quaternions have + * three and four elements respectively (also adjacant). Structural types + * (struct, union, array) have as many adjacant elements as their size + * dictates. + * + * Temporary vars are pseudo allocated and their addresses are added as + * for normal local vars. + * + * Note, however, that flowvar_t::define also includes real function + * statements that assign to the variable. + * + * # Pseudo Address Space + * Temporary variables are _effectively_ local variables and thus will + * be treated as such by the analizer in that their addresses and sizes + * will be used to determine which and how many set elements to use. + * + * However, at this stage, temporary variables do not have any address + * space assigned to them because their lifetimes are generally limited + * to a few statements and the memory used for the temp vars may be + * recycled. Thus, give temp vars a pseudo address space just past the + * address space used for source-defined local variables. As each temp + * var is added to the analyzer, get_temp_address() assigns the temp var + * an address using function_t::tmpaddr as a starting point. + * + * add_operand() takes care of setting flowvar_t::flowaddr for both locals + * and temps. + */ static void flow_build_vars (function_t *func) { statement_t *s; - operand_t *operands[4]; + operand_t *operands[FLOW_OPERANDS]; int num_vars = 0; int i, j; set_t *stuse; @@ -327,9 +526,27 @@ flow_build_vars (function_t *func) set_iter_t *var_i; flowvar_t *var; - // first, count .return and .param_[0-7] as they are always needed + // First, run through the statements making sure any accessed variables + // have their flowvars reset. Local variables will be fine, but global + // variables make have had flowvars added in a previous function, and it's + // easier to just clear them all. + // This is done before .return and .param so they won't get reset just + // after being counted + for (i = 0; i < func->num_statements; i++) { + s = func->statements[i]; + flow_analyze_statement (s, 0, 0, 0, operands); + for (j = 0; j < FLOW_OPERANDS; j++) { + if (operands[j] && operands[j]->op_type == op_def) { + def_visit_all (operands[j]->o.def, 0, + flow_def_clear_flowvars, 0); + } + } + } + // count .return and .param_[0-7] as they are always needed for (i = 0; i < num_flow_params; i++) { - flow_params[i].op.o.def = param_symbol (flow_params[i].name)->s.def; + def_t *def = param_symbol (flow_params[i].name)->s.def; + def_visit_all (def, 0, flow_def_clear_flowvars, 0); + flow_params[i].op.o.def = def; num_vars += count_operand (&flow_params[i].op); } // then run through the statements in the function looking for accessed @@ -343,11 +560,15 @@ flow_build_vars (function_t *func) if (!num_vars) return; - func->vars = malloc (num_vars * sizeof (daglabel_t *)); + func->vars = malloc (num_vars * sizeof (flowvar_t *)); stuse = set_new (); stdef = set_new (); + // set up pseudo address space for temp vars so accessing tmp vars + // though aliases analyses correctly + func->tmpaddr = func->num_statements + func->symtab->space->size; + func->num_vars = 0; // incremented by add_operand // first, add .return and .param_[0-7] as they are always needed for (i = 0; i < num_flow_params; i++) @@ -359,7 +580,12 @@ flow_build_vars (function_t *func) flow_analyze_statement (s, 0, 0, 0, operands); for (j = 0; j < 4; j++) add_operand (func, operands[j]); - + } + // and set the use/def sets for the vars (has to be a separate pass + // because the allias handling reqruires the flow address to be valid + // (ie, not -1) + for (i = 0; i < func->num_statements; i++) { + s = func->statements[i]; flow_analyze_statement (s, stuse, stdef, 0, 0); for (var_i = set_first (stdef); var_i; var_i = set_next (var_i)) { var = func->vars[var_i->element]; @@ -376,22 +602,17 @@ flow_build_vars (function_t *func) if (flowvar_is_global (func->vars[i])) set_add (func->global_vars, i); } - // create dummy defs for local vars + // Put the local varibals in their place (set var->defined to the addresses + // spanned by the var) for (i = 0; i < func->num_vars; i++) { - int offset, size; int j; var = func->vars[i]; - if (flowvar_is_global (var) || flowvar_is_param (var)) + if (flowvar_is_global (var) || flowvar_is_param (var)) { continue; - if (var->op->op_type == op_temp) { - j = func->symtab->space->size + var->number; - set_add (var->define, func->num_statements + j); - } else { - offset = def_offset (var->op->o.def); - size = def_size (var->op->o.def); - for (j = offset; j < offset + size; j++) - set_add (var->define, func->num_statements + j); + } + for (j = 0; j < var->op->size; j++) { + set_add (var->define, var->flowaddr + j); } } @@ -399,8 +620,23 @@ flow_build_vars (function_t *func) set_delete (stdef); } +/** Add the tempop's spanned addresses to the kill set + */ static int -flow_kill_aliases_visit (def_t *def, void *_kill) +flow_tempop_kill_aliases (tempop_t *tempop, void *_kill) +{ + set_t *kill = (set_t *) _kill; + flowvar_t *var; + var = tempop->flowvar; + if (var) + set_union (kill, var->define); + return 0; +} + +/** Add the def's spanned addresses to the kill set + */ +static int +flow_def_kill_aliases (def_t *def, void *_kill) { set_t *kill = (set_t *) _kill; flowvar_t *var; @@ -410,6 +646,13 @@ flow_kill_aliases_visit (def_t *def, void *_kill) return 0; } +/** Add the flowvar's spanned addresses to the kill set + * + * If the flowvar refers to an alias, then the real def/tempop and any + * overlapping aliases are aslo killed. + * + * However, other aliases cannot kill anything in the uninitialized set. + */ static void flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) { @@ -419,27 +662,22 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) set_union (kill, var->define); op = var->op; tmp = set_new (); + // collect the kill sets from any aliases if (op->op_type == op_temp) { - if (op->o.tempop.alias) { - op = op->o.tempop.alias; - var = op->o.tempop.flowvar; - if (var) - set_union (tmp, var->define); - } - for (op = op->o.tempop.alias_ops; op; op = op->next) { - var = op->o.tempop.flowvar; - if (var) - set_union (tmp, var->define); - } + tempop_visit_all (&op->o.tempop, 1, flow_tempop_kill_aliases, tmp); } else if (op->op_type == op_def) { - def_visit_all (op->o.def, 1, flow_kill_aliases_visit, tmp); - // don't allow aliases to kill definitions in the entry dummy block + def_visit_all (op->o.def, 1, flow_def_kill_aliases, tmp); + } + // don't allow aliases to kill definitions in the entry dummy block + if (uninit) { set_difference (tmp, uninit); } // merge the alias kills with the current def's kills set_union (kill, tmp); } +/** Compute reaching defs + */ static void flow_reaching_defs (flowgraph_t *graph) { @@ -457,15 +695,37 @@ flow_reaching_defs (flowgraph_t *graph) flowvar_t *var; // First, create out for the entry dummy node using fake statement numbers. + //\f[ \bigcup\limits_{i=1}^{\infty} F_{i} \f] + //\f[ \bigcap\limits_{i=1}^{\infty} F_{i} \f] + + /** The dummy entry node reaching defs \a out set is initialized to: + * \f[ out_{reaching}=[\bigcup\limits_{v \in \{locals\}} define_{v}] + * \setminus \{statements\} \f] + * where {\a locals} is the set of local def and tempop flowvars (does + * not include parameters), \a define is the set of addresses spanned + * by the flowvar (see flow_build_vars()) (XXX along with statement + * gens), and {\a statements} is the set of all statements in the + * function (ensures the \a out set does not include any initializers in + * the code nodes). + * + * All other entry node sets are initialized to empty. + */ + // kill represents the set of all statements in the function kill = set_new (); for (i = 0; i < graph->func->num_statements; i++) set_add (kill, i); + // uninit uninit = set_new (); for (i = 0; i < graph->func->num_vars; i++) { var = graph->func->vars[i]; set_union (uninit, var->define);// do not want alias handling here - set_difference (uninit, kill); // remove any gens from the function } + /** Any possible gens from the function code are removed from the + * \a uninit set (which becomes the \a out set of the entry node's + * reaching defs) in order to prevent them leaking into the real nodes. + */ + set_difference (uninit, kill); // remove any gens from the function + // initialize the reaching defs sets in the entry node graph->nodes[graph->num_nodes]->reaching_defs.out = uninit; graph->nodes[graph->num_nodes]->reaching_defs.in = set_new (); graph->nodes[graph->num_nodes]->reaching_defs.gen = set_new (); @@ -504,7 +764,7 @@ flow_reaching_defs (flowgraph_t *graph) changed = 0; // flow down the graph for (i = 0; i < graph->num_nodes; i++) { - node = graph->nodes[graph->dfo[i]]; + node = graph->nodes[graph->depth_first[i]]; in = node->reaching_defs.in; out = node->reaching_defs.out; gen = node->reaching_defs.gen; @@ -528,6 +788,8 @@ flow_reaching_defs (flowgraph_t *graph) set_delete (stkill); } +/** Update the node's \a use set from the statement's \a use set + */ static void live_set_use (set_t *stuse, set_t *use, set_t *def) { @@ -536,6 +798,8 @@ live_set_use (set_t *stuse, set_t *use, set_t *def) set_union (use, stuse); } +/** Update the node's \a def set from the statement's \a def set + */ static void live_set_def (set_t *stdef, set_t *use, set_t *def) { @@ -589,7 +853,7 @@ flow_live_vars (flowgraph_t *graph) // flow UP the graph because live variable analysis uses information // from a node's successors rather than its predecessors. for (j = graph->num_nodes - 1; j >= 0; j--) { - node = graph->nodes[graph->dfo[j]]; + node = graph->nodes[graph->depth_first[j]]; set_empty (tmp); for (succ = set_first (node->successors); succ; succ = set_next (succ)) @@ -681,7 +945,7 @@ flow_uninitialized (flowgraph_t *graph) defs = set_new (); for (i = 0; i < graph->num_nodes; i++) { - node = graph->nodes[graph->dfo[i]]; + node = graph->nodes[graph->depth_first[i]]; set_empty (defs); // collect definitions of all variables "used" in this node. use from // the live vars analysis is perfect for the job @@ -759,23 +1023,81 @@ flow_generate (flowgraph_t *graph) return code; } +static int +flow_tempop_add_aliases (tempop_t *tempop, void *_set) +{ + set_t *set = (set_t *) _set; + flowvar_t *var; + var = tempop->flowvar; + if (var) + set_add (set, var->number); + return 0; +} + +static int +flow_def_add_aliases (def_t *def, void *_set) +{ + set_t *set = (set_t *) _set; + flowvar_t *var; + var = def->flowvar; + if (var) + set_add (set, var->number); + return 0; +} + static void -flow_add_op_var (set_t *set, operand_t *op) +flow_add_op_var (set_t *set, operand_t *op, int is_use) { flowvar_t *var; + int ol = is_use ? 1 : 2; if (!set) return; if (!(var = flow_get_var (op))) return; set_add (set, var->number); + + // FIXME XXX I think the curent implementation will have problems + // for the def set when assigning to an alias as right now the real + // var is being treated as assigned as well. Want to handle partial + // defs properly, but I am as yet uncertain of how. + if (op->op_type == op_temp) { + tempop_visit_all (&op->o.tempop, ol, flow_tempop_add_aliases, set); + } else { + def_visit_all (op->o.def, ol, flow_def_add_aliases, set); + } +} + +static operand_t * +flow_analyze_pointer_operand (operand_t *ptrop, set_t *def) +{ + operand_t *op = 0; + + if (ptrop->op_type == op_value && ptrop->o.value->lltype == ev_pointer) { + ex_pointer_t *ptr = &ptrop->o.value->v.pointer; + if (ptrop->o.value->v.pointer.def) { + def_t *alias; + alias = alias_def (ptr->def, ptr->type, ptr->val); + op = def_operand (alias, ptr->type, ptrop->expr); + } + if (ptrop->o.value->v.pointer.tempop) { + op = ptrop->o.value->v.pointer.tempop; + } + if (op) { + flow_add_op_var (def, op, 0); + } + } + return op; } void flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, - operand_t *operands[4]) + operand_t *operands[FLOW_OPERANDS]) { int i, start, calln = -1; + operand_t *res_op = 0; + operand_t *aux_op1 = 0; + operand_t *aux_op2 = 0; if (use) set_empty (use); @@ -784,7 +1106,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, if (kill) set_empty (kill); if (operands) { - for (i = 0; i < 4; i++) + for (i = 0; i < FLOW_OPERANDS; i++) operands[i] = 0; } @@ -792,10 +1114,10 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, case st_none: internal_error (s->expr, "not a statement"); case st_expr: - flow_add_op_var (def, s->opc); - flow_add_op_var (use, s->opa); + flow_add_op_var (def, s->opc, 0); + flow_add_op_var (use, s->opa, 1); if (s->opb) - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opb, 1); if (operands) { operands[0] = s->opc; operands[1] = s->opa; @@ -803,8 +1125,8 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, } break; case st_assign: - flow_add_op_var (def, s->opb); - flow_add_op_var (use, s->opa); + flow_add_op_var (def, s->opb, 0); + flow_add_op_var (use, s->opa, 1); if (operands) { operands[0] = s->opb; operands[1] = s->opa; @@ -812,48 +1134,48 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, break; case st_ptrassign: case st_move: - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); - if (!strcmp (s->opcode, "")) { - flow_add_op_var (def, s->opc); + case st_ptrmove: + case st_memset: + case st_ptrmemset: + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); + if (!strcmp (s->opcode, "") + || !strcmp (s->opcode, "")) { + flow_add_op_var (def, s->opc, 0); + res_op = s->opc; } else if (!strcmp (s->opcode, "")) { - flow_add_op_var (use, s->opc); - if (s->opc->op_type == op_value - && s->opc->o.value->type == ev_pointer - && s->opc->o.value->v.pointer.def) { - operand_t *op; - ex_pointer_t *ptr = &s->opc->o.value->v.pointer; - op = def_operand (ptr->def, ptr->type); - flow_add_op_var (def, op); - if (operands) - operands[0] = op; - else - free_operand (op); - } else { - if (operands) - operands[3] = s->opc; - } + flow_add_op_var (use, s->opc, 0); + aux_op2 = flow_analyze_pointer_operand (s->opa, use); + res_op = flow_analyze_pointer_operand (s->opc, def); + aux_op1 = s->opc; + } else if (!strcmp (s->opcode, "")) { + flow_add_op_var (use, s->opc, 0); + res_op = flow_analyze_pointer_operand (s->opc, def); + aux_op1 = s->opc; + } else if (!strcmp (s->opcode, ".=")) { + flow_add_op_var (use, s->opc, 1); + res_op = flow_analyze_pointer_operand (s->opb, def); + aux_op1 = s->opc; } else { - if (s->opc) - flow_add_op_var (use, s->opc); + internal_error (s->expr, "unexpected opcode '%s' for %d", + s->opcode, s->type); } if (kill) { - //FIXME set of everything + set_everything (kill); } if (operands) { - if (!strcmp (s->opcode, "")) - operands[0] = s->opc; + operands[0] = res_op; operands[1] = s->opa; operands[2] = s->opb; - if (strncmp (s->opcode, "opc; + operands[3] = aux_op1; + operands[4] = aux_op2; } break; case st_state: - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); if (s->opc) - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 1); //FIXME entity members if (operands) { operands[1] = s->opa; @@ -864,30 +1186,42 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, case st_func: if (strcmp (s->opcode, "") == 0 || strcmp (s->opcode, "") == 0) { - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); } else if (strcmp (s->opcode, "") == 0) { - if (use) - set_add (use, 0); //FIXME assumes .return location + if (use) { + flow_add_op_var (use, &flow_params[0].op, 1); + } } if (strncmp (s->opcode, "opcode[5] - '0'; - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); } else if (strncmp (s->opcode, "opcode[6] - '0'; - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); if (s->opc) - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 1); } if (calln >= 0) { if (use) { - for (i = start; i < calln; i++) - set_add (use, i + 1);//FIXME assumes .param_N locations + for (i = start; i < calln; i++) { + flow_add_op_var (use, &flow_params[i + 1].op, 1); + } + } + if (def) { + for (i = 0; i < num_flow_params; i++) { + flow_add_op_var (def, &flow_params[i].op, 0); + } + } + if (kill) { + for (i = 0; i < num_flow_params; i++) { + flow_kill_aliases (kill, + flow_get_var (&flow_params[i].op), + 0); + } } - if (kill) - set_add (kill, 0); //FIXME assumes .return location } if (operands) { operands[1] = s->opa; @@ -897,9 +1231,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, break; case st_flow: if (strcmp (s->opcode, "") != 0) { - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); if (strcmp (s->opcode, "") == 0) - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opb, 1); } if (operands) { operands[1] = s->opa; @@ -960,7 +1294,7 @@ flow_find_successors (flowgraph_t *graph) if (sb->next) { set_add (node->successors, sb->next->flownode->id); } else { - bug (0, "code drops off the end of the function"); + bug (st->expr, "code drops off the end of the function"); // this shouldn't happen // however, make the exit dummy block the node's successor set_add (node->successors, graph->num_nodes + 1); @@ -981,7 +1315,7 @@ flow_make_edges (flowgraph_t *graph) flownode_t *node; set_iter_t *succ; - if (graph->edges); + if (graph->edges) free (graph->edges); graph->edges = malloc (graph->num_edges * sizeof (flowedge_t)); for (j = 0, i = 0; i < graph->num_nodes + 2; i++) { @@ -1039,7 +1373,6 @@ flow_find_dominators (flowgraph_t *graph) changed = 0; for (i = 1; i < graph->num_nodes; i++) { node = graph->nodes[i]; - pred = set_first (node->predecessors); set_empty (work); for (pred = set_first (node->predecessors); pred; pred = set_next (pred)) @@ -1139,7 +1472,7 @@ df_search (flowgraph_t *graph, set_t *visited, int *i, int n) } } node->dfn = --*i; - graph->dfo[node->dfn] = n; + graph->depth_first[node->dfn] = n; } static void @@ -1152,11 +1485,11 @@ flow_build_dfst (flowgraph_t *graph) set_add (visited, graph->num_nodes); set_add (visited, graph->num_nodes + 1); - if (graph->dfo) - free (graph->dfo); + if (graph->depth_first) + free (graph->depth_first); if (graph->dfst) set_delete (graph->dfst); - graph->dfo = calloc (graph->num_nodes, sizeof (int)); + graph->depth_first = calloc (graph->num_nodes, sizeof (int)); graph->dfst = set_new (); i = graph->num_nodes; df_search (graph, visited, &i, 0); @@ -1212,6 +1545,35 @@ flow_make_node (sblock_t *sblock, int id, function_t *func) return node; } +/** Build the flow graph for the function. + * + * In addition to the nodes create by the statement blocks, there are two + * dummy blocks: + * + * \dot + * digraph flow_build_graph { + * layout = dot; rankdir = TB; compound =true; nodesp = 1.0; + * dummy_entry [shape=box,label="entry"]; + * sblock0 [label="code"]; sblock1 [label="code"]; + * sblock2 [label="code"]; sblock3 [label="code"]; + * dummy_exit [shape=box,label="exit"]; + * dummy_entry -> sblock0; sblock0 -> sblock1; + * sblock1 -> sblock2; sblock2 -> sblock1; + * sblock2 -> dummy_exit; sblock1 -> sblock3; + * sblock3 -> dummy_exit; + * } + * \enddot + * + * The entry block is used for detecting use of uninitialized local variables + * and the exit block is used for ensuring global variables are treated as + * live at function exit. + * + * The exit block, which also is empty of statements, has its live vars + * \a use set initilized to the set of global defs, which are simply numbered + * by their index in the functions list of flowvars. All other exit node sets + * are initialized to empty. + * \f[ use_{live}=globals \f] + */ static flowgraph_t * flow_build_graph (function_t *func) { @@ -1245,7 +1607,7 @@ flow_build_graph (function_t *func) flow_make_edges (graph); flow_build_dfst (graph); if (options.block_dot.flow) - dump_dot (va ("flow-%d", pass), graph, dump_dot_flow); + dump_dot (va (0, "flow-%d", pass), graph, dump_dot_flow); pass++; } while (flow_remove_unreachable_nodes (graph)); flow_find_predecessors (graph); @@ -1262,6 +1624,8 @@ flow_data_flow (function_t *func) flow_build_statements (func); flow_build_vars (func); graph = flow_build_graph (func); + if (options.block_dot.statements) + dump_dot ("statements", graph, dump_dot_flow_statements); flow_reaching_defs (graph); if (options.block_dot.reaching) dump_dot ("reaching", graph, dump_dot_flow_reaching); @@ -1273,3 +1637,5 @@ flow_data_flow (function_t *func) flow_cleanup_dags (graph); func->sblock = flow_generate (graph); } + +///@} diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 873f734b6..4e7ef61f3 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -44,26 +44,27 @@ #include "QF/hash.h" #include "QF/va.h" -#include "qfcc.h" +#include "tools/qfcc/include/qfcc.h" -#include "codespace.h" -#include "debug.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "flow.h" -#include "function.h" -#include "opcodes.h" -#include "options.h" -#include "reloc.h" -#include "shared.h" -#include "statements.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/flow.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/opcodes.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static param_t *params_freelist; static function_t *functions_freelist; @@ -119,7 +120,7 @@ param_append_identifiers (param_t *params, symbol_t *idents, type_t *type) return params; } -param_t * +static param_t * _reverse_params (param_t *params, param_t *next) { param_t *p = params; @@ -137,6 +138,20 @@ reverse_params (param_t *params) return _reverse_params (params, 0); } +param_t * +append_params (param_t *params, param_t *more_params) +{ + if (params) { + param_t *p; + for (p = params; p->next; ) { + p = p->next; + } + p->next = more_params; + return params; + } + return more_params; +} + param_t * copy_params (param_t *params) { @@ -155,23 +170,40 @@ parse_params (type_t *type, param_t *parms) { param_t *p; type_t *new; + type_t *ptype; + int count = 0; + + if (type && is_class (type)) { + error (0, "cannot return an object (forgot *?)"); + type = &type_id; + } new = new_type (); new->type = ev_func; + new->alignment = 1; new->t.func.type = type; new->t.func.num_params = 0; for (p = parms; p; p = p->next) { - if (new->t.func.num_params > MAX_PARMS) { - error (0, "too many params"); - return type; + if (p->type) { + count++; } + } + if (count) { + new->t.func.param_types = malloc (count * sizeof (type_t)); + } + for (p = parms; p; p = p->next) { if (!p->selector && !p->type && !p->name) { if (p->next) internal_error (0, 0); new->t.func.num_params = -(new->t.func.num_params + 1); } else if (p->type) { - new->t.func.param_types[new->t.func.num_params] = p->type; + if (is_class (p->type)) { + error (0, "cannot use an object as a parameter (forgot *?)"); + p->type = &type_id; + } + ptype = (type_t *) unalias_type (p->type); //FIXME cast + new->t.func.param_types[new->t.func.num_params] = ptype; new->t.func.num_params++; } } @@ -186,7 +218,7 @@ check_params (param_t *params) if (!params) return 0; while (p) { - if (p->type == &type_void) { + if (p->type && is_void(p->type)) { if (p->name) { error (0, "parameter %d ('%s') has incomplete type", num, p->name); @@ -205,19 +237,19 @@ check_params (param_t *params) } static overloaded_function_t * -get_function (const char *name, type_t *type, int overload, int create) +get_function (const char *name, const type_t *type, int overload, int create) { const char *full_name; overloaded_function_t *func; if (!overloaded_functions) { - overloaded_functions = Hash_NewTable (1021, ol_func_get_key, 0, 0); - function_map = Hash_NewTable (1021, func_map_get_key, 0, 0); + overloaded_functions = Hash_NewTable (1021, ol_func_get_key, 0, 0, 0); + function_map = Hash_NewTable (1021, func_map_get_key, 0, 0, 0); } name = save_string (name); - full_name = save_string (va ("%s|%s", name, encode_params (type))); + full_name = save_string (va (0, "%s|%s", name, encode_params (type))); func = Hash_Find (overloaded_functions, full_name); if (func) { @@ -264,7 +296,7 @@ function_symbol (symbol_t *sym, int overload, int create) overloaded_function_t *func; symbol_t *s; - func = get_function (name, sym->type, overload, create); + func = get_function (name, unalias_type (sym->type), overload, create); if (func && func->overloaded) name = func->full_name; @@ -272,7 +304,7 @@ function_symbol (symbol_t *sym, int overload, int create) if ((!s || s->table != current_symtab) && create) { s = new_symbol (name); s->sy_type = sy_func; - s->type = sym->type; + s->type = (type_t *) unalias_type (sym->type); // FIXME cast s->params = sym->params; s->s.func = 0; // function not yet defined symtab_addsymbol (current_symtab, s); @@ -286,8 +318,8 @@ func_compare (const void *a, const void *b) { overloaded_function_t *fa = *(overloaded_function_t **) a; overloaded_function_t *fb = *(overloaded_function_t **) b; - type_t *ta = fa->type; - type_t *tb = fb->type; + const type_t *ta = fa->type; + const type_t *tb = fb->type; int na = ta->t.func.num_params; int nb = tb->t.func.num_params; int ret, i; @@ -326,8 +358,9 @@ find_function (expr_t *fexpr, expr_t *params) return e; type.t.func.num_params++; } - if (type.t.func.num_params > MAX_PARMS) - return fexpr; + i = type.t.func.num_params * sizeof (type_t); + type.t.func.param_types = alloca(i); + memset (type.t.func.param_types, 0, i); for (i = 0, e = params; e; i++, e = e->next) { type.t.func.param_types[type.t.func.num_params - 1 - i] = get_type (e); if (e->type == ex_error) @@ -339,14 +372,17 @@ find_function (expr_t *fexpr, expr_t *params) for (func_count = 0; funcs[func_count]; func_count++) ; if (func_count < 2) { - free (funcs); - return fexpr; + f = (overloaded_function_t *) funcs[0]; + if (func_count && !f->overloaded) { + free (funcs); + return fexpr; + } } type.t.func.type = ((overloaded_function_t *) funcs[0])->type->t.func.type; dummy.type = find_type (&type); qsort (funcs, func_count, sizeof (void *), func_compare); - dummy.full_name = save_string (va ("%s|%s", fexpr->e.symbol->name, + dummy.full_name = save_string (va (0, "%s|%s", fexpr->e.symbol->name, encode_params (&type))); dummy_p = bsearch (&dummy_p, funcs, func_count, sizeof (void *), func_compare); @@ -427,7 +463,8 @@ check_function (symbol_t *fsym) fsym->type->t.func.type = &type_void;//FIXME better type? } if (type_size (fsym->type->t.func.type) > type_size (&type_param)) { - error (0, "return value too large to be passed by value"); + error (0, "return value too large to be passed by value (%d)", + type_size (&type_param)); fsym->type->t.func.type = &type_void;//FIXME better type? } for (p = params, i = 0; p; p = p->next, i++) { @@ -458,12 +495,19 @@ build_scope (symbol_t *fsym, symtab_t *parent) symtab = new_symtab (parent, stab_local); fsym->s.func->symtab = symtab; + fsym->s.func->label_scope = new_symtab (0, stab_local); symtab->space = defspace_new (ds_virtual); current_symtab = symtab; - if (fsym->type->t.func.num_params < 0) { + if (!fsym->s.func) { + internal_error (0, "function %s not defined", fsym->name); + } + if (!is_func (fsym->s.func->type)) { + internal_error (0, "function type %s not a funciton", fsym->name); + } + if (fsym->s.func->type->t.func.num_params < 0) { args = new_symbol_type (".args", &type_va_list); - initialize_def (args, args->type, 0, symtab->space, sc_param); + initialize_def (args, 0, symtab->space, sc_param); } for (p = fsym->params, i = 0; p; p = p->next) { @@ -476,14 +520,14 @@ build_scope (symbol_t *fsym, symtab_t *parent) p->name = save_string (""); } param = new_symbol_type (p->name, p->type); - initialize_def (param, param->type, 0, symtab->space, sc_param); + initialize_def (param, 0, symtab->space, sc_param); i++; } if (args) { while (i < MAX_PARMS) { - param = new_symbol_type (va (".par%d", i), &type_param); - initialize_def (param, &type_param, 0, symtab->space, sc_param); + param = new_symbol_type (va (0, ".par%d", i), &type_param); + initialize_def (param, 0, symtab->space, sc_param); i++; } } @@ -515,6 +559,7 @@ make_function (symbol_t *sym, const char *nice_name, defspace_t *space, if (!sym->s.func) { sym->s.func = new_function (sym->name, nice_name); sym->s.func->sym = sym; + sym->s.func->type = unalias_type (sym->type); } if (sym->s.func->def && sym->s.func->def->external && storage != sc_extern) { @@ -576,12 +621,26 @@ begin_function (symbol_t *sym, const char *nicename, symtab_t *parent, return sym->s.func; } +static void +build_function (symbol_t *fsym) +{ + const type_t *func_type = fsym->s.func->type; + if (func_type->t.func.num_params > MAX_PARMS) { + error (0, "too many params"); + } + // FIXME +// f->def->constant = 1; +// f->def->nosave = 1; +// f->def->initialized = 1; +// G_FUNCTION (f->def->ofs) = f->function_num; +} + function_t * build_code_function (symbol_t *fsym, expr_t *state_expr, expr_t *statements) { if (fsym->sy_type != sy_func) // probably in error recovery return 0; - build_function (fsym->s.func); + build_function (fsym); if (state_expr) { state_expr->next = statements; statements = state_expr; @@ -616,15 +675,22 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) if (sym->s.func->def->external) return 0; + sym->s.func->def->initialized = 1; + sym->s.func->def->constant = 1; + sym->s.func->def->nosave = 1; add_function (sym->s.func); if (is_integer_val (bi_val)) bi = expr_integer (bi_val); else bi = expr_float (bi_val); + if (bi < 0) { + error (bi_val, "builtin functions must be positive or 0"); + return 0; + } sym->s.func->builtin = bi; reloc_def_func (sym->s.func, sym->s.func->def); - build_function (sym->s.func); + build_function (sym); finish_function (sym->s.func); // for debug info @@ -633,16 +699,6 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) return sym->s.func; } -void -build_function (function_t *f) -{ - // FIXME -// f->def->constant = 1; -// f->def->nosave = 1; -// f->def->initialized = 1; -// G_FUNCTION (f->def->ofs) = f->function_num; -} - void finish_function (function_t *f) { diff --git a/tools/qfcc/source/grab.c b/tools/qfcc/source/grab.c index 03edaa41a..0d59c1217 100644 --- a/tools/qfcc/source/grab.c +++ b/tools/qfcc/source/grab.c @@ -44,12 +44,12 @@ #include "QF/hash.h" #include "QF/quakeio.h" -#include "diagnostic.h" -#include "expr.h" -#include "grab.h" -#include "options.h" -#include "qfcc.h" -#include "strpool.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/grab.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/strpool.h" int grab_frame; int grab_other; @@ -69,12 +69,17 @@ static frame_t *frame_list; static frame_t **frame_tail = &frame_list; static frame_t grab_list[] = { - {0, "cd", 0}, - {0, "origin", 0}, - {0, "base", 0}, - {0, "flags", 0}, - {0, "scale", 0}, - {0, "skin", 0}, + {0, "modelname", 0}, + {0, "base", 0}, + {0, "cd", 0}, + {0, "sync", 0}, + {0, "origin", 0}, + {0, "eyeposition", 0}, + {0, "scale", 0}, + {0, "flags", 0}, + {0, "skin", 0}, + {0, "framegroupstart", 0}, + {0, "skingroupstart", 0}, }; static const char * @@ -100,8 +105,8 @@ do_grab (const char *token) size_t i; initialized = 1; - frame_tab = Hash_NewTable (1021, frame_get_key, frame_free, 0); - grab_tab = Hash_NewTable (1021, frame_get_key, 0, 0); + frame_tab = Hash_NewTable (1021, frame_get_key, frame_free, 0, 0); + grab_tab = Hash_NewTable (1021, frame_get_key, 0, 0, 0); for (i = 0; i < sizeof (grab_list) / sizeof (grab_list[0]); i++) Hash_Add (grab_tab, &grab_list[i]); } diff --git a/tools/qfcc/source/idstuff.c b/tools/qfcc/source/idstuff.c index 629862003..1bc222f49 100644 --- a/tools/qfcc/source/idstuff.c +++ b/tools/qfcc/source/idstuff.c @@ -43,16 +43,16 @@ #include #include -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "qfcc.h" -#include "expr.h" -#include "idstuff.h" -#include "options.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/idstuff.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" #define MAX_SOUNDS 1024 #define MAX_MODELS 1024 @@ -295,7 +295,7 @@ WriteProgdefs (dprograms_t *progs, const char *filename) crc = CRC_Block ((byte *) dstr->str, dstr->size - 1); dasprintf (dstr, "#define PROGHEADER_CRC %u\n", crc); - dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, be one must " + dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, but one must " "maintain formalities */"); if (filename) { diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 772f3fd35..eb5aeb2bb 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -58,21 +58,21 @@ #include "QF/pakfile.h" #include "QF/va.h" -#include "class.h" -#include "codespace.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "linker.h" -#include "obj_file.h" -#include "obj_type.h" -#include "options.h" -#include "qfcc.h" -#include "reloc.h" -#include "strpool.h" -#include "type.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/linker.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/type.h" static void linker_internal_error (const char *fmt, ...) __attribute__ ((format (printf, 1, 2), noreturn)); @@ -128,8 +128,8 @@ static builtin_sym_t builtin_symbols[] __attribute__ ((used)) = { {".param_6", &type_param, QFOD_NOSAVE | QFOD_GLOBAL}, {".param_7", &type_param, QFOD_NOSAVE | QFOD_GLOBAL}, }; -static const int num_builtins = sizeof (builtin_symbols) - / sizeof (builtin_symbols[0]); +static const unsigned num_builtins = sizeof (builtin_symbols) + / sizeof (builtin_symbols[0]); static defref_t *defrefs_freelist; @@ -147,13 +147,14 @@ static qfo_t *work; static int work_base[qfo_num_spaces]; static int work_func_base; static defref_t **work_defrefs; -static int num_work_defrefs; +static unsigned num_work_defrefs; static strpool_t *work_strings; static codespace_t *work_code; static defspace_t *work_near_data; static defspace_t *work_far_data; static defspace_t *work_entity_data; static defspace_t *work_type_data; +static defspace_t *work_debug_data; static qfo_reloc_t *work_loose_relocs; static int work_num_loose_relocs; @@ -163,6 +164,7 @@ static defspace_t **work_spaces[qfo_num_spaces] = { &work_far_data, &work_entity_data, &work_type_data, + &work_debug_data, }; static dstring_t *linker_current_file; @@ -282,6 +284,8 @@ alloc_data (int space, int size) static void resolve_external_def (defref_t *ext, defref_t *def) { + qfot_type_t *ext_type; + qfot_type_t *def_type; if (!(REF (ext)->flags & QFOD_EXTERNAL)) { def_error (REF (ext), "%s %x", WORKSTR (REF (ext)->name), REF (ext)->flags); @@ -292,7 +296,15 @@ resolve_external_def (defref_t *ext, defref_t *def) REF (def)->flags); linker_internal_error ("def is an external or local def"); } - if (REF (ext)->type != REF (def)->type) { + ext_type = WORKTYPE (REF(ext)->type); + if (ext_type->meta == ty_alias) { + ext_type = WORKTYPE (ext_type->alias.aux_type); + } + def_type = WORKTYPE (REF (def)->type); + if (def_type->meta == ty_alias) { + def_type = WORKTYPE (def_type->alias.aux_type); + } + if (ext_type != def_type) { linker_type_mismatch (REF (ext), REF (def)); return; } @@ -408,14 +420,17 @@ process_type_def (defref_t *ref, qfo_mspace_t *space, qfo_def_t *old) memcpy (new_type, old_type, old_type->size * sizeof (pr_type_t)); define_def (ref, extern_type_defs, defined_type_defs); } - // save the new address in the old def's type field so relocation - // records can be updated. + // Save the new address in the old def's type field so relocation + // records can be updated. Type encoding defs start with no type + // (type = 0). The old def's offset is not modified because it is used + // for finding the def when adjusting relocation records that point + // to fields inside the type encoding. old->type = REF (ref)->offset; - // mark the old type encoding as having been transfered, and save the + // Mark the old type encoding as having been transfered, and save the // new address in the encoding's class field so def and function types // can be updated easily. - old_type->ty = -1; - old_type->t.class = REF (ref)->offset; + old_type->meta = -1; + old_type->class = REF (ref)->offset; } } @@ -436,7 +451,7 @@ adjust_reloc_offset (qfo_reloc_t *reloc) static int add_relocs (qfo_t *qfo, int start, int count, int target) { - int size; + unsigned size; qfo_reloc_t *ireloc; qfo_reloc_t *oreloc; @@ -446,9 +461,11 @@ add_relocs (qfo_t *qfo, int start, int count, int target) oreloc = work->relocs + work->num_relocs; for ( ; work->num_relocs < size; ireloc++, oreloc++) { *oreloc = *ireloc; + // Mark the reloc as having been copied and record the new reloc record + // number in the old reloc's offset ireloc->type = -1; ireloc->offset = work->num_relocs++; - if (oreloc->space < 0 || oreloc->space >= qfo->num_spaces) { + if (oreloc->space >= qfo->num_spaces) { linker_error ("bad reloc space: %d (%d)", oreloc->space, qfo->num_spaces); oreloc->type = rel_none; @@ -485,8 +502,20 @@ add_defs (qfo_t *qfo, qfo_mspace_t *space, qfo_mspace_t *dest_space, odef->file = linker_add_string (QFOSTR (qfo, idef->file)); idef->file = -1; // mark def as copied idef->line = num_work_defrefs; // so def can be found + // In the first passs, process_type_def sets the type meta to -1 and + // class to the offset of the copied type, but the null type encodiing + // is not modified. Other defs are processed in the second pass. type = QFOTYPE(idef->type); - odef->type = type->t.class; // pointer to type in work + if (idef->type && (int) type->meta != -1) { + linker_internal_error ("reference to type that has not been " + "relocated"); + } + // Type encodings have no type (type = 0) so setting the type + // to the idef type class has no effect. + odef->type = type->class; // pointer to type in work + // don't add unused (no attached relocs) external defs to the work + // defref list so they will not cause unused object files to be + // pulled in from libraries if (odef->flags & QFOD_EXTERNAL && !odef->num_relocs) continue; ref = get_defref (odef, dest_space); @@ -638,18 +667,18 @@ linker_find_def (const char *name) void linker_begin (void) { - int i; + unsigned i; linker_current_file = dstring_newstr (); - extern_data_defs = Hash_NewTable (16381, defs_get_key, 0, 0); - defined_data_defs = Hash_NewTable (16381, defs_get_key, 0, 0); + extern_data_defs = Hash_NewTable (16381, defs_get_key, 0, 0, 0); + defined_data_defs = Hash_NewTable (16381, defs_get_key, 0, 0, 0); - extern_field_defs = Hash_NewTable (16381, defs_get_key, 0, 0); - defined_field_defs = Hash_NewTable (16381, defs_get_key, 0, 0); + extern_field_defs = Hash_NewTable (16381, defs_get_key, 0, 0, 0); + defined_field_defs = Hash_NewTable (16381, defs_get_key, 0, 0, 0); - extern_type_defs = Hash_NewTable (16381, defs_get_key, 0, 0); - defined_type_defs = Hash_NewTable (16381, defs_get_key, 0, 0); + extern_type_defs = Hash_NewTable (16381, defs_get_key, 0, 0, 0); + defined_type_defs = Hash_NewTable (16381, defs_get_key, 0, 0, 0); work_strings = strpool_new (); work_code = codespace_new (); @@ -657,6 +686,7 @@ linker_begin (void) work_far_data = defspace_new (ds_backed); work_entity_data = defspace_new (ds_virtual); work_type_data = defspace_new (ds_backed); + work_debug_data = defspace_new (ds_backed); pr.strings = work_strings; @@ -682,6 +712,9 @@ linker_begin (void) work->spaces[qfo_type_space].type = qfos_type; work->spaces[qfo_type_space].d.data = work_type_data->data; work->spaces[qfo_type_space].data_size = work_type_data->size; + work->spaces[qfo_debug_space].type = qfos_debug; + work->spaces[qfo_debug_space].d.data = work_type_data->data; + work->spaces[qfo_debug_space].data_size = work_type_data->size; for (i = 0; i < qfo_num_spaces; i++) work->spaces[i].id = i; @@ -792,21 +825,28 @@ update_type_space_reloc (qfo_mspace_t *space, qfo_reloc_t *reloc) qfo_def_t dummy; qfo_def_t *def; - if (reloc->type == -1) + if (reloc->type == -1) { + // The reloc has been copied, and the record number of the new reloc + // is in the old reloc's offset. reloc = work->relocs + reloc->offset; + } dummy.offset = reloc->offset; def = (qfo_def_t *) bsearch (&dummy, space->defs, space->num_defs, sizeof (qfo_def_t), type_def_compare); - if (!def) + if (!def) { linker_internal_error ("relocation record with invalid address. " "corrupt object file?"); - reloc->offset += def->type - def->offset; + } + // The new offset of the type encoding is stored in the def's type field. + // The old offset is in the def's offset field. The reloc's offset points + // to somewhere within the type encoding. + reloc->offset = def->type + (reloc->offset - def->offset); } static int process_type_space (qfo_t *qfo, qfo_mspace_t *space, int pass) { - int i; + unsigned i; if (pass != 0) return 0; @@ -816,14 +856,15 @@ process_type_space (qfo_t *qfo, qfo_mspace_t *space, int pass) } qfo_type_defs = space; add_defs (qfo, space, work->spaces + qfo_type_space, process_type_def); - // the defs in qfo are no longer needed by the rest of the linker, so - // we're free to mess around with them + // The defs in qfo are no longer needed by the rest of the linker, so + // we're free to mess around with them. - // sort the defs by addres. Unfortunately, they will usually be in order, - // so qsort will likely be pessimistic, but oh well. + // Sort the defs by addres so they can found using bsearch when adjusting + // the targets of type encoding relocs. Unfortunately, they will usually + // be in order, so qsort will likely be pessimistic, but oh well. qsort (space->defs, space->num_defs, sizeof (qfo_def_t), type_def_compare); - // update the offsets of all relocation records that point into the type + // Update the offsets of all relocation records that point into the type // encoding space. for (i = 0; i < qfo->num_relocs; i++) { qfo_reloc_t *reloc = qfo->relocs + i; @@ -831,12 +872,26 @@ process_type_space (qfo_t *qfo, qfo_mspace_t *space, int pass) if (reloc->space != space->id) continue; update_type_space_reloc (space, reloc); - // while we're at it, update the strings so the type space strings - // are always correct. + // while we're at it, relocate all references in the type encoding + // space so the type encodings are always correct. if (reloc->type == rel_def_string) { string_t str; str = linker_add_string (QFOSTR (qfo, reloc->target)); QFO_STRING (work, reloc->space, reloc->offset) = str; + } else if (reloc->type == rel_def_def || reloc->type == -1) { + qfo_def_t *def; + if (reloc->type == -1) { + // The reloc has been copied, and the record number of the new + // reloc is in the old reloc's offset. + reloc = work->relocs + reloc->offset; + } + if (reloc->target >= work->spaces[reloc->space].num_defs) { + linker_error ("Invalid reloc target def %d / %d.\n", + reloc->target, qfo->num_defs); + continue; + } + def = work->spaces[reloc->space].defs + reloc->target; + QFO_INT (work, reloc->space, reloc->offset) = def->offset; } } for (i = 0; i < num_builtins; i++) { @@ -857,10 +912,24 @@ process_type_space (qfo_t *qfo, qfo_mspace_t *space, int pass) return 0; } +static int +process_debug_space (qfo_t *qfo, qfo_mspace_t *space, int pass) +{ + if (pass != 1) + return 0; + if (space->type != qfos_debug) { + linker_internal_error ("bad space type for add_data_space (): %d", + space->type); + } + add_defs (qfo, space, work->spaces + qfo_debug_space, process_data_def); + add_data (qfo_debug_space, space); + return 0; +} + static void process_funcs (qfo_t *qfo) { - int size; + unsigned size; qfo_func_t *func; qfot_type_t *type; @@ -871,7 +940,7 @@ process_funcs (qfo_t *qfo) while (work->num_funcs < size) { func = work->funcs + work->num_funcs++; type = QFOTYPE(func->type); - func->type = type->t.class; + func->type = type->class; func->name = linker_add_string (QFOSTR (qfo, func->name)); func->file = linker_add_string (QFOSTR (qfo, func->file)); if (func->code > 0) @@ -888,7 +957,7 @@ process_funcs (qfo_t *qfo) static void process_lines (qfo_t *qfo) { - int size; + unsigned size; pr_lineno_t *line; if (!qfo->num_lines) @@ -920,7 +989,7 @@ process_loose_relocs (qfo_t *qfo) qfo->num_loose_relocs * sizeof (qfo_reloc_t)); while (work_num_loose_relocs < size) { reloc = work_loose_relocs + work_num_loose_relocs++; - if (reloc->space < 0 || reloc->space >= qfo->num_spaces) { + if (reloc->space >= qfo->num_spaces) { linker_error ("bad reloc space"); reloc->type = rel_none; continue; @@ -940,6 +1009,9 @@ process_loose_relocs (qfo_t *qfo) if (reloc->type == rel_def_op) reloc->target += work_base[qfo_code_space]; adjust_reloc_offset (reloc); + if (reloc->type == rel_def_string) { + QFO_STRING (work, reloc->space, reloc->offset) = reloc->target; + } } } @@ -953,8 +1025,9 @@ linker_add_qfo (qfo_t *qfo) process_strings_space, process_entity_space, process_type_space, + process_debug_space, }; - int i; + unsigned i; int pass; qfo_mspace_t *space; @@ -965,7 +1038,7 @@ linker_add_qfo (qfo_t *qfo) work_func_base = work->num_funcs; for (pass = 0; pass < 2; pass++) { for (i = 0, space = qfo->spaces; i < qfo->num_spaces; i++, space++) { - if ((int) space->type < 0 || space->type > qfos_type) { + if ((int) space->type < 0 || space->type > qfos_debug) { linker_error ("bad space type"); return 1; } @@ -1027,12 +1100,13 @@ linker_add_lib (const char *libname) path_t start = {path_head, "."}; path_t *path = &start; const char *path_name = 0; - int i, j; + int i; + unsigned j; int did_something; if (strncmp (libname, "-l", 2) == 0) { while (path) { - path_name = va ("%s/lib%s.a", path->path, libname + 2); + path_name = va (0, "%s/lib%s.a", path->path, libname + 2); pack = pack_open (path_name); if (pack) break; @@ -1101,7 +1175,7 @@ static __attribute__ ((used)) void undefined_def (qfo_def_t *def) { qfo_def_t line_def; - pr_int_t i; + pr_uint_t i; qfo_reloc_t *reloc = work->relocs + def->relocs; for (i = 0; i < def->num_relocs; i++, reloc++) { @@ -1113,14 +1187,14 @@ undefined_def (qfo_def_t *def) || reloc->type == rel_op_c_def_ofs) && work->lines) { qfo_func_t *func = work->funcs; - qfo_func_t *best = func; - pr_int_t best_dist = reloc->offset - func->code; + qfo_func_t *best = 0; + pr_uint_t best_dist; pr_lineno_t *line; - while (best_dist && func - work->funcs < work->num_funcs) { - if (func->code <= reloc->offset) { - if (best_dist < 0 - || reloc->offset - func->code < best_dist) { + while (func - work->funcs < work->num_funcs) { + if (func->code >= 0 + && (pr_uint_t) func->code <= reloc->offset) { + if (!best || reloc->offset - func->code < best_dist) { best = func; best_dist = reloc->offset - func->code; } @@ -1160,7 +1234,7 @@ check_defs (void) defref_t *_d = Hash_Find (defined_data_defs, "self"); if (_d) { qfo_def_t *d = REF (_d); - if (QFO_TYPEMETA (work, d->type) == ty_none + if (QFO_TYPEMETA (work, d->type) == ty_basic && QFO_TYPETYPE (work, d->type) == ev_entity) def_warning (d, "@self and self used together"); } @@ -1195,7 +1269,7 @@ build_qfo (void) { qfo_t *qfo; int size; - int i, j; + unsigned i, j; qfo_reloc_t *reloc; qfo_def_t **defs; @@ -1280,17 +1354,6 @@ build_qfo (void) reloc++; } } - for (i = 0; i < qfo->num_relocs; i++) { - qfo_def_t *def; - - reloc = qfo->relocs + i; - if (reloc->space != qfo_type_space) - continue; - if (reloc->type != rel_def_def) - continue; - def = qfo->defs + reloc->target; - QFO_INT (qfo, reloc->space, reloc->offset) = def->offset; - } return qfo; } diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index ab1c873a8..a1d05ce9d 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -44,23 +44,23 @@ #include "QF/pr_obj.h" #include "QF/va.h" -#include "qfcc.h" +#include "tools/qfcc/include/qfcc.h" -#include "expr.h" -#include "class.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "method.h" -#include "options.h" -#include "reloc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static hashtab_t *known_methods; @@ -89,8 +89,12 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_params) dstring_t *name = dstring_newstr (); dstring_t *types = dstring_newstr (); - opt_params = reverse_params (opt_params); - selector = _reverse_params (selector, opt_params); + if (!ret_type) { + ret_type = &type_id; + } + + selector = reverse_params (selector); + selector = append_params (selector, opt_params); cmd->next = selector; self->next = cmd; @@ -109,11 +113,12 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_params) free (name); free (types); - //print_type (meth->type); puts (""); + //print_type (meth->type); meth->def = 0; if (!known_methods) - known_methods = Hash_NewTable (1021, method_get_key, method_free, 0); + known_methods = Hash_NewTable (1021, method_get_key, + method_free, 0, 0); Hash_Add (known_methods, meth); return meth; @@ -147,6 +152,12 @@ add_method (methodlist_t *methodlist, method_t *method) if (method->next) internal_error (0, "add_method: method loop detected"); + for (method_t *m = methodlist->head; m; m = m->next) { + if (method_compare (m, method)) { + debug (0, "dropping duplicate method: %s", method->name); + return; + } + } *methodlist->tail = method; methodlist->tail = &method->next; } @@ -199,20 +210,114 @@ new_methodlist (void) return l; } -void -copy_methods (methodlist_t *dst, methodlist_t *src) +static uintptr_t +methodset_get_hash (const void *_method, void *unused) { - method_t *s, *d; + method_t *method = (method_t *) _method; + uintptr_t hash; - for (s = src->head; s; s = s->next) { - d = malloc (sizeof (method_t)); - *d = *s; - d->next = 0; - add_method (dst, d); + hash = Hash_String (method->name); + return hash ^ (method->instance << 3); +} + +static int +methodset_compare (const void *_m1, const void *_m2, void *unused) +{ + method_t *m1 = (method_t *) _m1; + method_t *m2 = (method_t *) _m2; + int cmp; + + cmp = strcmp (m1->name, m2->name) == 0; + return cmp && m1->instance == m2->instance; +} + +methodset_t * +new_methodset (void) +{ + methodset_t *s = malloc (sizeof (*s)); + s->tab = Hash_NewTable (31, 0, 0, 0, 0); + Hash_SetHashCompare (s->tab, methodset_get_hash, methodset_compare); + return s; +} + +void +methodset_add_methods (methodset_t *methodset, methodlist_t *methods) +{ + method_t *m; + + for (m = methods->head; m; m = m->next) { + Hash_AddElement (methodset->tab, m); } } int +methodset_contains_method (methodset_t *methodset, method_t *method) +{ + return Hash_FindElement (methodset->tab, method) != 0; +} + +static int __attribute__((pure)) +method_in_list (methodlist_t *method_list, method_t *method) +{ + method_t *m; + + for (m = method_list->head; m; m = m->next) { + if (method_compare (m, method)) { + return 1; + } + } + return 0; +} + +void +merge_method_lists (methodlist_t *dst, methodlist_t *src) +{ + while (src->head) { + method_t *s = src->head; + src->head = s->next; + s->next = 0; + if (method_in_list (dst, s)) { + debug (0, "dropping duplicate method: %s", s->name); + free (s); + } else { + // add_method does the duplicate check + *dst->tail = s; + dst->tail = &s->next; + } + } + free (src); +} + +void +copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except) +{ + method_t *s, *d; + param_t *self; + + for (s = src->head; s; s = s->next) { + if (methodset_contains_method (except, s) || method_in_list (dst, s)) { + debug (0, "skipping duplicate method: %s", s->name); + continue; + } + d = malloc (sizeof (method_t)); + *d = *s; + // The above is only a shallow copy and thus even though the methods + // are not shared between the source and destination lists, the + // parameters are. Thus, duplicate the self (first) parameter so + // changing its type to match the class into which it is inserted does + // not affect the source list. The rest of the parameters do not need + // to be copied as they will not be altered. + self = malloc (sizeof (param_t)); + *self = *d->params; + d->params = self; + d->next = 0; + // add_method does the duplicate check + *dst->tail = d; + dst->tail = &d->next; + } +} + +__attribute__((pure)) int method_compare (method_t *m1, method_t *m2) { if (m1->instance != m2->instance) @@ -275,6 +380,20 @@ find_method (const char *sel_name) return Hash_Find (known_methods, sel_name); } +method_t * +methodlist_find_method (methodlist_t *methodlist, selector_t *selector, + int instance) +{ + method_t *m; + + for (m = methodlist->head; m; m = m->next) { + if (m->instance == instance && strcmp (selector->name, m->name) == 0) { + return m; + } + } + return 0; +} + void selector_name (dstring_t *sel_id, keywordarg_t *selector) { @@ -341,9 +460,9 @@ selector_index (const char *sel_id) selector_t *sel = &_sel; if (!sel_hash) { - sel_hash = Hash_NewTable (1021, 0, 0, 0); + sel_hash = Hash_NewTable (1021, 0, 0, 0, 0); Hash_SetHashCompare (sel_hash, sel_get_hash, sel_compare); - sel_index_hash = Hash_NewTable (1021, 0, 0, 0); + sel_index_hash = Hash_NewTable (1021, 0, 0, 0, 0); Hash_SetHashCompare (sel_index_hash, sel_index_get_hash, sel_index_compare); } @@ -365,7 +484,7 @@ get_selector (expr_t *sel) selector_t _sel = {0, 0, 0}; if (sel->type != ex_expr && sel->e.expr.op != '&' - && sel->e.expr.type != &type_SEL) { + && !is_SEL(sel->e.expr.type)) { error (sel, "not a selector"); return 0; } @@ -410,7 +529,7 @@ emit_selectors (void) static void emit_methods_next (def_t *def, void *data, int index) { - if (def->type != &type_pointer) + if (!is_pointer(def->type)) internal_error (0, "%s: expected pointer def", __FUNCTION__); D_INT (def) = 0; } @@ -420,7 +539,7 @@ emit_methods_count (def_t *def, void *data, int index) { methodlist_t *methods = (methodlist_t *) data; - if (def->type != &type_integer) + if (!is_integer(def->type)) internal_error (0, "%s: expected integer def", __FUNCTION__); D_INT (def) = methods->count; } @@ -432,7 +551,7 @@ emit_methods_list_item (def_t *def, void *data, int index) method_t *m; pr_method_t *meth; - if (!is_array (def->type) || def->type->t.array.type != &type_obj_method) + if (!is_array (def->type) || !is_method(def->type->t.array.type)) internal_error (0, "%s: expected array of method def", __FUNCTION__); if (index < 0 || index >= methods->count) @@ -474,7 +593,7 @@ emit_methods (methodlist_t *methods, const char *name, int instance) if (!methods) return 0; - for (count = 0, m = methods->head; m; m = m->next) + for (count = 0, m = methods->head; m; m = m->next) { if (!m->instance == !instance) { if (!m->def && options.warnings.unimplemented) { warning (0, "Method `%c%s' not implemented", @@ -483,14 +602,15 @@ emit_methods (methodlist_t *methods, const char *name, int instance) if (m->def) count++; } + } if (!count) return 0; methods->count = count; methods->instance = instance; - methods_struct[2].type = array_type (&type_obj_method, count); - return emit_structure (va ("_OBJ_%s_METHODS_%s", type, name), 's', - methods_struct, 0, methods, sc_static); + methods_struct[2].type = array_type (&type_method, count); + return emit_structure (va (0, "_OBJ_%s_METHODS_%s", type, name), 's', + methods_struct, 0, methods, 0, sc_static); } static void @@ -498,7 +618,7 @@ emit_method_list_count (def_t *def, void *data, int index) { methodlist_t *methods = (methodlist_t *) data; - if (def->type != &type_integer) + if (!is_integer(def->type)) internal_error (0, "%s: expected integer def", __FUNCTION__); D_INT (def) = methods->count; } @@ -510,9 +630,11 @@ emit_method_list_item (def_t *def, void *data, int index) method_t *m; pr_method_description_t *desc; - if (def->type != &type_obj_method_description) - internal_error (0, "%s: expected method_descripting def", + if (!is_array (def->type) + || !is_method_description(def->type->t.array.type)) { + internal_error (0, "%s: expected array of method_description def", __FUNCTION__); + } if (index < 0 || index >= methods->count) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, methods->count); @@ -520,7 +642,7 @@ emit_method_list_item (def_t *def, void *data, int index) desc = D_POINTER (pr_method_description_t, def); for (m = methods->head; m; m = m->next) { - if (!m->instance != !methods->instance || !m->def) + if (!m->instance != !methods->instance) continue; if (!index--) break; @@ -546,7 +668,7 @@ emit_method_descriptions (methodlist_t *methods, const char *name, return 0; for (count = 0, m = methods->head; m; m = m->next) - if (!m->instance == !instance && m->def) + if (!m->instance == !instance) count++; if (!count) return 0; @@ -554,10 +676,9 @@ emit_method_descriptions (methodlist_t *methods, const char *name, methods->count = count; methods->instance = instance; - method_list_struct[1].type = array_type (&type_obj_method_description, - count); - return emit_structure (va ("_OBJ_%s_METHODS_%s", type, name), 's', - method_list_struct, 0, methods, sc_static); + method_list_struct[1].type = array_type (&type_method_description, count); + return emit_structure (va (0, "_OBJ_%s_METHODS_%s", type, name), 's', + method_list_struct, 0, methods, 0, sc_static); } void @@ -603,20 +724,27 @@ method_check_params (method_t *method, expr_t *args) arg_list[i--] = a; for (i = 2; i < count; i++) { expr_t *e = arg_list[i]; - type_t *t = get_type (e); + type_t *arg_type = mtype->t.func.param_types[i]; + type_t *t; - if (!t) + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (arg_type, e), e); + } + t = get_type (e); + if (!t) { return e; + } if (i < param_count) { - if (e->type != ex_nil) - if (!type_assignable (mtype->t.func.param_types[i], t)) { - err = param_mismatch (e, i - 1, method->name, - mtype->t.func.param_types[i], t); + if (e->type != ex_nil) { + if (!type_assignable (arg_type, t)) { + err = param_mismatch (e, i - 1, method->name, arg_type, t); } + } } else { - if (is_integer_val (e) && options.warnings.vararg_integer) + if (is_integer_val (e) && options.warnings.vararg_integer) { warning (e, "passing integer consant into ... function"); + } } } free (arg_list); diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 1c81381f1..a8e6ae5fb 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -31,6 +31,8 @@ # include "config.h" #endif +#define _GNU_SOURCE // for qsort_r + #ifdef HAVE_STRING_H # include #endif @@ -44,23 +46,23 @@ #include "QF/quakeio.h" #include "QF/va.h" -#include "codespace.h" -#include "debug.h" -#include "def.h" -#include "defspace.h" -#include "emit.h" -#include "expr.h" -#include "function.h" -#include "obj_file.h" -#include "obj_type.h" -#include "options.h" -#include "qfcc.h" -#include "reloc.h" -#include "statements.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static int count_relocs (reloc_t *r) @@ -181,6 +183,7 @@ qfo_count_stuff (qfo_t *qfo, pr_info_t *pr) qfo_count_space_stuff (qfo, pr->far_data); qfo_count_space_stuff (qfo, pr->entity_data); qfo_count_space_stuff (qfo, pr->type_data); + qfo_count_space_stuff (qfo, pr->debug_data); qfo_count_function_stuff (qfo, pr->func_head); qfo->num_relocs += count_relocs (pr->relocs); } @@ -188,11 +191,16 @@ qfo_count_stuff (qfo_t *qfo, pr_info_t *pr) static void qfo_init_string_space (qfo_t *qfo, qfo_mspace_t *space, strpool_t *strings) { + size_t size = strings->size * sizeof (*strings->strings); strings->qfo_space = space - qfo->spaces; space->type = qfos_string; space->num_defs = 0; space->defs = 0; - space->d.strings = strings->strings; + space->d.strings = 0; + if (strings->strings) { + space->d.strings = malloc (size); + memcpy (space->d.strings, strings->strings, size); + } space->data_size = strings->size; space->id = qfo_strings_space; } @@ -200,11 +208,16 @@ qfo_init_string_space (qfo_t *qfo, qfo_mspace_t *space, strpool_t *strings) static void qfo_init_code_space (qfo_t *qfo, qfo_mspace_t *space, codespace_t *code) { + size_t size = code->size * sizeof (*code->code); code->qfo_space = space - qfo->spaces; space->type = qfos_code; space->num_defs = 0; space->defs = 0; - space->d.code = code->code; + space->d.code = 0; + if (code->code) { + space->d.code = malloc (size); + memcpy (space->d.code, code->code, size); + } space->data_size = code->size; space->id = qfo_code_space; } @@ -213,11 +226,16 @@ static void qfo_init_data_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs, qfo_mspace_t *space, defspace_t *data) { + size_t size = data->size * sizeof (*data->data); data->qfo_space = space - qfo->spaces; space->type = qfos_data; space->defs = *defs; space->num_defs = qfo_encode_defs (qfo, data->defs, defs, relocs); - space->d.data = data->data; + space->d.data = 0; + if (data->data) { + space->d.data = malloc (size); + memcpy (space->d.data, data->data, size); + } space->data_size = data->size; } @@ -238,15 +256,38 @@ static void qfo_init_type_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs, qfo_mspace_t *space, defspace_t *data) { + size_t size = data->size * sizeof (*data->data); data->qfo_space = space - qfo->spaces; space->type = qfos_type; space->defs = *defs; space->num_defs = qfo_encode_defs (qfo, data->defs, defs, relocs); - space->d.data = data->data; + space->d.data = 0; + if (data->data) { + space->d.data = malloc (size); + memcpy (space->d.data, data->data, size); + } space->data_size = data->size; space->id = qfo_type_space; } +static void +qfo_init_debug_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs, + qfo_mspace_t *space, defspace_t *data) +{ + size_t size = data->size * sizeof (*data->data); + data->qfo_space = space - qfo->spaces; + space->type = qfos_debug; + space->defs = *defs; + space->num_defs = qfo_encode_defs (qfo, data->defs, defs, relocs); + space->d.data = 0; + if (data->data) { + space->d.data = malloc (size); + memcpy (space->d.data, data->data, size); + } + space->data_size = data->size; + space->id = qfo_debug_space; +} + static void qfo_encode_functions (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs, qfo_mspace_t *space, function_t *functions) @@ -311,6 +352,8 @@ qfo_from_progs (pr_info_t *pr) pr->entity_data); qfo_init_type_space (qfo, &def, &reloc, &qfo->spaces[qfo_type_space], pr->type_data); + qfo_init_debug_space (qfo, &def, &reloc, &qfo->spaces[qfo_debug_space], + pr->debug_data); qfo_encode_functions (qfo, &def, &reloc, qfo->spaces + qfo_num_spaces, pr->func_head); @@ -360,6 +403,8 @@ qfo_space_size (qfo_mspace_t *space) return 0; case qfos_type: return space->data_size * sizeof (*space->d.data); + case qfos_debug: + return space->data_size * sizeof (*space->d.data); } return 0; } @@ -385,6 +430,7 @@ qfo_byteswap_space (void *space, int size, qfos_type_t type) case qfos_data: case qfos_entity: case qfos_type: + case qfos_debug: for (val = (pr_type_t *) space, c = 0; c < size; c++, val++) val->integer_var = LittleLong (val->integer_var); break; @@ -394,9 +440,9 @@ qfo_byteswap_space (void *space, int size, qfos_type_t type) int qfo_write (qfo_t *qfo, const char *filename) { - int size; + unsigned size; int space_offset; - int i; + unsigned i; byte *data; qfo_header_t *header; qfo_space_t *spaces; @@ -408,8 +454,10 @@ qfo_write (qfo_t *qfo, const char *filename) QFile *file; file = Qopen (filename, options.gzip ? "wbz9" : "wb"); - if (!file) + if (!file) { + perror (va (0, "failed to open %s for writing", filename)); return -1; + } size = sizeof (qfo_header_t); size += sizeof (qfo_space_t) * qfo->num_spaces; @@ -499,7 +547,7 @@ qfo_read (QFile *file) qfo_header_t *header; qfo_space_t *spaces; qfo_t *qfo; - int i; + unsigned i; size = Qfilesize (file); data = malloc (size); @@ -605,9 +653,9 @@ qfo_delete (qfo_t *qfo) if (qfo->data) { free (qfo->data); } else { - int i; + unsigned i; for (i = 0; i < qfo->num_spaces; i++) - free (qfo->spaces->d.data); + free (qfo->spaces[i].d.data); free (qfo->relocs); free (qfo->defs); free (qfo->funcs); @@ -624,11 +672,12 @@ get_def_type (qfo_t *qfo, pointer_t type) if (type >= qfo->spaces[qfo_type_space].data_size) return ev_void; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); - switch ((ty_meta_e)type_def->ty) { - case ty_none: + switch ((ty_meta_e)type_def->meta) { + case ty_alias: //XXX + case ty_basic: // field, pointer and function types store their basic type in // the same location. - return type_def->t.type; + return type_def->type; case ty_struct: case ty_union: return ev_invalid; @@ -643,7 +692,7 @@ get_def_type (qfo_t *qfo, pointer_t type) return ev_invalid; } -static etype_t +static __attribute__((pure)) int get_type_size (qfo_t *qfo, pointer_t type) { qfot_type_t *type_def; @@ -651,19 +700,21 @@ get_type_size (qfo_t *qfo, pointer_t type) if (type >= qfo->spaces[qfo_type_space].data_size) return 1; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); - switch ((ty_meta_e)type_def->ty) { - case ty_none: + switch ((ty_meta_e)type_def->meta) { + case ty_alias: + return get_type_size (qfo, type_def->alias.aux_type); + case ty_basic: // field, pointer and function types store their basic type in // the same location. - return pr_type_size[type_def->t.type]; + return pr_type_size[type_def->type]; case ty_struct: - for (i = size = 0; i < type_def->t.strct.num_fields; i++) - size += get_type_size (qfo, type_def->t.strct.fields[i].type); + for (i = size = 0; i < type_def->strct.num_fields; i++) + size += get_type_size (qfo, type_def->strct.fields[i].type); return size; case ty_union: - for (i = size = 0; i < type_def->t.strct.num_fields; i++) { + for (i = size = 0; i < type_def->strct.num_fields; i++) { int s; - s = get_type_size (qfo, type_def->t.strct.fields[i].type); + s = get_type_size (qfo, type_def->strct.fields[i].type); if (s > size) size = s; } @@ -671,14 +722,72 @@ get_type_size (qfo_t *qfo, pointer_t type) case ty_enum: return pr_type_size[ev_integer]; case ty_array: - return type_def->t.array.size - * get_type_size (qfo, type_def->t.array.type); + return type_def->array.size + * get_type_size (qfo, type_def->array.type); case ty_class: return 0; // FIXME } return 0; } +int +qfo_log2 (unsigned x) +{ + int log2 = 0; + + while (x > 1) { + x >>= 1; + log2++; + } + return log2; +} + +static __attribute__((pure)) int +get_type_alignment_log (qfo_t *qfo, pointer_t type) +{ + qfot_type_t *type_def; + int i, alignment; + if (type >= qfo->spaces[qfo_type_space].data_size) + return 0; + type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); + switch ((ty_meta_e)type_def->meta) { + case ty_alias: + return get_type_alignment_log (qfo, type_def->alias.aux_type); + case ty_basic: + // field, pointer and function types store their basic type in + // the same location. + return qfo_log2 (ev_types[type_def->type]->alignment); + case ty_struct: + case ty_union: + for (i = alignment = 0; i < type_def->strct.num_fields; i++) { + qfot_var_t *field = type_def->strct.fields + i; + int a; + a = get_type_alignment_log (qfo, field->type); + if (a > alignment) { + alignment = a; + } + } + return alignment; + case ty_enum: + return qfo_log2 (ev_types[ev_integer]->alignment); + case ty_array: + return get_type_alignment_log (qfo, type_def->array.type); + case ty_class: + return 0; // FIXME + } + return 0; +} + +static __attribute__((pure)) dparmsize_t +get_parmsize (qfo_t *qfo, pointer_t type) +{ + dparmsize_t parmsize = { + get_type_size (qfo, type), + get_type_alignment_log (qfo, type), + }; + return parmsize; +} + static void function_params (qfo_t *qfo, qfo_func_t *func, dfunction_t *df) { @@ -689,17 +798,22 @@ function_params (qfo_t *qfo, qfo_func_t *func, dfunction_t *df) if (func->type >= qfo->spaces[qfo_type_space].data_size) return; type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type); - if (type->ty != ty_none && type->t.type != ev_func) + if (type->meta == ty_alias) { + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, + type->alias.aux_type); + } + if (type->meta != ty_basic || type->type != ev_func) return; - df->numparms = num_params = type->t.func.num_params; + df->numparms = num_params = type->func.num_params; if (num_params < 0) num_params = ~num_params; - for (i = 0; i < num_params; i++) - df->parm_size[i] = get_type_size (qfo, type->t.func.param_types[i]); + for (i = 0; i < num_params; i++) { + df->parm_size[i] = get_parmsize (qfo, type->func.param_types[i]); + } } static void -convert_def (qfo_t *qfo, const qfo_def_t *def, ddef_t *ddef) +qfo_def_to_ddef (qfo_t *qfo, const qfo_def_t *def, ddef_t *ddef) { ddef->type = get_def_type (qfo, def->type); ddef->ofs = def->offset; @@ -712,10 +826,20 @@ convert_def (qfo_t *qfo, const qfo_def_t *def, ddef_t *ddef) ddef->type |= DEF_SAVEGLOBAL; } +static void +qfo_def_to_prdef (qfo_t *qfo, const qfo_def_t *def, pr_def_t *prdef) +{ + prdef->type = get_def_type (qfo, def->type); + prdef->size = get_type_size (qfo, def->type); + prdef->ofs = def->offset; + prdef->name = def->name; + prdef->type_encoding = def->type; +} + static void qfo_relocate_refs (qfo_t *qfo) { - int i; + unsigned i; qfo_reloc_t *reloc; for (i = 0, reloc = qfo->relocs; i < qfo->num_relocs; i++, reloc++) { @@ -773,6 +897,25 @@ qfo_relocate_refs (qfo_t *qfo) } } +static unsigned +align_globals_size (unsigned size) +{ + if (options.code.progsversion == PROG_ID_VERSION) + return size; + return RUP (size, 16 / sizeof (pr_type_t)); +} + +static int +qfo_def_compare (const void *i1, const void *i2, void *d) +{ + __auto_type defs = (const qfo_def_t *) d; + unsigned ind1 = *(unsigned *) i1; + unsigned ind2 = *(unsigned *) i2; + const qfo_def_t *def1 = defs + ind1; + const qfo_def_t *def2 = defs + ind2; + return def1->offset - def2->offset; +} + dprograms_t * qfo_to_progs (qfo_t *qfo, int *size) { @@ -786,28 +929,39 @@ qfo_to_progs (qfo_t *qfo, int *size) pr_type_t *locals; pr_type_t *far_data; pr_type_t *type_data; + pr_type_t *xdef_data; dprograms_t *progs; qfo_def_t *types_def = 0; - int i, j; + qfo_def_t *xdefs_def = 0; + unsigned i, j; + unsigned near_data_size = 0; unsigned locals_size = 0; int locals_start; - int big_locals = 0; + int type_encodings_start; + int xdefs_start; + unsigned big_locals = 0; int big_func = 0; + pr_xdefs_t *xdefs = 0; + xdef_t *xdef; + unsigned *def_indices; + unsigned *far_def_indices; + unsigned *field_def_indices; *size = RUP (sizeof (dprograms_t), 16); progs = calloc (1, *size); progs->version = options.code.progsversion; progs->numstatements = qfo->spaces[qfo_code_space].data_size; progs->numglobaldefs = qfo->spaces[qfo_near_data_space].num_defs; - //FIXME ddef offsets are 16 bits + //ddef offsets are 16 bits so the ddef ofs will likely be invalid + //thus it will be forced invalid and the true offset written to the + //.xdefs array in the progs file progs->numglobaldefs += qfo->spaces[qfo_far_data_space].num_defs; progs->numfielddefs = qfo->spaces[qfo_entity_space].num_defs; progs->numfunctions = qfo->num_funcs + 1; progs->numstrings = qfo->spaces[qfo_strings_space].data_size; progs->numglobals = qfo->spaces[qfo_near_data_space].data_size; - progs->numglobals += qfo->spaces[qfo_far_data_space].data_size; - progs->numglobals += qfo->spaces[qfo_type_space].data_size; - locals_start = qfo->spaces[qfo_near_data_space].data_size; + progs->numglobals = align_globals_size (progs->numglobals); + locals_start = progs->numglobals; for (i = qfo_num_spaces; i < qfo->num_spaces; i++) { if (options.code.local_merging) { if (locals_size < qfo->spaces[i].data_size) { @@ -815,12 +969,21 @@ qfo_to_progs (qfo_t *qfo, int *size) big_locals = i; } } else { - locals_size += qfo->spaces[i].data_size; + locals_size += align_globals_size (qfo->spaces[i].data_size); } } progs->numglobals += locals_size; + near_data_size = progs->numglobals; progs->numglobals = RUP (progs->numglobals, 16 / sizeof (pr_type_t)); + progs->numglobals += qfo->spaces[qfo_far_data_space].data_size; + type_encodings_start = progs->numglobals; + progs->numglobals += qfo->spaces[qfo_type_space].data_size; + progs->numglobals = RUP (progs->numglobals, type_xdef.alignment); + xdefs_start = progs->numglobals; + progs->numglobals += progs->numglobaldefs * type_size (&type_xdef); + progs->numglobals += progs->numfielddefs * type_size (&type_xdef); progs->entityfields = qfo->spaces[qfo_entity_space].data_size; + // qfo_debug_space does not go in the progs file *size += progs->numstatements * sizeof (dstatement_t); *size += progs->numglobaldefs * sizeof (ddef_t); *size += progs->numfielddefs * sizeof (ddef_t); @@ -833,6 +996,29 @@ qfo_to_progs (qfo_t *qfo, int *size) memset (progs + 1, 0, *size - sizeof (dprograms_t)); data += RUP (sizeof (dprograms_t), 16); + def_indices = alloca ((progs->numglobaldefs + progs->numfielddefs) + * sizeof (*def_indices)); + far_def_indices = def_indices + qfo->spaces[qfo_near_data_space].num_defs; + field_def_indices = def_indices + progs->numglobaldefs; + for (unsigned i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { + def_indices[i] = i; + } + for (unsigned i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { + far_def_indices[i] = i; + } + for (unsigned i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { + field_def_indices[i] = i; + } + qsort_r (def_indices, qfo->spaces[qfo_near_data_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_near_data_space].defs); + qsort_r (far_def_indices, qfo->spaces[qfo_far_data_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_far_data_space].defs); + qsort_r (field_def_indices, qfo->spaces[qfo_entity_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_entity_space].defs); + progs->ofs_strings = data - (byte *) progs; strings = (char *) data; data += RUP (progs->numstrings * sizeof (char), 16); @@ -856,9 +1042,10 @@ qfo_to_progs (qfo_t *qfo, int *size) progs->ofs_globals = data - (byte *) progs; globals = (pr_type_t*) data; - locals = globals + qfo->spaces[qfo_near_data_space].data_size; - far_data = locals + locals_size; - type_data = far_data + qfo->spaces[qfo_far_data_space].data_size; + locals = globals + locals_start; + far_data = globals + near_data_size; + type_data = globals + type_encodings_start; + xdef_data = globals + xdefs_start; memcpy (strings, qfo->spaces[qfo_strings_space].d.strings, qfo->spaces[qfo_strings_space].data_size * sizeof (char)); @@ -880,7 +1067,7 @@ qfo_to_progs (qfo_t *qfo, int *size) for (j = 0; j < space->num_defs; j++) space->defs[j].offset += locals_start; if (!options.code.local_merging) - locals_start += df->locals; + locals_start += align_globals_size (df->locals); df->profile = 0; df->s_name = qf->name; df->s_file = qf->file; @@ -888,25 +1075,33 @@ qfo_to_progs (qfo_t *qfo, int *size) } for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { - qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; - if (!strcmp (QFO_GETSTR (qfo, def->name), ".type_encodings")) + unsigned ind = def_indices[i]; + qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + ind; + const char *defname = QFO_GETSTR (qfo, def->name); + if (!strcmp (defname, ".type_encodings")) types_def = def; - convert_def (qfo, def, globaldefs++); + if (!strcmp (defname, ".xdefs")) + xdefs_def = def; + qfo_def_to_ddef (qfo, def, globaldefs++); } - //FIXME ddef offsets are 16 bits for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { - qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; + unsigned ind = far_def_indices[i]; + qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + ind; def->offset += far_data - globals; - convert_def (qfo, def, globaldefs++); + qfo_def_to_ddef (qfo, def, globaldefs); + // the correct offset will be written to the far data space + globaldefs->ofs = -1; + globaldefs++; } for (i = 0; i < qfo->spaces[qfo_type_space].num_defs; i++) { - qfo->spaces[qfo_type_space].defs[i].offset += type_data - globals; + qfo->spaces[qfo_type_space].defs[i].offset += type_encodings_start; } for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { - convert_def (qfo, qfo->spaces[qfo_entity_space].defs + i, + unsigned ind = field_def_indices[i]; + qfo_def_to_ddef (qfo, qfo->spaces[qfo_entity_space].defs + ind, fielddefs + i); } @@ -914,7 +1109,7 @@ qfo_to_progs (qfo_t *qfo, int *size) memcpy (globals, qfo->spaces[qfo_near_data_space].d.data, qfo->spaces[qfo_near_data_space].data_size * sizeof (pr_type_t)); qfo->spaces[qfo_near_data_space].d.data = globals; - // lcear locals data + // clear locals data memset (locals, 0, locals_size * sizeof (pr_type_t)); // copy far data memcpy (far_data, qfo->spaces[qfo_far_data_space].d.data, @@ -929,9 +1124,33 @@ qfo_to_progs (qfo_t *qfo, int *size) if (types_def) { qfot_type_encodings_t *encodings; encodings = (qfot_type_encodings_t *) &globals[types_def->offset]; - encodings->types = type_data - globals; + encodings->types = type_encodings_start; encodings->size = qfo->spaces[qfo_type_space].data_size; } + if (xdefs_def) { + xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; + xdef = (xdef_t *) xdef_data; + xdefs->xdefs = xdefs_start; + xdefs->num_xdefs = progs->numglobaldefs + progs->numfielddefs; + for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; + i++, xdef++) { + qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; + } + for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; + i++, xdef++) { + qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; + } + for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; + i++, xdef++) { + qfo_def_t *def = qfo->spaces[qfo_entity_space].defs + i; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; + } + } // undo the relocation of the offsets of local defs so the local defs have // the correct offset in the debug info @@ -949,20 +1168,23 @@ qfo_to_progs (qfo_t *qfo, int *size) if (options.verbosity >= 0) { const char *big_function = ""; if (big_func) - big_function = va (" (%s)", strings + qfo->funcs[big_func].name); + big_function = va (0, " (%s)", strings + qfo->funcs[big_func].name); printf ("%6i strofs\n", progs->numstrings); printf ("%6i statements\n", progs->numstatements); printf ("%6i functions\n", progs->numfunctions); printf ("%6i global defs\n", progs->numglobaldefs); - printf ("%6i fielddefs\n", progs->numfielddefs); + printf ("%6i field defs\n", progs->numfielddefs); printf ("%6i globals\n", progs->numglobals); - printf (" %6i near globals\n", - qfo->spaces[qfo_near_data_space].data_size + locals_size); + printf (" %6i near globals\n", near_data_size); printf (" %6i locals size%s\n", locals_size, big_function); printf (" %6i far globals\n", qfo->spaces[qfo_far_data_space].data_size); printf (" %6i type globals\n", qfo->spaces[qfo_type_space].data_size); + if (xdefs) { + printf (" %6i extended defs\n", + xdefs->num_xdefs * type_size (&type_xdef)); + } printf ("%6i entity fields\n", progs->entityfields); } @@ -976,11 +1198,12 @@ pr_debug_header_t * qfo_to_sym (qfo_t *qfo, int *size) { pr_debug_header_t *sym; - int i, j; + unsigned i, j; pr_auxfunction_t *auxfuncs; pr_auxfunction_t *aux; pr_lineno_t *linenos; - ddef_t *locals, *ld; + pr_def_t *locals, *ld, *debug_defs; + pr_type_t *debug_data; *size = sizeof (pr_debug_header_t); sym = calloc (1, *size); @@ -988,7 +1211,7 @@ qfo_to_sym (qfo_t *qfo, int *size) sym->version = PROG_DEBUG_VERSION; for (i = 0; i < qfo->num_funcs; i++) { qfo_func_t *func = qfo->funcs + i; - int num_locals = 0; + unsigned num_locals = 0; if (func->locals_space) num_locals = qfo->spaces[func->locals_space].num_defs; @@ -998,26 +1221,34 @@ qfo_to_sym (qfo_t *qfo, int *size) sym->num_locals += num_locals; } sym->num_linenos = qfo->num_lines; + sym->num_debug_defs = qfo->spaces[qfo_debug_space].num_defs; + sym->debug_data_size = qfo->spaces[qfo_debug_space].data_size; *size += sym->num_auxfunctions * sizeof (pr_auxfunction_t); *size += sym->num_linenos * sizeof (pr_lineno_t); - *size += sym->num_locals * sizeof (ddef_t); + *size += sym->num_locals * sizeof (pr_def_t); + *size += sym->num_debug_defs * sizeof (pr_def_t); + *size += sym->debug_data_size * sizeof (pr_type_t); sym = realloc (sym, *size); auxfuncs = (pr_auxfunction_t *)(sym + 1); linenos = (pr_lineno_t *)(auxfuncs + sym->num_auxfunctions); - locals = (ddef_t *)(linenos + sym->num_linenos); + locals = (pr_def_t *)(linenos + sym->num_linenos); + debug_defs = locals + sym->num_locals; + debug_data = (pr_type_t *)(debug_defs + sym->num_debug_defs); sym->auxfunctions = (char *) auxfuncs - (char *) sym; sym->linenos = (char *) linenos - (char *) sym; sym->locals = (char *) locals - (char *) sym; + sym->debug_defs = (char *) debug_defs - (char *) sym; + sym->debug_data = (char *) debug_data - (char *) sym; ld = locals; for (i = 0, aux = auxfuncs; i < qfo->num_funcs; i++) { qfo_func_t *func = qfo->funcs + i; qfo_def_t *def = 0; - int num_locals = 0; + unsigned num_locals = 0; qfot_type_t *type; if (func->locals_space) { @@ -1034,15 +1265,27 @@ qfo_to_sym (qfo_t *qfo, int *size) qfo->lines[func->line_info].fa.func = aux - auxfuncs; if (num_locals) { aux->local_defs = ld - locals; - for (j = 0; j < num_locals; j++) - convert_def (qfo, def++, ld++); + for (j = 0; j < num_locals; j++, def++, ld++) { + qfo_def_to_prdef (qfo, def, ld); + } } aux->num_locals = num_locals; //FIXME check type type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type); - aux->return_type = type->t.func.return_type; + if (type->meta == ty_alias) { + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, + type->alias.aux_type); + } + aux->return_type = type->func.return_type; aux++; } memcpy (linenos, qfo->lines, qfo->num_lines * sizeof (pr_lineno_t)); + for (i = 0; i < sym->num_debug_defs; i++) { + qfo_def_t *def = &qfo->spaces[qfo_debug_space].defs[i]; + pr_def_t *prdef = &debug_defs[i]; + qfo_def_to_prdef (qfo, def, prdef); + } + memcpy (debug_data, qfo->spaces[qfo_debug_space].d.data, + sym->debug_data_size * sizeof (*debug_data)); return sym; } diff --git a/tools/qfcc/source/obj_type.c b/tools/qfcc/source/obj_type.c index 2b77a864f..7f87e43df 100644 --- a/tools/qfcc/source/obj_type.c +++ b/tools/qfcc/source/obj_type.c @@ -42,16 +42,16 @@ #include "compat.h" -#include "class.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "obj_type.h" -#include "qfcc.h" -#include "reloc.h" -#include "symtab.h" -#include "value.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/value.h" #define ENC_DEF(dest,def) EMIT_DEF (pr.type_data, dest, def) #define ENC_STR(dest,str) \ @@ -63,7 +63,7 @@ reloc_def_string (&loc); \ } while (0) -typedef def_t *(*encode_f) (type_t *type); +typedef def_t *(*encode_f) (type_t *type, defspace_t *space); static string_t encoding_string (const char *string) @@ -75,26 +75,26 @@ encoding_string (const char *string) } static def_t * -qfo_new_encoding (type_t *type, int size) +qfo_new_encoding (type_t *type, int size, defspace_t *space) { qfot_type_t *enc; def_t *def; - size += sizeof (qfot_type_t) - sizeof (enc->t); + size += field_offset (qfot_type_t, type); size /= sizeof (pr_type_t); - def = new_def (type->encoding, 0, pr.type_data, sc_static); + def = new_def (type->encoding, 0, space, sc_static); def->offset = defspace_alloc_loc (pr.type_data, size); enc = D_POINTER (qfot_type_t, def); - enc->ty = type->meta; + enc->meta = type->meta; enc->size = size; ENC_STR (enc->encoding, type->encoding); return def; } static def_t * -qfo_encode_func (type_t *type) +qfo_encode_func (type_t *type, defspace_t *space) { int param_count; int size; @@ -109,14 +109,15 @@ qfo_encode_func (type_t *type) if (param_count < 0) param_count = ~param_count; param_type_defs = alloca (param_count * sizeof (def_t *)); - return_type_def = qfo_encode_type (type->t.func.type); + return_type_def = qfo_encode_type (type->t.func.type, space); for (i = 0; i < param_count; i++) - param_type_defs[i] = qfo_encode_type (type->t.func.param_types[i]); + param_type_defs[i] = qfo_encode_type (type->t.func.param_types[i], + space); size = field_offset (qfot_func_t, param_types[param_count]); - def = qfo_new_encoding (type, size); + def = qfo_new_encoding (type, size, space); enc = D_POINTER (qfot_type_t, def); - func = &enc->t.func; + func = &enc->func; func->type = ev_func; ENC_DEF (func->return_type, return_type_def); func->num_params = type->t.func.num_params; @@ -126,39 +127,39 @@ qfo_encode_func (type_t *type) } static def_t * -qfo_encode_fldptr (type_t *type) +qfo_encode_fldptr (type_t *type, defspace_t *space) { qfot_type_t *enc; def_t *def; def_t *type_def; - type_def = qfo_encode_type (type->t.fldptr.type); - def = qfo_new_encoding (type, sizeof (enc->t.fldptr)); + type_def = qfo_encode_type (type->t.fldptr.type, space); + def = qfo_new_encoding (type, sizeof (enc->fldptr), space); enc = D_POINTER (qfot_type_t, def); - enc->t.fldptr.type = type->type; - ENC_DEF (enc->t.fldptr.aux_type, type_def); + enc->fldptr.type = type->type; + ENC_DEF (enc->fldptr.aux_type, type_def); return def; } static def_t * -qfo_encode_none (type_t *type) +qfo_encode_basic (type_t *type, defspace_t *space) { qfot_type_t *enc; def_t *def; if (type->type == ev_func) - return qfo_encode_func (type); + return qfo_encode_func (type, space); else if (type->type == ev_pointer || type->type == ev_field) - return qfo_encode_fldptr (type); + return qfo_encode_fldptr (type, space); - def = qfo_new_encoding (type, sizeof (enc->t.type)); + def = qfo_new_encoding (type, sizeof (enc->type), space); enc = D_POINTER (qfot_type_t, def); - enc->t.type = type->type; + enc->type = type->type; return def; } static def_t * -qfo_encode_struct (type_t *type) +qfo_encode_struct (type_t *type, defspace_t *space) { sy_type_e sy; int num_fields; @@ -185,9 +186,9 @@ qfo_encode_struct (type_t *type) } size = field_offset (qfot_struct_t, fields[num_fields]); - def = qfo_new_encoding (type, size); + def = qfo_new_encoding (type, size, space); enc = D_POINTER (qfot_type_t, def); - strct = &enc->t.strct; + strct = &enc->strct; ENC_STR (strct->tag, type->name); strct->num_fields = num_fields; @@ -200,7 +201,7 @@ qfo_encode_struct (type_t *type) if (i == num_fields) internal_error (0, "whoa, what happened?"); if (type->meta != ty_enum) { - field_types[i] = qfo_encode_type (sym->type); + field_types[i] = qfo_encode_type (sym->type, space); } else { field_types[i] = type_default->type_def; } @@ -225,46 +226,69 @@ qfo_encode_struct (type_t *type) } static def_t * -qfo_encode_array (type_t *type) +qfo_encode_array (type_t *type, defspace_t *space) { qfot_type_t *enc; def_t *def; def_t *array_type_def; - array_type_def = qfo_encode_type (type->t.array.type); + array_type_def = qfo_encode_type (type->t.array.type, space); - def = qfo_new_encoding (type, sizeof (enc->t.array)); + def = qfo_new_encoding (type, sizeof (enc->array), space); enc = D_POINTER (qfot_type_t, def); - ENC_DEF (enc->t.array.type, array_type_def); - enc->t.array.base = type->t.array.base; - enc->t.array.size = type->t.array.size; + ENC_DEF (enc->array.type, array_type_def); + enc->array.base = type->t.array.base; + enc->array.size = type->t.array.size; return def; } static def_t * -qfo_encode_class (type_t *type) +qfo_encode_class (type_t *type, defspace_t *space) { qfot_type_t *enc; def_t *def; - def = qfo_new_encoding (type, sizeof (enc->t.class)); + def = qfo_new_encoding (type, sizeof (enc->class), space); enc = D_POINTER (qfot_type_t, def); - ENC_STR (enc->t.class, type->t.class->name); + ENC_STR (enc->class, type->t.class->name); + return def; +} + +static def_t * +qfo_encode_alias (type_t *type, defspace_t *space) +{ + qfot_type_t *enc; + def_t *def; + def_t *type_def; + def_t *full_def; + + type_def = qfo_encode_type (type->t.alias.aux_type, space); + full_def = qfo_encode_type (type->t.alias.full_type, space); + + def = qfo_new_encoding (type, sizeof (enc->alias), space); + enc = D_POINTER (qfot_type_t, def); + enc->alias.type = type->type; + ENC_DEF (enc->alias.aux_type, type_def); + ENC_DEF (enc->alias.full_type, full_def); + if (type->name) { + ENC_STR (enc->alias.name, type->name); + } return def; } def_t * -qfo_encode_type (type_t *type) +qfo_encode_type (type_t *type, defspace_t *space) { reloc_t *relocs = 0; static encode_f funcs[] = { - qfo_encode_none, // ty_none + qfo_encode_basic, // ty_basic qfo_encode_struct, // ty_struct qfo_encode_struct, // ty_union qfo_encode_struct, // ty_enum qfo_encode_array, // ty_array qfo_encode_class, // ty_class + qfo_encode_alias, // ty_alias }; if (type->type_def && type->type_def->external) { @@ -274,11 +298,11 @@ qfo_encode_type (type_t *type) } if (type->type_def) return type->type_def; - if (type->meta > ty_class) + if (type->meta >= sizeof (funcs) / (sizeof (funcs[0]))) internal_error (0, "bad type meta type"); if (!type->encoding) type->encoding = type_get_encoding (type); - type->type_def = funcs[type->meta] (type); + type->type_def = funcs[type->meta] (type, space); reloc_attach_relocs (relocs, &type->type_def->relocs); return type->type_def; } diff --git a/tools/qfcc/source/opcodes.c b/tools/qfcc/source/opcodes.c index 4d8bb4678..a9bda7a3c 100644 --- a/tools/qfcc/source/opcodes.c +++ b/tools/qfcc/source/opcodes.c @@ -41,11 +41,11 @@ #include -#include "opcodes.h" -#include "options.h" -#include "qfcc.h" -#include "statements.h" -#include "type.h" +#include "tools/qfcc/include/opcodes.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/type.h" hashtab_t *opcode_type_table; hashtab_t *opcode_void_table; @@ -102,9 +102,9 @@ opcode_find (const char *name, operand_t *op_a, operand_t *op_b, int i; search_op.name = name; - search_op.type_a = op_a ? op_a->type : ev_invalid; - search_op.type_b = op_b ? op_b->type : ev_invalid; - search_op.type_c = op_c ? op_c->type : ev_invalid; + search_op.type_a = op_a ? low_level_type (op_a->type) : ev_invalid; + search_op.type_b = op_b ? low_level_type (op_b->type) : ev_invalid; + search_op.type_c = op_c ? low_level_type (op_c->type) : ev_invalid; op = Hash_FindElement (opcode_type_table, &search_op); if (op) return op; @@ -131,16 +131,17 @@ opcode_free (void *_op, void *unused) void opcode_init (void) { - opcode_t *op, *mop; + const opcode_t *op; + opcode_t *mop; if (opcode_type_table) { Hash_FlushTable (opcode_void_table); Hash_FlushTable (opcode_type_table); } else { PR_Opcode_Init (); - opcode_type_table = Hash_NewTable (1021, 0, opcode_free, 0); + opcode_type_table = Hash_NewTable (1021, 0, opcode_free, 0, 0); Hash_SetHashCompare (opcode_type_table, get_hash, compare); - opcode_void_table = Hash_NewTable (1021, get_key, 0, 0); + opcode_void_table = Hash_NewTable (1021, get_key, 0, 0, 0); } for (op = pr_opcodes; op->name; op++) { if (op->min_version > options.code.progsversion) diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index 4edb03623..09989684c 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -45,11 +45,11 @@ #include "QF/pr_comp.h" #include "QF/va.h" -#include "cpp.h" -#include "linker.h" -#include "options.h" -#include "qfcc.h" -#include "strpool.h" +#include "tools/qfcc/include/cpp.h" +#include "tools/qfcc/include/linker.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/strpool.h" const char *this_program; const char **source_files; @@ -69,11 +69,13 @@ enum { OPT_PROGDEFS, OPT_QCCX_ESCAPES, OPT_TRADITIONAL, + OPT_BUG, }; static struct option const long_options[] = { {"advanced", no_argument, 0, OPT_ADVANCED}, {"block-dot", optional_argument, 0, OPT_BLOCK_DOT}, + {"bug", required_argument, 0, OPT_BUG}, {"code", required_argument, 0, 'C'}, {"cpp", required_argument, 0, OPT_CPP}, {"define", required_argument, 0, 'D'}, @@ -92,7 +94,6 @@ static struct option const long_options[] = { {"relocatable", no_argument, 0, 'r'}, {"save-temps", no_argument, 0, 'S'}, {"source", required_argument, 0, 's'}, - {"strip-path", required_argument, 0, 'p'}, {"traditional", no_argument, 0, OPT_TRADITIONAL}, {"undefine", required_argument, 0, 'U'}, {"verbose", no_argument, 0, 'v'}, @@ -118,7 +119,6 @@ static const char *short_options = "o:" // output file "O" // optimize "P:" // progs.src name - "p:" // strip path "q" // quiet "r" // partial linking "S" // save temps @@ -139,6 +139,7 @@ usage (int status) "Options:\n" " --advanced Advanced Ruamoko mode\n" " default for separate compilation mode\n" +" --bug OPTION,... Set bug options\n" " -C, --code OPTION,... Set code generation options\n" " -c Only compile, don't link\n" " --cpp CPPSPEC cpp execution command line\n" @@ -163,8 +164,6 @@ usage (int status) " -o, --output-file FILE Specify output file name\n" " --progdefs Genderate progdefs.h\n" " -P, --progs-src FILE File to use instead of progs.src\n" -" -p, --strip-path NUM Strip NUM leading path elements from file\n" -" names\n" " --qccx-escapes Use QCCX escape sequences instead of standard\n" " C/QuakeForge sequences.\n" " -q, --quiet Inhibit usual output\n" @@ -191,14 +190,16 @@ code_usage (void) printf ("%s - QuakeForge Code Compiler\n", this_program); printf ("Code generation options\n"); printf ( +" [no-]const-initializers Treat initialized globals as constants.\n" " [no-]cow Allow assignment to initialized globals.\n" " [no-]cpp Preprocess all input files with cpp.\n" " [no-]crc Write progdefs.h crc to progs.dat.\n" " [no-]debug Generate debug information.\n" " [no-]fast-float Use float values directly in \"if\" statements.\n" -" help Display his text.\n" +" help Display this text.\n" " [no-]local-merging Merge the local variable blocks into one.\n" " [no-]optimize Perform various optimizations on the code.\n" +" [no-]promote-float Promote float when passed through ...\n" " [no-]short-circuit Generate short circuit code for logical\n" " operators.\n" " [no-]single-cpp Convert progs.src to cpp input file.\n" @@ -264,6 +265,21 @@ notice_usage (void) exit (0); } +static void +bug_usage (void) +{ + printf ("%s - QuakeForge Code Compiler\n", this_program); + printf ("Bug options\n"); + printf ( +" help Display his text.\n" +" none Turn off all bugs (don't we wish: messages).\n" +" die Change bugs to internal errors.\n" +"\n" +"This is a developer feature and thus not in the manual page\n" + ); + exit (0); +} + static void add_file (const char *file) { @@ -281,6 +297,8 @@ DecodeArgs (int argc, char **argv) int c; int saw_E = 0, saw_MD = 0; + add_cpp_undef ("-undef"); + add_cpp_undef ("-nostdinc"); add_cpp_def ("-D__QFCC__=1"); add_cpp_def ("-D__QUAKEC__=1"); @@ -289,6 +307,7 @@ DecodeArgs (int argc, char **argv) options.code.vector_components = -1; options.code.crc = -1; options.code.fast_float = true; + options.code.promote_float = true; options.warnings.uninited_variable = true; options.warnings.unused = true; options.warnings.executable = true; @@ -302,7 +321,6 @@ DecodeArgs (int argc, char **argv) options.single_cpp = true; options.save_temps = false; options.verbosity = 0; - options.strip_path = 0; sourcedir = ""; progs_src = "progs.src"; @@ -323,7 +341,7 @@ DecodeArgs (int argc, char **argv) } break; case 'l': // lib file - add_file (va ("-l%s", NORMALIZE (optarg))); + add_file (va (0, "-l%s", NORMALIZE (optarg))); break; case 'L': linker_add_path (NORMALIZE (optarg)); @@ -341,9 +359,6 @@ DecodeArgs (int argc, char **argv) case 'P': // progs-src progs_src = save_string (NORMALIZE (optarg)); break; - case 'p': - options.strip_path = atoi (optarg); - break; case 'F': options.files_dat = true; break; @@ -372,16 +387,19 @@ DecodeArgs (int argc, char **argv) options.traditional = 1; options.advanced = false; options.code.progsversion = PROG_ID_VERSION; + options.code.const_initializers = true; break; case OPT_TRADITIONAL: options.traditional = 2; options.advanced = false; options.code.progsversion = PROG_ID_VERSION; + options.code.const_initializers = true; break; case OPT_ADVANCED: options.traditional = 0; options.advanced = true; options.code.progsversion = PROG_VERSION; + options.code.const_initializers = false; break; case OPT_BLOCK_DOT: if (optarg) { @@ -411,6 +429,8 @@ DecodeArgs (int argc, char **argv) options.block_dot.flow = flag; } else if (!(strcasecmp (temp, "reaching"))) { options.block_dot.reaching = flag; + } else if (!(strcasecmp (temp, "statements"))) { + options.block_dot.statements = flag; } else if (!(strcasecmp (temp, "live"))) { options.block_dot.live = flag; } else if (!(strcasecmp (temp, "post"))) { @@ -428,6 +448,7 @@ DecodeArgs (int argc, char **argv) options.block_dot.expr = true; options.block_dot.flow = true; options.block_dot.reaching = true; + options.block_dot.statements = true; options.block_dot.live = true; options.block_dot.post = true; } @@ -462,6 +483,8 @@ DecodeArgs (int argc, char **argv) options.code.debug = flag; } else if (!(strcasecmp (temp, "fast-float"))) { options.code.fast_float = flag; + } else if (!(strcasecmp (temp, "promote-float"))) { + options.code.promote_float = flag; } else if (!strcasecmp (temp, "help")) { code_usage (); } else if (!(strcasecmp (temp, "local-merging"))) { @@ -483,6 +506,8 @@ DecodeArgs (int argc, char **argv) options.code.progsversion = PROG_ID_VERSION; else options.code.progsversion = PROG_VERSION; + } else if (!(strcasecmp (temp, "const-initializers"))) { + options.code.const_initializers = flag; } temp = strtok (NULL, ","); } @@ -587,6 +612,23 @@ DecodeArgs (int argc, char **argv) free (opts); } break; + case OPT_BUG:{ + char *opts = strdup (optarg); + char *temp = strtok (opts, ","); + + while (temp) { + if (!strcasecmp (temp, "help")) { + bug_usage (); + } else if (!(strcasecmp (temp, "none"))) { + options.bug.silent = true; + } else if (!(strcasecmp (temp, "die"))) { + options.bug.promote = true; + } + temp = strtok (NULL, ","); + } + free (opts); + } + break; case OPT_CPP: // --cpp= cpp_name = save_string (optarg); break; @@ -670,8 +712,11 @@ DecodeArgs (int argc, char **argv) options.code.local_merging = true; if (options.code.vector_components == (qboolean) -1) options.code.vector_components = false; + } else { + options.code.promote_float = 0; } if (options.code.progsversion == PROG_ID_VERSION) { + options.code.promote_float = 0; add_cpp_def ("-D__VERSION6__=1"); if (options.code.crc == (qboolean) -1) options.code.crc = true; @@ -682,7 +727,8 @@ DecodeArgs (int argc, char **argv) // add the default paths if (!options.no_default_paths) { - add_cpp_def (nva ("-I%s", QFCC_INCLUDE_PATH)); + add_cpp_sysinc ("-isystem"); + add_cpp_sysinc (QFCC_INCLUDE_PATH); linker_add_path (QFCC_LIB_PATH); } diff --git a/tools/qfcc/source/pragma.c b/tools/qfcc/source/pragma.c index c5e8e816d..d82f2aef4 100644 --- a/tools/qfcc/source/pragma.c +++ b/tools/qfcc/source/pragma.c @@ -39,13 +39,24 @@ #endif #include +#include "QF/alloc.h" #include "QF/pr_comp.h" -#include "diagnostic.h" -#include "opcodes.h" -#include "options.h" -#include "pragma.h" -#include "type.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/opcodes.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/pragma.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/type.h" + +typedef struct pragma_arg_s { + struct pragma_arg_s *next; + const char *arg; +} pragma_arg_t; + +static pragma_arg_t *pragma_args_freelist; +static pragma_arg_t *pragma_args; +static pragma_arg_t **pragma_args_tail = &pragma_args; static void set_traditional (int traditional) @@ -73,20 +84,58 @@ set_traditional (int traditional) opcode_init (); // reset the opcode table } -void -pragma (const char *id) +static void +set_bug (pragma_arg_t *args) { + if (!args) { + warning (0, "missing bug flag"); + return; + } + const char *flag = args->arg; + if (!strcmp (flag, "none")) { + options.bug.silent = true; + } else if (!strcmp (flag, "!none")) { + options.bug.silent = false; + } else if (!strcmp (flag, "die")) { + options.bug.promote = true; + } else if (!strcmp (flag, "!die")) { + options.bug.promote = false; + } + if (args->next) { + warning (0, "pragma bug: ignoring extra arguments"); + } +} + +void +pragma_process () +{ + if (!pragma_args) { + warning (0, "empty pragma"); + return; + } + const char *id = pragma_args->arg; if (!strcmp (id, "traditional")) { set_traditional (2); - return; - } - if (!strcmp (id, "extended")) { + } else if (!strcmp (id, "extended")) { set_traditional (1); - return; - } - if (!strcmp (id, "advanced")) { + } else if (!strcmp (id, "advanced")) { set_traditional (0); - return; + } else if (!strcmp (id, "bug")) { + set_bug (pragma_args->next); + } else { + warning (0, "unknown pragma: '%s'", id); } - warning (0, "unknown pragma: %s", id); + *pragma_args_tail = pragma_args_freelist; + pragma_args_tail = &pragma_args; + pragma_args = 0; +} + +void +pragma_add_arg (const char *id) +{ + pragma_arg_t *arg; + ALLOC (16, pragma_arg_t, pragma_args, arg); + arg->arg = save_string (id); + *pragma_args_tail = arg; + pragma_args_tail = &arg->next; } diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 7d190cb48..50e54817d 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -45,22 +45,22 @@ #include #include -#include "class.h" -#include "debug.h" -#include "diagnostic.h" -#include "expr.h" -#include "grab.h" -#include "options.h" -#include "pragma.h" -#include "qfcc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/grab.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/pragma.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" -#include "qc-parse.h" +#include "tools/qfcc/source/qc-parse.h" #ifndef YY_PROTO # define YY_PROTO(x) x @@ -72,6 +72,13 @@ #define YY_DECL int yylex YY_PROTO(( void )) YY_DECL; +int yyget_lineno (void) __attribute__((pure)); +int yyget_leng (void) __attribute__((pure)); +int yywrap (void) __attribute__((const)); +char *yyget_text (void) __attribute__((pure)); +int yyget_debug (void) __attribute__((pure)); +FILE *yyget_in (void) __attribute__((pure)); +FILE *yyget_out (void) __attribute__((pure)); static int keyword_or_id (char *token); @@ -86,6 +93,8 @@ B [01] X [0-9a-fA-F] ID [a-zA-Z_][a-zA-Z_0-9]* FLOAT ({D}+|{D}*\.{D}+|{D}+\.{D}*)([eE]{m}?{D}+)? +FLOATf {FLOAT}[fF] +FLOATd {FLOAT}[dD] INT ({D}+|0[xX]{X}+|0[bB]{B}) RANGE \.\. ELLIPSIS \.\.\. @@ -129,10 +138,36 @@ STRING \"(\\.|[^"\\])*\" } {FLOAT} { + // advanced code defaults to double, but traditional + // and extended code defaults to float + if (options.traditional < 1) { + double d = strtod (yytext, 0); + qc_yylval.expr = new_double_expr (d); + qc_yylval.expr->implicit = 1; + } else { + float f = strtof (yytext, 0); + qc_yylval.expr = new_float_expr (f); + } + return VALUE; + } +{FLOATf} { float f = strtof (yytext, 0); qc_yylval.expr = new_float_expr (f); return VALUE; } +{FLOATd} { + // advanced code defaults to double, but traditional + // and extended code defaults to float + if (options.traditional < 1) { + double d = strtod (yytext, 0); + qc_yylval.expr = new_double_expr (d); + } else { + float f = strtof (yytext, 0); + qc_yylval.expr = new_float_expr (f); + warning (0, "truncating double constant to float"); + } + return VALUE; + } {ID} { int tok = keyword_or_id(yytext); @@ -182,6 +217,11 @@ STRING \"(\\.|[^"\\])*\" return ASX; } +"%%=" { + qc_yylval.op = MOD; + return ASX; + } + "<<=" { qc_yylval.op = SHL; return ASX; @@ -197,6 +237,11 @@ STRING \"(\\.|[^"\\])*\" return yytext[0]; } +"%%" { + qc_yylval.pointer = 0; // ensure pointer vals are null + return MOD; + } + {ELLIPSIS} return ELLIPSIS; "<<" return SHL; @@ -238,9 +283,12 @@ STRING \"(\\.|[^"\\])*\" write_frame_macros (s); BEGIN (GRAB_OTHER); // ignore rest of line } -{ID} { pragma (yytext); } +{ID} { pragma_add_arg (yytext); } <*>\r*\n { + if (YY_START == PRAGMA) { + pragma_process (); + } pr.source_line++; BEGIN (INITIAL); } @@ -271,8 +319,8 @@ typedef struct { static keyword_t obj_keywords[] = { {"id", OBJECT, &type_id }, {"Class", TYPE, &type_Class }, - {"Method", TYPE, &type_obj_method}, - {"Super", TYPE, &type_obj_super }, + {"Method", TYPE, &type_method }, + {"Super", TYPE, &type_super }, {"SEL", TYPE, &type_SEL }, {"IMP", TYPE, &type_IMP }, @@ -305,6 +353,7 @@ static keyword_t obj_keywords[] = { // make the language features available to traditional code. static keyword_t at_keywords[] = { {"for", FOR }, + {"goto", GOTO }, {"break", BREAK }, {"continue", CONTINUE}, {"switch", SWITCH }, @@ -326,10 +375,11 @@ static keyword_t at_keywords[] = { // be supported (sanely) by v6 progs. static keyword_t qf_keywords[] = { {"quaternion", TYPE, &type_quaternion}, + {"double", TYPE, &type_double}, {"int", TYPE, &type_integer }, {"unsigned", TYPE, &type_integer },//FIXME - {"function", TYPE, &type_function }, + {"@function", TYPE, &type_function }, {"@args", ARGS, 0 }, {"@va_list", TYPE, &type_va_list }, {"@param", TYPE, &type_param }, @@ -389,10 +439,10 @@ keyword_or_id (char *token) if (!keyword_tab) { size_t i; - keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0); - qf_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0); - at_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0); - obj_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0); + keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); + qf_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); + at_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); + obj_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); #define NUMKEYS(_k) (sizeof (_k) / sizeof (_k[0])) @@ -442,6 +492,8 @@ keyword_or_id (char *token) #ifdef YY_FLEX_REALLOC_HACK static __attribute__ ((used)) void *(*const yy_flex_realloc_hack)(void *,yy_size_t) = yy_flex_realloc; #else +#ifdef yyunput static __attribute__ ((used)) void (*yyunput_hack)(int, char*) = yyunput; +#endif static __attribute__ ((used)) int (*input_hack)(void) = input; #endif diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 2ab9d4144..32161c4b7 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -42,25 +42,26 @@ #include #include +#include -#include "class.h" -#include "debug.h" -#include "def.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "function.h" -#include "method.h" -#include "options.h" -#include "qfcc.h" -#include "reloc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "switch.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/switch.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" #define YYDEBUG 1 #define YYERROR_VERBOSE 1 @@ -97,6 +98,7 @@ int yylex (void); void *pointer; // for ensuring pointer values are null struct type_s *type; struct expr_s *expr; + struct element_s *element; struct function_s *function; struct switch_block_s *switch_block; struct param_s *param; @@ -122,7 +124,7 @@ int yylex (void); %nonassoc STORAGEX %left COMMA -%right '=' ASX PAS /* pointer assign */ +%right '=' ASX %right '?' ':' %left OR %left AND @@ -135,7 +137,7 @@ int yylex (void); %left SHL SHR %left '+' '-' -%left '*' '/' '%' +%left '*' '/' '%' MOD %right SIZEOF UNARY INCOP %left HYPERUNARY %left '.' '(' '[' @@ -144,8 +146,8 @@ int yylex (void); %token VALUE STRING %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS -%token NIL IFBE IFB IFAE IFA SWITCH CASE DEFAULT ENUM TYPEDEF -%token ARGS EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT +%token NIL IFBE IFB IFAE IFA GOTO SWITCH CASE DEFAULT ENUM +%token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT %token STRUCT %token TYPE %token OBJECT TYPE_NAME @@ -153,7 +155,7 @@ int yylex (void); %token PROTECTED PROTOCOL PUBLIC SELECTOR REFERENCE SELF THIS %type optional_specifiers specifiers local_specifiers -%type storage_class save_storage +%type storage_class save_storage set_spec_storage %type type_specifier type_specifier_or_storage_class %type type @@ -180,18 +182,22 @@ int yylex (void); %type methoddef %type opt_initializer var_initializer local_def -%type opt_expr fexpr expr element_list element vector_expr -%type optional_state_expr texpr +%type opt_init opt_expr comma_expr expr +%type compound_init element_list +%type element +%type optional_state_expr texpr vector_expr %type statement statements compound_statement -%type else label break_label continue_label -%type unary_expr cast_expr opt_arg_list arg_list +%type else bool_label break_label continue_label +%type unary_expr ident_expr cast_expr expr_list +%type opt_arg_list arg_list arg_expr +%type init_var_decl_list init_var_decl %type switch_block -%type identifier +%type identifier label %type overloaded_identifier %type identifier_list -%type selector reserved_word +%type protocol_name_list selector reserved_word %type optional_param_list unaryselector keyworddecl %type keywordselector %type methodproto methoddecl @@ -252,6 +258,44 @@ spec_merge (specifier_t spec, specifier_t new) return spec; } +static specifier_t +default_type (specifier_t spec, symbol_t *sym) +{ + if (!spec.type) { + spec.type = type_default; + warning (0, "type defaults to '%s' in declaration of '%s'", + type_default->name, sym->name); + } + return spec; +} + +static int +is_anonymous_struct (specifier_t spec) +{ + if (spec.sym) { + return 0; + } + if (!is_struct (spec.type)) { + return 0; + } + if (!spec.type->t.symtab || spec.type->t.symtab->parent) { + return 0; + } + // struct and union type names always begin with "tag ". Untagged s/u + // are "tag ..". + if (spec.type->name[4] != '.') { + return 0; + } + return 1; +} + +static int +is_null_spec (specifier_t spec) +{ + static specifier_t null_spec; + return memcmp (&spec, &null_spec, sizeof (spec)) == 0; +} + %} %expect 0 @@ -300,18 +344,39 @@ external_def_list external_def : optional_specifiers external_decl_list ';' { } - | optional_specifiers ';' { } + | optional_specifiers ';' + { + if (!is_null_spec ($1)) { + if (!$1.type && !$1.sym) { + warning (0, "useless specifiers"); + } else if ($1.type && !$1.sym) { + if (is_anonymous_struct ($1)){ + warning (0, "unnamed struct/union that defines " + "no instances"); + } else if (!is_enum ($1.type) && !is_struct ($1.type)) { + warning (0, "useless type name in empty declaration"); + } + } else if (!$1.type && $1.sym) { + bug (0, "wha? %p %p", $1.type, $1.sym); + } else { + bug (0, "wha? %p %p", $1.type, $1.sym); + } + } + } | optional_specifiers qc_func_params { type_t **type; + type_t *ret_type; $$ = $1; // copy spec bits and storage // .float () foo; is a field holding a function variable rather // than a function that returns a float field. - for (type = &$$.type; *type && (*type)->type == ev_field; - type = &(*type)->t.fldptr.type) - ; - *type = parse_params (*type, $2); - $$.type = find_type ($$.type); + for (type = &$1.type; *type && (*type)->type == ev_field; + type = &(*type)->t.fldptr.type) { + } + ret_type = *type; + *type = 0; + *type = parse_params (0, $2); + $$.type = find_type (append_type ($1.type, ret_type)); if ($$.type->type != ev_field) $$.params = $2; } @@ -337,6 +402,14 @@ save_storage } ; +set_spec_storage + : /* emtpy */ + { + $$ = $0; + $$.storage = current_storage; + } + ; + function_body : optional_state_expr { @@ -382,57 +455,44 @@ external_decl_list external_decl : var_decl { - specifier_t spec = $0; - type_t *type; - - if (!spec.type) - spec.type = type_default; - type = find_type (append_type ($1->type, spec.type)); + specifier_t spec = default_type ($0, $1); + $1->type = find_type (append_type ($1->type, spec.type)); if (spec.is_typedef) { - $1->type = type; $1->sy_type = sy_type; + $1->type=find_type (alias_type ($1->type, $1->type, $1->name)); symtab_addsymbol (current_symtab, $1); } else { - initialize_def ($1, type, 0, current_symtab->space, - spec.storage); + initialize_def ($1, 0, current_symtab->space, spec.storage); if ($1->s.def) $1->s.def->nosave |= spec.nosave; } } | var_decl var_initializer { - specifier_t spec = $0; - type_t *type; + specifier_t spec = default_type ($0, $1); - if (!spec.type) - spec.type = type_default; - type = find_type (append_type ($1->type, spec.type)); + $1->type = find_type (append_type ($1->type, spec.type)); if (spec.is_typedef) { error (0, "typedef %s is initialized", $1->name); - $1->type = type; $1->sy_type = sy_type; + $1->type=find_type (alias_type ($1->type, $1->type, $1->name)); symtab_addsymbol (current_symtab, $1); } else { - initialize_def ($1, type, $2, current_symtab->space, - spec.storage); + initialize_def ($1, $2, current_symtab->space, spec.storage); if ($1->s.def) $1->s.def->nosave |= spec.nosave; } } | function_decl { - specifier_t spec = $0; - if (!spec.type) - spec.type = type_default; + specifier_t spec = default_type ($0, $1); $1->type = find_type (append_type ($1->type, spec.type)); if (spec.is_typedef) { $1->sy_type = sy_type; + $1->type=find_type (alias_type ($1->type, $1->type, $1->name)); symtab_addsymbol (current_symtab, $1); } else { $1 = function_symbol ($1, spec.is_overload, 1); - // things might be a confused mess from earlier errors - if ($1->sy_type == sy_func) - make_function ($1, 0, $1->table->space, spec.storage); } } ; @@ -474,6 +534,15 @@ specifiers type : type_specifier | type type_specifier + { + // deal with eg "int id" + $1.sym = $2.sym; + + if (!$1.sym) { + error (0, "two or more data types in declaration specifiers"); + } + $$ = $1; + } ; type_specifier_or_storage_class @@ -491,6 +560,7 @@ type_specifier | TYPE_NAME { $$ = make_spec ($1->type, 0, 0, 0); + $$.sym = $1; } | OBJECT protocolrefs { @@ -502,6 +572,7 @@ type_specifier } else { $$ = make_spec (&type_id, 0, 0, 0); } + $$.sym = $1; } | CLASS_NAME protocolrefs { @@ -513,6 +584,7 @@ type_specifier } else { $$ = make_spec ($1->type, 0, 0, 0); } + $$.sym = $1; } // NOTE: fields don't parse the way they should. This is not a problem // for basic types, but functions need special treatment @@ -554,6 +626,7 @@ optional_enum_list enum_list : '{' enum_init enumerator_list optional_comma '}' { + current_symtab = current_symtab->parent; $$ = finish_enum ($3); } ; @@ -563,6 +636,7 @@ enum_init { $$ = find_enum ($-1); start_enum ($$); + current_symtab = $$->type->t.symtab; } ; @@ -578,7 +652,7 @@ enumerator_list enumerator : identifier { add_enum ($0, $1, 0); } - | identifier '=' fexpr { add_enum ($0, $1, $3); } + | identifier '=' expr { add_enum ($0, $1, $3); } ; struct_specifier @@ -586,8 +660,22 @@ struct_specifier { symbol_t *sym; sym = find_struct ($1, $2, 0); - if (!sym->table) + if (!sym->table) { symtab_addsymbol (current_symtab, sym); + } else { + if (!sym->type) { + internal_error (0, "broken structure symbol?"); + } + if (sym->type->meta == ty_enum + || (sym->type->meta == ty_struct && sym->type->t.symtab)) { + error (0, "%s %s redefined", + $1 == 's' ? "struct" : "union", $2->name); + $1 = 0; + } else if (sym->type->meta != ty_struct) { + internal_error (0, "%s is not a struct or union", + $2->name); + } + } current_symtab = new_symtab (current_symtab, stab_local); } struct_defs '}' @@ -596,10 +684,12 @@ struct_specifier symtab_t *symtab = current_symtab; current_symtab = symtab->parent; - sym = build_struct ($1, $2, symtab, 0); - $$ = make_spec (sym->type, 0, 0, 0); - if (!sym->table) - symtab_addsymbol (current_symtab, sym); + if ($1) { + sym = build_struct ($1, $2, symtab, 0); + $$ = make_spec (sym->type, 0, 0, 0); + if (!sym->table) + symtab_addsymbol (current_symtab, sym); + } } | STRUCT tag { @@ -617,7 +707,7 @@ struct_defs | DEFS '(' identifier ')' { $3 = check_undefined ($3); - if (!$3->type || !obj_is_class ($3->type)) { + if (!$3->type || !is_class ($3->type)) { error (0, "`%s' is not a class", $3->name); } else { // replace the struct symbol table with one built from @@ -637,6 +727,35 @@ struct_def_list struct_def : type struct_decl_list | type + { + if ($1.sym && $1.sym->type != $1.type) { + // a type name (id, typedef, etc) was used as a field name. + // this is allowed in C + $1.sym = new_symbol ($1.sym->name); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else if (is_anonymous_struct ($1)) { + // anonymous struct/union + // type->name always begins with "tag " + $1.sym = new_symbol (va (0, ".anonymous.%s", + $1.type->name + 4)); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + $1.sym->visibility = vis_anonymous; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else { + // bare type + warning (0, "declaration does not declare anything"); + } + $$ = $1; + } ; struct_decl_list @@ -650,17 +769,25 @@ struct_decl { if (!$0.type) $0.type = type_default; - $1->type = append_type ($1->type, $0.type); - $1->type = find_type ($1->type); + $1->type = find_type (append_type ($1->type, $0.type)); + $1->sy_type = sy_var; + $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); + if (!$1->table) { + error (0, "duplicate field `%s'", $1->name); + } } | var_decl { if (!$0.type) $0.type = type_default; - $1->type = append_type ($1->type, $0.type); - $1->type = find_type ($1->type); + $1->type = find_type (append_type ($1->type, $0.type)); + $1->sy_type = sy_var; + $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); + if (!$1->table) { + error (0, "duplicate field `%s'", $1->name); + } } | var_decl ':' expr %prec COMMA {} | ':' expr %prec COMMA {} @@ -735,7 +862,7 @@ qc_func_params | '(' ps qc_var_list ')' { $$ = check_params ($3); } | '(' ps TYPE ')' { - if ($3 != &type_void) + if (!is_void ($3)) PARSE_ERROR; $$ = 0; } @@ -789,6 +916,7 @@ abstract_decl $1.type = type_default; $$->type = find_type (append_type ($$->type, $1.type)); } + | error { $$ = new_symbol (""); } ; qc_param_decl @@ -838,9 +966,8 @@ abs_decl ; array_decl - : '[' fexpr ']' + : '[' expr ']' { - $2 = fold_constants ($2); if (!is_integer_val ($2) || expr_integer ($2) < 1) { error (0, "invalid array size"); $$ = 0; @@ -903,19 +1030,16 @@ decl : function_decl {} | var_decl opt_initializer { - specifier_t spec = $0; - type_t *type; - storage_class_t sc = $0.storage; + specifier_t spec = default_type ($0, $1); + storage_class_t sc = spec.storage; struct defspace_s *space = current_symtab->space; - if (!spec.type) - spec.type = type_default; if (sc == sc_static) space = pr.near_data; - type = find_type (append_type ($1->type, spec.type)); - initialize_def ($1, type, $2, space, sc); + $1->type = find_type (append_type ($1->type, spec.type)); + initialize_def ($1, $2, space, sc); if ($1->s.def) - $1->s.def->nosave |= $0.nosave; + $1->s.def->nosave |= spec.nosave; } ; @@ -966,18 +1090,29 @@ overloaded_identifier ; non_code_func - : '=' '#' fexpr + : '=' '#' expr { + if ($-1.storage == sc_extern) { + error (0, "initializing external variable"); + } build_builtin_function ($0, $3, 0); } - | '=' fexpr + | '=' expr { - symbol_t *sym = $0; - specifier_t spec = $-1; - initialize_def (sym, sym->type, $2, current_symtab->space, - spec.storage); - if (sym->s.def) - sym->s.def->nosave |= spec.nosave; + if (local_expr) { + symbol_t *sym = $0; + specifier_t spec = $-1; + initialize_def (sym, $2, current_symtab->space, spec.storage); + if (sym->s.def) + sym->s.def->nosave |= spec.nosave; + } else { + if (is_integer_val ($2) || is_float_val ($2)) { + error (0, "invalid function initializer." + " did you forget #?"); + } else { + error (0, "cannot create global function variables"); + } + } } | /* emtpy */ { @@ -988,8 +1123,7 @@ non_code_func if (sym->sy_type == sy_func) make_function (sym, 0, sym->table->space, spec.storage); } else { - initialize_def (sym, sym->type, 0, current_symtab->space, - spec.storage); + initialize_def (sym, 0, current_symtab->space, spec.storage); if (sym->s.def) sym->s.def->nosave |= spec.nosave; } @@ -1020,8 +1154,19 @@ opt_initializer ; var_initializer - : '=' fexpr { $$ = $2; } - | '=' '{' element_list optional_comma '}' { $$ = $3; } + : '=' expr { $$ = $2; } + | '=' compound_init + { + if (!$2 && is_scalar ($-1.type)) { + error (0, "empty scalar initializer"); + } + $$ = $2 ? $2 : new_nil_expr (); + } + ; + +compound_init + : '{' element_list optional_comma '}' { $$ = $2; } + | '{' '}' { $$ = 0; } ; optional_state_expr @@ -1032,18 +1177,18 @@ optional_state_expr element_list : element { - $$ = new_block_expr (); - append_expr ($$, $1); + $$ = new_compound_init (); + append_element ($$, $1); } - | element_list ',' element + | element_list ',' element { - append_expr ($$, $3); + append_element ($$, $3); } ; element - : '{' element_list optional_comma '}' { $$ = $2; } - | fexpr { $$ = $1; } + : compound_init { $$ = new_element ($1, 0); } + | expr { $$ = new_element ($1, 0); } ; optional_comma @@ -1051,22 +1196,28 @@ optional_comma | ',' ; -compound_statement - : '{' +push_scope + : /* empty */ { if (!options.traditional) { current_symtab = new_symtab (current_symtab, stab_local); current_symtab->space = current_symtab->parent->space; } } - statements '}' + ; + +pop_scope + : /* empty */ { if (!options.traditional) current_symtab = current_symtab->parent; - $$ = $3; } ; +compound_statement + : '{' push_scope statements '}' pop_scope { $$ = $3; } + ; + statements : /*empty*/ { @@ -1092,6 +1243,26 @@ local_def local_expr = 0; (void) ($2); } + | specifiers ';' + { + if (!is_null_spec ($1)) { + if (!$1.type && !$1.sym) { + warning (0, "useless specifiers"); + } else if ($1.type && !$1.sym) { + if (is_anonymous_struct ($1)){ + warning (0, "unnamed struct/union that defines " + "no instances"); + } else if (!is_enum ($1.type) && !is_struct ($1.type)) { + warning (0, "useless type name in empty declaration"); + } + } else if (!$1.type && $1.sym) { + bug (0, "wha? %p %p", $1.type, $1.sym); + } else { + bug (0, "wha? %p %p", $1.type, $1.sym); + } + } + $$ = 0; + } ; statement @@ -1099,10 +1270,8 @@ statement | error ';' { $$ = 0; yyerrok; } | compound_statement { $$ = $1; } | local_def { $$ = $1; } - | RETURN opt_expr ';' - { - $$ = return_expr (current_func, $2); - } + | RETURN opt_expr ';' { $$ = return_expr (current_func, $2); } + | RETURN compound_init ';' { $$ = return_expr (current_func, $2); } | BREAK ';' { $$ = 0; @@ -1119,7 +1288,11 @@ statement else error (0, "continue outside of loop"); } - | CASE fexpr ':' + | label + { + $$ = named_label_expr ($1); + } + | CASE expr ':' { $$ = case_label_expr (switch_block, $2); } @@ -1127,12 +1300,17 @@ statement { $$ = case_label_expr (switch_block, 0); } - | SWITCH break_label '(' fexpr switch_block ')' compound_statement + | SWITCH break_label '(' expr switch_block ')' compound_statement { $$ = switch_expr (switch_block, break_label, $7); switch_block = $5; break_label = $2; } + | GOTO NAME + { + expr_t *label = named_label_expr ($2); + $$ = goto_expr (label); + } | IF not '(' texpr ')' statement %prec IFX { $$ = build_if_statement ($2, $4, $6, 0, 0); @@ -1141,13 +1319,16 @@ statement { $$ = build_if_statement ($2, $4, $6, $7, $8); } - | FOR break_label continue_label - '(' opt_expr ';' opt_expr ';' opt_expr ')' statement + | FOR push_scope break_label continue_label + '(' opt_init ';' opt_expr ';' opt_expr ')' statement pop_scope { - $$ = build_for_statement ($5, $7, $9, $11, + if ($6) { + $6 = build_block_expr ($6); + } + $$ = build_for_statement ($6, $8, $10, $12, break_label, continue_label); - break_label = $2; - continue_label = $3; + break_label = $3; + continue_label = $4; } | WHILE break_label continue_label not '(' texpr ')' statement { @@ -1163,7 +1344,7 @@ statement break_label = $2; continue_label = $3; } - | fexpr ';' + | comma_expr ';' { $$ = $1; } @@ -1183,6 +1364,10 @@ else ; label + : NAME ':' + ; + +bool_label : /* empty */ { $$ = new_label_expr (); @@ -1214,8 +1399,40 @@ switch_block } ; +opt_init + : comma_expr + | type set_spec_storage init_var_decl_list { $$ = $3; } + | /* empty */ + { + $$ = 0; + } + ; + +init_var_decl_list + : init_var_decl + { + $$ = $1; + } + | init_var_decl_list ',' { $$ = $0; } init_var_decl + { + $4->next = $1; + $$ = $4; + } + ; + +init_var_decl + : var_decl opt_initializer + { + specifier_t spec = $0; + $1->type = find_type (append_type ($1->type, spec.type)); + $1->sy_type = sy_var; + initialize_def ($1, 0, current_symtab->space, spec.storage); + $$ = assign_expr (new_symbol_expr ($1), $2); + } + ; + opt_expr - : fexpr + : comma_expr | /* empty */ { $$ = 0; @@ -1231,6 +1448,7 @@ unary_expr | '(' expr ')' { $$ = $2; $$->paren = 1; } | unary_expr '(' opt_arg_list ')' { $$ = function_expr ($1, $3); } | unary_expr '[' expr ']' { $$ = array_expr ($1, $3); } + | unary_expr '.' ident_expr { $$ = field_expr ($1, $3); } | unary_expr '.' unary_expr { $$ = field_expr ($1, $3); } | INCOP unary_expr { $$ = incop_expr ($1, $2, 0); } | unary_expr INCOP { $$ = incop_expr ($2, $1, 1); } @@ -1249,8 +1467,14 @@ unary_expr | obj_expr { $$ = $1; } ; +ident_expr + : OBJECT { $$ = new_symbol_expr ($1); } + | CLASS_NAME { $$ = new_symbol_expr ($1); } + | TYPE_NAME { $$ = new_symbol_expr ($1); } + ; + vector_expr - : '[' fexpr ',' arg_list ']' + : '[' expr ',' expr_list ']' { expr_t *t = $4; while (t->next) @@ -1271,10 +1495,11 @@ cast_expr expr : cast_expr | expr '=' expr { $$ = assign_expr ($1, $3); } + | expr '=' compound_init { $$ = assign_expr ($1, $3); } | expr ASX expr { $$ = asx_expr ($2, $1, $3); } | expr '?' expr ':' expr { $$ = conditional_expr ($1, $3, $5); } - | expr AND label expr { $$ = bool_expr (AND, $3, $1, $4); } - | expr OR label expr { $$ = bool_expr (OR, $3, $1, $4); } + | expr AND bool_label expr { $$ = bool_expr (AND, $3, $1, $4); } + | expr OR bool_label expr { $$ = bool_expr (OR, $3, $1, $4); } | expr EQ expr { $$ = binary_expr (EQ, $1, $3); } | expr NE expr { $$ = binary_expr (NE, $1, $3); } | expr LE expr { $$ = binary_expr (LE, $1, $3); } @@ -1291,14 +1516,32 @@ expr | expr '|' expr { $$ = binary_expr ('|', $1, $3); } | expr '^' expr { $$ = binary_expr ('^', $1, $3); } | expr '%' expr { $$ = binary_expr ('%', $1, $3); } - ; - -fexpr - : expr { $$ = fold_constants ($1); } + | expr MOD expr { $$ = binary_expr (MOD, $1, $3); } ; texpr - : fexpr { $$ = convert_bool ($1, 1); } + : expr { $$ = convert_bool ($1, 1); } + ; + +comma_expr + : expr_list + { + if ($1->next) { + expr_t *res = $1; + $1 = build_block_expr ($1); + $1->e.block.result = res; + } + $$ = $1; + } + ; + +expr_list + : expr + | expr_list ',' expr + { + $3->next = $1; + $$ = $3; + } ; opt_arg_list @@ -1307,14 +1550,19 @@ opt_arg_list ; arg_list - : fexpr - | arg_list ',' fexpr + : arg_expr + | arg_list ',' arg_expr { $3->next = $1; $$ = $3; } ; +arg_expr + : expr + | compound_init + ; + const : VALUE | NIL { $$ = new_nil_expr (); } @@ -1338,6 +1586,7 @@ identifier obj_def : classdef { } | classdecl + | protocoldecl | protocoldef | { if (!current_class) PARSE_ERROR; } methoddef | END @@ -1376,9 +1625,13 @@ classdecl class_name : identifier %prec CLASS_NOT_CATEGORY { - $1 = check_undefined ($1); - if (!$1->type || !obj_is_class ($1->type)) { - error (0, "`%s' is not a class %p", $1->name, $1->type); + if (!$1->type) { + $$ = get_class ($1, 1); + if (!$1->table) { + symtab_addsymbol (current_symtab, $1); + } + } else if (!is_class ($1->type)) { + error (0, "`%s' is not a class", $1->name); $$ = get_class (0, 1); } else { $$ = $1->type->t.class; @@ -1399,6 +1652,7 @@ new_class_name $1 = check_redefined ($1); $$ = get_class ($1, 1); } + $$->interface_declared = 1; current_class = &$$->class_type; if (!$1->table) symtab_addsymbol (current_symtab, $1); @@ -1417,6 +1671,12 @@ class_with_super new_class_with_super : new_class_name ':' class_name { + if (!$3->interface_declared) { + $3->interface_declared = 1; + error (0, "cannot find interface declaration for `%s', " + "superclass of `%s'", $3->name, $1->name); + } + $1->interface_declared = 1; $1->super_class = $3; $$ = $1; } @@ -1465,17 +1725,18 @@ category_reference } ; - protocol_name : identifier { $$ = get_protocol ($1->name, 0); - if ($$) { - error (0, "redefinition of %s", $1->name); + if ($$ && $$->methods) { + error (0, "redefinition of protocol %s", $1->name); $$ = get_protocol (0, 1); - } else { + } + if (!$$) { $$ = get_protocol ($1->name, 1); } + $$->methods = new_methodlist (); current_class = &$$->class_type; } ; @@ -1568,18 +1829,33 @@ classdef | REFERENCE category_reference ';' { } ; +protocoldecl + : protocol + protocol_name_list ';' + { + while ($2) { + get_protocol ($2->name, 1); + $2 = $2->next; + } + } + ; + protocoldef - : PROTOCOL { $$ = current_class; } + : protocol protocol_name - protocolrefs { protocol_add_protocols ($3, $4); $$ = 0; } - methodprotolist { protocol_add_methods ($3, $6); } + protocolrefs { protocol_add_protocols ($2, $3); $$ = 0; } + methodprotolist { protocol_add_methods ($2, $5); } END { - current_class = $2; - (void) ($5); + current_class = $1; + (void) ($4); } ; +protocol + : PROTOCOL { $$ = current_class; } + ; + protocolrefs : /* emtpy */ { $$ = 0; } | LT { $$ = new_protocol_list (); } @@ -1622,6 +1898,7 @@ ivar_decl_list tab = $$->parent; // preserve the ivars inheritance chain build_struct ('s', 0, $$, 0); $$->parent = tab; + current_visibility = vis_public; } ; @@ -1643,6 +1920,25 @@ ivar_decls ivar_decl : type ivars + | type + { + if (is_anonymous_struct ($1)) { + // anonymous struct/union + // type->name always begins with "tag " + $1.sym = new_symbol (va (0, ".anonymous.%s", + $1.type->name + 4)); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + $1.sym->visibility = vis_anonymous; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else { + // bare type + warning (0, "declaration does not declare anything"); + } + } ; ivars @@ -1727,6 +2023,10 @@ methodproto $2->instance = 0; $$ = $2; } + | '-' error ';' + { $$ = new_method (&type_id, new_param ("", 0, 0), 0); } + | '+' error ';' + { $$ = new_method (&type_id, new_param ("", 0, 0), 0); } | '-' methoddecl ';' { $2->instance = 1; @@ -1751,8 +2051,7 @@ optional_param_list | ',' param_list { $$ = $2; } | ',' param_list ',' ELLIPSIS { - $$ = new_param (0, 0, 0); - $$->next = $2; + $$ = param_append_identifiers ($2, 0, 0); } ; @@ -1765,6 +2064,10 @@ keywordselector | keywordselector keyworddecl { $2->next = $1; $$ = $2; } ; +protocol_name_list + : identifier + | protocol_name_list ',' identifier { $3->next = $1; $$ = $3; } + selector : NAME { $$ = $1; } | CLASS_NAME { $$ = $1; } @@ -1817,7 +2120,7 @@ obj_messageexpr ; receiver - : fexpr + : expr | CLASS_NAME { $$ = new_symbol_expr ($1); diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index fdf455b5d..1a8406186 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -65,31 +65,31 @@ #include #include -#include "qfcc.h" -#include "class.h" -#include "codespace.h" -#include "cpp.h" -#include "debug.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "function.h" -#include "grab.h" -#include "idstuff.h" -#include "linker.h" -#include "method.h" -#include "obj_file.h" -#include "opcodes.h" -#include "options.h" -#include "reloc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/cpp.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/grab.h" +#include "tools/qfcc/include/idstuff.h" +#include "tools/qfcc/include/linker.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/opcodes.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" options_t options; @@ -137,10 +137,21 @@ InitData (void) if (pr.code) { codespace_delete (pr.code); strpool_delete (pr.strings); + defspace_delete (pr.near_data); + defspace_delete (pr.far_data); + defspace_delete (pr.entity_data); + defspace_delete (pr.type_data); + defspace_delete (pr.debug_data); + strpool_delete (pr.comp_file_set); } - if (pr.linenos) + if (pr.comp_files.a) { + DARRAY_CLEAR (&pr.comp_files); + } + + if (pr.linenos) { free (pr.linenos); + } memset (&pr, 0, sizeof (pr)); pr.source_line = 1; @@ -148,6 +159,9 @@ InitData (void) pr.code = codespace_new (); memset (codespace_newstatement (pr.code), 0, sizeof (dstatement_t)); pr.strings = strpool_new (); + if (options.code.promote_float) { + ReuseString ("@float_promoted@"); + } pr.num_functions = 1; pr.num_linenos = 0; @@ -165,20 +179,23 @@ InitData (void) pr.type_data = defspace_new (ds_backed); defspace_alloc_loc (pr.type_data, 4);// reserve space for a null descriptor + pr.debug_data = defspace_new (ds_backed); + pr.comp_file_set = strpool_new (); + DARRAY_INIT (&pr.comp_files, 16); + pr.symtab = new_symtab (0, stab_global); pr.symtab->space = pr.near_data; current_symtab = pr.symtab; pr.entity_data = defspace_new (ds_virtual); pr.entity_fields = new_symtab (0, stab_global); - pr.entity_fields->space = pr.entity_data;; + pr.entity_fields->space = pr.entity_data; clear_functions (); clear_frame_macros (); clear_classes (); clear_immediates (); clear_selectors (); - chain_initial_types (); } static int @@ -249,12 +266,16 @@ WriteSym (pr_debug_header_t *sym, int size) pr_auxfunction_t *auxfunctions; pr_lineno_t *linenos; - ddef_t *locals; + pr_def_t *locals; + pr_def_t *debug_defs; + pr_type_t *debug_data; #define P(t,o) ((t *)((char *)sym + sym->o)) auxfunctions = P (pr_auxfunction_t, auxfunctions); linenos = P (pr_lineno_t, linenos); - locals = P (ddef_t, locals); + locals = P (pr_def_t, locals); + debug_defs = P (pr_def_t, debug_defs); + debug_data = P (pr_type_t, debug_data); #undef P for (i = 0; i < sym->num_auxfunctions; i++) { @@ -273,8 +294,20 @@ WriteSym (pr_debug_header_t *sym, int size) } for (i = 0; i < sym->num_locals; i++) { locals[i].type = LittleShort (locals[i].type); - locals[i].ofs = LittleShort (locals[i].ofs); - locals[i].s_name = LittleLong (locals[i].s_name); + locals[i].size = LittleShort (locals[i].size); + locals[i].ofs = LittleLong (locals[i].ofs); + locals[i].name = LittleLong (locals[i].name); + locals[i].type_encoding = LittleLong (locals[i].type_encoding); + } + for (i = 0; i < sym->num_debug_defs; i++) { + debug_defs[i].type = LittleShort (debug_defs[i].type); + debug_defs[i].size = LittleShort (debug_defs[i].size); + debug_defs[i].ofs = LittleLong (debug_defs[i].ofs); + debug_defs[i].name = LittleLong (debug_defs[i].name); + debug_defs[i].type_encoding = LittleLong (debug_defs[i].type_encoding); + } + for (i = 0; i < sym->debug_data_size; i++) { + debug_data[i].integer_var = LittleLong (debug_data[i].integer_var); } if (!(h = Qopen (options.debug_file, "wb"))) @@ -295,23 +328,7 @@ begin_compilation (void) } const char * -strip_path (const char *filename) -{ - const char *p = filename; - int i = options.strip_path; - - while (i-- > 0) { - while (*p && *p != '/') - p++; - if (!*p) - break; - filename = ++p; - } - return filename; -} - -static const char * -file_basename (const char *filename) +file_basename (const char *filename, int keepdot) { const char *p; const char *dot; @@ -322,7 +339,7 @@ file_basename (const char *filename) for (dot = p = filename + strlen (filename); p > filename; p--) { if (p[-1] == '/' || p[-1] == '\\') break; - if (p[0] == '.') + if (!keepdot && p[0] == '.') dot = p; } dstring_copysubstr (base, p, dot - p); @@ -381,8 +398,10 @@ compile_to_obj (const char *file, const char *obj, lang_t lang) return !options.preprocess_only; InitData (); + chain_initial_types (); begin_compilation (); - pr.source_file = ReuseString (strip_path (file)); + pr.comp_dir = save_cwd (); + add_source_file (file); err = yyparse () || pr.error_count; fclose (*yyin); if (cpp_name && !options.save_temps) { @@ -391,14 +410,20 @@ compile_to_obj (const char *file, const char *obj, lang_t lang) exit (1); } } - write_frame_macros (va ("%s.frame", file_basename (file))); + if (options.frames_files) { + write_frame_macros (va (0, "%s.frame", file_basename (file, 0))); + } if (!err) { qfo_t *qfo; class_finish_module (); - qfo = qfo_from_progs (&pr); - err = qfo_write (qfo, obj); - qfo_delete (qfo); + err = pr.error_count; + if (!err) { + debug_finish_module (obj); + qfo = qfo_from_progs (&pr); + err = qfo_write (qfo, obj); + qfo_delete (qfo); + } } return err; } @@ -415,8 +440,12 @@ finish_link (void) flags = (QFOD_GLOBAL | QFOD_CONSTANT | QFOD_INITIALIZED | QFOD_NOSAVE); if (options.code.progsversion != PROG_ID_VERSION) { pr_int_t param_size = type_size (&type_param); + pr_int_t param_alignment = qfo_log2 (type_param.alignment); linker_add_def (".param_size", &type_integer, flags, ¶m_size); + linker_add_def (".param_alignment", &type_integer, flags, + ¶m_alignment); + linker_add_def (".xdefs", &type_xdefs, flags, 0); } if (options.code.debug) { @@ -436,7 +465,12 @@ finish_link (void) } else { int size; dprograms_t *progs; + pr_debug_header_t *sym = 0; + int sym_size = 0; + if (options.code.debug) { + sym = qfo_to_sym (qfo, &sym_size); + } progs = qfo_to_progs (qfo, &size); //finish_compilation (); @@ -450,9 +484,6 @@ finish_link (void) WriteProgs (progs, size); if (options.code.debug) { - pr_debug_header_t *sym; - int sym_size = 0; - sym = qfo_to_sym (qfo, &sym_size); sym->crc = CRC_Block ((byte *) progs, size); WriteSym (sym, sym_size); } @@ -460,7 +491,7 @@ finish_link (void) return 0; } -static lang_t +static __attribute__((pure)) lang_t file_language (const char *file, const char *ext) { static ext_lang_t ext_lang[] = { @@ -535,6 +566,7 @@ separate_compile (void) dstring_delete (extension); if (!err && !options.compile) { InitData (); + chain_initial_types (); linker_begin (); for (file = source_files; *file; file++) { if (strncmp (*file, "-l", 2)) { @@ -589,6 +621,14 @@ load_file (const char *fname) return src; } +/** Parse a cpp line number directive. + + Parses a cpp line directive of the form "# 1 file", setting the line and + file fields of \a script. "#line 1 file" is supported, too. + + \param script the script being parsed + \param filename storage for the parsed filename +*/ static void parse_cpp_line (script_t *script, dstring_t *filename) { @@ -618,7 +658,7 @@ compile_file (const char *filename) if (!*yyin) return !options.preprocess_only; - pr.source_file = ReuseString (strip_path (filename)); + add_source_file (filename); pr.source_line = 1; clear_frame_macros (); err = yyparse () || pr.error_count; @@ -704,6 +744,7 @@ progs_src_compile (void) setup_sym_file (options.output_file); InitData (); + chain_initial_types (); begin_compilation (); @@ -731,12 +772,15 @@ progs_src_compile (void) fprintf (single, "#include \"%s\"\n", qc_filename->str); if (options.frames_files) fprintf (single, "$frame_write \"%s.frame\"\n", - file_basename (qc_filename->str)); + file_basename (qc_filename->str, 0)); } else { if (compile_file (qc_filename->str)) return 1; - write_frame_macros (va ("%s.frame", - file_basename (qc_filename->str))); + if (options.frames_files) { + write_frame_macros (va (0, "%s.frame", + file_basename (qc_filename->str, + 0))); + } } if (!Script_TokenAvailable (script, 0)) break; @@ -758,6 +802,7 @@ progs_src_compile (void) } class_finish_module (); + debug_finish_module (options.output_file); qfo = qfo_from_progs (&pr); if (options.compile) { qfo_write (qfo, options.output_file); @@ -805,6 +850,7 @@ main (int argc, char **argv) parse_cpp_name (); opcode_init (); + InitData (); init_types (); clear_immediates (); diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index d6bf84927..eea6aa7e8 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -63,10 +63,10 @@ #include "QF/va.h" #include "QF/zone.h" -#include "obj_file.h" -#include "obj_type.h" -#include "qfprogs.h" -#include "reloc.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/qfprogs.h" +#include "tools/qfcc/include/reloc.h" const char *reloc_names[] = { "none", @@ -128,7 +128,6 @@ static edict_t *edicts; static int num_edicts; static int reserved_edicts = 1; static progs_t pr; -static int need_progs; static qfo_t *qfo; static const char *source_path = ""; @@ -176,7 +175,7 @@ file_error (progs_t *pr, const char *name) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -184,13 +183,14 @@ load_file (progs_t *pr, const char *name) file = open_file (name, &size); if (!file) { - file = open_file (va ("%s.gz", name), &size); + file = open_file (va (0, "%s.gz", name), &size); if (!file) return 0; } sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } @@ -233,12 +233,11 @@ init_qf (void) { Sys_Init (); - Cvar_Get ("pr_debug", va ("%d", verbosity), 0, 0, ""); + Cvar_Get ("pr_debug", va (0, "%d", 1+verbosity), 0, 0, ""); Cvar_Get ("pr_source_path", source_path, 0, 0, ""); PR_Init_Cvars (); - PR_Init (); - pr.edicts = &edicts; + pr.pr_edicts = &edicts; pr.num_edicts = &num_edicts; pr.reserved_edicts = &reserved_edicts; pr.file_error = file_error; @@ -246,58 +245,18 @@ init_qf (void) pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; - func_tab = Hash_NewTable (1021, 0, 0, 0); + PR_Init (&pr); + + func_tab = Hash_NewTable (1021, 0, 0, 0, 0); Hash_SetHashCompare (func_tab, func_hash, func_compare); } -static void -convert_qfo (void) -{ - int size; - int i; - - pr.progs = qfo_to_progs (qfo, &size); - -#define P(t,o) ((t *)((char *)pr.progs + pr.progs->o)) - pr.pr_statements = P (dstatement_t, ofs_statements); - pr.pr_strings = P (char, ofs_strings); - pr.pr_stringsize = pr.progs->numstrings; - pr.pr_functions = P (dfunction_t, ofs_functions); - pr.pr_globaldefs = P (ddef_t, ofs_globaldefs); - pr.pr_fielddefs = P (ddef_t, ofs_fielddefs); - pr.pr_globals = P (pr_type_t, ofs_globals); - pr.globals_size = pr.progs->numglobals; - pr.pr_edict_size = max (1, pr.progs->entityfields) * 4; - pr.pr_edictareasize = 1 * pr.pr_edict_size; -#undef P - - if (verbosity) { - pr.debug = qfo_to_sym (qfo, &size); -#define P(t,o) ((t *)((char *)pr.debug + pr.debug->o)) - pr.auxfunctions = P (pr_auxfunction_t, auxfunctions); - pr.linenos = P (pr_lineno_t, linenos); - pr.local_defs = P (ddef_t, locals); -#undef P - - pr.local_defs = calloc (qfo->num_defs, sizeof (ddef_t)); - - pr.auxfunction_map = calloc (pr.progs->numfunctions, - sizeof (pr_auxfunction_t *)); - for (i = 0; (int) i < pr.progs->numfunctions; i++) //FIXME (cast) - pr.auxfunction_map[i] = 0; - - for (i = 0; i < (int) pr.debug->num_auxfunctions; i++) { - pr_auxfunction_t *aux = pr.auxfunctions + i; - pr.auxfunction_map[aux->function] = aux; - } - } -} - static int load_progs (const char *name) { QFile *file; - int i, size; + int size; + pr_uint_t i; char buff[5]; Hash_FlushTable (func_tab); @@ -310,6 +269,7 @@ load_progs (const char *name) Qread (file, buff, 4); buff[4] = 0; Qseek (file, 0, SEEK_SET); + qfo = 0; if (!strcmp (buff, QFO)) { qfo = qfo_read (file); Qclose (file); @@ -317,19 +277,19 @@ load_progs (const char *name) if (!qfo) return 0; - if (!need_progs) - return 1; - convert_qfo (); + return 1; } else { pr.progs_name = name; - PR_LoadProgsFile (&pr, file, size, 1, 0); + pr.max_edicts = 1; + pr.zone_size = 0; + PR_LoadProgsFile (&pr, file, size); Qclose (file); if (!pr.progs) return 0; - PR_LoadStrings (&pr); PR_ResolveGlobals (&pr); + PR_LoadStrings (&pr); PR_LoadDebug (&pr); } for (i = 0; i < pr.progs->numfunctions; i++) { @@ -348,10 +308,10 @@ typedef struct { operation_t operations[] = { {disassemble_progs, 0}, // disassemble {dump_globals, qfo_globals}, // globals - {dump_strings, 0}, // strings - {dump_fields, 0}, // fields + {dump_strings, qfo_strings}, // strings + {dump_fields, qfo_fields}, // fields {dump_functions, qfo_functions}, // functions - {dump_lines, 0}, // lines + {dump_lines, qfo_lines}, // lines {dump_modules, 0}, // modules {0, qfo_relocs}, // relocs {dump_types, qfo_types}, // types @@ -410,12 +370,11 @@ main (int argc, char **argv) } init_qf (); while (optind < argc) { - need_progs = !func->qfo; if (!load_progs (argv[optind++])) return 1; if (qfo && func->qfo) func->qfo (qfo); - else if (func->progs) + else if (!qfo && func->progs) func->progs (&pr); else fprintf (stderr, "can't process %s\n", argv[optind - 1]); diff --git a/tools/qfcc/source/qp-lex.l b/tools/qfcc/source/qp-lex.l index e98b6511b..a57185209 100644 --- a/tools/qfcc/source/qp-lex.l +++ b/tools/qfcc/source/qp-lex.l @@ -35,17 +35,17 @@ #include "QF/hash.h" -#include "debug.h" -#include "diagnostic.h" -#include "expr.h" -#include "grab.h" -#include "qfcc.h" -#include "shared.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/grab.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" -#include "qp-parse.h" +#include "tools/qfcc/source/qp-parse.h" #ifndef YY_PROTO # define YY_PROTO(x) x @@ -57,9 +57,16 @@ #define YY_DECL int yylex YY_PROTO(( void )) YY_DECL; +int yyget_lineno (void) __attribute__((pure)); +int yyget_leng (void) __attribute__((pure)); +int yywrap (void) __attribute__((const)); +char *yyget_text (void) __attribute__((pure)); +int yyget_debug (void) __attribute__((pure)); +FILE *yyget_in (void) __attribute__((pure)); +FILE *yyget_out (void) __attribute__((pure)); static int keyword_or_id (const char *token); -static int convert_relop (const char *relop); +static int convert_relop (const char *relop) __attribute__((pure)); %} @@ -241,7 +248,7 @@ keyword_or_id (const char *token) if (!keyword_tab) { size_t i; - keyword_tab = Hash_NewTable (1021, keyword_get_key, 0, 0); + keyword_tab = Hash_NewTable (1021, keyword_get_key, 0, 0, 0); for (i = 0; i < sizeof (keywords) / sizeof (keywords[0]); i++) Hash_Add (keyword_tab, &keywords[i]); } @@ -296,7 +303,9 @@ convert_relop (const char *relop) #ifdef YY_FLEX_REALLOC_HACK static __attribute__ ((used)) void *(*const yy_flex_realloc_hack)(void *,yy_size_t) = yy_flex_realloc; #else +#ifdef yyunput static __attribute__ ((used)) void (*yyunput_hack)(int, char*) = yyunput; +#endif static __attribute__ ((used)) int (*input_hack)(void) = input; #endif diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index 9731402a5..15159deb0 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -41,15 +41,15 @@ #include "QF/dstring.h" -#include "codespace.h" -#include "diagnostic.h" -#include "expr.h" -#include "function.h" -#include "qfcc.h" -#include "reloc.h" -#include "shared.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" #define YYDEBUG 1 #define YYERROR_VERBOSE 1 @@ -105,7 +105,7 @@ int yylex (void); %nonassoc STORAGEX %left COMMA -%right '=' ASX PAS /* pointer assign */ +%right '=' ASX %right '?' ':' %left OR %left AND @@ -139,6 +139,29 @@ int yylex (void); %type sign %{ + +static void +build_dotmain (symbol_t *program) +{ + symbol_t *dotmain = new_symbol (".main"); + expr_t *code; + expr_t *exitcode; + + dotmain->params = 0; + dotmain->type = parse_params (&type_integer, 0); + dotmain->type = find_type (dotmain->type); + dotmain = function_symbol (dotmain, 0, 1); + + exitcode = new_symbol_expr (symtab_lookup (current_symtab, "ExitCode")); + + current_func = begin_function (dotmain, 0, current_symtab, 0); + current_symtab = current_func->symtab; + code = new_block_expr (); + append_expr (code, function_expr (new_symbol_expr (program), 0)); + append_expr (code, return_expr (current_func, exitcode)); + build_code_function (dotmain, 0, code); +} + %} %% @@ -159,15 +182,7 @@ program build_code_function ($1, 0, $4); current_symtab = st; - $4 = function_expr (new_symbol_expr ($1), 0); - $1 = new_symbol (".main"); - $1->params = 0; - $1->type = parse_params (&type_void, 0); - $1->type = find_type ($1->type); - $1 = function_symbol ($1, 0, 1); - current_func = begin_function ($1, 0, current_symtab, 0); - current_symtab = current_func->symtab; - build_code_function ($1, 0, $4); + build_dotmain ($1); current_symtab = st; } ; @@ -178,6 +193,15 @@ program_head { $$ = $3; + // FIXME need units and standard units + { + symbol_t *sym = new_symbol ("ExitCode"); + sym->type = &type_integer; + initialize_def (sym, 0, current_symtab->space, sc_global); + if (sym->s.def) { + sym->s.def->nosave = 1; + } + } $$->type = parse_params (&type_void, 0); $$->type = find_type ($$->type); $$ = function_symbol ($$, 0, 1); @@ -207,8 +231,8 @@ declarations { while ($3) { symbol_t *next = $3->next; - initialize_def ($3, $5, 0, current_symtab->space, - current_storage); + $3->type = $5; + initialize_def ($3, 0, current_symtab->space, current_storage); $3 = next; } } @@ -375,6 +399,7 @@ statement else : ELSE { + // this is only to get the the file and line number info $$ = new_nil_expr (); } ; diff --git a/tools/qfcc/source/reloc.c b/tools/qfcc/source/reloc.c index 29f1663d8..c1d471d0a 100644 --- a/tools/qfcc/source/reloc.c +++ b/tools/qfcc/source/reloc.c @@ -41,15 +41,15 @@ #include "QF/alloc.h" -#include "codespace.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "function.h" -#include "qfcc.h" -#include "reloc.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" static reloc_t *refs_freelist; @@ -210,7 +210,7 @@ reloc_op_def_ofs (def_t *def, int offset, int field) } void -reloc_def_def (def_t *def, def_t *location) +reloc_def_def (def_t *def, const def_t *location) { reloc_t *ref; @@ -221,7 +221,7 @@ reloc_def_def (def_t *def, def_t *location) } void -reloc_def_def_ofs (def_t *def, def_t *location) +reloc_def_def_ofs (def_t *def, const def_t *location) { reloc_t *ref; @@ -232,7 +232,7 @@ reloc_def_def_ofs (def_t *def, def_t *location) } void -reloc_def_func (function_t *func, def_t *location) +reloc_def_func (function_t *func, const def_t *location) { reloc_t *ref; @@ -243,7 +243,7 @@ reloc_def_func (function_t *func, def_t *location) } void -reloc_def_string (def_t *location) +reloc_def_string (const def_t *location) { reloc_t *ref; @@ -254,7 +254,7 @@ reloc_def_string (def_t *location) } void -reloc_def_field (def_t *def, def_t *location) +reloc_def_field (def_t *def, const def_t *location) { reloc_t *ref; @@ -265,7 +265,7 @@ reloc_def_field (def_t *def, def_t *location) } void -reloc_def_field_ofs (def_t *def, def_t *location) +reloc_def_field_ofs (def_t *def, const def_t *location) { reloc_t *ref; @@ -276,7 +276,7 @@ reloc_def_field_ofs (def_t *def, def_t *location) } void -reloc_def_op (ex_label_t *label, def_t *location) +reloc_def_op (const ex_label_t *label, const def_t *location) { reloc_t *ref; diff --git a/tools/qfcc/source/shared.c b/tools/qfcc/source/shared.c index 25e0ac979..cee0d06c1 100644 --- a/tools/qfcc/source/shared.c +++ b/tools/qfcc/source/shared.c @@ -31,14 +31,14 @@ # include "config.h" #endif -#include "class.h" -#include "diagnostic.h" -#include "expr.h" -#include "function.h" -#include "options.h" -#include "shared.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" function_t *current_func; class_type_t *current_class; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index f331a39f0..0743c5c40 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -42,28 +42,46 @@ #include "qfalloca.h" #include "QF/alloc.h" +#include "QF/mathlib.h" #include "QF/va.h" -#include "dags.h" -#include "diagnostic.h" -#include "dot.h" -#include "expr.h" -#include "function.h" -#include "options.h" -#include "qfcc.h" -#include "reloc.h" -#include "statements.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" -#include "value.h" -#include "qc-parse.h" +#include "tools/qfcc/include/dags.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/dot.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/statements.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" -static const char *op_type_names[] = { +#include "tools/qfcc/source/qc-parse.h" + +const char *op_type_names[] = { "op_def", "op_value", "op_label", "op_temp", + "op_alias", + "op_nil", +}; + +const char *st_type_names[] = { + "st_none", + "st_expr", + "st_assign", + "st_ptrassign", + "st_move", + "st_ptrmove", + "st_memset", + "st_ptrmemset", + "st_state", + "st_func", + "st_flow", }; const char * @@ -74,6 +92,22 @@ optype_str (op_type_e type) return op_type_names[type]; } +static const char * +tempop_string (operand_t *tmpop) +{ + tempop_t *tempop = &tmpop->o.tempop; + if (tempop->alias) { + return va (0, "", + pr_type_name[tempop->type->type], + tmpop, tempop->users, + tempop->alias, + tempop->offset, + tempop->alias->o.tempop.users); + } + return va (0, "", pr_type_name[tempop->type->type], + tmpop, tempop->users); +} + const char * operand_string (operand_t *op) { @@ -83,37 +117,49 @@ operand_string (operand_t *op) case op_def: return op->o.def->name; case op_value: - switch (op->o.value->type) { + switch (op->o.value->lltype) { case ev_string: - return va ("\"%s\"", + return va (0, "\"%s\"", quote_string (op->o.value->v.string_val)); + case ev_double: + return va (0, "%g", op->o.value->v.double_val); case ev_float: - return va ("%g", op->o.value->v.float_val); + return va (0, "%g", op->o.value->v.float_val); case ev_vector: - return va ("'%g %g %g'", + return va (0, "'%g %g %g'", op->o.value->v.vector_val[0], op->o.value->v.vector_val[1], op->o.value->v.vector_val[2]); case ev_quat: - return va ("'%g %g %g %g'", + return va (0, "'%g %g %g %g'", op->o.value->v.quaternion_val[0], op->o.value->v.quaternion_val[1], op->o.value->v.quaternion_val[2], op->o.value->v.quaternion_val[3]); case ev_pointer: - return va ("ptr %d", op->o.value->v.pointer.val); + if (op->o.value->v.pointer.def) { + return va (0, "ptr %s+%d", + op->o.value->v.pointer.def->name, + op->o.value->v.pointer.val); + } else if(op->o.value->v.pointer.tempop) { + operand_t *tempop = op->o.value->v.pointer.tempop; + return va (0, "ptr %s+%d", tempop_string (tempop), + op->o.value->v.pointer.val); + } else { + return va (0, "ptr %d", op->o.value->v.pointer.val); + } case ev_field: - return va ("field %d", op->o.value->v.pointer.val); + return va (0, "field %d", op->o.value->v.pointer.val); case ev_entity: - return va ("ent %d", op->o.value->v.integer_val); + return va (0, "ent %d", op->o.value->v.integer_val); case ev_func: - return va ("func %d", op->o.value->v.integer_val); + return va (0, "func %d", op->o.value->v.integer_val); case ev_integer: - return va ("int %d", op->o.value->v.integer_val); + return va (0, "int %d", op->o.value->v.integer_val); case ev_uinteger: - return va ("uint %u", op->o.value->v.uinteger_val); + return va (0, "uint %u", op->o.value->v.uinteger_val); case ev_short: - return va ("short %d", op->o.value->v.short_val); + return va (0, "short %d", op->o.value->v.short_val); case ev_void: return "(void)"; case ev_invalid: @@ -125,39 +171,38 @@ operand_string (operand_t *op) case op_label: return op->o.label->name; case op_temp: - if (op->o.tempop.alias) - return va ("", - pr_type_name[op->type], - op, op->o.tempop.users, - op->o.tempop.alias, - op->o.tempop.alias->o.tempop.users); - return va ("", pr_type_name[op->o.tempop.type->type], - op, op->o.tempop.users); + return tempop_string (op); case op_alias: { const char *alias = operand_string (op->o.alias); char *buf = alloca (strlen (alias) + 1); strcpy (buf, alias); - return va ("alias(%s,%s)", pr_type_name[op->type], buf); + return va (0, "alias(%s,%s)", pr_type_name[op->type->type], + buf); } + case op_nil: + return va (0, "nil"); } return ("??"); } static void -print_operand (operand_t *op) +_print_operand (operand_t *op) { switch (op->op_type) { case op_def: - printf ("(%s) ", pr_type_name[op->type]); + printf ("(%s) ", pr_type_name[op->type->type]); printf ("%s", op->o.def->name); break; case op_value: - printf ("(%s) ", pr_type_name[op->type]); - switch (op->o.value->type) { + printf ("(%s) ", pr_type_name[op->type->type]); + switch (op->o.value->lltype) { case ev_string: printf ("\"%s\"", op->o.value->v.string_val); break; + case ev_double: + printf ("%g", op->o.value->v.double_val); + break; case ev_float: printf ("%g", op->o.value->v.float_val); break; @@ -194,36 +239,47 @@ print_operand (operand_t *op) case ev_void: case ev_invalid: case ev_type_count: - internal_error (0, "weird value type"); + internal_error (op->expr, "weird value type"); } break; case op_label: printf ("block %p", op->o.label->dest); break; case op_temp: - printf ("tmp (%s) %p", pr_type_name[op->type], op); + printf ("tmp (%s) %p", pr_type_name[op->type->type], op); if (op->o.tempop.def) printf (" %s", op->o.tempop.def->name); break; case op_alias: - printf ("alias(%s,", pr_type_name[op->type]); - print_operand (op->o.alias); + printf ("alias(%s,", pr_type_name[op->type->type]); + _print_operand (op->o.alias); printf (")"); + break; + case op_nil: + printf ("nil"); + break; } } +void +print_operand (operand_t *op) +{ + _print_operand (op); + puts (""); +} + void print_statement (statement_t *s) { printf ("(%s, ", s->opcode); if (s->opa) - print_operand (s->opa); + _print_operand (s->opa); printf (", "); if (s->opb) - print_operand (s->opb); + _print_operand (s->opb); printf (", "); if (s->opc) - print_operand (s->opc); + _print_operand (s->opc); printf (")\n"); } @@ -257,15 +313,18 @@ new_statement (st_type_t type, const char *opcode, expr_t *expr) statement->type = type; statement->opcode = save_string (opcode); statement->expr = expr; + statement->number = -1; // indicates flow analysis not done yet return statement; } static operand_t * -new_operand (op_type_e op) +new_operand (op_type_e op, expr_t *expr, void *return_addr) { operand_t *operand; ALLOC (256, operand_t, operands, operand); operand->op_type = op; + operand->expr = expr; + operand->return_addr = return_addr; return operand; } @@ -299,65 +358,157 @@ free_sblock (sblock_t *sblock) } operand_t * -def_operand (def_t *def, type_t *type) +nil_operand (type_t *type, expr_t *expr) +{ + operand_t *op; + op = new_operand (op_nil, expr, __builtin_return_address (0)); + op->type = type; + op->size = type_size (type); + return op; +} + +operand_t * +def_operand (def_t *def, type_t *type, expr_t *expr) { operand_t *op; if (!type) type = def->type; - op = new_operand (op_def); - op->type = low_level_type (type); + op = new_operand (op_def, expr, __builtin_return_address (0)); + op->type = type; + op->size = type_size (type); op->o.def = def; return op; } operand_t * -value_operand (ex_value_t *value) +return_operand (type_t *type, expr_t *expr) +{ + symbol_t *return_symbol; + return_symbol = make_symbol (".return", &type_param, pr.symtab->space, + sc_extern); + return def_operand (return_symbol->s.def, type, expr); +} + +operand_t * +value_operand (ex_value_t *value, expr_t *expr) { operand_t *op; - op = new_operand (op_value); + op = new_operand (op_value, expr, __builtin_return_address (0)); op->type = value->type; op->o.value = value; return op; } operand_t * -temp_operand (type_t *type) +temp_operand (type_t *type, expr_t *expr) { - operand_t *op = new_operand (op_temp); + operand_t *op = new_operand (op_temp, expr, __builtin_return_address (0)); op->o.tempop.type = type; - op->type = low_level_type (type); + op->type = type; op->size = type_size (type); return op; } +int +tempop_overlap (tempop_t *t1, tempop_t *t2) +{ + int offs1 = t1->offset; + int offs2 = t2->offset; + int size1 = type_size (t1->type); + int size2 = type_size (t2->type); + + if (t1->alias) { + offs1 += t1->alias->o.tempop.offset; + } + if (t2->alias) { + offs2 += t2->alias->o.tempop.offset; + } + if (offs1 <= offs2 && offs1 + size1 >= offs2 + size2) + return 2; // t1 fully overlaps t2 + if (offs1 < offs2 + size2 && offs2 < offs1 + size1) + return 1; // t1 and t2 at least partially overlap + return 0; +} + +int +tempop_visit_all (tempop_t *tempop, int overlap, + int (*visit) (tempop_t *, void *), void *data) +{ + tempop_t *start_tempop = tempop; + operand_t *top; + int ret; + + if ((ret = visit (tempop, data))) + return ret; + if (tempop->alias) { + top = tempop->alias; + if (top->op_type != op_temp) { + internal_error (top->expr, "temp alias of non-temp operand"); + } + tempop = &top->o.tempop; + if ((ret = visit (tempop, data))) + return ret; + } else { + overlap = 0; + } + for (top = tempop->alias_ops; top; top = top->next) { + if (top->op_type != op_temp) { + internal_error (top->expr, "temp alias of non-temp operand"); + } + tempop = &top->o.tempop; + if (tempop == start_tempop) + continue; + if (overlap && tempop_overlap (tempop, start_tempop) < overlap) + continue; + if ((ret = visit (tempop, data))) + return ret; + } + return 0; +} + operand_t * -alias_operand (etype_t type, operand_t *op) +alias_operand (type_t *type, operand_t *op, expr_t *expr) { operand_t *aop; - if (pr_type_size[type] != pr_type_size[op->type]) - internal_error (0, "aliasing operand with type of diffent size"); - aop = new_operand (op_alias); + if (type_size (type) != type_size (op->type)) { + internal_error (op->expr, + "aliasing operand with type of different size: %d, %d", + type_size (type), type_size (op->type)); + } + aop = new_operand (op_alias, expr, __builtin_return_address (0)); aop->o.alias = op; aop->type = type; - aop->size = pr_type_size[type]; + aop->size = type_size (type); return aop; } +operand_t * +label_operand (expr_t *label) +{ + operand_t *lop; + + if (label->type != ex_label) { + internal_error (label, "not a label expression"); + } + lop = new_operand (op_label, label, __builtin_return_address (0)); + lop->o.label = &label->e.label; + return lop; +} + static operand_t * -short_operand (short short_val) +short_operand (short short_val, expr_t *expr) { ex_value_t *val = new_short_val (short_val); - return value_operand (val); + return value_operand (val, expr); } static const char * convert_op (int op) { switch (op) { - case PAS: return ".="; case OR: return "||"; case AND: return "&&"; case EQ: return "=="; @@ -372,6 +523,7 @@ convert_op (int op) case '*': return "*"; case '/': return "/"; case '%': return "%"; + case MOD: return "%%"; case '&': return "&"; case '|': return "|"; case '^': return "^"; @@ -453,7 +605,7 @@ statement_get_targetlist (statement_t *s) sblock_t **target_list; int count = 0, i; def_t *table = 0; - expr_t *e; + element_t *e; if (statement_is_cond (s)) { count = 1; @@ -471,10 +623,10 @@ statement_get_targetlist (statement_t *s) target_list[0] = statement_get_target (s); } else if (statement_is_jumpb (s)) { if (table->alias) - internal_error (0, "aliased jump table"); - e = table->initializer->e.block.head; //FIXME check!!! + internal_error (s->opa->expr, "aliased jump table"); + e = table->initializer->e.compound.head; //FIXME check!!! for (i = 0; i < count; e = e->next, i++) - target_list[i] = e->e.labelref.label->dest; + target_list[i] = e->expr->e.labelref.label->dest; } return target_list; } @@ -511,8 +663,7 @@ statement_branch (sblock_t *sblock, expr_t *e) if (e->type == ex_uexpr && e->e.expr.op == 'g') { s = new_statement (st_flow, "", e); - s->opa = new_operand (op_label); - s->opa->o.label = &e->e.expr.e1->e.label; + s->opa = label_operand (e->e.expr.e1); } else { if (e->e.expr.op == 'g') { s = new_statement (st_flow, "", e); @@ -522,8 +673,7 @@ statement_branch (sblock_t *sblock, expr_t *e) opcode = convert_op (e->e.expr.op); s = new_statement (st_flow, opcode, e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - s->opb = new_operand (op_label); - s->opb->o.label = &e->e.expr.e2->e.label; + s->opb = label_operand (e->e.expr.e2); } } @@ -532,50 +682,247 @@ statement_branch (sblock_t *sblock, expr_t *e) return sblock->next; } +static sblock_t * +expr_address (sblock_t *sblock, expr_t *e, operand_t **op) +{ + statement_t *s; + s = new_statement (st_expr, "&", e); + sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); + s->opc = temp_operand (e->e.expr.type, e); + sblock_add_statement (sblock, s); + *(op) = s->opc; + return sblock; +} + +static operand_t * +operand_address (operand_t *reference, expr_t *e) +{ + def_t *def; + type_t *type; + int offset = 0; + + type = reference->type; + switch (reference->op_type) { + case op_def: + // assumes aliasing is only one level deep which should be the + // case + def = reference->o.def; + if (def->alias) { + offset = def->offset; + def = def->alias; + } + return value_operand (new_pointer_val (offset, type, def, 0), e); + case op_temp: + // assumes aliasing is only one level deep which should be the + // case + if (reference->o.tempop.alias) { + offset = reference->o.tempop.offset; + reference = reference->o.tempop.alias; + } + return value_operand (new_pointer_val (offset, type, 0, + reference), e); + case op_alias: + //op_alias comes only from alias_operand and that is called + // by dags, so not expected + case op_value: + case op_label: + case op_nil: + break; + } + internal_error (e, "invalid operand type for operand address: %s", + op_type_names[reference->op_type]); +} + +static __attribute__((pure)) int +is_const_ptr (expr_t *e) +{ + if ((e->type != ex_value || e->e.value->lltype != ev_pointer) + || !(POINTER_VAL (e->e.value->v.pointer) >= 0 + && POINTER_VAL (e->e.value->v.pointer) < 65536)) { + return 0; + } + return 1; +} + +static __attribute__((pure)) int +is_indirect (expr_t *e) +{ + if ((e->type == ex_expr || e->type == ex_uexpr) + && e->e.expr.op == '.') { + return 1; + } + return 0; +} + +static sblock_t * +expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) +{ + statement_t *s; + expr_t *dst_expr = e->e.expr.e1; + expr_t *src_expr = e->e.expr.e2; + type_t *dst_type = get_type (dst_expr); + type_t *src_type = get_type (src_expr); + unsigned count; + expr_t *count_expr; + operand_t *dst = 0; + operand_t *size = 0; + static const char *opcode_sets[][2] = { + {"", ""}, + {"", ""}, + }; + const unsigned max_count = 1 << 16; + const char **opcode_set = opcode_sets[0]; + const char *opcode; + int need_ptr = 0; + st_type_t type = st_move; + + if ((src && src->op_type == op_nil) || src_expr->type == ex_nil) { + // switch to memset because nil is type agnostic 0 and structures + // can be any size + src_expr = new_integer_expr (0); + sblock = statement_subexpr (sblock, src_expr, &src); + opcode_set = opcode_sets[1]; + if (op) { + *op = nil_operand (dst_type, src_expr); + } + type = st_memset; + if (is_indirect (dst_expr)) { + goto dereference_dst; + } + } else { + if (!src) { + // This is the very right-hand node of a non-nil assignment chain + // (there may be more chains somwhere within src_expr, but they + // are not part of this chain as they are separated by another + // expression). + sblock = statement_subexpr (sblock, src_expr, &src); + } + // send the source operand back up through the assignment chain + // before modifying src if its address is needed + if (op) { + *op = src; + } + if (is_indirect (dst_expr) || is_indirect (src_expr)) { + src = operand_address (src, src_expr); + goto dereference_dst; + } + } + if (0) { +dereference_dst: + // dst_expr is a dereferenced pointer, so need to un-dereference it + // to get the pointer and switch to storep instructions. + dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); + need_ptr = 1; + } + sblock = statement_subexpr (sblock, dst_expr, &dst); + + if (type_size (dst_type) != type_size (src_type)) { + bug (e, "dst and src sizes differ in expr_assign_copy: %d %d", + type_size (dst_type), type_size (src_type)); + } + count = min (type_size (dst_type), type_size (src_type)); + if (count < (1 << 16)) { + count_expr = expr_file_line (new_short_expr (count), e); + } else { + count_expr = expr_file_line (new_integer_expr (count), e); + } + sblock = statement_subexpr (sblock, count_expr, &size); + + if (count < max_count && !need_ptr) { + opcode = opcode_set[0]; + } else { + opcode = opcode_set[1]; + type++; // from st_move/st_memset to st_ptrmove/st_ptrmemset + } + + s = new_statement (type, opcode, e); + s->opa = src; + s->opb = size; + s->opc = dst; + sblock_add_statement (sblock, s); + return sblock; +} + static sblock_t * expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) { statement_t *s; expr_t *src_expr = e->e.expr.e2; expr_t *dst_expr = e->e.expr.e1; + type_t *dst_type = get_type (dst_expr); operand_t *src = 0; operand_t *dst = 0; operand_t *ofs = 0; const char *opcode = convert_op (e->e.expr.op); st_type_t type; - if (e->e.expr.op == '=') { - sblock = statement_subexpr (sblock, dst_expr, &dst); - src = dst; + if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { sblock = statement_subexpr (sblock, src_expr, &src); - ofs = 0; - if (op) - *op = dst; - if (src == dst) - return sblock; - type = st_assign; + if (is_structural (dst_type)) { + return expr_assign_copy (sblock, e, op, src); + } + if (is_indirect (dst_expr)) { + goto dereference_dst; + } else { + sblock = statement_subexpr (sblock, dst_expr, &dst); + } } else { - //FIXME this sucks. find a better way to handle both pointer - //dereferences and pointer assignements - sblock = statement_subexpr (sblock, src_expr, &src); - if (dst_expr->type == ex_expr - && extract_type (dst_expr->e.expr.e1) == ev_pointer - && !is_constant (dst_expr->e.expr.e1)) { + if (is_structural (dst_type)) { + return expr_assign_copy (sblock, e, op, src); + } + + if (is_indirect (dst_expr)) { + // If both dst_expr and src_expr are indirect, then a staging temp + // is needed, but emitting src_expr first generates that temp + // because src is null. If src_expr is not indirect and is a simple + // variable reference, then just the ref will be generated and thus + // will be assigned to the dereferenced destination. If src_expr + // is not simple, then a temp will be generated, so all good. + sblock = statement_subexpr (sblock, src_expr, &src); + goto dereference_dst; + } else { + // dst_expr is direct and known to be an l-value, so emitting + // its expression will simply generate a reference to that l-value + // which will be used as the default location to store src_expr's + // result + sblock = statement_subexpr (sblock, dst_expr, &dst); + src = dst; + sblock = statement_subexpr (sblock, src_expr, &src); + } + } + type = st_assign; + + if (0) { +dereference_dst: + // dst_expr is a dereferenced pointer, so need to un-dereference it + // to get the pointer and switch to storep instructions. + dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); + opcode = ".="; // FIXME find a nicer representation (lose strings?) + if (dst_expr->type == ex_expr && !is_const_ptr (dst_expr->e.expr.e1)) { sblock = statement_subexpr (sblock, dst_expr->e.expr.e1, &dst); sblock = statement_subexpr (sblock, dst_expr->e.expr.e2, &ofs); } else { - if (dst_expr->type == ex_uexpr - && dst_expr->e.expr.op == '&') { - opcode = "="; - dst_expr = unary_expr ('.', dst_expr); - } sblock = statement_subexpr (sblock, dst_expr, &dst); ofs = 0; } - if (op) - *op = src; type = st_ptrassign; } + if (op) { + *op = src; + } + if (src == dst) { + return sblock; + } + + if (is_entity (dst->type) && ofs && is_field (ofs->type)) { + s = new_statement (st_expr, "&", dst_expr); + s->opa = dst; + s->opb = ofs; + s->opc = temp_operand (&type_pointer, dst_expr); + sblock_add_statement (sblock, s); + dst = s->opc; + ofs = 0; + } s = new_statement (type, opcode, e); s->opa = src; s->opb = dst; @@ -603,7 +950,8 @@ expr_move (sblock_t *sblock, expr_t *e, operand_t **op) dst = *op; sblock = statement_subexpr (sblock, src_expr, &src); sblock = statement_subexpr (sblock, size_expr, &size); - s = new_statement (st_move, convert_op (e->e.expr.op), e); + s = new_statement (e->e.expr.op == 'm' ? st_move : st_ptrmove, + convert_op (e->e.expr.op), e); s->opa = src; s->opb = size; s->opc = dst; @@ -659,21 +1007,20 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) pref = "R"; sblock = statement_subexpr (sblock, param, &arguments[ind]); if (options.code.vector_calls && a->type == ex_value - && a->e.value->type == ev_vector) + && a->e.value->lltype == ev_vector) sblock = vector_call (sblock, a, param, ind, &arguments[ind]); else sblock = statement_subexpr (sblock, a, &arguments[ind]); continue; } if (is_struct (get_type (param))) { - //FIXME this should be done in the expression tree expr_t *mov = assign_expr (param, a); mov->line = a->line; mov->file = a->file; sblock = statement_slist (sblock, mov); } else { if (options.code.vector_calls && a->type == ex_value - && a->e.value->type == ev_vector) { + && a->e.value->lltype == ev_vector) { sblock = vector_call (sblock, a, param, ind, 0); } else { operand_t *p = 0; @@ -690,7 +1037,7 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) } } } - opcode = va ("<%sCALL%d>", pref, count); + opcode = va (0, "<%sCALL%d>", pref, count); s = new_statement (st_func, opcode, call); sblock = statement_subexpr (sblock, func, &s->opa); s->opb = arguments[0]; @@ -700,32 +1047,13 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) return sblock->next; } -static sblock_t * -expr_address (sblock_t *sblock, expr_t *e, operand_t **op) -{ - if (e->type == ex_uexpr) { - sblock = statement_subexpr (sblock, e->e.expr.e1, op); - (*op)->type = ev_pointer; - } - return sblock; -} - static statement_t * lea_statement (operand_t *pointer, operand_t *offset, expr_t *e) { statement_t *s = new_statement (st_expr, "&", e); s->opa = pointer; s->opb = offset; - s->opc = temp_operand (&type_pointer); - return s; -} - -static statement_t * -address_statement (operand_t *value, expr_t *e) -{ - statement_t *s = new_statement (st_expr, "&", e); - s->opa = value; - s->opc = temp_operand (&type_pointer); + s->opc = temp_operand (&type_pointer, e); return s; } @@ -740,7 +1068,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) && e->e.expr.e1->type == ex_symbol) { if (e->e.expr.e1->e.symbol->sy_type != sy_var) internal_error (e, "address of non-var"); - *op = def_operand (e->e.expr.e1->e.symbol->s.def, type); + *op = def_operand (e->e.expr.e1->e.symbol->s.def, type, e); } else if (e->type == ex_expr && e->e.expr.op == '&') { statement_t *s; operand_t *ptr = 0; @@ -748,7 +1076,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) sblock = statement_subexpr (sblock, e->e.expr.e1, &ptr); sblock = statement_subexpr (sblock, e->e.expr.e2, &offs); if (!*op) - *op = temp_operand (type); + *op = temp_operand (type, e); if (low_level_type (type) == ev_void) { operand_t *src_addr; operand_t *dst_addr; @@ -757,14 +1085,12 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) src_addr = s->opc; sblock_add_statement (sblock, s); - //FIXME an address immediate would be nice. - s = address_statement (*op, e); - dst_addr = s->opc; - sblock_add_statement (sblock, s); + dst_addr = operand_address (*op, e); - s = new_statement (st_move, "", deref); + s = new_statement (st_ptrmove, "", deref); s->opa = src_addr; - s->opb = short_operand (type_size (type)); + //FIXME large types + s->opb = short_operand (type_size (type), e); s->opc = dst_addr; sblock_add_statement (sblock, s); } else { @@ -774,20 +1100,20 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) s->opc = *op; sblock_add_statement (sblock, s); } - } else if (e->type == ex_value && e->e.value->type == ev_pointer) { + } else if (e->type == ex_value && e->e.value->lltype == ev_pointer) { ex_pointer_t *ptr = &e->e.value->v.pointer; *op = def_operand (alias_def (ptr->def, ptr->type, ptr->val), - ptr->type); + ptr->type, e); } else { statement_t *s; operand_t *ptr = 0; sblock = statement_subexpr (sblock, e, &ptr); if (!*op) - *op = temp_operand (type); + *op = temp_operand (type, e); s = new_statement (st_expr, ".", deref); s->opa = ptr; - s->opb = short_operand (0); + s->opb = short_operand (0, e); s->opc = *op; sblock_add_statement (sblock, s); } @@ -804,6 +1130,64 @@ expr_block (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static sblock_t * +expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) +{ + operand_t *aop = 0; + operand_t *top; + type_t *type; + def_t *def; + int offset = 0; + + if (e->type == ex_expr) { + offset = expr_integer (e->e.expr.e2); + } + type = e->e.expr.type; + sblock = statement_subexpr (sblock, e->e.expr.e1, &aop); + if (type_compatible (aop->type, type)) { + //FIXME type_compatible??? shouldn't that be type_size ==? + if (offset) { + internal_error (e, "offset alias of same size type"); + } + *op = aop; + return sblock; + } + if (aop->op_type == op_temp) { + while (aop->o.tempop.alias) { + aop = aop->o.tempop.alias; + if (aop->op_type != op_temp) + internal_error (e, "temp alias of non-temp var"); + if (aop->o.tempop.alias) + bug (e, "aliased temp alias"); + } + for (top = aop->o.tempop.alias_ops; top; top = top->next) { + if (top->type == type && top->o.tempop.offset == offset) { + break; + } + } + if (!top) { + top = temp_operand (type, e); + top->o.tempop.alias = aop; + top->o.tempop.offset = offset; + top->next = aop->o.tempop.alias_ops; + aop->o.tempop.alias_ops = top; + } + *op = top; + } else if (aop->op_type == op_def) { + def = aop->o.def; + while (def->alias) + def = def->alias; + *op = def_operand (alias_def (def, type, offset), 0, e); + } else if (aop->op_type == op_value) { + *op = value_operand (aop->o.value, e); + (*op)->type = type; + } else { + internal_error (e, "invalid alias target: %s: %s", + optype_str (aop->op_type), operand_string (aop)); + } + return sblock; +} + static sblock_t * expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -815,13 +1199,15 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) sblock = expr_call (sblock, e, op); break; case '=': - case PAS: sblock = expr_assign (sblock, e, op); break; case 'm': case 'M': sblock = expr_move (sblock, e, op); break; + case 'A': + sblock = expr_alias (sblock, e, op); + break; default: opcode = convert_op (e->e.expr.op); if (!opcode) @@ -830,7 +1216,7 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb); if (!*op) - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s->opc = *op; sblock_add_statement (sblock, s); break; @@ -838,49 +1224,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } -static sblock_t * -expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) -{ - operand_t *aop = 0; - operand_t *top; - etype_t type; - def_t *def; - - type = low_level_type (e->e.expr.type); - sblock = statement_subexpr (sblock, e->e.expr.e1, &aop); - if (aop->type == type) { - *op = aop; - return sblock; - } - if (aop->op_type == op_temp) { - while (aop->o.tempop.alias) { - aop = aop->o.tempop.alias; - if (aop->op_type != op_temp) - internal_error (e, "temp alias of non-temp var"); - } - for (top = aop->o.tempop.alias_ops; top; top = top->next) - if (top->type == type) - break; - if (!top) { - top = new_operand (op_temp); - top->type = type; - top->o.tempop.alias = aop; - top->next = aop->o.tempop.alias_ops; - aop->o.tempop.alias_ops = top; - } - *op = top; - } else if (aop->op_type == op_def) { - def = aop->o.def; - while (def->alias) - def = def->alias; - *op = def_operand (alias_def (def, ev_types[type], 0), 0); - } else { - internal_error (e, "invalid alias target: %s: %s", - optype_str (aop->op_type), operand_string (aop)); - } - return sblock; -} - static sblock_t * expr_cast (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -889,11 +1232,10 @@ expr_cast (sblock_t *sblock, expr_t *e, operand_t **op) statement_t *s; src_type = get_type (e->e.expr.e1); - if ((src_type->type == ev_integer && type->type == ev_float) - || (src_type->type == ev_float && type->type == ev_integer)) { + if (is_scalar (src_type) && is_scalar (type)) { operand_t *src = 0; sblock = statement_subexpr (sblock, e->e.expr.e1, &src); - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s = new_statement (st_expr, "", e); s->opa = src; s->opc = *op; @@ -950,27 +1292,37 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op) s = new_statement (st_expr, opcode, e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); if (!*op) - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s->opc = *op; sblock_add_statement (sblock, s); } return sblock; } +static sblock_t * +expr_def (sblock_t *sblock, expr_t *e, operand_t **op) +{ + *op = def_operand (e->e.def, e->e.def->type, e); + return sblock; +} + static sblock_t * expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op) { symbol_t *sym = e->e.symbol; if (sym->sy_type == sy_var) { - *op = def_operand (sym->s.def, sym->type); + *op = def_operand (sym->s.def, sym->type, e); } else if (sym->sy_type == sy_const) { - *op = value_operand (sym->s.value); + *op = value_operand (sym->s.value, e); } else if (sym->sy_type == sy_func) { - *op = def_operand (sym->s.func->def, 0); + if (!sym->s.func) { + make_function (sym, 0, pr.symtab->space, sc_extern); + } + *op = def_operand (sym->s.func->def, 0, e); } else { - internal_error (e, "unexpected symbol type: %s", - symtype_str(sym->sy_type)); + internal_error (e, "unexpected symbol type: %s for %s", + symtype_str (sym->sy_type), sym->name); } return sblock; } @@ -979,15 +1331,118 @@ static sblock_t * expr_temp (sblock_t *sblock, expr_t *e, operand_t **op) { if (!e->e.temp.op) - e->e.temp.op = temp_operand (e->e.temp.type); + e->e.temp.op = temp_operand (e->e.temp.type, e); *op = e->e.temp.op; return sblock; } +static sblock_t * +expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op) +{ + expr_t *x, *y, *z, *w; + expr_t *s, *v; + expr_t *ax, *ay, *az, *aw; + expr_t *as, *av; + expr_t *tmp; + type_t *vec_type = get_type (e); + int file = pr.source_file; + int line = pr.source_line; + + pr.source_file = e->file; + pr.source_line = e->line; + + tmp = new_temp_def_expr (vec_type); + if (is_vector(vec_type)) { + // guaranteed to have three elements + x = e->e.vector.list; + y = x->next; + z = y->next; + ax = new_name_expr ("x"); + ay = new_name_expr ("y"); + az = new_name_expr ("z"); + ax = assign_expr (field_expr (tmp, ax), x); + ay = assign_expr (field_expr (tmp, ay), y); + az = assign_expr (field_expr (tmp, az), z); + sblock = statement_slist (sblock, ax); + sblock = statement_slist (sblock, ay); + sblock = statement_slist (sblock, az); + } else { + // guaranteed to have two or four elements + if (e->e.vector.list->next->next) { + // four vals: x, y, z, w + x = e->e.vector.list; + y = x->next; + z = y->next; + w = z->next; + ax = new_name_expr ("x"); + ay = new_name_expr ("y"); + az = new_name_expr ("z"); + aw = new_name_expr ("w"); + ax = assign_expr (field_expr (tmp, ax), x); + ay = assign_expr (field_expr (tmp, ay), y); + az = assign_expr (field_expr (tmp, az), z); + aw = assign_expr (field_expr (tmp, aw), w); + sblock = statement_slist (sblock, ax); + sblock = statement_slist (sblock, ay); + sblock = statement_slist (sblock, az); + sblock = statement_slist (sblock, aw); + } else { + // v, s + v = e->e.vector.list; + s = v->next; + av = new_name_expr ("v"); + as = new_name_expr ("s"); + av = assign_expr (field_expr (tmp, av), v); + as = assign_expr (field_expr (tmp, as), s); + sblock = statement_slist (sblock, av); + sblock = statement_slist (sblock, as); + } + } + pr.source_file = file; + pr.source_line = line; + sblock = statement_subexpr (sblock, tmp, op); + return sblock; +} + +static sblock_t * +expr_nil (sblock_t *sblock, expr_t *e, operand_t **op) +{ + type_t *nil = e->e.nil; + expr_t *size_expr; + size_t nil_size; + operand_t *zero; + operand_t *size; + statement_t *s; + + if (!is_struct (nil) && !is_array (nil)) { + *op = value_operand (new_nil_val (nil), e); + return sblock; + } + if (!*op) { + *op = temp_operand (nil, e); + } + nil_size = type_size (nil); + if (nil_size < 0x10000) { + size_expr = new_short_expr (nil_size); + } else { + size_expr = new_integer_expr (nil_size); + } + sblock = statement_subexpr (sblock, new_integer_expr(0), &zero); + sblock = statement_subexpr (sblock, size_expr, &size); + + s = new_statement (st_memset, "", e); + s->opa = zero; + s->opb = size; + s->opc = *op; + sblock_add_statement (sblock, s); + + return sblock; +} + static sblock_t * expr_value (sblock_t *sblock, expr_t *e, operand_t **op) { - *op = value_operand (e->e.value); + *op = value_operand (e->e.value, e); return sblock; } @@ -1003,21 +1458,25 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) expr_block, // ex_block expr_expr, expr_uexpr, + expr_def, expr_symbol, expr_temp, - 0, // ex_vector - 0, // ex_nil + expr_vector_e, // ex_vector + expr_nil, expr_value, + 0, // ex_compound + 0, // ex_memset }; if (!e) { *op = 0; return sblock; } - if (e->type > ex_value) - internal_error (e, "bad expression type"); + if (e->type > ex_memset) + internal_error (e, "bad sub-expression type"); if (!sfuncs[e->type]) - internal_error (e, "unexpected expression type"); + internal_error (e, "unexpected sub-expression type: %s", + expr_names[e->type]); sblock = sfuncs[e->type] (sblock, e, op); return sblock; @@ -1178,7 +1637,11 @@ statement_label (sblock_t *sblock, expr_t *e) e->e.label.next = sblock->labels; sblock->labels = &e->e.label; } else { - debug (e, "dropping unused label %s", e->e.label.name); + if (e->e.label.symbol) { + warning (e, "unused label %s", e->e.label.symbol->name); + } else { + debug (e, "dropping unused label %s", e->e.label.name); + } } return sblock; } @@ -1211,7 +1674,6 @@ statement_expr (sblock_t *sblock, expr_t *e) sblock = statement_branch (sblock, e); break; case '=': - case PAS: sblock = expr_assign (sblock, e, 0); break; case 'm': @@ -1248,8 +1710,10 @@ statement_uexpr (sblock_t *sblock, expr_t *e) } } s = new_statement (st_func, opcode, e); - if (e->e.expr.e1) + if (e->e.expr.e1) { + s->opa = return_operand (get_type (e->e.expr.e1), e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); + } sblock_add_statement (sblock, s); sblock->next = new_sblock (); sblock = sblock->next; @@ -1266,10 +1730,36 @@ statement_uexpr (sblock_t *sblock, expr_t *e) return sblock; } +static sblock_t * +statement_memset (sblock_t *sblock, expr_t *e) +{ + expr_t *dst = e->e.memset.dst; + expr_t *val = e->e.memset.val; + expr_t *count = e->e.memset.count; + const char *opcode = ""; + statement_t *s; + + if (is_constant (count)) { + if (is_integer (get_type (count)) + && (unsigned) expr_integer (count) < 0x10000) { + count = new_short_expr (expr_integer (count)); + } + if (is_uinteger (get_type (count)) && expr_integer (count) < 0x10000) { + count = new_short_expr (expr_uinteger (count)); + } + } + s = new_statement (st_move, opcode, e); + sblock = statement_subexpr (sblock, dst, &s->opc); + sblock = statement_subexpr (sblock, count, &s->opb); + sblock = statement_subexpr (sblock, val, &s->opa); + sblock_add_statement (sblock, s); + return sblock; +} + static sblock_t * statement_nonexec (sblock_t *sblock, expr_t *e) { - if (options.warnings.executable) + if (!e->rvalue && options.warnings.executable) warning (e, "Non-executable statement; executing programmer instead."); return sblock; } @@ -1286,15 +1776,18 @@ statement_slist (sblock_t *sblock, expr_t *e) statement_block, statement_expr, statement_uexpr, + statement_nonexec, // ex_def statement_nonexec, // ex_symbol statement_nonexec, // ex_temp statement_nonexec, // ex_vector statement_nonexec, // ex_nil statement_nonexec, // ex_value + 0, // ex_compound + statement_memset, }; for (/**/; e; e = e->next) { - if (e->type > ex_value) + if (e->type > ex_memset) internal_error (e, "bad expression type"); sblock = sfuncs[e->type] (sblock, e); } @@ -1383,7 +1876,7 @@ remove_label_from_dest (ex_label_t *label) sblock_t *sblock; ex_label_t **l; - if (!label) + if (!label || !label->dest) return; debug (0, "dropping deceased label %s", label->name); @@ -1420,14 +1913,21 @@ thread_jumps (sblock_t *blocks) if (!sblock->statements) continue; s = (statement_t *) sblock->tail; - if (statement_is_goto (s)) + if (statement_is_goto (s)) { label = &s->opa->o.label; - else if (statement_is_cond (s)) + if (!(*label)->dest && (*label)->symbol) { + error (s->opa->expr, "undefined label `%s'", + (*label)->symbol->name); + (*label)->symbol = 0; + } + } else if (statement_is_cond (s)) { label = &s->opb->o.label; - else + } else { continue; + } for (l = *label; - l->dest->statements && statement_is_goto (l->dest->statements); + l->dest && l->dest->statements + && statement_is_goto (l->dest->statements); l = l->dest->statements->opa->o.label) { } if (l != *label) { @@ -1528,10 +2028,6 @@ static void check_final_block (sblock_t *sblock) { statement_t *s = 0; - symbol_t *return_symbol = 0; - def_t *return_def = 0; - operand_t *return_operand = 0; - const char *return_opcode = ""; if (!sblock) return; @@ -1544,7 +2040,7 @@ check_final_block (sblock_t *sblock) if (statement_is_return (s)) return; } - if (current_func->sym->type->t.func.type != &type_void) + if (!is_void(current_func->sym->type->t.func.type)) warning (0, "control reaches end of non-void function"); if (s && s->type >= st_func) { // func and flow end blocks, so we need to add a new block to take the @@ -1552,16 +2048,11 @@ check_final_block (sblock_t *sblock) sblock->next = new_sblock (); sblock = sblock->next; } + s = new_statement (st_func, "", 0); if (options.traditional || options.code.progsversion == PROG_ID_VERSION) { - return_symbol = make_symbol (".return", &type_param, pr.symtab->space, - sc_extern); - return_def = return_symbol->s.def; - return_opcode = ""; + s->opcode = save_string (""); + s->opa = return_operand (&type_void, 0); } - if (return_symbol) - return_operand = def_operand (return_def, &type_void); - s = new_statement (st_func, return_opcode, 0); - s->opa = return_operand; sblock_add_statement (sblock, s); } @@ -1586,11 +2077,11 @@ make_statements (expr_t *e) do { did_something = thread_jumps (sblock); if (options.block_dot.thread) - dump_dot (va ("thread-%d", pass), sblock, dump_dot_sblock); + dump_dot (va (0, "thread-%d", pass), sblock, dump_dot_sblock); did_something |= remove_dead_blocks (sblock); sblock = merge_blocks (sblock); if (options.block_dot.dead) - dump_dot (va ("dead-%d", pass), sblock, dump_dot_sblock); + dump_dot (va (0, "dead-%d", pass), sblock, dump_dot_sblock); pass++; } while (did_something); check_final_block (sblock); diff --git a/tools/qfcc/source/strpool.c b/tools/qfcc/source/strpool.c index 8b32ae71e..fa30c74d5 100644 --- a/tools/qfcc/source/strpool.c +++ b/tools/qfcc/source/strpool.c @@ -39,13 +39,14 @@ #endif #include #include +#include #include "QF/dstring.h" #include "QF/hash.h" -#include "diagnostic.h" -#include "options.h" -#include "strpool.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/strpool.h" static hashtab_t *saved_strings; @@ -63,7 +64,7 @@ strpool_new (void) { strpool_t *strpool = calloc (1, sizeof (strpool_t)); - strpool->str_tab = Hash_NewTable (16381, strpool_get_key, 0, strpool); + strpool->str_tab = Hash_NewTable (16381, strpool_get_key, 0, strpool, 0); strpool->size = 1; strpool->max_size = 16384; strpool->strings = malloc (strpool->max_size); @@ -77,7 +78,7 @@ strpool_build (const char *strings, int size) intptr_t s; strpool_t *strpool = malloc (sizeof (strpool_t)); - strpool->str_tab = Hash_NewTable (16381, strpool_get_key, 0, strpool); + strpool->str_tab = Hash_NewTable (16381, strpool_get_key, 0, strpool, 0); strpool->size = size + (*strings != 0); strpool->max_size = (strpool->size + 16383) & ~16383; strpool->strings = malloc (strpool->max_size); @@ -120,6 +121,14 @@ strpool_addstr (strpool_t *strpool, const char *str) return s; } +int +strpool_findstr (strpool_t *strpool, const char *str) +{ + if (!str) + return 0; + return (intptr_t) Hash_Find (strpool->str_tab, str); +} + static const char * ss_get_key (const void *s, void *unused) { @@ -131,7 +140,7 @@ save_string (const char *str) { char *s; if (!saved_strings) - saved_strings = Hash_NewTable (16381, ss_get_key, 0, 0); + saved_strings = Hash_NewTable (16381, ss_get_key, 0, 0, 0); s = Hash_Find (saved_strings, str); if (s) return s; @@ -140,6 +149,15 @@ save_string (const char *str) return s; } +const char * +save_cwd (void) +{ + char *cwd = getcwd (0, 0); + const char *str = save_string (cwd); + free (cwd); + return str; +} + const char * make_string (char *token, char **end) { @@ -188,6 +206,10 @@ make_string (char *token, char **end) boldnext = 0; c = '\'' ^ mask; break; + case '?': + boldnext = 0; + c = '?' ^ mask; + break; case '0': case '1': case '2': diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 4cb81fa74..ef9bd7389 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -47,20 +47,21 @@ #include #include -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "obj_type.h" -#include "qfcc.h" -#include "reloc.h" -#include "shared.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" static symbol_t * find_tag (ty_meta_e meta, symbol_t *tag, type_t *type) @@ -69,13 +70,13 @@ find_tag (ty_meta_e meta, symbol_t *tag, type_t *type) symbol_t *sym; if (tag) { - tag_name = va ("tag %s", tag->name); + tag_name = va (0, "tag %s", tag->name); } else { const char *path = GETSTR (pr.source_file); const char *file = strrchr (path, '/'); if (!file++) file = path; - tag_name = va ("tag .%s.%d", file, pr.source_line); + tag_name = va (0, "tag .%s.%d", file, pr.source_line); } sym = symtab_lookup (current_symtab, tag_name); if (sym) { @@ -112,6 +113,8 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) { symbol_t *sym = find_struct (su, tag, type); symbol_t *s; + int alignment = 1; + symbol_t *as; symtab->parent = 0; // disconnect struct's symtab from parent scope @@ -122,7 +125,12 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) for (s = symtab->symbols; s; s = s->next) { if (s->sy_type != sy_var) continue; + if (is_class (s->type)) { + error (0, "statically allocated instance of class %s", + s->type->t.class->name); + } if (su == 's') { + symtab->size = RUP (symtab->size, s->type->alignment); s->s.offset = symtab->size; symtab->size += type_size (s->type); } else { @@ -130,12 +138,42 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) if (size > symtab->size) symtab->size = size; } + if (s->type->alignment > alignment) { + alignment = s->type->alignment; + } + if (s->visibility == vis_anonymous) { + symtab_t *anonymous; + symbol_t *t = s->next; + int offset = s->s.offset; + + if (!is_struct (s->type)) { + internal_error (0, "non-struct/union anonymous field"); + } + anonymous = s->type->t.symtab; + for (as = anonymous->symbols; as; as = as->next) { + if (as->visibility == vis_anonymous || as->sy_type!= sy_var) { + continue; + } + if (Hash_Find (symtab->tab, as->name)) { + error (0, "ambiguous field `%s' in anonymous %s", + as->name, su == 's' ? "struct" : "union"); + } else { + s->next = copy_symbol (as); + s = s->next; + s->s.offset += offset; + s->table = symtab; + Hash_Add (symtab->tab, s); + } + } + s->next = t; + } } if (!type) sym->type = find_type (sym->type); // checks the tag, not the symtab sym->type->t.symtab = symtab; + sym->type->alignment = alignment; if (!type && sym->type->type_def->external) //FIXME should not be necessary - sym->type->type_def = qfo_encode_type (sym->type); + sym->type->type_def = qfo_encode_type (sym->type, pr.type_data); return sym; } @@ -159,29 +197,44 @@ start_enum (symbol_t *sym) symbol_t * finish_enum (symbol_t *sym) { - sym->type = find_type (sym->type); + symbol_t *enum_sym; + symbol_t *name; + type_t *enum_type; + symtab_t *enum_tab; + + enum_type = sym->type = find_type (sym->type); + enum_tab = enum_type->t.symtab; + enum_type->alignment = 1; + + for (name = enum_tab->symbols; name; name = name->next) { + name->type = sym->type; + + enum_sym = new_symbol_type (name->name, enum_type); + enum_sym->sy_type = sy_const; + enum_sym->s.value = name->s.value; + symtab_addsymbol (enum_tab->parent, enum_sym); + } return sym; } void add_enum (symbol_t *enm, symbol_t *name, expr_t *val) { - symbol_t *sym; type_t *enum_type = enm->type; - symtab_t *enum_tab; + symtab_t *enum_tab = enum_type->t.symtab; int value; - if (name->table == current_symtab) + if (name->table == current_symtab || name->table == enum_tab) error (0, "%s redefined", name->name); if (name->table) name = new_symbol (name->name); name->sy_type = sy_const; name->type = enum_type; - enum_tab = enum_type->t.symtab; value = 0; if (enum_tab->symbols) value = ((symbol_t *)(enum_tab->symtail))->s.value->v.integer_val + 1; if (val) { + convert_name (val); if (!is_constant (val)) error (val, "non-constant initializer"); else if (!is_integer_val (val)) @@ -191,10 +244,6 @@ add_enum (symbol_t *enm, symbol_t *name, expr_t *val) } name->s.value = new_integer_val (value); symtab_addsymbol (enum_tab, name); - sym = new_symbol_type (name->name, name->type); - sym->sy_type = sy_const; - sym->s.value = name->s.value; - symtab_addsymbol (enum_tab->parent, sym); } int @@ -246,6 +295,7 @@ make_structure (const char *name, int su, struct_def_t *defs, type_t *type) strct = new_symtab (0, stab_struct); while (defs->name) { field = new_symbol_type (defs->name, defs->type); + field->sy_type = sy_var; if (!symtab_addsymbol (strct, field)) internal_error (0, "duplicate symbol: %s", defs->name); defs++; @@ -256,7 +306,7 @@ make_structure (const char *name, int su, struct_def_t *defs, type_t *type) def_t * emit_structure (const char *name, int su, struct_def_t *defs, type_t *type, - void *data, storage_class_t storage) + void *data, defspace_t *space, storage_class_t storage) { int i, j; int saw_null = 0; @@ -291,7 +341,10 @@ emit_structure (const char *name, int su, struct_def_t *defs, type_t *type, if (storage != sc_global && storage != sc_static) internal_error (0, "structure %s must be global or static", name); - struct_sym = make_symbol (name, type, pr.far_data, storage); + if (!space) { + space = pr.far_data; + } + struct_sym = make_symbol (name, type, space, storage); struct_def = struct_sym->s.def; if (struct_def->initialized) @@ -302,7 +355,7 @@ emit_structure (const char *name, int su, struct_def_t *defs, type_t *type, for (i = 0, field_sym = type->t.symtab->symbols; field_sym; i++, field_sym = field_sym->next) { field_def.type = field_sym->type; - field_def.name = save_string (va ("%s.%s", name, field_sym->name)); + field_def.name = save_string (va (0, "%s.%s", name, field_sym->name)); field_def.space = struct_def->space; field_def.offset = struct_def->offset + field_sym->s.offset; if (!defs[i].emit) { diff --git a/tools/qfcc/source/stub.c b/tools/qfcc/source/stub.c index af6e70131..af31e546f 100644 --- a/tools/qfcc/source/stub.c +++ b/tools/qfcc/source/stub.c @@ -2,32 +2,56 @@ # include "config.h" #endif -#include "class.h" -#include "codespace.h" -#include "diagnostic.h" -#include "debug.h" -#include "def.h" -#include "defspace.h" -#include "emit.h" -#include "expr.h" -#include "function.h" -#include "obj_file.h" -#include "options.h" -#include "qfcc.h" -#include "strpool.h" -#include "type.h" -#include "value.h" +#include + +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/codespace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/dot.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/obj_file.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" struct dstring_s; options_t options; int num_linenos; pr_lineno_t *linenos; pr_info_t pr; -string_t ReuseString (const char *str) {return 0;} -void encode_type (struct dstring_s *str, const type_t *type) {} -codespace_t *codespace_new (void) {return 0;} +type_t type_Class; +type_t type_SEL; +type_t type_id; +__attribute__((const)) string_t ReuseString (const char *str) {return 0;} +__attribute__((const)) codespace_t *codespace_new (void) {return 0;} void codespace_addcode (codespace_t *codespace, struct dstatement_s *code, int size) {} -int function_parms (function_t *f, byte *parm_size) {return 0;} +__attribute__((const)) int function_parms (function_t *f, byte *parm_size) {return 0;} void def_to_ddef (def_t *def, ddef_t *ddef, int aux) {} -expr_t *warning (expr_t *e, const char *fmt, ...) {return 0;} -expr_t *error (expr_t *e, const char *fmt, ...) {return 0;} +__attribute__((noreturn)) void _internal_error (expr_t *e, const char *file, int line, const char *fmt, ...) {abort();} +__attribute__((const)) expr_t *_warning (expr_t *e, const char *file, int line, const char *fmt, ...) {return 0;} +__attribute__((const)) expr_t *_error (expr_t *e, const char *file, int line, const char *fmt, ...) {return 0;} +__attribute__((const)) symbol_t *make_structure (const char *name, int su, struct_def_t *defs, type_t *type) {return 0;} +__attribute__((const)) symbol_t *symtab_addsymbol (symtab_t *symtab, symbol_t *symbol) {return 0;} +__attribute__((const)) symbol_t *new_symbol_type (const char *name, type_t *type) {return 0;} +__attribute__((const)) def_t *qfo_encode_type (type_t *type, defspace_t *space) {return 0;} +__attribute__((const)) int obj_types_assignable (const type_t *dst, const type_t *src) {return 0;} +void print_protocollist (struct dstring_s *dstr, protocollist_t *protocollist) {} +int is_id (const type_t *type){return type->type;} +int is_SEL (const type_t *type){return type->type;} +int is_Class (const type_t *type){return type->type;} +int compare_protocols (protocollist_t *protos1, protocollist_t *protos2){return protos1->count - protos2->count;} +void dump_dot (const char *stage, void *data, + void (*dump_func) (void *data, const char *fname)){} +void dump_dot_type (void *_t, const char *filename){} +char *fubar; +const char *file_basename(const char *p, int keepdot) { return fubar;} diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 80321a9ab..77f490c76 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -42,18 +42,18 @@ #include #include -#include "def.h" -#include "diagnostic.h" -#include "expr.h" -#include "opcodes.h" -#include "options.h" -#include "qfcc.h" -#include "reloc.h" -#include "switch.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/opcodes.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/switch.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" -#include "qc-parse.h" +#include "tools/qfcc/source/qc-parse.h" typedef struct case_node_s { expr_t *low; @@ -63,7 +63,7 @@ typedef struct case_node_s { struct case_node_s *left, *right; } case_node_t; -static ex_value_t * +static __attribute__((pure)) ex_value_t * get_value (expr_t *e) { if (e->type == ex_symbol) @@ -73,7 +73,7 @@ get_value (expr_t *e) return e->e.value; } -static uintptr_t +static __attribute__((pure)) uintptr_t get_hash (const void *_cl, void *unused) { case_label_t *cl = (case_label_t *) _cl; @@ -82,7 +82,7 @@ get_hash (const void *_cl, void *unused) if (!cl->value) return 0; val = get_value (cl->value); - return Hash_Buffer (&val->v, sizeof (val->v)) + val->type; + return Hash_Buffer (&val->v, sizeof (val->v)) + val->lltype; } static int @@ -166,13 +166,13 @@ new_switch_block (void) switch_block_t *switch_block = malloc (sizeof (switch_block_t)); SYS_CHECKMEM (switch_block); - switch_block->labels = Hash_NewTable (127, 0, 0, 0); + switch_block->labels = Hash_NewTable (127, 0, 0, 0, 0); Hash_SetHashCompare (switch_block->labels, get_hash, compare); switch_block->test = 0; return switch_block; } -static int +static __attribute__((pure)) int label_compare (const void *_a, const void *_b) { const case_label_t **a = (const case_label_t **) _a; @@ -213,7 +213,7 @@ new_case_node (expr_t *low, expr_t *high) if (!is_integer_val (low)) internal_error (low, "switch"); size = expr_integer (high) - expr_integer (low) + 1; - node->labels = calloc (size, sizeof (case_node_t *)); + node->labels = calloc (size, sizeof (expr_t *)); } node->left = node->right = 0; return node; @@ -337,17 +337,18 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val, const char *table_name = new_label_name (); int i; expr_t *range = binary_expr ('-', tree->high, tree->low); + expr_t *label; - range = fold_constants (range); - - table_init = new_block_expr (); + table_init = new_compound_init (); for (i = 0; i <= high - low; i++) { tree->labels[i]->e.label.used++; - append_expr (table_init, address_expr (tree->labels[i], 0, 0)); + label = address_expr (tree->labels[i], 0, 0); + append_element (table_init, new_element (label, 0)); } - table_sym = new_symbol (table_name); - initialize_def (table_sym, array_type (&type_integer, high - low + 1), - table_init, pr.near_data, sc_static); + table_sym = new_symbol_type (table_name, + array_type (&type_integer, + high - low + 1)); + initialize_def (table_sym, table_init, pr.near_data, sc_static); table_expr = new_symbol_expr (table_sym); if (tree->left) { @@ -428,8 +429,7 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label, for (l = labels; *l; l++) num_labels++; if (options.code.progsversion == PROG_ID_VERSION - || (type != &type_string - && type != &type_float && !is_integral (type)) + || (!is_string(type) && !is_float(type) && !is_integral (type)) || num_labels < 8) { for (l = labels; *l; l++) { expr_t *cmp = binary_expr (EQ, sw_val, (*l)->value); @@ -445,7 +445,7 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label, int op; case_node_t *case_tree; - if (type == &type_string) + if (is_string(type)) temp = new_temp_def_expr (&type_integer); else temp = new_temp_def_expr (type); diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c index 3e18cf615..ca08069bf 100644 --- a/tools/qfcc/source/symtab.c +++ b/tools/qfcc/source/symtab.c @@ -37,27 +37,29 @@ #include "QF/alloc.h" #include "QF/hash.h" -#include "class.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "function.h" -#include "qfcc.h" -#include "reloc.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" static symtab_t *symtabs_freelist; static symbol_t *symbols_freelist; static const char *sy_type_names[] = { + "sy_name", "sy_var", "sy_const", "sy_type", "sy_expr", "sy_func", "sy_class", + "sy_convert", }; const char * @@ -104,7 +106,7 @@ new_symtab (symtab_t *parent, stab_type_e type) symtab->type = type; if (symtab->type == stab_global) tabsize = 1023; - symtab->tab = Hash_NewTable (tabsize, sym_getkey, 0, 0); + symtab->tab = Hash_NewTable (tabsize, sym_getkey, 0, 0, 0); symtab->symtail = &symtab->symbols; return symtab; } @@ -151,7 +153,7 @@ symtab_removesymbol (symtab_t *symtab, symbol_t *symbol) for (s = &symtab->symbols; *s && *s != symbol; s = & (*s)->next) ; if (!*s) - internal_error (0, "symtab_removesymbol"); + internal_error (0, "attempt to remove symbol not in symtab"); *s = (*s)->next; if (symtab->symtail == &symbol->next) symtab->symtail = s; @@ -164,6 +166,7 @@ symbol_t * copy_symbol (symbol_t *symbol) { symbol_t *sym = new_symbol (symbol->name); + sym->visibility = symbol->visibility; sym->type = symbol->type; sym->params = copy_params (symbol->params); sym->sy_type = symbol->sy_type; @@ -181,7 +184,8 @@ symtab_flat_copy (symtab_t *symtab, symtab_t *parent) newtab = new_symtab (parent, stab_local); do { for (symbol = symtab->symbols; symbol; symbol = symbol->next) { - if (Hash_Find (newtab->tab, symbol->name)) + if (symbol->visibility == vis_anonymous + || Hash_Find (newtab->tab, symbol->name)) continue; newsym = copy_symbol (symbol); symtab_addsymbol (newtab, newsym); @@ -234,5 +238,6 @@ make_symbol (const char *name, type_t *type, defspace_t *space, sym->s.def = new_def (name, type, space, storage); reloc_attach_relocs (relocs, &sym->s.def->relocs); } + sym->sy_type = sy_var; return sym; } diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 586a7b1a0..c6b92b94e 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -47,53 +47,78 @@ #include "QF/sys.h" #include "QF/va.h" -#include "class.h" -#include "def.h" -#include "diagnostic.h" -#include "expr.h" -#include "function.h" -#include "obj_type.h" -#include "options.h" -#include "qfcc.h" -#include "strpool.h" -#include "struct.h" -#include "symtab.h" -#include "type.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/obj_type.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" // simple types. function types are dynamically allocated type_t type_invalid = { ev_invalid, "invalid" }; -type_t type_void = { ev_void, "void" }; -type_t type_string = { ev_string, "string" }; -type_t type_float = { ev_float, "float" }; -type_t type_vector = { ev_vector, "vector" }; -type_t type_entity = { ev_entity, "entity" }; -type_t type_field = {ev_field, "field", ty_none, {{&type_void}} }; +type_t type_void = { ev_void, "void", 1 }; +type_t type_string = { ev_string, "string", 1 }; +type_t type_float = { ev_float, "float", 1 }; +type_t type_vector = { ev_vector, "vector", 1 }; +type_t type_entity = { ev_entity, "entity", 1 }; +type_t type_field = {ev_field, "field", 1, ty_basic, {{&type_void}} }; // type_function is a void() function used for state defs -type_t type_function = { ev_func, "function", ty_none, {{&type_void}} }; -type_t type_pointer = { ev_pointer, "pointer", ty_none, {{&type_void}} }; -type_t type_quaternion = { ev_quat, "quaternion" }; -type_t type_integer = { ev_integer, "integer" }; -type_t type_uinteger = { ev_uinteger, "uinteger" }; -type_t type_short = { ev_short, "short" }; +type_t type_function = { ev_func, "function", 1, ty_basic, + {{&type_void}} }; +type_t type_pointer = { ev_pointer, "pointer", 1, ty_basic, + {{&type_void}} }; +type_t type_quaternion = { ev_quat, "quaternion", 1 }; +type_t type_integer = { ev_integer, "int", 1 }; +type_t type_uinteger = { ev_uinteger, "uint", 1 }; +type_t type_short = { ev_short, "short", 1 }; +type_t type_double = { ev_double, "double", 2 }; type_t *type_nil; type_t *type_default; // these will be built up further -type_t type_va_list = { ev_invalid, 0, ty_struct }; -type_t type_param = { ev_invalid, 0, ty_struct }; -type_t type_zero = { ev_invalid, 0, ty_struct }; -type_t type_type_encodings = { ev_invalid, "@type_encodings", ty_struct }; +type_t type_va_list = { ev_invalid, 0, 0, ty_struct }; +type_t type_param = { ev_invalid, 0, 0, ty_struct }; +type_t type_zero = { ev_invalid, 0, 0, ty_struct }; +type_t type_type_encodings = { ev_invalid, "@type_encodings", 0, + ty_struct }; +type_t type_xdef = { ev_invalid, "@xdef", 0, ty_struct }; +type_t type_xdef_pointer = { ev_pointer, 0, 1, ty_basic, {{&type_xdef}} }; +type_t type_xdefs = { ev_invalid, "@xdefs", 0, ty_struct }; -type_t type_floatfield = { ev_field, ".float", ty_none, {{&type_float}} }; +type_t type_floatfield = { ev_field, ".float", 1, ty_basic, + {{&type_float}} }; + +type_t *ev_types[ev_type_count] = { + &type_void, + &type_string, + &type_float, + &type_vector, + &type_entity, + &type_field, + &type_function, + &type_pointer, + &type_quaternion, + &type_integer, + &type_uinteger, + &type_short, + &type_double, + &type_invalid, +}; static type_t *types_freelist; etype_t low_level_type (type_t *type) { - if (type->type >= ev_type_count) + if (type->type > ev_type_count) internal_error (0, "invalid type"); if (type->type == ev_type_count) internal_error (0, "found 'type count' type"); @@ -131,7 +156,7 @@ chain_type (type_t *type) if (!type->encoding) type->encoding = type_get_encoding (type); if (!type->type_def) - type->type_def = qfo_encode_type (type); + type->type_def = qfo_encode_type (type, pr.type_data); } type_t * @@ -164,6 +189,7 @@ free_type (type_t *type) case ev_integer: case ev_uinteger: case ev_short: + case ev_double: break; case ev_field: case ev_pointer: @@ -181,44 +207,118 @@ free_type (type_t *type) FREE (types, type); } +static type_t * +copy_chain (type_t *type, type_t *append) +{ + type_t *new = 0; + type_t **n = &new; + + while (type) { + *n = new_type (); + **n = *type; + switch (type->meta) { + case ty_basic: + switch (type->type) { + case ev_void: + case ev_string: + case ev_float: + case ev_vector: + case ev_entity: + case ev_type_count: + case ev_quat: + case ev_integer: + case ev_uinteger: + case ev_short: + case ev_double: + internal_error (0, "copy basic type"); + case ev_field: + case ev_pointer: + n = &(*n)->t.fldptr.type; + type = type->t.fldptr.type; + break; + case ev_func: + n = &(*n)->t.func.type; + type = type->t.func.type; + break; + case ev_invalid: + internal_error (0, "invalid basic type"); + break; + } + break; + case ty_array: + n = &(*n)->t.array.type; + type = type->t.array.type; + break; + case ty_struct: + case ty_union: + case ty_enum: + case ty_class: + case ty_alias: //XXX is this correct? + internal_error (0, "copy object type %d", type->meta); + } + } + *n = append; + return new; +} + type_t * append_type (type_t *type, type_t *new) { type_t **t = &type; while (*t) { - switch ((*t)->type) { - case ev_void: - case ev_string: - case ev_float: - case ev_vector: - case ev_entity: - case ev_type_count: - case ev_quat: - case ev_integer: - case ev_uinteger: - case ev_short: - internal_error (0, "append to basic type"); - case ev_field: - case ev_pointer: - t = &(*t)->t.fldptr.type; + switch ((*t)->meta) { + case ty_basic: + switch ((*t)->type) { + case ev_void: + case ev_string: + case ev_float: + case ev_vector: + case ev_entity: + case ev_type_count: + case ev_quat: + case ev_integer: + case ev_uinteger: + case ev_short: + case ev_double: + internal_error (0, "append to basic type"); + case ev_field: + case ev_pointer: + t = &(*t)->t.fldptr.type; + type->alignment = 1; + break; + case ev_func: + t = &(*t)->t.func.type; + type->alignment = 1; + break; + case ev_invalid: + internal_error (0, "invalid basic type"); + break; + } break; - case ev_func: - t = &(*t)->t.func.type; - break; - case ev_invalid: - if ((*t)->meta == ty_array) - t = &(*t)->t.array.type; - else - internal_error (0, "append to object type"); + case ty_array: + t = &(*t)->t.array.type; + type->alignment = new->alignment; break; + case ty_struct: + case ty_union: + case ty_enum: + case ty_class: + case ty_alias: //XXX is this correct? + internal_error (0, "append to object type"); } } - *t = new; + if (type && new->meta == ty_alias) { + type_t *chain = find_type (copy_chain (type, new)); + *t = new->t.alias.aux_type; + type = alias_type (type, chain, 0); + } else { + *t = new; + } return type; } -static int +static __attribute__((pure)) int types_same (type_t *a, type_t *b) { int i, count; @@ -226,7 +326,7 @@ types_same (type_t *a, type_t *b) if (a->type != b->type || a->meta != b->meta) return 0; switch (a->meta) { - case ty_none: + case ty_basic: switch (a->type) { case ev_field: case ev_pointer: @@ -266,6 +366,11 @@ types_same (type_t *a, type_t *b) if (a->t.class != b->t.class) return 0; return compare_protocols (a->protos, b->protos); + case ty_alias: + // names have gone through save_string + return (a->name == b->name + && a->t.alias.aux_type == b->t.alias.aux_type + && a->t.alias.full_type == b->t.alias.full_type); } internal_error (0, "we be broke"); } @@ -287,7 +392,7 @@ find_type (type_t *type) if (type->freeable) { switch (type->meta) { - case ty_none: + case ty_basic: switch (type->type) { case ev_field: case ev_pointer: @@ -315,6 +420,9 @@ find_type (type_t *type) break; case ty_class: break; + case ty_alias: + type->t.alias.aux_type = find_type (type->t.alias.aux_type); + break; } } @@ -344,9 +452,10 @@ field_type (type_t *aux) else new = new_type (); new->type = ev_field; - new->t.fldptr.type = aux; - if (aux) - new = find_type (new); + new->alignment = 1; + if (aux) { + new = find_type (append_type (new, aux)); + } return new; } @@ -361,9 +470,10 @@ pointer_type (type_t *aux) else new = new_type (); new->type = ev_pointer; - new->t.fldptr.type = aux; - if (aux) - new = find_type (new); + new->alignment = 1; + if (aux) { + new = find_type (append_type (new, aux)); + } return new; } @@ -377,12 +487,15 @@ array_type (type_t *aux, int size) memset (&_new, 0, sizeof (_new)); else new = new_type (); - new->type = ev_invalid; new->meta = ty_array; - new->t.array.type = aux; + new->type = ev_invalid; + if (aux) { + new->alignment = aux->alignment; + } new->t.array.size = size; - if (aux) - new = find_type (new); + if (aux) { + new = find_type (append_type (new, aux)); + } return new; } @@ -397,6 +510,9 @@ based_array_type (type_t *aux, int base, int top) else new = new_type (); new->type = ev_invalid; + if (aux) { + new->alignment = aux->alignment; + } new->meta = ty_array; new->t.array.type = aux; new->t.array.base = base; @@ -406,6 +522,43 @@ based_array_type (type_t *aux, int base, int top) return new; } +type_t * +alias_type (type_t *type, type_t *alias_chain, const char *name) +{ + type_t *alias = new_type (); + alias->meta = ty_alias; + alias->type = type->type; + alias->alignment = type->alignment; + if (type == alias_chain && type->meta == ty_alias) { + // typedef of a type that contains a typedef somewhere + // grab the alias-free branch for type + type = alias_chain->t.alias.aux_type; + if (!alias_chain->name) { + // the other typedef is further inside, so replace the unnamed + // alias node with the typedef + alias_chain = alias_chain->t.alias.full_type; + } + } + alias->t.alias.aux_type = type; + alias->t.alias.full_type = alias_chain; + if (name) { + alias->name = save_string (name); + } + return alias; +} + +const type_t * +unalias_type (const type_t *type) +{ + if (type->meta == ty_alias) { + type = type->t.alias.aux_type; + if (type->meta == ty_alias) { + internal_error (0, "alias type node in alias-free chain"); + } + } + return type; +} + void print_type_str (dstring_t *str, const type_t *type) { @@ -413,79 +566,95 @@ print_type_str (dstring_t *str, const type_t *type) dasprintf (str, " (null)"); return; } - switch (type->type) { - case ev_field: - dasprintf (str, ".("); - print_type_str (str, type->t.fldptr.type); - dasprintf (str, ")"); - break; - case ev_func: - print_type_str (str, type->t.func.type); - if (type->t.func.num_params == -1) { - dasprintf (str, "(...)"); + switch (type->meta) { + case ty_alias: + dasprintf (str, "({%s=", type->name); + print_type_str (str, type->t.alias.aux_type); + dstring_appendstr (str, "})"); + return; + case ty_class: + dasprintf (str, " %s", type->t.class->name); + if (type->protos) + print_protocollist (str, type->protos); + return; + case ty_enum: + dasprintf (str, " enum %s", type->name); + return; + case ty_struct: + dasprintf (str, " struct %s", type->name); + return; + case ty_union: + dasprintf (str, " union %s", type->name); + return; + case ty_array: + print_type_str (str, type->t.array.type); + if (type->t.array.base) { + dasprintf (str, "[%d..%d]", type->t.array.base, + type->t.array.base + type->t.array.size - 1); } else { - int c, i; - dasprintf (str, "("); - if ((c = type->t.func.num_params) < 0) - c = ~c; // num_params is one's compliment - for (i = 0; i < c; i++) { - if (i) - dasprintf (str, ", "); - print_type_str (str, type->t.func.param_types[i]); - } - if (type->t.func.num_params < 0) - dasprintf (str, ", ..."); - dasprintf (str, ")"); + dasprintf (str, "[%d]", type->t.array.size); } - break; - case ev_pointer: - if (obj_is_id (type)) { - dasprintf (str, "id"); - if (type->t.fldptr.type->protos) - print_protocollist (str, type->t.fldptr.type->protos); - break; - } - if (type == &type_SEL) { - dasprintf (str, "SEL"); - break; - } - dasprintf (str, "(*"); - print_type_str (str, type->t.fldptr.type); - dasprintf (str, ")"); - break; - case ev_invalid: - switch (type->meta) { - case ty_class: - dasprintf (str, " %s", type->t.class->name); - if (type->protos) - print_protocollist (str, type->protos); - break; - case ty_enum: - dasprintf (str, " enum %s", type->name); - break; - case ty_struct: - dasprintf (str, " struct %s", type->name); - break; - case ty_union: - dasprintf (str, " union %s", type->name); - break; - case ty_array: - print_type_str (str, type->t.array.type); - if (type->t.array.base) { - dasprintf (str, "[%d..%d]", type->t.array.base, - type->t.array.base + type->t.array.size - 1); + return; + case ty_basic: + switch (type->type) { + case ev_field: + dasprintf (str, ".("); + print_type_str (str, type->t.fldptr.type); + dasprintf (str, ")"); + return; + case ev_func: + print_type_str (str, type->t.func.type); + if (type->t.func.num_params == -1) { + dasprintf (str, "(...)"); } else { - dasprintf (str, "[%d]", type->t.array.size); + int c, i; + dasprintf (str, "("); + if ((c = type->t.func.num_params) < 0) + c = ~c; // num_params is one's compliment + for (i = 0; i < c; i++) { + if (i) + dasprintf (str, ", "); + print_type_str (str, type->t.func.param_types[i]); + } + if (type->t.func.num_params < 0) + dasprintf (str, ", ..."); + dasprintf (str, ")"); } - break; - case ty_none: + return; + case ev_pointer: + if (is_id (type)) { + dasprintf (str, "id"); + if (type->t.fldptr.type->protos) + print_protocollist (str, type->t.fldptr.type->protos); + return; + } + if (is_SEL(type)) { + dasprintf (str, "SEL"); + return; + } + dasprintf (str, "(*"); + print_type_str (str, type->t.fldptr.type); + dasprintf (str, ")"); + return; + case ev_void: + case ev_string: + case ev_float: + case ev_vector: + case ev_entity: + case ev_quat: + case ev_integer: + case ev_uinteger: + case ev_short: + case ev_double: + dasprintf (str, " %s", pr_type_name[type->type]); + return; + case ev_invalid: + case ev_type_count: break; } break; - default: - dasprintf (str, " %s", pr_type_name[type->type]); - break; } + internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); } void @@ -509,7 +678,7 @@ encode_params (const type_t *type) else count = type->t.func.num_params; for (i = 0; i < count; i++) - encode_type (encoding, type->t.func.param_types[i]); + encode_type (encoding, unalias_type (type->t.func.param_types[i])); if (type->t.func.num_params < 0) dasprintf (encoding, "."); @@ -559,131 +728,195 @@ encode_type (dstring_t *encoding, const type_t *type) { if (!type) return; - switch (type->type) { - case ev_void: - dasprintf (encoding, "v"); - break; - case ev_string: - dasprintf (encoding, "*"); - break; - case ev_float: - dasprintf (encoding, "f"); - break; - case ev_vector: - dasprintf (encoding, "V"); - break; - case ev_entity: - dasprintf (encoding, "E"); - break; - case ev_field: - dasprintf (encoding, "F"); - encode_type (encoding, type->t.fldptr.type); - break; - case ev_func: - dasprintf (encoding, "("); - encode_type (encoding, type->t.func.type); - dasprintf (encoding, "%s)", encode_params (type)); - break; - case ev_pointer: - if (type == &type_id) { - dasprintf (encoding, "@"); + switch (type->meta) { + case ty_alias: // XXX do I want this, or just the unaliased type? + dasprintf (encoding, "{%s>", type->name); + encode_type (encoding, type->t.alias.aux_type); + dasprintf (encoding, "}"); + return; + case ty_class: + encode_class (encoding, type); + return; + case ty_enum: + encode_enum (encoding, type); + return; + case ty_struct: + case ty_union: + encode_struct (encoding, type); + return; + case ty_array: + dasprintf (encoding, "["); + dasprintf (encoding, "%d", type->t.array.size); + if (type->t.array.base) + dasprintf (encoding, ":%d", type->t.array.base); + dasprintf (encoding, "="); + encode_type (encoding, type->t.array.type); + dasprintf (encoding, "]"); + return; + case ty_basic: + switch (type->type) { + case ev_void: + dasprintf (encoding, "v"); + return; + case ev_string: + dasprintf (encoding, "*"); + return; + case ev_double: + dasprintf (encoding, "d"); + return; + case ev_float: + dasprintf (encoding, "f"); + return; + case ev_vector: + dasprintf (encoding, "V"); + return; + case ev_entity: + dasprintf (encoding, "E"); + return; + case ev_field: + dasprintf (encoding, "F"); + encode_type (encoding, type->t.fldptr.type); + return; + case ev_func: + dasprintf (encoding, "("); + encode_type (encoding, type->t.func.type); + dasprintf (encoding, "%s)", encode_params (type)); + return; + case ev_pointer: + if (is_id(type)) { + dasprintf (encoding, "@"); + return; + } + if (is_SEL(type)) { + dasprintf (encoding, ":"); + return; + } + if (is_Class(type)) { + dasprintf (encoding, "#"); + return; + } + type = type->t.fldptr.type; + dasprintf (encoding, "^"); + encode_type (encoding, type); + return; + case ev_quat: + dasprintf (encoding, "Q"); + return; + case ev_integer: + dasprintf (encoding, "i"); + return; + case ev_uinteger: + dasprintf (encoding, "I"); + return; + case ev_short: + dasprintf (encoding, "s"); + return; + case ev_invalid: + case ev_type_count: break; } - if (type == &type_SEL) { - dasprintf (encoding, ":"); - break; - } - if (type == &type_Class) { - dasprintf (encoding, "#"); - break; - } - type = type->t.fldptr.type; - dasprintf (encoding, "^"); - encode_type (encoding, type); - break; - case ev_quat: - dasprintf (encoding, "Q"); - break; - case ev_integer: - dasprintf (encoding, "i"); - break; - case ev_uinteger: - dasprintf (encoding, "I"); - break; - case ev_short: - dasprintf (encoding, "s"); - break; - case ev_invalid: - switch (type->meta) { - case ty_class: - encode_class (encoding, type); - break; - case ty_enum: - encode_enum (encoding, type); - break; - case ty_struct: - case ty_union: - encode_struct (encoding, type); - break; - case ty_array: - dasprintf (encoding, "["); - dasprintf (encoding, "%d", type->t.array.size); - if (type->t.array.base) - dasprintf (encoding, ":%d", type->t.array.base); - dasprintf (encoding, "="); - encode_type (encoding, type->t.array.type); - dasprintf (encoding, "]"); - break; - case ty_none: - dasprintf (encoding, "?"); - break; - } - break; - case ev_type_count: - dasprintf (encoding, "?"); break; } + internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); } int is_void (const type_t *type) { + type = unalias_type (type); return type->type == ev_void; } int is_enum (const type_t *type) { + type = unalias_type (type); if (type->type == ev_invalid && type->meta == ty_enum) return 1; return 0; } int -is_integral (const type_t *type) +is_integer (const type_t *type) { + type = unalias_type (type); etype_t t = type->type; - if (t == ev_integer || t == ev_uinteger || t == ev_short) + if (t == ev_integer) return 1; return is_enum (type); } +int +is_uinteger (const type_t *type) +{ + type = unalias_type (type); + etype_t t = type->type; + + if (t == ev_uinteger) + return 1; + return is_enum (type); +} + +int +is_short (const type_t *type) +{ + type = unalias_type (type); + etype_t t = type->type; + + if (t == ev_short) + return 1; + return is_enum (type); +} + +int +is_integral (const type_t *type) +{ + type = unalias_type (type); + if (is_integer (type) || is_uinteger (type) || is_short (type)) + return 1; + return is_enum (type); +} + +int +is_double (const type_t *type) +{ + type = unalias_type (type); + return type->type == ev_double; +} + int is_float (const type_t *type) { + type = unalias_type (type); return type->type == ev_float; } int is_scalar (const type_t *type) { - return is_float (type) || is_integral (type); + type = unalias_type (type); + return is_float (type) || is_integral (type) || is_double (type); +} + +int +is_vector (const type_t *type) +{ + type = unalias_type (type); + return type->type == ev_vector; +} + +int +is_quaternion (const type_t *type) +{ + type = unalias_type (type); + return type->type == ev_quat; } int is_math (const type_t *type) { + type = unalias_type (type); etype_t t = type->type; return t == ev_vector || t == ev_quat || is_scalar (type); @@ -692,6 +925,7 @@ is_math (const type_t *type) int is_struct (const type_t *type) { + type = unalias_type (type); if (type->type == ev_invalid && (type->meta == ty_struct || type->meta == ty_union)) return 1; @@ -701,24 +935,90 @@ is_struct (const type_t *type) int is_pointer (const type_t *type) { + type = unalias_type (type); if (type->type == ev_pointer) return 1; return 0; } +int +is_field (const type_t *type) +{ + type = unalias_type (type); + if (type->type == ev_field) + return 1; + return 0; +} + +int +is_entity (const type_t *type) +{ + type = unalias_type (type); + if (type->type == ev_entity) + return 1; + return 0; +} + int is_array (const type_t *type) { + type = unalias_type (type); if (type->type == ev_invalid && type->meta == ty_array) return 1; return 0; } +int +is_func (const type_t *type) +{ + type = unalias_type (type); + if (type->type == ev_func) + return 1; + return 0; +} + +int +is_structural (const type_t *type) +{ + type = unalias_type (type); + return is_struct (type) || is_array (type); +} + +int +is_string (const type_t *type) +{ + type = unalias_type (type); + if (type->type == ev_string) + return 1; + return 0; +} + +int +type_compatible (const type_t *dst, const type_t *src) +{ + // same type + if (dst == src) { + return 1; + } + if (is_field (dst) && is_field (src)) { + return 1; + } + if (is_func (dst) && is_func (src)) { + return 1; + } + if (is_pointer (dst) && is_pointer (src)) { + return 1; + } + return 0; +} + int type_assignable (const type_t *dst, const type_t *src) { int ret; + dst = unalias_type (dst); + src = unalias_type (src); // same type if (dst == src) return 1; @@ -744,6 +1044,9 @@ type_assignable (const type_t *dst, const type_t *src) dst = dst->t.fldptr.type; src = src->t.fldptr.type; + if (dst == src) { + return 1; + } if (is_void (dst)) return 1; if (is_void (src)) @@ -754,55 +1057,78 @@ type_assignable (const type_t *dst, const type_t *src) int type_size (const type_t *type) { - if (!type) - return 0; - switch (type->type) { - case ev_void: - case ev_string: - case ev_float: - case ev_vector: - case ev_entity: - case ev_field: - case ev_func: - case ev_pointer: - case ev_quat: - case ev_integer: - case ev_uinteger: - case ev_short: - case ev_type_count: + switch (type->meta) { + case ty_basic: return pr_type_size[type->type]; - case ev_invalid: - switch (type->meta) { - case ty_enum: - if (!type->t.symtab) - return 0; - return type_size (&type_integer); - case ty_struct: - case ty_union: - if (!type->t.symtab) - return 0; - return type->t.symtab->size; - case ty_class: - { - class_t *class = type->t.class; - int size; - if (!class->ivars) - return 0; - size = class->ivars->size; - if (class->super_class) - size += type_size (class->super_class->type); - return size; - } - case ty_array: - return type->t.array.size * type_size (type->t.array.type); - case ty_none: + case ty_struct: + case ty_union: + if (!type->t.symtab) + return 0; + return type->t.symtab->size; + case ty_enum: + if (!type->t.symtab) + return 0; + return type_size (&type_integer); + case ty_array: + return type->t.array.size * type_size (type->t.array.type); + case ty_class: + { + class_t *class = type->t.class; + int size; + if (!class->ivars) return 0; + size = class->ivars->size; + if (class->super_class) + size += type_size (class->super_class->type); + return size; } - break; + case ty_alias: + return type_size (type->t.alias.aux_type); } return 0; } +static void +chain_basic_types (void) +{ + chain_type (&type_void); + chain_type (&type_string); + chain_type (&type_float); + chain_type (&type_vector); + type_entity.t.symtab = pr.entity_fields; + chain_type (&type_entity); + chain_type (&type_field); + chain_type (&type_function); + chain_type (&type_pointer); + chain_type (&type_floatfield); + if (!options.traditional) { + chain_type (&type_quaternion); + chain_type (&type_integer); + chain_type (&type_uinteger); + chain_type (&type_short); + chain_type (&type_double); + } +} + +static void +chain_structural_types (void) +{ + chain_type (&type_param); + chain_type (&type_zero); + chain_type (&type_type_encodings); + chain_type (&type_xdef); + chain_type (&type_xdef_pointer); + chain_type (&type_xdefs); + chain_type (&type_va_list); +} + +void +chain_initial_types (void) +{ + chain_basic_types (); + chain_structural_types (); +} + void init_types (void) { @@ -819,6 +1145,7 @@ init_types (void) {"integer_val", &type_integer}, {"uinteger_val", &type_uinteger}, {"quaternion_val", &type_quaternion}, + {"double_val", &type_double}, {0, 0} }; static struct_def_t param_struct[] = { @@ -834,6 +1161,7 @@ init_types (void) {"integer_val", &type_integer}, {"uinteger_val", &type_uinteger}, {"quaternion_val", &type_quaternion}, + {"double_val", &type_double}, {0, 0} }; static struct_def_t vector_struct[] = { @@ -843,8 +1171,8 @@ init_types (void) {0, 0} }; static struct_def_t quaternion_struct[] = { - {"s", &type_float}, {"v", &type_vector}, + {"s", &type_float}, {0, 0} }; static struct_def_t type_encoding_struct[] = { @@ -852,6 +1180,23 @@ init_types (void) {"size", &type_integer}, {0, 0} }; + static struct_def_t xdef_struct[] = { + {"types", &type_pointer}, + {"offset", &type_pointer}, + {0, 0} + }; + static struct_def_t xdefs_struct[] = { + {"xdefs", &type_xdef_pointer}, + {"num_xdefs", &type_pointer}, + {0, 0} + }; + static struct_def_t va_list_struct[] = { + {"count", &type_integer}, + {"list", 0}, // type will be filled in at runtime + {0, 0} + }; + + chain_basic_types (); type_nil = &type_quaternion; type_default = &type_integer; @@ -869,65 +1214,34 @@ init_types (void) make_structure ("@param", 'u', param_struct, &type_param); make_structure ("@vector", 's', vector_struct, &type_vector); type_vector.type = ev_vector; - type_vector.meta = ty_none; + type_vector.meta = ty_basic; make_structure ("@type_encodings", 's', type_encoding_struct, &type_type_encodings); - - if (options.traditional) - return; - - make_structure ("@quaternion", 's', quaternion_struct, &type_quaternion); - type_quaternion.type = ev_quat; - type_quaternion.meta = ty_none; - { - symbol_t *sym; - sym = new_symbol_type ("w", &type_float); - sym->s.offset = 0; - symtab_addsymbol (type_quaternion.t.symtab, sym); - sym = new_symbol_type ("x", &type_float); - sym->s.offset = 1; - symtab_addsymbol (type_quaternion.t.symtab, sym); - sym = new_symbol_type ("y", &type_float); - sym->s.offset = 2; - symtab_addsymbol (type_quaternion.t.symtab, sym); - sym = new_symbol_type ("z", &type_float); - sym->s.offset = 3; - symtab_addsymbol (type_quaternion.t.symtab, sym); - } -} - -void -chain_initial_types (void) -{ - static struct_def_t va_list_struct[] = { - {"count", &type_integer}, - {"list", 0}, // type will be filled in at runtime - {0, 0} - }; - - chain_type (&type_void); - chain_type (&type_string); - chain_type (&type_float); - chain_type (&type_vector); - type_entity.t.symtab = pr.entity_fields; - chain_type (&type_entity); - chain_type (&type_field); - chain_type (&type_function); - chain_type (&type_pointer); - chain_type (&type_floatfield); - if (!options.traditional) { - chain_type (&type_quaternion); - chain_type (&type_integer); - chain_type (&type_uinteger); - chain_type (&type_short); - } - - chain_type (&type_param); - chain_type (&type_zero); - chain_type (&type_type_encodings); + make_structure ("@xdef", 's', xdef_struct, &type_xdef); + make_structure ("@xdefs", 's', xdefs_struct, &type_xdefs); va_list_struct[1].type = pointer_type (&type_param); make_structure ("@va_list", 's', va_list_struct, &type_va_list); - chain_type (&type_va_list); + + make_structure ("@quaternion", 's', quaternion_struct, &type_quaternion); + type_quaternion.type = ev_quat; + type_quaternion.meta = ty_basic; + { + symbol_t *sym; + sym = new_symbol_type ("x", &type_float); + sym->s.offset = 0; + symtab_addsymbol (type_quaternion.t.symtab, sym); + sym = new_symbol_type ("y", &type_float); + sym->s.offset = 1; + symtab_addsymbol (type_quaternion.t.symtab, sym); + sym = new_symbol_type ("z", &type_float); + sym->s.offset = 2; + symtab_addsymbol (type_quaternion.t.symtab, sym); + sym = new_symbol_type ("w", &type_float); + sym->s.offset = 3; + symtab_addsymbol (type_quaternion.t.symtab, sym); + } + + chain_structural_types (); } diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index 1eab5ec68..db98cd60a 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -45,17 +45,17 @@ #include "QF/mathlib.h" #include "QF/va.h" -#include "qfcc.h" -#include "def.h" -#include "defspace.h" -#include "diagnostic.h" -#include "emit.h" -#include "expr.h" -#include "reloc.h" -#include "strpool.h" -#include "symtab.h" -#include "type.h" -#include "value.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" typedef struct { def_t *def; @@ -69,6 +69,7 @@ typedef struct { ex_pointer_t pointer; float quaternion_val[4]; int integer_val; + double double_val; } i; } immediate_t; @@ -79,7 +80,7 @@ static uintptr_t value_get_hash (const void *_val, void *unused) { const ex_value_t *val = (const ex_value_t *) _val; - return Hash_Buffer (&val->v, sizeof (val->v)) + val->type; + return Hash_Buffer (&val->v, sizeof (val->v)) ^ (uintptr_t) val->type; } static int @@ -100,6 +101,13 @@ new_value (void) return value; } +static void +set_val_type (ex_value_t *val, type_t *type) +{ + val->type = type; + val->lltype = low_level_type (type); +} + static ex_value_t * find_value (const ex_value_t *val) { @@ -119,18 +127,28 @@ new_string_val (const char *string_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_string; + set_val_type (&val, &type_string); if (string_val) val.v.string_val = save_string (string_val); return find_value (&val); } +ex_value_t * +new_double_val (double double_val) +{ + ex_value_t val; + memset (&val, 0, sizeof (val)); + set_val_type (&val, &type_double); + val.v.double_val = double_val; + return find_value (&val); +} + ex_value_t * new_float_val (float float_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_float; + set_val_type (&val, &type_float); val.v.float_val = float_val; return find_value (&val); } @@ -140,7 +158,7 @@ new_vector_val (const float *vector_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_vector; + set_val_type (&val, &type_vector); VectorCopy (vector_val, val.v.vector_val); return find_value (&val); } @@ -150,7 +168,7 @@ new_entity_val (int entity_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_entity; + set_val_type (&val, &type_entity); val.v.entity_val = entity_val; return find_value (&val); } @@ -160,7 +178,7 @@ new_field_val (int field_val, type_t *type, def_t *def) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_field; + set_val_type (&val, field_type (type)); val.v.pointer.val = field_val; val.v.pointer.type = type; val.v.pointer.def = def; @@ -172,21 +190,26 @@ new_func_val (int func_val, type_t *type) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_func; + set_val_type (&val, type); val.v.func_val.val = func_val; val.v.func_val.type = type; return find_value (&val); } ex_value_t * -new_pointer_val (int pointer_val, type_t *type, def_t *def) +new_pointer_val (int pointer_val, type_t *type, def_t *def, + struct operand_s *tempop) { ex_value_t val; + if (!type) { + internal_error (0, "pointer value with no type"); + } memset (&val, 0, sizeof (val)); - val.type = ev_pointer; + set_val_type (&val, pointer_type (type)); val.v.pointer.val = pointer_val; val.v.pointer.type = type; val.v.pointer.def = def; + val.v.pointer.tempop = tempop; return find_value (&val); } @@ -195,7 +218,7 @@ new_quaternion_val (const float *quaternion_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_quat; + set_val_type (&val, &type_quaternion); QuatCopy (quaternion_val, val.v.quaternion_val); return find_value (&val); } @@ -205,7 +228,7 @@ new_integer_val (int integer_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_integer; + set_val_type (&val, &type_integer); val.v.integer_val = integer_val; return find_value (&val); } @@ -215,7 +238,7 @@ new_uinteger_val (int uinteger_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_uinteger; + set_val_type (&val, &type_uinteger); val.v.uinteger_val = uinteger_val; return find_value (&val); } @@ -225,7 +248,7 @@ new_short_val (short short_val) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = ev_short; + set_val_type (&val, &type_short); val.v.short_val = short_val; return find_value (&val); } @@ -235,10 +258,13 @@ new_nil_val (type_t *type) { ex_value_t val; memset (&val, 0, sizeof (val)); - val.type = low_level_type (type); - if (val.type == ev_pointer|| val.type == ev_field ) + set_val_type (&val, type); + if (val.lltype == ev_void) { + val.lltype = type_nil->type; + } + if (val.lltype == ev_pointer || val.lltype == ev_field ) val.v.pointer.type = type->t.fldptr.type; - if (val.type == ev_func) + if (val.lltype == ev_func) val.v.func_val.type = type; return find_value (&val); } @@ -252,6 +278,7 @@ static hashtab_t *func_imm_defs; static hashtab_t *pointer_imm_defs; static hashtab_t *quaternion_imm_defs; static hashtab_t *integer_imm_defs; +static hashtab_t *double_imm_defs; static void imm_free (void *_imm, void *unused) @@ -259,7 +286,7 @@ imm_free (void *_imm, void *unused) free (_imm); } -static uintptr_t +static __attribute__((pure)) uintptr_t imm_get_hash (const void *_imm, void *_tab) { immediate_t *imm = (immediate_t *) _imm; @@ -283,6 +310,8 @@ imm_get_hash (const void *_imm, void *_tab) } else if (tab == &quaternion_imm_defs) { return Hash_Buffer (&imm->i.quaternion_val, sizeof (&imm->i.quaternion_val)); + } else if (tab == &double_imm_defs) { + return Hash_Buffer (&imm->i.double_val, sizeof (&imm->i.double_val)); } else if (tab == &integer_imm_defs) { return imm->i.integer_val; } else { @@ -290,7 +319,7 @@ imm_get_hash (const void *_imm, void *_tab) } } -static int +static __attribute__((pure)) int imm_compare (const void *_imm1, const void *_imm2, void *_tab) { immediate_t *imm1 = (immediate_t *) _imm1; @@ -316,9 +345,9 @@ imm_compare (const void *_imm1, const void *_imm2, void *_tab) return !memcmp (&imm1->i.pointer, &imm2->i.pointer, sizeof (imm1->i.pointer)); } else if (tab == &quaternion_imm_defs) { - return (VectorCompare (imm1->i.quaternion_val, - imm2->i.quaternion_val) - && imm1->i.quaternion_val[3] == imm2->i.quaternion_val[3]); + return QuatCompare (imm1->i.quaternion_val, imm2->i.quaternion_val); + } else if (tab == &double_imm_defs) { + return imm1->i.double_val == imm2->i.double_val; } else if (tab == &integer_imm_defs) { return imm1->i.integer_val == imm2->i.integer_val; } else { @@ -335,13 +364,31 @@ ReuseString (const char *str) static float value_as_float (ex_value_t *value) { - if (value->type == ev_uinteger) + if (value->lltype == ev_uinteger) return value->v.uinteger_val; - if (value->type == ev_integer) + if (value->lltype == ev_integer) return value->v.integer_val; - if (value->type == ev_short) + if (value->lltype == ev_short) return value->v.short_val; - if (value->type == ev_float) + if (value->lltype == ev_double) + return value->v.double_val; + if (value->lltype == ev_float) + return value->v.float_val; + return 0; +} + +static double +value_as_double (ex_value_t *value) +{ + if (value->lltype == ev_uinteger) + return value->v.uinteger_val; + if (value->lltype == ev_integer) + return value->v.integer_val; + if (value->lltype == ev_short) + return value->v.short_val; + if (value->lltype == ev_double) + return value->v.double_val; + if (value->lltype == ev_float) return value->v.float_val; return 0; } @@ -349,13 +396,15 @@ value_as_float (ex_value_t *value) static int value_as_int (ex_value_t *value) { - if (value->type == ev_uinteger) + if (value->lltype == ev_uinteger) return value->v.uinteger_val; - if (value->type == ev_integer) + if (value->lltype == ev_integer) return value->v.integer_val; - if (value->type == ev_short) + if (value->lltype == ev_short) return value->v.short_val; - if (value->type == ev_float) + if (value->lltype == ev_double) + return value->v.double_val; + if (value->lltype == ev_float) return value->v.float_val; return 0; } @@ -363,13 +412,15 @@ value_as_int (ex_value_t *value) static unsigned value_as_uint (ex_value_t *value) { - if (value->type == ev_uinteger) + if (value->lltype == ev_uinteger) return value->v.uinteger_val; - if (value->type == ev_integer) + if (value->lltype == ev_integer) return value->v.integer_val; - if (value->type == ev_short) + if (value->lltype == ev_short) return value->v.short_val; - if (value->type == ev_float) + if (value->lltype == ev_double) + return value->v.double_val; + if (value->lltype == ev_float) return value->v.float_val; return 0; } @@ -377,13 +428,16 @@ value_as_uint (ex_value_t *value) ex_value_t * convert_value (ex_value_t *value, type_t *type) { - if (!is_scalar (type) || !is_scalar (ev_types[value->type])) { + if (!is_scalar (type) || !is_scalar (ev_types[value->lltype])) { error (0, "unable to convert non-scalar value"); return value; } if (is_float (type)) { float val = value_as_float (value); return new_float_val (val); + } else if (is_double (type)) { + double val = value_as_double (value); + return new_double_val (val); } else if (type->type == ev_short) { int val = value_as_int (value); return new_short_val (val); @@ -402,12 +456,12 @@ alias_value (ex_value_t *value, type_t *type) { ex_value_t new; - if (type_size (type) != type_size (ev_types[value->type])) { + if (type_size (type) != type_size (ev_types[value->lltype])) { error (0, "unable to alias different sized values"); return value; } new = *value; - new.type = type->type; + set_val_type (&new, type); return find_value (&new); } @@ -438,9 +492,9 @@ emit_value (ex_value_t *value, def_t *def) clear_immediates (); } cn = 0; - if (val.type == ev_void) - val.type = type_nil->type; - switch (val.type) { +// if (val.type == ev_void) +// val.type = type_nil->type; + switch (val.lltype) { case ev_entity: tab = entity_imm_defs; type = &type_entity; @@ -459,13 +513,13 @@ emit_value (ex_value_t *value, def_t *def) break; case ev_integer: case ev_uinteger: - if (!def || def->type != &type_float) { + if (!def || !is_float(def->type)) { tab = integer_imm_defs; type = &type_integer; break; } val.v.float_val = val.v.integer_val; - val.type = ev_float; + val.lltype = ev_float; case ev_float: tab = float_imm_defs; type = &type_float; @@ -483,6 +537,10 @@ emit_value (ex_value_t *value, def_t *def) tab = quaternion_imm_defs; type = &type_quaternion; break; + case ev_double: + tab = double_imm_defs; + type = &type_double; + break; default: internal_error (0, 0); } @@ -530,7 +588,7 @@ emit_value (ex_value_t *value, def_t *def) cn->initialized = cn->constant = 1; cn->nosave = 1; // copy the immediate to the global area - switch (val.type) { + switch (val.lltype) { case ev_string: reloc_def_string (cn); break; @@ -558,7 +616,7 @@ emit_value (ex_value_t *value, def_t *def) memcpy (D_POINTER (void, cn), &val.v, 4 * type_size (type)); - imm = make_def_imm (cn, tab, &val); + make_def_imm (cn, tab, &val); return cn; } @@ -580,39 +638,50 @@ clear_immediates (void) Hash_FlushTable (pointer_imm_defs); Hash_FlushTable (quaternion_imm_defs); Hash_FlushTable (integer_imm_defs); + Hash_FlushTable (double_imm_defs); } else { - value_table = Hash_NewTable (16381, 0, 0, 0); + value_table = Hash_NewTable (16381, 0, 0, 0, 0); Hash_SetHashCompare (value_table, value_get_hash, value_compare); - string_imm_defs = Hash_NewTable (16381, 0, imm_free, &string_imm_defs); + string_imm_defs = Hash_NewTable (16381, 0, imm_free, + &string_imm_defs, 0); Hash_SetHashCompare (string_imm_defs, imm_get_hash, imm_compare); - float_imm_defs = Hash_NewTable (16381, 0, imm_free, &float_imm_defs); + float_imm_defs = Hash_NewTable (16381, 0, imm_free, + &float_imm_defs, 0); Hash_SetHashCompare (float_imm_defs, imm_get_hash, imm_compare); - vector_imm_defs = Hash_NewTable (16381, 0, imm_free, &vector_imm_defs); + vector_imm_defs = Hash_NewTable (16381, 0, imm_free, + &vector_imm_defs, 0); Hash_SetHashCompare (vector_imm_defs, imm_get_hash, imm_compare); - entity_imm_defs = Hash_NewTable (16381, 0, imm_free, &entity_imm_defs); + entity_imm_defs = Hash_NewTable (16381, 0, imm_free, + &entity_imm_defs, 0); Hash_SetHashCompare (entity_imm_defs, imm_get_hash, imm_compare); - field_imm_defs = Hash_NewTable (16381, 0, imm_free, &field_imm_defs); + field_imm_defs = Hash_NewTable (16381, 0, imm_free, + &field_imm_defs, 0); Hash_SetHashCompare (field_imm_defs, imm_get_hash, imm_compare); - func_imm_defs = Hash_NewTable (16381, 0, imm_free, &func_imm_defs); + func_imm_defs = Hash_NewTable (16381, 0, imm_free, + &func_imm_defs, 0); Hash_SetHashCompare (func_imm_defs, imm_get_hash, imm_compare); - pointer_imm_defs = - Hash_NewTable (16381, 0, imm_free, &pointer_imm_defs); + pointer_imm_defs = Hash_NewTable (16381, 0, imm_free, + &pointer_imm_defs, 0); Hash_SetHashCompare (pointer_imm_defs, imm_get_hash, imm_compare); - quaternion_imm_defs = - Hash_NewTable (16381, 0, imm_free, &quaternion_imm_defs); + quaternion_imm_defs = Hash_NewTable (16381, 0, imm_free, + &quaternion_imm_defs, 0); Hash_SetHashCompare (quaternion_imm_defs, imm_get_hash, imm_compare); - integer_imm_defs = - Hash_NewTable (16381, 0, imm_free, &integer_imm_defs); + integer_imm_defs = Hash_NewTable (16381, 0, imm_free, + &integer_imm_defs, 0); Hash_SetHashCompare (integer_imm_defs, imm_get_hash, imm_compare); + + double_imm_defs = Hash_NewTable (16381, 0, imm_free, + &double_imm_defs, 0); + Hash_SetHashCompare (double_imm_defs, imm_get_hash, imm_compare); } def = make_symbol (".zero", &type_zero, 0, sc_extern)->s.def; diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am deleted file mode 100644 index c4302f32f..000000000 --- a/tools/qfcc/test/Makefile.am +++ /dev/null @@ -1,166 +0,0 @@ -AUTOMAKE_OPTIONS= foreign -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFCC_INCS) - -QFCC_DEP=$(builddir)/../source/qfcc$(EXEEXT) -QFCC=$(QFCC_DEP) - -QCFLAGS=-qq -O -g --no-default-paths -Werror -QCPPFLAGS= -QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) - -SUFFIXES=.qfo .r -.r.qfo: - $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -c -o $@ $< - sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo - $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo - -QFCC_TEST_LIBS=@QFCC_TEST_LIBS@ -QFCC_TEST_DEPS=@QFCC_TEST_DEPS@ -QFCC_TEST_INCS=@QFCC_TEST_INCS@ - -test_progs_dat=\ - chewed-alias.dat \ - chewed-return.dat \ - func-expr.dat \ - func-static.dat \ - deadbool.dat \ - infloop.dat \ - modulo.dat \ - paramret.dat \ - return-ivar.dat \ - sendv.dat \ - state.dat \ - structlive.dat \ - structptr.dat \ - vecinit.dat \ - while.dat \ - voidfor.dat - -fail_progs_dat=\ - $E - -TESTS=$(test_progs_dat:.dat=.run) -XFAIL_TESTS=$(fail_progs_dat:.dat=.run) - -check_PROGRAMS=test-harness $(test_progs_dat) - -test_harness_SOURCES= test-bi.c test-harness.c -test_harness_LDADD= $(QFCC_TEST_LIBS) -test_harness_DEPENDENCIES= $(QFCC_TEST_DEPS) - -chewed_alias_dat_SOURCES=chewed-alias.r -chewed_alias_obj=$(chewed_alias_dat_SOURCES:.r=.qfo) -chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(chewed_alias_obj) -chewed-alias.run: Makefile build-run - $(srcdir)/build-run $@ - -chewed_return_dat_SOURCES=chewed-return.r -chewed_return_obj=$(chewed_return_dat_SOURCES:.r=.qfo) -chewed-return.dat$(EXEEXT): $(chewed_return_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(chewed_return_obj) -chewed-return.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ - -func_expr_dat_SOURCES=func-expr.r -func_expr_obj=$(func_expr_dat_SOURCES:.r=.qfo) -func-expr.dat$(EXEEXT): $(func_expr_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(func_expr_obj) -func-expr.run: Makefile build-run - $(srcdir)/build-run $@ - -func_static_dat_SOURCES=func-static.r -func_static_obj=$(func_static_dat_SOURCES:.r=.qfo) -func-static.dat$(EXEEXT): $(func_static_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(func_static_obj) -func-static.run: Makefile build-run - $(srcdir)/build-run $@ - -deadbool_dat_SOURCES=deadbool.r -deadbool_obj=$(deadbool_dat_SOURCES:.r=.qfo) -deadbool.dat$(EXEEXT): $(deadbool_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(deadbool_obj) -deadbool.run: Makefile build-run - $(srcdir)/build-run $@ - -infloop_dat_SOURCES=infloop.r -infloop_obj=$(infloop_dat_SOURCES:.r=.qfo) -infloop.dat$(EXEEXT): $(infloop_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(infloop_obj) -infloop.run: Makefile build-run - $(srcdir)/build-run $@ - -modulo_dat_SOURCES=modulo.r -modulo_obj=$(modulo_dat_SOURCES:.r=.qfo) -modulo.dat$(EXEEXT): $(modulo_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(modulo_obj) -modulo.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ - -paramret_dat_SOURCES=paramret.r -paramret_obj=$(paramret_dat_SOURCES:.r=.qfo) -paramret.dat$(EXEEXT): $(paramret_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(paramret_obj) -paramret.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ - -return_ivar_dat_SOURCES=return-ivar.r -return_ivar_obj=$(return_ivar_dat_SOURCES:.r=.qfo) -return-ivar.dat$(EXEEXT): $(return_ivar_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(return_ivar_obj) -return-ivar.run: Makefile build-run - $(srcdir)/build-run $@ - -sendv_dat_SOURCES=sendv.r -sendv_obj=$(sendv_dat_SOURCES:.r=.qfo) -sendv.dat$(EXEEXT): $(sendv_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(sendv_obj) -sendv.run: Makefile build-run - $(srcdir)/build-run $@ - -state_dat_SOURCES=state.r -state_obj=$(state_dat_SOURCES:.r=.qfo) -state.dat$(EXEEXT): $(state_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(state_obj) -state.run: Makefile build-run - $(srcdir)/build-run $@ - -structlive_dat_SOURCES=structlive.r -structlive_obj=$(structlive_dat_SOURCES:.r=.qfo) -structlive.dat$(EXEEXT): $(structlive_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(structlive_obj) -structlive.run: Makefile build-run - $(srcdir)/build-run $@ - -structptr_dat_SOURCES=structptr.r -structptr_obj=$(structptr_dat_SOURCES:.r=.qfo) -structptr.dat$(EXEEXT): $(structptr_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(structptr_obj) -structptr.run: Makefile build-run - $(srcdir)/build-run $@ - -vecinit_dat_SOURCES=vecinit.r -vecinit_obj=$(vecinit_dat_SOURCES:.r=.qfo) -vecinit.dat$(EXEEXT): $(vecinit_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(vecinit_obj) -vecinit.run: Makefile build-run - $(srcdir)/build-run $@ - -while_dat_SOURCES=while.r -while_obj=$(while_dat_SOURCES:.r=.qfo) -while.dat$(EXEEXT): $(while_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(while_obj) -while.run: Makefile build-run - $(srcdir)/build-run $@ - -voidfor_dat_SOURCES=voidfor.r -voidfor_obj=$(voidfor_dat_SOURCES:.r=.qfo) -voidfor.dat$(EXEEXT): $(voidfor_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(voidfor_obj) -voidfor.run: Makefile build-run - $(srcdir)/build-run $@ - -include ./$(DEPDIR)/*.Qo - -EXTRA_DIST= test-bi.h build-run -CLEANFILES= *.dat *.sym *.qfo *.run diff --git a/tools/qfcc/test/Makemodule.am b/tools/qfcc/test/Makemodule.am new file mode 100644 index 000000000..f328fcb6e --- /dev/null +++ b/tools/qfcc/test/Makemodule.am @@ -0,0 +1,610 @@ +QFCC_TEST_LIBS=@QFCC_TEST_LIBS@ +QFCC_TEST_DEPS=@QFCC_TEST_DEPS@ +QFCC_TEST_INCS=@QFCC_TEST_INCS@ + +test_bins=\ + tools/qfcc/test/test-defspace + +fail_bins= + +test_progs_dat=\ + tools/qfcc/test/address-cast.dat \ + tools/qfcc/test/alignment.dat \ + tools/qfcc/test/assignchain.dat \ + tools/qfcc/test/anonstruct.dat \ + tools/qfcc/test/chewed-alias.dat \ + tools/qfcc/test/chewed-return.dat \ + tools/qfcc/test/comma-expr.dat \ + tools/qfcc/test/compound.dat \ + tools/qfcc/test/deadbool.dat \ + tools/qfcc/test/double.dat \ + tools/qfcc/test/double-alias.dat \ + tools/qfcc/test/enum.dat \ + tools/qfcc/test/fordecl.dat \ + tools/qfcc/test/func-expr.dat \ + tools/qfcc/test/func-expr2.dat \ + tools/qfcc/test/func-static.dat \ + tools/qfcc/test/gcd.dat \ + tools/qfcc/test/infloop.dat \ + tools/qfcc/test/ivar-struct-return.dat \ + tools/qfcc/test/methodparams.dat \ + tools/qfcc/test/modulo.dat \ + tools/qfcc/test/nilparamret.dat \ + tools/qfcc/test/overload.dat \ + tools/qfcc/test/paramret.dat \ + tools/qfcc/test/quaternion.dat \ + tools/qfcc/test/return-ivar.dat \ + tools/qfcc/test/sendv.dat \ + tools/qfcc/test/state.dat \ + tools/qfcc/test/static-init.dat \ + tools/qfcc/test/struct-init-param.dat \ + tools/qfcc/test/struct-nil-init.dat \ + tools/qfcc/test/structarray.dat \ + tools/qfcc/test/structlive.dat \ + tools/qfcc/test/structptr.dat \ + tools/qfcc/test/structstruct.dat \ + tools/qfcc/test/swap.dat \ + tools/qfcc/test/triangle.dat \ + tools/qfcc/test/typedef.dat \ + tools/qfcc/test/typelinker.dat \ + tools/qfcc/test/unaryminus.dat \ + tools/qfcc/test/vecaddr.dat \ + tools/qfcc/test/vecexpr.dat \ + tools/qfcc/test/vecinit.dat \ + tools/qfcc/test/voidfor.dat \ + tools/qfcc/test/while.dat \ + tools/qfcc/test/zerolinker.dat + +fail_progs_dat= + +test_build_errors=\ + tools/qfcc/test/classarray.r \ + tools/qfcc/test/double-demote-float.r \ + tools/qfcc/test/double-demote-float-ainit.r \ + tools/qfcc/test/double-demote-float-ginit.r \ + tools/qfcc/test/double-demote-float-linit.r \ + tools/qfcc/test/double-demote-int.r \ + tools/qfcc/test/double-demote-int-ainit.r \ + tools/qfcc/test/double-demote-int-ginit.r \ + tools/qfcc/test/double-demote-int-linit.r \ + tools/qfcc/test/double-int-compare.r \ + tools/qfcc/test/double-float-compare.r + +fail_build_errors= + +test_defspace_src=\ + tools/qfcc/test/tw-defspace.c tools/qfcc/test/tw-diagnostic.c tools/qfcc/test/tw-strpool.c + +TESTS += \ + $(test_bins) \ + $(test_progs_dat:.dat=.run) \ + $(test_build_errors:.r=.run) +XFAIL_TESTS += \ + $(fail_bins) \ + $(fail_progs_dat:.dat=.run) \ + $(fail_build_errors:.r=.run) + +check_PROGRAMS += \ + tools/qfcc/test/test-harness \ + $(test_progs_dat) \ + $(test_bins) + +tools_qfcc_test_test_defspace_SOURCES= tools/qfcc/test/test-defspace.c $(test_defspace_src) +tools_qfcc_test_test_defspace_LDADD= $(QFCC_LIBS) +tools_qfcc_test_test_defspace_DEPENDENCIES= $(QFCC_DEPS) + +tools_qfcc_test_test_harness_SOURCES= tools/qfcc/test/test-bi.c tools/qfcc/test/test-harness.c +tools_qfcc_test_test_harness_LDADD= $(QFCC_TEST_LIBS) +tools_qfcc_test_test_harness_DEPENDENCIES= $(QFCC_TEST_DEPS) + +qfcc_test_run_deps = Makefile tools/qfcc/test/build-run +qfcc_fail_run_deps = Makefile tools/qfcc/test/build-compile-fail-run +tools_qfcc_test_address_cast_dat_SOURCES=tools/qfcc/test/address-cast.r +address_cast_obj=$(tools_qfcc_test_address_cast_dat_SOURCES:.r=.o) +address_cast_dep=$(call qcautodep,$(tools_qfcc_test_address_cast_dat_SOURCES)) +tools/qfcc/test/address-cast.dat$(EXEEXT): $(address_cast_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(address_cast_obj) +tools/qfcc/test/address-cast.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(address_cast_dep) # am--include-marker +r_depfiles_remade += $(address_cast_dep) + +tools_qfcc_test_alignment_dat_SOURCES=tools/qfcc/test/alignment.r +alignment_obj=$(tools_qfcc_test_alignment_dat_SOURCES:.r=.o) +alignment_dep=$(call qcautodep,$(tools_qfcc_test_alignment_dat_SOURCES)) +tools/qfcc/test/alignment.dat$(EXEEXT): $(alignment_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(alignment_obj) +tools/qfcc/test/alignment.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(alignment_dep) # am--include-marker +r_depfiles_remade += $(alignment_dep) + +tools_qfcc_test_anonstruct_dat_SOURCES=tools/qfcc/test/anonstruct.r +anonstruct_obj=$(tools_qfcc_test_anonstruct_dat_SOURCES:.r=.o) +anonstruct_dep=$(call qcautodep,$(tools_qfcc_test_anonstruct_dat_SOURCES)) +tools/qfcc/test/anonstruct.dat$(EXEEXT): $(anonstruct_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(anonstruct_obj) +tools/qfcc/test/anonstruct.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(anonstruct_dep) # am--include-marker +r_depfiles_remade += $(anonstruct_dep) + +tools_qfcc_test_assignchain_dat_SOURCES=tools/qfcc/test/assignchain.r +assignchain_obj=$(tools_qfcc_test_assignchain_dat_SOURCES:.r=.o) +assignchain_dep=$(call qcautodep,$(tools_qfcc_test_assignchain_dat_SOURCES)) +tools/qfcc/test/assignchain.dat$(EXEEXT): $(assignchain_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(assignchain_obj) +tools/qfcc/test/assignchain.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(assignchain_dep) # am--include-marker +r_depfiles_remade += $(assignchain_dep) + +tools_qfcc_test_chewed_alias_dat_SOURCES=tools/qfcc/test/chewed-alias.r +chewed_alias_obj=$(tools_qfcc_test_chewed_alias_dat_SOURCES:.r=.o) +chewed_alias_dep=$(call qcautodep,$(tools_qfcc_test_chewed_alias_dat_SOURCES)) +tools/qfcc/test/chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(chewed_alias_obj) +tools/qfcc/test/chewed-alias.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(chewed_alias_dep) # am--include-marker +r_depfiles_remade += $(chewed_alias_dep) + +tools_qfcc_test_chewed_return_dat_SOURCES=tools/qfcc/test/chewed-return.r +chewed_return_obj=$(tools_qfcc_test_chewed_return_dat_SOURCES:.r=.o) +chewed_return_dep=$(call qcautodep,$(tools_qfcc_test_chewed_return_dat_SOURCES)) +tools/qfcc/test/chewed-return.dat$(EXEEXT): $(chewed_return_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(chewed_return_obj) +tools/qfcc/test/chewed-return.run: $(qfcc_test_run_deps) + @TEST_HARNESS_OPTS=--float $(top_srcdir)/tools/qfcc/test/build-run $@ +include $(chewed_return_dep) # am--include-marker +r_depfiles_remade += $(chewed_return_dep) + +tools_qfcc_test_comma_expr_dat_SOURCES=tools/qfcc/test/comma-expr.r +comma_expr_obj=$(tools_qfcc_test_comma_expr_dat_SOURCES:.r=.o) +comma_expr_dep=$(call qcautodep,$(tools_qfcc_test_comma_expr_dat_SOURCES)) +tools/qfcc/test/comma-expr.dat$(EXEEXT): $(comma_expr_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(comma_expr_obj) +tools/qfcc/test/comma-expr.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(comma_expr_dep) # am--include-marker +r_depfiles_remade += $(comma_expr_dep) + +tools_qfcc_test_compound_dat_SOURCES=tools/qfcc/test/compound.r +compound_obj=$(tools_qfcc_test_compound_dat_SOURCES:.r=.o) +compound_dep=$(call qcautodep,$(tools_qfcc_test_compound_dat_SOURCES)) +tools/qfcc/test/compound.dat$(EXEEXT): $(compound_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(compound_obj) +tools/qfcc/test/compound.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(compound_dep) # am--include-marker +r_depfiles_remade += $(compound_dep) + +tools_qfcc_test_deadbool_dat_SOURCES=tools/qfcc/test/deadbool.r +deadbool_obj=$(tools_qfcc_test_deadbool_dat_SOURCES:.r=.o) +deadbool_dep=$(call qcautodep,$(tools_qfcc_test_deadbool_dat_SOURCES)) +tools/qfcc/test/deadbool.dat$(EXEEXT): $(deadbool_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(deadbool_obj) +tools/qfcc/test/deadbool.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(deadbool_dep) # am--include-marker +r_depfiles_remade += $(deadbool_dep) + +tools_qfcc_test_double_dat_SOURCES=tools/qfcc/test/double.r +double_obj=$(tools_qfcc_test_double_dat_SOURCES:.r=.o) +double_dep=$(call qcautodep,$(tools_qfcc_test_double_dat_SOURCES)) +tools/qfcc/test/double.dat$(EXEEXT): $(double_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(double_obj) +tools/qfcc/test/double.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(double_dep) # am--include-marker +r_depfiles_remade += $(double_dep) + +tools_qfcc_test_double_alias_dat_SOURCES=tools/qfcc/test/double-alias.r +double_alias_obj=$(tools_qfcc_test_double_alias_dat_SOURCES:.r=.o) +double_alias_dep=$(call qcautodep,$(tools_qfcc_test_double_alias_dat_SOURCES)) +tools/qfcc/test/double-alias.dat$(EXEEXT): $(double_alias_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(double_alias_obj) +tools/qfcc/test/double-alias.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(double_alias_dep) # am--include-marker +r_depfiles_remade += $(double_alias_dep) + +tools/qfcc/test/classarray.run$(EXEEXT): tools/qfcc/test/classarray.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-int.run$(EXEEXT): tools/qfcc/test/double-demote-int.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-float.run$(EXEEXT): tools/qfcc/test/double-demote-float.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-int-ainit.run$(EXEEXT): tools/qfcc/test/double-demote-int-ainit.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-float-ainit.run$(EXEEXT): tools/qfcc/test/double-demote-float-ainit.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-int-ginit.run$(EXEEXT): tools/qfcc/test/double-demote-int-ginit.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-float-ginit.run$(EXEEXT): tools/qfcc/test/double-demote-float-ginit.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-int-linit.run$(EXEEXT): tools/qfcc/test/double-demote-int-linit.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-demote-float-linit.run$(EXEEXT): tools/qfcc/test/double-demote-float-linit.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-int-compare.run$(EXEEXT): tools/qfcc/test/double-int-compare.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools/qfcc/test/double-float-compare.run$(EXEEXT): tools/qfcc/test/double-float-compare.r $(qfcc_fail_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + +tools_qfcc_test_enum_dat_SOURCES=tools/qfcc/test/enum.r +enum_obj=$(tools_qfcc_test_enum_dat_SOURCES:.r=.o) +enum_dep=$(call qcautodep,$(tools_qfcc_test_enum_dat_SOURCES)) +tools/qfcc/test/enum.dat$(EXEEXT): $(enum_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(enum_obj) +tools/qfcc/test/enum.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(enum_dep) # am--include-marker +r_depfiles_remade += $(enum_dep) + +tools_qfcc_test_fordecl_dat_SOURCES=tools/qfcc/test/fordecl.r +fordecl_obj=$(tools_qfcc_test_fordecl_dat_SOURCES:.r=.o) +fordecl_dep=$(call qcautodep,$(tools_qfcc_test_fordecl_dat_SOURCES)) +tools/qfcc/test/fordecl.dat$(EXEEXT): $(fordecl_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(fordecl_obj) +tools/qfcc/test/fordecl.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(fordecl_dep) # am--include-marker +r_depfiles_remade += $(fordecl_dep) + +tools_qfcc_test_func_expr_dat_SOURCES=tools/qfcc/test/func-expr.r +func_expr_obj=$(tools_qfcc_test_func_expr_dat_SOURCES:.r=.o) +func_expr_dep=$(call qcautodep,$(tools_qfcc_test_func_expr_dat_SOURCES)) +tools/qfcc/test/func-expr.dat$(EXEEXT): $(func_expr_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(func_expr_obj) +tools/qfcc/test/func-expr.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(func_expr_dep) # am--include-marker +r_depfiles_remade += $(func_expr_dep) + +tools_qfcc_test_func_expr2_dat_SOURCES=tools/qfcc/test/func-expr2.r +func_expr2_obj=$(tools_qfcc_test_func_expr2_dat_SOURCES:.r=.o) +func_expr2_dep=$(call qcautodep,$(tools_qfcc_test_func_expr2_dat_SOURCES)) +tools/qfcc/test/func-expr2.dat$(EXEEXT): $(func_expr2_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(func_expr2_obj) +tools/qfcc/test/func-expr2.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(func_expr2_dep) # am--include-marker +r_depfiles_remade += $(func_expr2_dep) + +tools_qfcc_test_func_static_dat_SOURCES=tools/qfcc/test/func-static.r +func_static_obj=$(tools_qfcc_test_func_static_dat_SOURCES:.r=.o) +func_static_dep=$(call qcautodep,$(tools_qfcc_test_func_static_dat_SOURCES)) +tools/qfcc/test/func-static.dat$(EXEEXT): $(func_static_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(func_static_obj) +tools/qfcc/test/func-static.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(func_static_dep) # am--include-marker +r_depfiles_remade += $(func_static_dep) + +tools_qfcc_test_gcd_dat_SOURCES=tools/qfcc/test/gcd.pas +gcd_obj=$(tools_qfcc_test_gcd_dat_SOURCES:.pas=.o) +gcd_dep=$(call qcautodep,$(tools_qfcc_test_gcd_dat_SOURCES)) +tools/qfcc/test/gcd.dat$(EXEEXT): $(gcd_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(gcd_obj) +tools/qfcc/test/gcd.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(gcd_dep) # am--include-marker +pas_depfiles_remade += $(gcd_dep) + +tools_qfcc_test_infloop_dat_SOURCES=tools/qfcc/test/infloop.r +infloop_obj=$(tools_qfcc_test_infloop_dat_SOURCES:.r=.o) +infloop_dep=$(call qcautodep,$(tools_qfcc_test_infloop_dat_SOURCES)) +tools/qfcc/test/infloop.dat$(EXEEXT): $(infloop_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(infloop_obj) +tools/qfcc/test/infloop.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(infloop_dep) # am--include-marker +r_depfiles_remade += $(infloop_dep) + +tools_qfcc_test_ivar_struct_return_dat_SOURCES=tools/qfcc/test/ivar-struct-return.r +ivar_struct_return_obj=$(tools_qfcc_test_ivar_struct_return_dat_SOURCES:.r=.o) +ivar_struct_return_dep=$(call qcautodep,$(tools_qfcc_test_ivar_struct_return_dat_SOURCES)) +tools/qfcc/test/ivar-struct-return.dat$(EXEEXT): $(ivar_struct_return_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(ivar_struct_return_obj) +tools/qfcc/test/ivar-struct-return.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(ivar_struct_return_dep) # am--include-marker +r_depfiles_remade += $(ivar_struct_return_dep) + +tools_qfcc_test_methodparams_dat_SOURCES=tools/qfcc/test/methodparams.r +methodparams_obj=$(tools_qfcc_test_methodparams_dat_SOURCES:.r=.o) +methodparams_dep=$(call qcautodep,$(tools_qfcc_test_methodparams_dat_SOURCES)) +tools/qfcc/test/methodparams.dat$(EXEEXT): $(methodparams_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(methodparams_obj) +tools/qfcc/test/methodparams.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(methodparams_dep) # am--include-marker +r_depfiles_remade += $(methodparams_dep) + +tools_qfcc_test_modulo_dat_SOURCES=tools/qfcc/test/modulo.r +modulo_obj=$(tools_qfcc_test_modulo_dat_SOURCES:.r=.o) +modulo_dep=$(call qcautodep,$(tools_qfcc_test_modulo_dat_SOURCES)) +tools/qfcc/test/modulo.dat$(EXEEXT): $(modulo_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(modulo_obj) +tools/qfcc/test/modulo.run: $(qfcc_test_run_deps) + @TEST_HARNESS_OPTS=--float $(top_srcdir)/tools/qfcc/test/build-run $@ +include $(modulo_dep) # am--include-marker +r_depfiles_remade += $(modulo_dep) + +tools_qfcc_test_nilparamret_dat_SOURCES=tools/qfcc/test/nilparamret.r +nilparamret_obj=$(tools_qfcc_test_nilparamret_dat_SOURCES:.r=.o) +nilparamret_dep=$(call qcautodep,$(tools_qfcc_test_nilparamret_dat_SOURCES)) +tools/qfcc/test/nilparamret.dat$(EXEEXT): $(nilparamret_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(nilparamret_obj) +tools/qfcc/test/nilparamret.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(nilparamret_dep) # am--include-marker +r_depfiles_remade += $(nilparamret_dep) + +tools_qfcc_test_overload_dat_SOURCES=tools/qfcc/test/overload.r +overload_obj=$(tools_qfcc_test_overload_dat_SOURCES:.r=.o) +overload_dep=$(call qcautodep,$(tools_qfcc_test_overload_dat_SOURCES)) +tools/qfcc/test/overload.dat$(EXEEXT): $(overload_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(overload_obj) +tools/qfcc/test/overload.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(overload_dep) # am--include-marker +r_depfiles_remade += $(overload_dep) + +tools_qfcc_test_paramret_dat_SOURCES=tools/qfcc/test/paramret.r +paramret_obj=$(tools_qfcc_test_paramret_dat_SOURCES:.r=.o) +paramret_dep=$(call qcautodep,$(tools_qfcc_test_paramret_dat_SOURCES)) +tools/qfcc/test/paramret.dat$(EXEEXT): $(paramret_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(paramret_obj) +tools/qfcc/test/paramret.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(paramret_dep) # am--include-marker +r_depfiles_remade += $(paramret_dep) + +tools_qfcc_test_quaternion_dat_SOURCES=tools/qfcc/test/quaternion.r +quaternion_obj=$(tools_qfcc_test_quaternion_dat_SOURCES:.r=.o) +quaternion_dep=$(call qcautodep,$(tools_qfcc_test_quaternion_dat_SOURCES)) +tools/qfcc/test/quaternion.dat$(EXEEXT): $(quaternion_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(quaternion_obj) +tools/qfcc/test/quaternion.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(quaternion_dep) # am--include-marker +r_depfiles_remade += $(quaternion_dep) + +tools_qfcc_test_return_ivar_dat_SOURCES=tools/qfcc/test/return-ivar.r +return_ivar_obj=$(tools_qfcc_test_return_ivar_dat_SOURCES:.r=.o) +return_ivar_dep=$(call qcautodep,$(tools_qfcc_test_return_ivar_dat_SOURCES)) +tools/qfcc/test/return-ivar.dat$(EXEEXT): $(return_ivar_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(return_ivar_obj) +tools/qfcc/test/return-ivar.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(return_ivar_dep) # am--include-marker +r_depfiles_remade += $(return_ivar_dep) + +tools_qfcc_test_sendv_dat_SOURCES=tools/qfcc/test/sendv.r +sendv_obj=$(tools_qfcc_test_sendv_dat_SOURCES:.r=.o) +sendv_dep=$(call qcautodep,$(tools_qfcc_test_sendv_dat_SOURCES)) +tools/qfcc/test/sendv.dat$(EXEEXT): $(sendv_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(sendv_obj) +tools/qfcc/test/sendv.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(sendv_dep) # am--include-marker +r_depfiles_remade += $(sendv_dep) + +tools_qfcc_test_state_dat_SOURCES=tools/qfcc/test/state.r +state_obj=$(tools_qfcc_test_state_dat_SOURCES:.r=.o) +state_dep=$(call qcautodep,$(tools_qfcc_test_state_dat_SOURCES)) +tools/qfcc/test/state.dat$(EXEEXT): $(state_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(state_obj) +tools/qfcc/test/state.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(state_dep) # am--include-marker +r_depfiles_remade += $(state_dep) + +tools_qfcc_test_static_init_dat_SOURCES=tools/qfcc/test/static-init.r +static_init_obj=$(tools_qfcc_test_static_init_dat_SOURCES:.r=.o) +static_init_dep=$(call qcautodep,$(tools_qfcc_test_static_init_dat_SOURCES)) +tools/qfcc/test/static-init.dat$(EXEEXT): $(static_init_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(static_init_obj) +tools/qfcc/test/static-init.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(static_init_dep) # am--include-marker +r_depfiles_remade += $(static_init_dep) + +tools_qfcc_test_struct_init_param_dat_SOURCES=tools/qfcc/test/struct-init-param.r +struct_init_param_obj=$(tools_qfcc_test_struct_init_param_dat_SOURCES:.r=.o) +struct_init_param_dep=$(call qcautodep,$(tools_qfcc_test_struct_init_param_dat_SOURCES)) +tools/qfcc/test/struct-init-param.dat$(EXEEXT): $(struct_init_param_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(struct_init_param_obj) +tools/qfcc/test/struct-init-param.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(struct_init_param_dep) # am--include-marker +r_depfiles_remade += $(struct_init_param_dep) + +tools_qfcc_test_struct_nil_init_dat_SOURCES=tools/qfcc/test/struct-nil-init.r +struct_nil_init_obj=$(tools_qfcc_test_struct_nil_init_dat_SOURCES:.r=.o) +struct_nil_init_dep=$(call qcautodep,$(tools_qfcc_test_struct_nil_init_dat_SOURCES)) +tools/qfcc/test/struct-nil-init.dat$(EXEEXT): $(struct_nil_init_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(struct_nil_init_obj) +tools/qfcc/test/struct-nil-init.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(struct_nil_init_dep) # am--include-marker +r_depfiles_remade += $(struct_nil_init_dep) + +tools_qfcc_test_structarray_dat_SOURCES=tools/qfcc/test/structarray.r +structarray_obj=$(tools_qfcc_test_structarray_dat_SOURCES:.r=.o) +structarray_dep=$(call qcautodep,$(tools_qfcc_test_structarray_dat_SOURCES)) +tools/qfcc/test/structarray.dat$(EXEEXT): $(structarray_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(structarray_obj) +tools/qfcc/test/structarray.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(structarray_dep) # am--include-marker +r_depfiles_remade += $(structarray_dep) + +tools_qfcc_test_structlive_dat_SOURCES=tools/qfcc/test/structlive.r +structlive_obj=$(tools_qfcc_test_structlive_dat_SOURCES:.r=.o) +structlive_dep=$(call qcautodep,$(tools_qfcc_test_structlive_dat_SOURCES)) +tools/qfcc/test/structlive.dat$(EXEEXT): $(structlive_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(structlive_obj) +tools/qfcc/test/structlive.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(structlive_dep) # am--include-marker +r_depfiles_remade += $(structlive_dep) + +tools_qfcc_test_structptr_dat_SOURCES=tools/qfcc/test/structptr.r +structptr_obj=$(tools_qfcc_test_structptr_dat_SOURCES:.r=.o) +structptr_dep=$(call qcautodep,$(tools_qfcc_test_structptr_dat_SOURCES)) +tools/qfcc/test/structptr.dat$(EXEEXT): $(structptr_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(structptr_obj) +tools/qfcc/test/structptr.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(structptr_dep) # am--include-marker +r_depfiles_remade += $(structptr_dep) + +tools_qfcc_test_structstruct_dat_SOURCES=tools/qfcc/test/structstruct.r +structstruct_obj=$(tools_qfcc_test_structstruct_dat_SOURCES:.r=.o) +structstruct_dep=$(call qcautodep,$(tools_qfcc_test_structstruct_dat_SOURCES)) +tools/qfcc/test/structstruct.dat$(EXEEXT): $(structstruct_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(structstruct_obj) +tools/qfcc/test/structstruct.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(structstruct_dep) # am--include-marker +r_depfiles_remade += $(structstruct_dep) + +tools_qfcc_test_swap_dat_SOURCES=tools/qfcc/test/swap.r +swap_obj=$(tools_qfcc_test_swap_dat_SOURCES:.r=.o) +swap_dep=$(call qcautodep,$(tools_qfcc_test_swap_dat_SOURCES)) +tools/qfcc/test/swap.dat$(EXEEXT): $(swap_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(swap_obj) +tools/qfcc/test/swap.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(swap_dep) # am--include-marker +r_depfiles_remade += $(swap_dep) + +tools_qfcc_test_triangle_dat_SOURCES=tools/qfcc/test/triangle.r +triangle_obj=$(tools_qfcc_test_triangle_dat_SOURCES:.r=.o) +triangle_dep=$(call qcautodep,$(tools_qfcc_test_triangle_dat_SOURCES)) +tools/qfcc/test/triangle.dat$(EXEEXT): $(triangle_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(triangle_obj) +tools/qfcc/test/triangle.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ 100000 100000 1.00005 50002.4961 +include $(triangle_dep) # am--include-marker +r_depfiles_remade += $(triangle_dep) + +tools_qfcc_test_typedef_dat_SOURCES=tools/qfcc/test/typedef.r +typedef_obj=$(tools_qfcc_test_typedef_dat_SOURCES:.r=.o) +typedef_dep=$(call qcautodep,$(tools_qfcc_test_typedef_dat_SOURCES)) +tools/qfcc/test/typedef.dat$(EXEEXT): $(typedef_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(typedef_obj) +tools/qfcc/test/typedef.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(typedef_dep) # am--include-marker +r_depfiles_remade += $(typedef_dep) + +tools_qfcc_test_typelinker_dat_SOURCES=tools/qfcc/test/typelinker_a.r tools/qfcc/test/typelinker_b.r +typelinker_obj=$(tools_qfcc_test_typelinker_dat_SOURCES:.r=.o) +typelinker_dep=$(call qcautodep,$(tools_qfcc_test_typelinker_dat_SOURCES)) +tools/qfcc/test/typelinker.dat$(EXEEXT): $(typelinker_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(typelinker_obj) +tools/qfcc/test/typelinker.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(typelinker_dep) # am--include-marker +r_depfiles_remade += $(typelinker_dep) + +tools_qfcc_test_unaryminus_dat_SOURCES=tools/qfcc/test/unaryminus.r +unaryminus_obj=$(tools_qfcc_test_unaryminus_dat_SOURCES:.r=.o) +unaryminus_dep=$(call qcautodep,$(tools_qfcc_test_unaryminus_dat_SOURCES)) +tools/qfcc/test/unaryminus.dat$(EXEEXT): $(unaryminus_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(unaryminus_obj) +tools/qfcc/test/unaryminus.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(unaryminus_dep) # am--include-marker +r_depfiles_remade += $(unaryminus_dep) + +tools_qfcc_test_vecaddr_dat_SOURCES=tools/qfcc/test/vecaddr.r +vecaddr_obj=$(tools_qfcc_test_vecaddr_dat_SOURCES:.r=.o) +vecaddr_dep=$(call qcautodep,$(tools_qfcc_test_vecaddr_dat_SOURCES)) +tools/qfcc/test/vecaddr.dat$(EXEEXT): $(vecaddr_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(vecaddr_obj) +tools/qfcc/test/vecaddr.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(vecaddr_dep) # am--include-marker +r_depfiles_remade += $(vecaddr_dep) + +tools_qfcc_test_vecexpr_dat_SOURCES=tools/qfcc/test/vecexpr.r +vecexpr_obj=$(tools_qfcc_test_vecexpr_dat_SOURCES:.r=.o) +vecexpr_dep=$(call qcautodep,$(tools_qfcc_test_vecexpr_dat_SOURCES)) +tools/qfcc/test/vecexpr.dat$(EXEEXT): $(vecexpr_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(vecexpr_obj) +tools/qfcc/test/vecexpr.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(vecexpr_dep) # am--include-marker +r_depfiles_remade += $(vecexpr_dep) + +tools_qfcc_test_vecinit_dat_SOURCES=tools/qfcc/test/vecinit.r +vecinit_obj=$(tools_qfcc_test_vecinit_dat_SOURCES:.r=.o) +vecinit_dep=$(call qcautodep,$(tools_qfcc_test_vecinit_dat_SOURCES)) +tools/qfcc/test/vecinit.dat$(EXEEXT): $(vecinit_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(vecinit_obj) +tools/qfcc/test/vecinit.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(vecinit_dep) # am--include-marker +r_depfiles_remade += $(vecinit_dep) + +tools_qfcc_test_voidfor_dat_SOURCES=tools/qfcc/test/voidfor.r +voidfor_obj=$(tools_qfcc_test_voidfor_dat_SOURCES:.r=.o) +voidfor_dep=$(call qcautodep,$(tools_qfcc_test_voidfor_dat_SOURCES)) +tools/qfcc/test/voidfor.dat$(EXEEXT): $(voidfor_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(voidfor_obj) +tools/qfcc/test/voidfor.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(voidfor_dep) # am--include-marker +r_depfiles_remade += $(voidfor_dep) + +tools_qfcc_test_while_dat_SOURCES=tools/qfcc/test/while.r +while_obj=$(tools_qfcc_test_while_dat_SOURCES:.r=.o) +while_dep=$(call qcautodep,$(tools_qfcc_test_while_dat_SOURCES)) +tools/qfcc/test/while.dat$(EXEEXT): $(while_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(while_obj) +tools/qfcc/test/while.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(while_dep) # am--include-marker +r_depfiles_remade += $(while_dep) + +tools_qfcc_test_zerolinker_dat_SOURCES=tools/qfcc/test/zerolinker.r +zerolinker_obj=$(tools_qfcc_test_zerolinker_dat_SOURCES:.r=.o) +zerolinker_dep=$(call qcautodep,$(tools_qfcc_test_zerolinker_dat_SOURCES)) +tools/qfcc/test/zerolinker.dat$(EXEEXT): $(zerolinker_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(zerolinker_obj) +tools/qfcc/test/zerolinker.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(zerolinker_dep) # am--include-marker +r_depfiles_remade += $(zerolinker_dep) + +EXTRA_DIST += \ + $(test_build_errors) \ + tools/qfcc/test/build-compile-fail-run \ + tools/qfcc/test/test-bi.h \ + tools/qfcc/test/build-run \ + tools/qfcc/test/test-defspace.h \ + tools/qfcc/test/test-harness.h \ + tools/qfcc/test/typelinker.h + +CLEANFILES += \ + tools/qfcc/test/*.dat \ + tools/qfcc/test/*.sym \ + tools/qfcc/test/*.run \ + tools/qfcc/test/*.frame \ + tools/qfcc/test/*.log \ + tools/qfcc/test/*.trs diff --git a/tools/qfcc/test/address-cast.r b/tools/qfcc/test/address-cast.r new file mode 100644 index 000000000..ed853f9e5 --- /dev/null +++ b/tools/qfcc/test/address-cast.r @@ -0,0 +1,21 @@ +int a; +double b; +int c = (int) &b; +double d; +void printf (string fmt, ...) = #0; + +int main() +{ + int di = (int) &d; + int fail = 0; + + if (!c) { + printf ("global init address cast fail: %d\n", c); + fail |= 1; + } + if (!di) { + printf ("local init address cast fail: %d\n", di); + fail |= 1; + } + return fail; +} diff --git a/tools/qfcc/test/alignment.r b/tools/qfcc/test/alignment.r new file mode 100644 index 000000000..9b867b2d6 --- /dev/null +++ b/tools/qfcc/test/alignment.r @@ -0,0 +1,36 @@ +int a; +double b; +int c; +double d; +void printf (string fmt, ...) = #0; + +int main() +{ + int fail = 0; + void *ap = &a; + void *bp = &b; + void *cp = &c; + void *dp = &d; + int aa = (int) ap; + int ba = (int) bp; + int ca = (int) cp; + int da = (int) dp; + + if (ba & 1) { + printf ("double b is not aligned: %d\n", ba); + fail |= 1; + } + if (da & 1) { + printf ("double d is not aligned: %d\n", da); + fail |= 1; + } + if (ca - aa != 1) { + printf ("int c (%d) is not adjacant to int a (%d)\n", ca, aa); + fail |= 1; + } + if (ba <= ca) { + printf ("double b does not come after int c: %d %d\n", ba, ca); + fail |= 1; + } + return fail; +} diff --git a/tools/qfcc/test/anonstruct.r b/tools/qfcc/test/anonstruct.r new file mode 100644 index 000000000..3c025bb38 --- /dev/null +++ b/tools/qfcc/test/anonstruct.r @@ -0,0 +1,52 @@ +void printf (string fmt, ...) = #0; + +typedef struct xyzzy_s { + int magic; +} xyzzy_t; + +typedef struct anon_s { + int foo; + int id; + struct { + int bar; + int baz; + }; + union { + int snafu; + float fizzle; + }; +} anon_t; + +int foo (float f) +{ + anon_t anon; + anon.fizzle = f; + return anon.snafu; +} + +int main() +{ + anon_t anon; + int ret = 0; + if ((int)&anon.snafu != (int)&anon.fizzle) { + printf ("anon union broken: %p %p\n", + &anon.snafu, &anon.fizzle); + ret |= 1; + } + if ((int)&anon.snafu - (int)&anon.baz != 1) { + printf ("snafu and baz not adjacant: snafu:%p baz:%p\n", + &anon.snafu, &anon.baz); + ret |= 1; + } + if ((int)&anon.baz - (int)&anon.bar != 1) { + printf ("baz and bar not adjacant: baz:%p bar:%p\n", + &anon.baz, &anon.bar); + ret |= 1; + } + if ((int)&anon.bar - (int)&anon.id != 1) { + printf ("bar not after id: bar:%p id:%p\n", + &anon.bar, &anon.id); + ret |= 1; + } + return ret; +} diff --git a/tools/qfcc/test/assignchain.r b/tools/qfcc/test/assignchain.r new file mode 100644 index 000000000..7f08c0494 --- /dev/null +++ b/tools/qfcc/test/assignchain.r @@ -0,0 +1,92 @@ +#include "test-harness.h" + +typedef struct foo { + int x; + float y; +} foo; + +int x, y; +int z = 42; +foo bar, baz; +foo foo_init = { 5, 6.25 }; + +int test_simple_global (void) +{ + int ret = 0; + x = y = z; + if (x != z || y != z) { + printf ("test_simple_global: x=%d y=%d z=%d\n", x, y, z); + ret |= 1; + } + return ret; +} + +int test_struct_global (void) +{ + int ret = 0; + bar = baz = foo_init; + if (bar.x != foo_init.x || bar.y != foo_init.y) { + printf ("test_struct_global: bar={%d %g} foo_init={%d %g}\n", + bar.x, bar.y, foo_init.x, foo_init.y); + ret |= 1; + } + if (baz.x != foo_init.x || baz.y != foo_init.y) { + printf ("test_struct_global: baz={%d %g} foo_init={%d %g}\n", + baz.x, baz.y, foo_init.x, foo_init.y); + ret |= 1; + } + bar = baz = nil; + if (bar.x || baz.x || bar.y || baz.y) { + printf ("test_struct_global: bar={%d %g} baz={%d %g}\n", + bar.x, bar.y, baz.x, baz.y); + ret |= 1; + } + return ret; +} + +int test_simple_pointer (int *x, int *y) +{ + int ret = 0; + *x = *y = z; + if (*x != z || *y != z) { + printf ("test_simple_pointer: *x=%d *y=%d z=%d\n", *x, *y, z); + ret |= 1; + } + return ret; +} + +int test_struct_pointer (foo *bar, foo *baz) +{ + int ret = 0; + *bar = *baz = foo_init; + if (bar.x != foo_init.x || bar.y != foo_init.y) { + printf ("test_struct_pointer: bar={%d %g} foo_init={%d %g}\n", + bar.x, bar.y, foo_init.x, foo_init.y); + ret |= 1; + } + if (baz.x != foo_init.x || baz.y != foo_init.y) { + printf ("test_struct_pointer: baz={%d %g} foo_init={%d %g}\n", + baz.x, baz.y, foo_init.x, foo_init.y); + ret |= 1; + } + *bar = foo_init; + *baz = foo_init; + *bar = *baz = nil; + if (bar.x || baz.x || bar.y || baz.y) { + printf ("test_struct: bar={%d %g} baz={%d %g}\n", + bar.x, bar.y, baz.x, baz.y); + ret |= 1; + } + return ret; +} + +int main () +{ + int ret = 0; + ret |= test_simple_global (); + ret |= test_struct_global (); + x = 0; y = 0; + ret |= test_simple_pointer (&x, &y); + ret |= test_struct_pointer (&bar, &baz); + return ret; +} diff --git a/tools/qfcc/test/build-compile-fail-run b/tools/qfcc/test/build-compile-fail-run new file mode 100755 index 000000000..415e894e7 --- /dev/null +++ b/tools/qfcc/test/build-compile-fail-run @@ -0,0 +1,15 @@ +#! /bin/sh + +script=$1 +shift + +cat > $script < $script < 0; ) { + i += 2; + j += 3; + } + if (i == 13 && j == 20) { + fail = 0; + } + + return fail; +} + +int +test_comma () +{ + int fail = 1; + if (return_comma() == 5) { + if (a == 3) { + fail = 0; + } + } + return fail; +} + +int +main () +{ + int fail = 0; + fail |= test_comma (); + fail |= test_for_comma (); + return fail; +} diff --git a/tools/qfcc/test/compound.r b/tools/qfcc/test/compound.r new file mode 100644 index 000000000..19a72d3fe --- /dev/null +++ b/tools/qfcc/test/compound.r @@ -0,0 +1,72 @@ +#include "test-harness.h" + +typedef struct Point { + int x; + int y; +} Point; + +typedef struct Size { + int width; + int height; +} Size; + +typedef struct Rect { + Point origin; + Size size; +} Rect; + +int test_simple_param (Point p, int x, int y) +{ + int ret = !(p.x == x && p.y == y); + if (ret) { + printf ("simple param: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y); + } + return ret; +} + +int test_nested_param (Rect r, int x, int y, int w, int h) +{ + int ret = !(r.origin.x == x && r.origin.y == y + && r.size.width == w && r.size.height == h); + if (ret) { + printf ("nested param: {{%d, %d}, {%d, %d}} != ", + r.origin.x, r.origin.y, r.size.width, r.size.height); + printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h); + } + return ret; +} + +int test_simple_assign (int x, int y) +{ + Point p; + p = { x, y }; + int ret = !(p.x == x && p.y == y); + if (ret) { + printf ("simple assign: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y); + } + return ret; +} + +int test_nested_assign (int x, int y, int w, int h) +{ + Rect r; + r = {{x, y}, {w, h}}; + int ret = !(r.origin.x == x && r.origin.y == y + && r.size.width == w && r.size.height == h); + if (ret) { + printf ("nested assign: {{%d, %d}, {%d, %d}} != ", + r.origin.x, r.origin.y, r.size.width, r.size.height); + printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h); + } + return ret; +} + +int main (void) +{ + int ret = 0; + ret |= test_simple_param ({1, 2}, 1, 2); + ret |= test_nested_param ({{1, 2}, {3, 4}}, 1, 2, 3, 4); + ret |= test_simple_assign (1, 2); + ret |= test_nested_assign (1, 2, 3, 4); + return ret; +} diff --git a/tools/qfcc/test/deadbool.r b/tools/qfcc/test/deadbool.r index c4869b293..c56aa0f10 100644 --- a/tools/qfcc/test/deadbool.r +++ b/tools/qfcc/test/deadbool.r @@ -9,7 +9,7 @@ void foo (void) return; if (!time) { ent = spawn (); - ent.f = time + 0.1; + ent.f = time + 0.1f; } } diff --git a/tools/qfcc/test/double-alias.r b/tools/qfcc/test/double-alias.r new file mode 100644 index 000000000..6050d2f6d --- /dev/null +++ b/tools/qfcc/test/double-alias.r @@ -0,0 +1,41 @@ +void printf (string fmt, ...) = #0; +# define M_PI 3.14159265358979323846 + +union { + double d; + int i[2]; +} type_pun; + +int alias_printf (string fmt, ...); + +int +test_alias () +{ + int fail = 0; + type_pun.d = M_PI; + fail = alias_printf ("%g %08x%08x\n", type_pun.d, + type_pun.i[1], type_pun.i[0]); + return fail; +} + +int +alias_printf (string fmt, ...) +{ + int fail = 0; + // this will fail on big-endian systems + fail = (@args.list[2].integer_val != 0x54442d18 + || @args.list[1].integer_val != 0x400921fb); + printf ("%g %08x%08x\n", + @args.list[0].integer_val, + @args.list[2].integer_val, + @args.list[1].integer_val); + return fail; +} + +int +main () +{ + int fail = 0; + fail |= test_alias (); + return fail; +} diff --git a/tools/qfcc/test/double-demote-float-ainit.r b/tools/qfcc/test/double-demote-float-ainit.r new file mode 100644 index 000000000..6d380447d --- /dev/null +++ b/tools/qfcc/test/double-demote-float-ainit.r @@ -0,0 +1,6 @@ +double a; +int b[] = {1.0d}; +int main () +{ + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-demote-float-ginit.r b/tools/qfcc/test/double-demote-float-ginit.r new file mode 100644 index 000000000..c88b5e987 --- /dev/null +++ b/tools/qfcc/test/double-demote-float-ginit.r @@ -0,0 +1,6 @@ +double a; +float b = 1.0d; +int main () +{ + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-demote-float-linit.r b/tools/qfcc/test/double-demote-float-linit.r new file mode 100644 index 000000000..796b2040f --- /dev/null +++ b/tools/qfcc/test/double-demote-float-linit.r @@ -0,0 +1,6 @@ +double a; +int main () +{ + float b = a; + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-demote-float.r b/tools/qfcc/test/double-demote-float.r new file mode 100644 index 000000000..330a0bdef --- /dev/null +++ b/tools/qfcc/test/double-demote-float.r @@ -0,0 +1,7 @@ +double a; +float b; +int main () +{ + b = a; + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-demote-int-ainit.r b/tools/qfcc/test/double-demote-int-ainit.r new file mode 100644 index 000000000..6d380447d --- /dev/null +++ b/tools/qfcc/test/double-demote-int-ainit.r @@ -0,0 +1,6 @@ +double a; +int b[] = {1.0d}; +int main () +{ + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-demote-int-ginit.r b/tools/qfcc/test/double-demote-int-ginit.r new file mode 100644 index 000000000..767328715 --- /dev/null +++ b/tools/qfcc/test/double-demote-int-ginit.r @@ -0,0 +1,6 @@ +double a; +int b = 1.0d; +int main () +{ + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-demote-int-linit.r b/tools/qfcc/test/double-demote-int-linit.r new file mode 100644 index 000000000..3a206f4b5 --- /dev/null +++ b/tools/qfcc/test/double-demote-int-linit.r @@ -0,0 +1,6 @@ +double a; +int main () +{ + int b = a; + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-demote-int.r b/tools/qfcc/test/double-demote-int.r new file mode 100644 index 000000000..bebef5436 --- /dev/null +++ b/tools/qfcc/test/double-demote-int.r @@ -0,0 +1,7 @@ +double a; +int b; +int main () +{ + b = a; + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-float-compare.r b/tools/qfcc/test/double-float-compare.r new file mode 100644 index 000000000..a219b0d4a --- /dev/null +++ b/tools/qfcc/test/double-float-compare.r @@ -0,0 +1,7 @@ +double a; +float b; +int main () +{ + int x = a == b; + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double-int-compare.r b/tools/qfcc/test/double-int-compare.r new file mode 100644 index 000000000..221516ed8 --- /dev/null +++ b/tools/qfcc/test/double-int-compare.r @@ -0,0 +1,7 @@ +double a; +int b; +int main () +{ + int x = a == b; + return 1; // test fails if compile succeeds +} diff --git a/tools/qfcc/test/double.r b/tools/qfcc/test/double.r new file mode 100644 index 000000000..326ccf906 --- /dev/null +++ b/tools/qfcc/test/double.r @@ -0,0 +1,106 @@ +void printf (string fmt, ...) = #0; +# define M_PI 3.14159265358979323846 + +union { + double d; + int i[2]; +} type_pun; + +int +test_format () +{ + int fail = 0; + type_pun.d = M_PI; + printf ("%g %08x%08x\n", type_pun.d, type_pun.i[1], type_pun.i[0]); + // this will fail on big-endian systems + fail = type_pun.i[0] != 0x54442d18 || type_pun.i[1] != 0x400921fb; + return fail; +} + +int +test_constant () +{ + int fail = 0; + double a, b, c, d, e; + a = 1; + b = 2.0; + c = 3.2f; + d = 3.2d; + e = 3.2; + printf ("%.17g %.17g %.17g %.17g %.17g\n", a, b, c, d, e); + // this will fail on big-endian systems + fail |= c == d; // 3.2 is not exactly representable, so must be different + fail |= c == e; // 3.2 is not exactly representable, so must be different + fail |= d != e; // 3.2d and 3.2 are both double, so must be the same + return fail; +} + +double less = 3; +double greater_equal = 3; +double less_equal = 5; +double greater = 5; + +int +test_copare () +{ + int fail = 0; + + fail |= !(less < greater); + fail |= (less > greater); + fail |= !(less != greater); + fail |= (less == greater); + fail |= !(less <= greater); + fail |= (less >= greater); + + fail |= (less_equal < greater); + fail |= (less_equal > greater); + fail |= !(less_equal == greater); + fail |= (less_equal != greater); + fail |= !(less_equal <= greater); + fail |= !(less_equal >= greater); + + fail |= (greater < less); + fail |= !(greater > less); + fail |= !(greater != less); + fail |= (greater == less); + fail |= (greater <= less); + fail |= !(greater >= less); + + fail |= (greater_equal < less); + fail |= (greater_equal > less); + fail |= !(greater_equal == less); + fail |= (greater_equal != less); + fail |= !(greater_equal <= less); + fail |= !(greater_equal >= less); + return fail; +} + +int +test_ops () +{ + int fail = 0; + double a = 6.25, b = 2.375; + double c; + + c = a + b; + fail |= c != 8.625; + c = a - b; + fail |= c != 3.875; + c = a * b; + fail |= c != 14.84375; + c = a / b; + fail |= c != 50d/19d; + c = a % b; + fail |= c != 1.5; + return fail; +} + +int +main () +{ + int fail = 0; + fail |= test_format (); + fail |= test_constant (); + fail |= test_ops (); + return fail; +} diff --git a/tools/qfcc/test/enum.r b/tools/qfcc/test/enum.r new file mode 100644 index 000000000..f1565cdf0 --- /dev/null +++ b/tools/qfcc/test/enum.r @@ -0,0 +1,13 @@ +typedef enum { + NO = 0, + YES +} BOOL; + +int +main() +{ + BOOL b; + b = 0; + b = YES; + return !b; +} diff --git a/tools/qfcc/test/fordecl.r b/tools/qfcc/test/fordecl.r new file mode 100644 index 000000000..70d57690a --- /dev/null +++ b/tools/qfcc/test/fordecl.r @@ -0,0 +1,29 @@ +void printf (string fmt, ...) = #0; + +int +test_fordecl () +{ + int fail = 1; + int count = 5; + int ti = -1, tj = -1; + + for (int i = 3, j = 5; count-- > 0; ) { + i += 2; + j += 3; + ti = i; + tj = j; + } + if (ti == 13 && tj == 20) { + fail = 0; + } + + return fail; +} + +int +main () +{ + int fail = 0; + fail |= test_fordecl (); + return fail; +} diff --git a/tools/qfcc/test/func-expr2.r b/tools/qfcc/test/func-expr2.r new file mode 100644 index 000000000..32dad106d --- /dev/null +++ b/tools/qfcc/test/func-expr2.r @@ -0,0 +1,23 @@ +typedef struct Extent_s { + int width; + int height; +} Extent; + +extern Extent get_size (void); +extern int getlen(void); + +int main (void) +{ + int x = get_size().width - getlen() - 1; + return x != 29; +} + +Extent get_size (void) +{ + return {38, 8}; +} + +int getlen (void) +{ + return 8; +} diff --git a/tools/qfcc/test/old/gcd.pas b/tools/qfcc/test/gcd.pas similarity index 73% rename from tools/qfcc/test/old/gcd.pas rename to tools/qfcc/test/gcd.pas index 04e193b26..3879a3d3d 100644 --- a/tools/qfcc/test/old/gcd.pas +++ b/tools/qfcc/test/gcd.pas @@ -1,5 +1,5 @@ program example (input, output); -var x, y: integer; +var x, y, g: integer; procedure printf (format:string; ...) := #0; function gcd (a, b: integer): integer; var c: quaternion; @@ -11,5 +11,7 @@ end; begin x := 130; y := 120; - printf ("%d\n", gcd (x, y)) + g := gcd (x, y); + printf ("%d\n", g); + ExitCode := g <> 10; end. diff --git a/tools/qfcc/test/ivar-struct-return.r b/tools/qfcc/test/ivar-struct-return.r new file mode 100644 index 000000000..8351293c8 --- /dev/null +++ b/tools/qfcc/test/ivar-struct-return.r @@ -0,0 +1,29 @@ +#pragma bug die +#include "test-harness.h" + +struct Point { + int x; + int y; +}; +typedef struct Point Point; + +@interface Object +{ + int foo; + Point origin; +} ++(Point) origin; +@end + +@implementation Object ++(Point) origin +{ + origin = {1, 2}; + return origin; +} +@end +int main() +{ + Point p = [Object origin]; + return !(p.x == 1 && p.y == 2); +} diff --git a/tools/qfcc/test/methodparams.r b/tools/qfcc/test/methodparams.r new file mode 100644 index 000000000..b29e6954b --- /dev/null +++ b/tools/qfcc/test/methodparams.r @@ -0,0 +1,29 @@ +typedef struct { int x, y; } Point; +@interface TextContext +- (void) mvvprintf: (Point) pos, string mft, @va_list args; +@end +@interface View +{ + TextContext *textContext; +} +- (void) mvprintf: (Point) pos, string mft, ...; +@end + +@implementation View +- (void) mvprintf: (Point) pos, string fmt, ... +{ + [textContext mvvprintf: pos, fmt, @args]; +} +@end +id obj_msgSend (id receiver, SEL op, ...) = #0; +void __obj_exec_class (struct obj_module *msg) = #0; +@interface Object +@end +@implementation Object +@end + +int +main (void) +{ + return 0; // to survive and prevail :) +} diff --git a/tools/qfcc/test/modulo.r b/tools/qfcc/test/modulo.r index 4d59fdf87..2d31a69a2 100644 --- a/tools/qfcc/test/modulo.r +++ b/tools/qfcc/test/modulo.r @@ -1,11 +1,34 @@ -#pragma traditional +void printf (string ftm, ...) = #0; -void (...) printf = #0; +float snafu (float a, float b) +{ + float c = a % b; + return c; +} + +int imodulo (int a, int b) +{ + return a %% b; +} + +float fmodulo (float a, float b) +{ + return a %% b; +} + +double dmodulo (double a, double b) +{ + return a %% b; +} + +#pragma traditional float foo (float a, float b) { float c = a % b; return c; } +#pragma advanced + float bar (float a, float b) { float c; @@ -15,14 +38,35 @@ float bar (float a, float b) return c; } +#pragma traditional float baz (float a, float b) { float c = (a + b) % (a - b); return c; } +#pragma advanced -float test (string name, float (func)(float a, float b), - float a, float b, float c) +@overload int +test (string name, string op, int (func)(int a, int b), int a, int b, int c) +{ + int ret; + + ret = func (a, b); + if (ret != c) { + if (func == baz) + printf ("%s: (%d + %d) %% (%d - %d): %d != %d\n", + name, a, b, a, b, ret, c); + else + printf ("%s: %d %s %d: %d != %d\n", + name, a, op, b, ret, c); + return 1; + } + return 0; +} + +@overload int +test (string name, string op, float (func)(float a, float b), + float a, float b, float c) { float ret; @@ -32,8 +76,27 @@ float test (string name, float (func)(float a, float b), printf ("%s: (%g + %g) %% (%g - %g): %g != %g\n", name, a, b, a, b, ret, c); else - printf ("%s: %g %% %g: %g != %g\n", - name, a, b, ret, c); + printf ("%s: %g %s %g: %g != %g\n", + name, a, op, b, ret, c); + return 1; + } + return 0; +} + +@overload int +test (string name, string op, double (func)(double a, double b), + double a, double b, double c) +{ + double ret; + + ret = func (a, b); + if (ret != c) { + if (func == baz) + printf ("%s: (%g + %g) %% (%g - %g): %g != %g\n", + name, a, b, a, b, ret, c); + else + printf ("%s: %g %s %g: %g != %g\n", + name, a, op, b, ret, c); return 1; } return 0; @@ -42,20 +105,56 @@ float test (string name, float (func)(float a, float b), float main (void) { float res = 0; - res |= test ("foo", foo, 5, 3, 2); - res |= test ("bar", bar, 5, 3, 2); - res |= test ("baz", baz, 5, 3, 0); + res |= test ("foo", "%", foo, 5, 3, 2); + res |= test ("bar", "%", bar, 5, 3, 2); + res |= test ("baz", "%", baz, 5, 3, 0); + res |= test ("snafu", "%", snafu, 5, 3, 2); - res |= test ("foo", foo, -5, 3, -2); - res |= test ("bar", bar, -5, 3, -2); - res |= test ("baz", baz, -5, 3, -2); + res |= test ("foo", "%", foo, -5, 3, -2); + res |= test ("bar", "%", bar, -5, 3, -2); + res |= test ("baz", "%", baz, -5, 3, -2); + res |= test ("snafu", "%", snafu, -5, 3, -2); - res |= test ("foo", foo, 5, -3, 2); - res |= test ("bar", bar, 5, -3, 2); - res |= test ("baz", baz, 5, -3, 2); + res |= test ("foo", "%", foo, 5, -3, 2); + res |= test ("bar", "%", bar, 5, -3, 2); + res |= test ("baz", "%", baz, 5, -3, 2); + res |= test ("snafu", "%", snafu, 5, -3, 2); - res |= test ("foo", foo, -5, -3, -2); - res |= test ("bar", bar, -5, -3, -2); - res |= test ("baz", baz, -5, -3, 0); + res |= test ("foo", "%", foo, -5, -3, -2); + res |= test ("bar", "%", bar, -5, -3, -2); + res |= test ("baz", "%", baz, -5, -3, 0); + res |= test ("snafu", "%", snafu, -5, -3, -2); + + res |= test ("foo", "%", foo, 5, 3.5, 1.5); + res |= test ("foo", "%", foo, -5, 3.5, -1.5); + res |= test ("snafu", "%", snafu, 5, 3.5, 1.5); + res |= test ("snafu", "%", snafu, -5, 3.5, -1.5); + + res |= test ("int modulo", "%%", imodulo, 5, 3, 2); + res |= test ("int modulo", "%%", imodulo, -5, 3, 1); + res |= test ("int modulo", "%%", imodulo, 5, -3, -1); + res |= test ("int modulo", "%%", imodulo, -5, -3, -2); + res |= test ("int modulo", "%%", imodulo, 6, 3, 0); + res |= test ("int modulo", "%%", imodulo, -6, 3, 0); + res |= test ("int modulo", "%%", imodulo, 6, -3, 0); + res |= test ("int modulo", "%%", imodulo, -6, -3, 0); + + res |= test ("float modulo", "%%", fmodulo, 5, 3, 2); + res |= test ("float modulo", "%%", fmodulo, -5, 3, 1); + res |= test ("float modulo", "%%", fmodulo, 5, -3, -1); + res |= test ("float modulo", "%%", fmodulo, -5, -3, -2); + res |= test ("float modulo", "%%", fmodulo, 6, 3, 0); + res |= test ("float modulo", "%%", fmodulo, -6, 3, 0); + res |= test ("float modulo", "%%", fmodulo, 6, -3, 0); + res |= test ("float modulo", "%%", fmodulo, -6, -3, 0); + + res |= test ("double modulo", "%%", dmodulo, 5, 3, 2); + res |= test ("double modulo", "%%", dmodulo, -5, 3, 1); + res |= test ("double modulo", "%%", dmodulo, 5, -3, -1); + res |= test ("double modulo", "%%", dmodulo, -5, -3, -2); + res |= test ("double modulo", "%%", dmodulo, 6, 3, 0); + res |= test ("double modulo", "%%", dmodulo, -6, 3, 0); + res |= test ("double modulo", "%%", dmodulo, 6, -3, 0); + res |= test ("double modulo", "%%", dmodulo, -6, -3, 0); return res; } diff --git a/tools/qfcc/test/nilparamret.r b/tools/qfcc/test/nilparamret.r new file mode 100644 index 000000000..fbe0b7dc5 --- /dev/null +++ b/tools/qfcc/test/nilparamret.r @@ -0,0 +1,26 @@ +typedef struct bar { + float x, y, z, w; +} bar; + +bar set_return(); + +@param foo() +{ + set_return(); + return nil; +} + +bar set_return() +{ + return {1, 2, 3, 4}; +} +void printf (string fmt, ...) = #0; +int main() +{ + @param r = foo(); + printf("%q\n", r); + return !(r.quaternion_val.x == 0 + && r.quaternion_val.y == 0 + && r.quaternion_val.z == 0 + && r.quaternion_val.w == 0); +} diff --git a/tools/qfcc/test/old/linkdef2.r b/tools/qfcc/test/old/linkdef2.r index 133235f69..20a72fa3a 100644 --- a/tools/qfcc/test/old/linkdef2.r +++ b/tools/qfcc/test/old/linkdef2.r @@ -5,5 +5,5 @@ id obj; integer foo (void) { [obj message]; - return bar () + baz ();; + return bar () + baz (); } diff --git a/tools/qfcc/test/old/overload.r b/tools/qfcc/test/old/overload.r deleted file mode 100644 index 60bd5cf46..000000000 --- a/tools/qfcc/test/old/overload.r +++ /dev/null @@ -1,30 +0,0 @@ -//integer foo; -//typedef integer foo; -//integer (void) foo = #0; -//integer (bag); -//.integer (sack); -//.integer (float sack)x; -//integer *bar, baz; -//integer snafu(void) -//{ -//} -//integer [8]blah; - -@overload void func (integer a, integer b, integer c); -@overload void func (integer a, integer b); -@overload void func (integer a, ...); -//@overload void func (integer a, integer b, ...); -@overload void func (string y); -//@overload void func (...); -void func (integer x) -{ -// func (""); -} -void func (string y) -{ -// func (0.0); -// func (0, 0.0); -// func (0, 0, 0.0); - func (0.0, ""); -// func (0, 0, 0, 0, 0.0); -} diff --git a/tools/qfcc/test/overload.r b/tools/qfcc/test/overload.r new file mode 100644 index 000000000..97c77bbdf --- /dev/null +++ b/tools/qfcc/test/overload.r @@ -0,0 +1,23 @@ +typedef enum { + NO = 0, + YES +} BOOL; + +@extern BOOL sel_is_mapped (SEL aSel); +BOOL (SEL aSel) sel_is_mapped = #0; + +@overload int foo(int x) +{ + return 1; +} + +@overload int foo(float x) +{ + return 2; +} + +int main() +{ + //FIXME fails on implicit cast of double to float + return !(foo(5) == 1 && foo (5.0f) == 2); +} diff --git a/tools/qfcc/test/quaternion.r b/tools/qfcc/test/quaternion.r new file mode 100644 index 000000000..6ac67911a --- /dev/null +++ b/tools/qfcc/test/quaternion.r @@ -0,0 +1,73 @@ +void printf (string fmt, ...) = #0; + +int +test_format () +{ + int fail = 0; + quaternion q = '1 2 3 4'; + vector v = '-1 -2 -3'; + float s = -4; + + if (q.x != 1 || q.y != 2 || q.z != 3 || q.w != 4) { + printf ("q = '1 2 3 4' -> %q\n", q); + fail = 1; + } + if (q.v != '1 2 3' || q.s != 4) { + printf ("q = '1 2 3 4' -> %v, %g\n", q.v, q.s); + fail = 1; + } + q = nil; + if (q.x != 0 || q.y != 0 || q.z != 0 || q.w != 0) { + printf ("q = nil -> %q\n", q); + fail = 1; + } + if (q.v != '0 0 0' || q.s != 0) { + printf ("q = nil -> %v, %g\n", q.v, q.s); + fail = 1; + } + q = [1, [2, 3, 4]]; + if (q.x != 2 || q.y != 3 || q.z != 4 || q.w != 1) { + printf ("q = [1, [2, 3, 4]] -> %q\n", q); + fail = 1; + } + if (q.v != '2 3 4' || q.s != 1) { + printf ("q = [1, [2, 3, 4]] -> %v, %g\n", q.v, q.s); + fail = 1; + } + q = [[5, 6, 7], 8]; + if (q.x != 5 || q.y != 6 || q.z != 7 || q.w != 8) { + printf ("q = [[5, 6, 7], 8] -> %q\n", q); + fail = 1; + } + if (q.v != '5 6 7' || q.s != 8) { + printf ("q = [[5, 6, 7], 8] -> %v, %g\n", q.v, q.s); + fail = 1; + } + q = [s, v]; + if (q.x != v.x || q.y != v.y || q.z != v.z || q.w != s) { + printf ("q = [s, v] -> %q (%v)\n", q, v); + fail = 1; + } + if (q.v != v || q.s != s) { + printf ("q = [s, v] -> %v, %g (%v)\n", q.v, q.s, v); + fail = 1; + } + q = [v, s]; + if (q.x != v.x || q.y != v.y || q.z != v.z || q.w != s) { + printf ("q = [v, s] -> %q (%v %s)\n", q, v, s); + fail = 1; + } + if (q.v != v || q.s != s) { + printf ("q = [v, s] -> %v, %g (%v %s)\n", q.v, q.s, v, s); + fail = 1; + } + return fail; +} + +int +main () +{ + int fail = 0; + fail |= test_format (); + return fail; +} diff --git a/tools/qfcc/test/sendv.r b/tools/qfcc/test/sendv.r index 979a72c43..aa2cb6665 100644 --- a/tools/qfcc/test/sendv.r +++ b/tools/qfcc/test/sendv.r @@ -8,12 +8,13 @@ int obj_increment_retaincount (id object) = #0; void send (id obj, string cmd, string str) { - @static @param params[1]; - @va_list va_list = {1, params}; - SEL sel; + @static @param params[3]; + @va_list va_list = {3, params}; + SEL sel = sel_get_uid (cmd); - params[0].string_val = str; - sel = sel_get_uid (cmd); + params[0].pointer_val = obj; + params[1].pointer_val = sel; + params[2].string_val = str; obj_msg_sendv (obj, sel, va_list); } diff --git a/tools/qfcc/test/state.r b/tools/qfcc/test/state.r index 7fec3c2d0..a7be65754 100644 --- a/tools/qfcc/test/state.r +++ b/tools/qfcc/test/state.r @@ -13,7 +13,7 @@ state0 (void) [$frame1, state1] { if (self.frame != $frame1 || self.think != state1 - || self.nextthink != 0.1) { + || self.nextthink != 0.1f) { printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink); exit (1); } @@ -21,10 +21,10 @@ state0 (void) void state1 (void) -[$frame2, state2, 0.2] +[$frame2, state2, 0.2f] { if (self.frame != $frame2 || self.think != state2 - || self.nextthink != 0.2) { + || self.nextthink != 0.2f) { printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink); exit (1); } @@ -32,10 +32,10 @@ state1 (void) void state2 (void) -[$frame0, state0, 0.5] +[$frame0, state0, 0.5f] { if (self.frame != $frame0 || self.think != state0 - || self.nextthink != 0.5) { + || self.nextthink != 0.5f) { printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink); exit (1); } diff --git a/tools/qfcc/test/static-init.r b/tools/qfcc/test/static-init.r new file mode 100644 index 000000000..bbbe3f9a7 --- /dev/null +++ b/tools/qfcc/test/static-init.r @@ -0,0 +1,19 @@ +#include "test-harness.h" + +int count_down () +{ + static int count = 2; + count--; + return count > 0; +} + +int main() +{ + int ret = 0; + count_down (); + if (count_down ()) { + printf ("did not reach 0\n"); + ret |= 1; + } + return ret; +} diff --git a/tools/qfcc/test/struct-init-param.r b/tools/qfcc/test/struct-init-param.r new file mode 100644 index 000000000..c3dd5927b --- /dev/null +++ b/tools/qfcc/test/struct-init-param.r @@ -0,0 +1,59 @@ +void printf (string fmt, ...) = #0; +typedef struct { + int x; + int y; +} Point; + +typedef struct { + int width; + int height; +} Extent; + +typedef struct Rect_s { + Point offset; + Extent extent; +} Rect; + +void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r); + +void *baz (Rect *obj, void *cmd, Rect *o, Point pos) +{ + Rect rect = { {1, 2}, {3, 4} }; + return foo (obj, cmd, o, pos, rect); +} + +void *bar (Rect *obj, void *cmd, Rect *o, Point pos) +{ + Rect rect = { {}, obj.extent }; + return foo (obj, cmd, o, pos, rect); +} + +void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r) +{ + *o = r; + return obj; +} + +Rect obj = { { 1, 2}, { 3, 4} }; +Rect o = { { 5, 6}, {7, 8} }; + +int main (void) +{ + int ret = 0; + int ok; + + bar(&obj, nil, &o, obj.offset); + ok = (o.offset.x == 0 && o.offset.y == 0 + && o.extent.width == 3 && o.extent.height == 4); + ret |= !ok; + printf ("%d %d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height, ok); + + baz(&obj, nil, &o, obj.offset); + ok = (o.offset.x == 1 && o.offset.y == 2 + && o.extent.width == 3 && o.extent.height == 4); + ret |= !ok; + printf ("%d %d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height, ok); + return ret; +} diff --git a/tools/qfcc/test/struct-nil-init.r b/tools/qfcc/test/struct-nil-init.r new file mode 100644 index 000000000..065a43b34 --- /dev/null +++ b/tools/qfcc/test/struct-nil-init.r @@ -0,0 +1,12 @@ +#pragma bug die + +struct foo { + quaternion x; + double y; +}; + +int main() +{ + struct foo bar = { }; + return bar.y; // to survive and prevail +} diff --git a/tools/qfcc/test/structarray.r b/tools/qfcc/test/structarray.r new file mode 100644 index 000000000..74d64214e --- /dev/null +++ b/tools/qfcc/test/structarray.r @@ -0,0 +1,23 @@ +void printf (string fmt, ...) = #0; +void *obj_malloc (int size) = #0; + +typedef struct { + int val; + int cap; + int ofs[]; +} valstruct_t; + +int foo[] = {1, 2, 3, 4, 5}; +valstruct_t *vs; +int dst; + +int +main () +{ + vs = (valstruct_t *)foo; + for (int i = 0; i < 2; i++) { + dst = vs.ofs[i]; + } + printf("dst = %d\n", dst); + return sizeof(foo) != 5 || dst != 4; +} diff --git a/tools/qfcc/test/structstruct.r b/tools/qfcc/test/structstruct.r new file mode 100644 index 000000000..c8ef25fad --- /dev/null +++ b/tools/qfcc/test/structstruct.r @@ -0,0 +1,61 @@ +#include "test-harness.h" + +typedef struct Point { + int x; + int y; +} Point; + +typedef struct Size { + int width; + int height; +} Size; + +typedef struct Rect { + Point origin; + Size size; +} Rect; + +Rect rect = {{1, 2}, {3, 4}}; +Point origin = {5, 6}; +Size size = {7, 8}; + +int +test_struct_1(Rect rect) +{ + return rect.origin.x; +} + +int +test_struct_2(Rect rect) +{ + return rect.origin.y; +} + +int +test_struct_3(Rect rect) +{ + return rect.size.width; +} + +int +test_struct_4(Rect rect) +{ + return rect.size.height; +} + +int +main() +{ + int ret = 0; + ret |= test_struct_1(rect) != 1; + ret |= test_struct_2(rect) != 2; + ret |= test_struct_3(rect) != 3; + ret |= test_struct_4(rect) != 4; + rect.origin = origin; + rect.size = size; + ret |= test_struct_1(rect) != 5; + ret |= test_struct_2(rect) != 6; + ret |= test_struct_3(rect) != 7; + ret |= test_struct_4(rect) != 8; + return ret; +} diff --git a/tools/qfcc/test/swap.r b/tools/qfcc/test/swap.r new file mode 100644 index 000000000..8a338be15 --- /dev/null +++ b/tools/qfcc/test/swap.r @@ -0,0 +1,15 @@ +void printf (string fmt, ...) = #0; + +float +swap (float a, float b) +{ + float t; + if (a < b) { t = a; a = b; b = t; } + return a - b; +} + +int +main () +{ + return swap (1, 2) > 0 ? 0 : 1; +} diff --git a/tools/qfcc/test/test-defspace.c b/tools/qfcc/test/test-defspace.c new file mode 100644 index 000000000..17d9ed12e --- /dev/null +++ b/tools/qfcc/test/test-defspace.c @@ -0,0 +1,117 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/qfcc.h" + +#include "tools/qfcc/test/test-defspace.h" + +options_t options; +pr_info_t pr; +function_t *current_func; +class_type_t *current_class; + +void +free_def (def_t *def) +{ + if (0) free (def); +} + +__attribute__((const))const char * +get_class_name (class_type_t *class_type, int prett) +{ + return 0; +} + +expr_t * +new_expr (void) +{ + return calloc(1, sizeof (expr_t)); +} + +static int +check_init_state (const defspace_t *space, const char *name) +{ + int pass = 1; + + if (space->free_locs) { + printf ("%s free_locs not null\n", name); + pass = 0; + } + if (space->defs) { + printf ("%s defs not null\n", name); + pass = 0; + } + if (space->def_tail != &space->defs) { + printf ("%s def_tail not pointing to defs\n", name); + pass = 0; + } + if (space->data) { + printf ("%s data not null\n", name); + pass = 0; + } + if (space->size) { + printf ("%s size not 0\n", name); + pass = 0; + } + if (space->max_size) { + printf ("%s max_size not 0\n", name); + pass = 0; + } + if (!space->grow) { + printf ("%s grow is null\n", name); + pass = 0; + } + if (space->qfo_space) { + printf ("%s qfo_space not 0\n", name); + pass = 0; + } + return pass; +} + +static int +test_init (void) +{ + int pass = 1; + defspace_t *backed = defspace_new (ds_backed); + defspace_t *virtual = defspace_new (ds_virtual); + + if (backed->grow == virtual->grow) { + printf ("expected different grow functions for backed and virtual\n"); + pass = 0; + } + + if (backed->type != ds_backed) { + printf ("backed ds has wrong type\n"); + pass = 0; + } + + if (virtual->type != ds_virtual) { + printf ("virtual ds has wrong type\n"); + pass = 0; + } + + pass &= check_init_state (backed, "backed"); + pass &= check_init_state (virtual, "virtual"); + + return pass; +} + +int +main (int argc, const char **argv) +{ + pr.strings = strpool_new (); + + int pass = 1; + + pass &= test_init (); + + return !pass; +} diff --git a/tools/qfcc/test/test-defspace.h b/tools/qfcc/test/test-defspace.h new file mode 100644 index 000000000..ab6fcd1e8 --- /dev/null +++ b/tools/qfcc/test/test-defspace.h @@ -0,0 +1,6 @@ +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/defspace.h" + +int def_list_is_empty (const defspace_t *space); +int def_list_is_valid (const defspace_t *space); +int free_locs_is_valid (const defspace_t *space); diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index 87cd26c55..5b0199317 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -31,6 +31,7 @@ # include "config.h" #endif +#include #include #include @@ -47,6 +48,7 @@ #define MAX_EDICTS 64 // 64 edicts should be enough for testing #define MAX_HEAP 1024*1024 // 1MB should be enough for testing +#define MAX_STACK 64*1024 // 64kB should be enough for testing // keep me sane when adding long options :P enum { @@ -70,10 +72,12 @@ static const char *short_options = "V" // version ; +static edict_t test_edicts[MAX_EDICTS]; + static edict_t *edicts; static int num_edicts; static int reserved_edicts; -static progs_t pr; +static progs_t test_pr; static const char *this_program; static struct { @@ -96,7 +100,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -104,7 +108,7 @@ load_file (progs_t *pr, const char *name) file = open_file (name, &size); if (!file) { - file = open_file (va ("%s.gz", name), &size); + file = open_file (va (0, "%s.gz", name), &size); if (!file) { return 0; } @@ -112,6 +116,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } @@ -127,31 +132,53 @@ free_progs_mem (progs_t *pr, void *mem) free (mem); } +static int +init_edicts (progs_t *pr) +{ + memset (test_edicts, 0, sizeof (test_edicts)); + + // init the data field of the edicts + for (int i = 0; i < MAX_EDICTS; i++) { + edict_t *ent = EDICT_NUM (&test_pr, i); + ent->pr = &test_pr; + ent->entnum = i; + ent->edict = EDICT_TO_PROG (&test_pr, ent); + } + return 1; +} + static void init_qf (void) { Sys_Init (); - Cvar_Get ("developer", va ("%d", options.developer), 0, 0, 0); + Cvar_Get ("developer", va (0, "%d", options.developer), 0, 0, 0); - Memory_Init (malloc (1024 * 1024), 1024 * 1024); + Memory_Init (Sys_Alloc (1024 * 1024), 1024 * 1024); - Cvar_Get ("pr_debug", "2", 0, 0, 0); + cvar_t *debug = Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "2", 0, 0, 0); + Cvar_Get ("pr_deadbeef_locals", "1", 0, 0, 0); - pr.edicts = &edicts; - pr.num_edicts = &num_edicts; - pr.reserved_edicts = &reserved_edicts; - pr.load_file = load_file; - pr.allocate_progs_mem = allocate_progs_mem; - pr.free_progs_mem = free_progs_mem; - pr.no_exec_limit = 0; // absolutely want a limit! - pr.pr_trace = options.trace; + if (options.trace > 1) { + Cvar_SetValue (debug, 4); + } + + test_pr.pr_edicts = &edicts; + test_pr.num_edicts = &num_edicts; + test_pr.reserved_edicts = &reserved_edicts; + test_pr.load_file = load_file; + test_pr.allocate_progs_mem = allocate_progs_mem; + test_pr.free_progs_mem = free_progs_mem; + test_pr.no_exec_limit = 0; // absolutely want a limit! PR_Init_Cvars (); - PR_Init (); - RUA_Init (&pr, 0); - PR_Cmds_Init(&pr); - BI_Init (&pr); + + PR_AddLoadFunc (&test_pr, init_edicts); + PR_Init (&test_pr); + + RUA_Init (&test_pr, 0); + PR_Cmds_Init(&test_pr); + BI_Init (&test_pr); } static int @@ -164,11 +191,20 @@ load_progs (const char *name) if (!file) { return 0; } - pr.progs_name = name; - PR_LoadProgsFile (&pr, file, size, 16, 1024 * 1024); + test_pr.progs_name = name; + test_pr.max_edicts = MAX_EDICTS; + test_pr.zone_size = MAX_HEAP; + test_pr.stack_size = MAX_STACK; + edicts = test_edicts; + + PR_LoadProgsFile (&test_pr, file, size); Qclose (file); - if (!PR_RunLoadFuncs (&pr)) - PR_Error (&pr, "unable to load %s", pr.progs_name); + if (!PR_RunLoadFuncs (&test_pr)) + PR_Error (&test_pr, "unable to load %s", test_pr.progs_name); + if (!PR_RunPostLoadFuncs (&test_pr)) + PR_Error (&test_pr, "unable to load %s", test_pr.progs_name); + test_pr.pr_trace_depth = -1; + test_pr.pr_trace = options.trace; return 1; } @@ -204,7 +240,7 @@ parse_options (int argc, char **argv) options.flote = 1; break; case 't': - options.trace = 1; + options.trace++; break; case 'h': usage (0); @@ -240,26 +276,27 @@ main (int argc, char **argv) if (!load_progs (name)) Sys_Error ("couldn't load %s", name); - PR_PushFrame (&pr); + PR_PushFrame (&test_pr); if (argc > 2) - pr_argc = argc - 1; - pr_argv = PR_Zone_Malloc (&pr, (pr_argc + 1) * 4); - pr_argv[0] = PR_SetTempString (&pr, name); + pr_argc = argc; + pr_argv = PR_Zone_Malloc (&test_pr, (pr_argc + 1) * 4); + pr_argv[0] = PR_SetTempString (&test_pr, name); for (i = 1; i < pr_argc; i++) - pr_argv[i] = PR_SetTempString (&pr, argv[1 + i]); + pr_argv[i] = PR_SetTempString (&test_pr, argv[i]); pr_argv[i] = 0; - if ((dfunc = PR_FindFunction (&pr, ".main")) - || (dfunc = PR_FindFunction (&pr, "main"))) - main_func = dfunc - pr.pr_functions; + if ((dfunc = PR_FindFunction (&test_pr, ".main")) + || (dfunc = PR_FindFunction (&test_pr, "main"))) + main_func = dfunc - test_pr.pr_functions; else - PR_Undefined (&pr, "function", "main"); - PR_RESET_PARAMS (&pr); - P_INT (&pr, 0) = pr_argc; - P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); - PR_ExecuteProgram (&pr, main_func); - PR_PopFrame (&pr); + PR_Undefined (&test_pr, "function", "main"); + PR_RESET_PARAMS (&test_pr); + P_INT (&test_pr, 0) = pr_argc; + P_POINTER (&test_pr, 1) = PR_SetPointer (&test_pr, pr_argv); + test_pr.pr_argc = 2; + PR_ExecuteProgram (&test_pr, main_func); + PR_PopFrame (&test_pr); if (options.flote) - return R_FLOAT (&pr); - return R_INT (&pr); + return R_FLOAT (&test_pr); + return R_INT (&test_pr); } diff --git a/tools/qfcc/test/test-harness.h b/tools/qfcc/test/test-harness.h index 959910534..63f368416 100644 --- a/tools/qfcc/test/test-harness.h +++ b/tools/qfcc/test/test-harness.h @@ -1,6 +1,9 @@ +void *obj_malloc (int size) = #0; void printf (string fmt, ...) = #0; int errno (void) = #0; string strerror (int err) = #0; void exit (int code) = #0; entity spawn (void) = #0; void remove (entity e) = #0; +id obj_msgSend (id receiver, SEL op, ...) = #0; +void __obj_exec_class (struct obj_module *msg) = #0; diff --git a/tools/qfcc/test/triangle.r b/tools/qfcc/test/triangle.r new file mode 100644 index 000000000..cec1f6884 --- /dev/null +++ b/tools/qfcc/test/triangle.r @@ -0,0 +1,33 @@ +void printf (string fmt, ...) = #0; +float (string s) stof = #0; +@overload float (float x) sqrt = #0; + +float +heron (float a, float b, float c) +{ + float s = (a + b + c) / 2; + return sqrt (s*(s-a)*(s-b)*(s-c)); +} + +float +kahan (float a, float b, float c) +{ + float t; + if (a < b) { t = a; a = b; b = t; } + if (b < c) { t = b; b = c; c = t; } + if (a < b) { t = a; a = b; b = t; } + return sqrt ((a + (b + c))*(c - (a - b))*(c + (a - b))*(a + (b - c)))/4; +} + +int +main (int argc, string *argv) +{ + float a = stof (argv[1]); + float b = stof (argv[2]); + float c = stof (argv[3]); + float expt = stof (argv[4]); + float h = heron (a, b, c); + float k = kahan (a, b, c); + printf ("%.9g %.9g %d\n", h, k, k == expt); + return k != expt; +} diff --git a/tools/qfcc/test/tw-defspace.c b/tools/qfcc/test/tw-defspace.c new file mode 100644 index 000000000..c1f599810 --- /dev/null +++ b/tools/qfcc/test/tw-defspace.c @@ -0,0 +1,55 @@ +#include "../source/defspace.c" +#include "test-defspace.h" + +__attribute__((pure)) int +def_list_is_empty (const defspace_t *space) +{ + return (!space->defs && space->def_tail == &space->defs); +} + +__attribute__((pure)) int +def_list_is_valid (const defspace_t *space) +{ + def_t *const *d = &space->defs; + + while (*d) { + d = &(*d)->next; + } + return d == space->def_tail; +} + +int +free_locs_is_valid (const defspace_t *space) +{ + int free_space = 0; + const locref_t *loc; + + for (loc = space->free_locs; loc; loc = loc->next) { + if (loc->ofs < 0) { + printf ("negative offset in free_locs\n"); + return 0; + } + if (loc->size <= 0) { + printf ("zero or negative size in free_locs\n"); + return 0; + } + if (loc->next && loc->ofs > loc->next->ofs) { + printf ("free_locs not in ascending order\n"); + return 0; + } + if (loc->next && loc->ofs + loc->size > loc->next->ofs) { + printf ("overlap in free_locs\n"); + return 0; + } + if (loc->next && loc->ofs + loc->size == loc->next->ofs) { + printf ("adjoining nodes in free_locs\n"); + return 0; + } + free_space += loc->size; + } + if (free_space > space->size) { + printf ("free_locs describes too much free space\n"); + return 0; + } + return 1; +} diff --git a/tools/qfcc/test/tw-diagnostic.c b/tools/qfcc/test/tw-diagnostic.c new file mode 100644 index 000000000..d84f8ad33 --- /dev/null +++ b/tools/qfcc/test/tw-diagnostic.c @@ -0,0 +1 @@ +#include "../source/diagnostic.c" diff --git a/tools/qfcc/test/tw-strpool.c b/tools/qfcc/test/tw-strpool.c new file mode 100644 index 000000000..74fbb8d75 --- /dev/null +++ b/tools/qfcc/test/tw-strpool.c @@ -0,0 +1 @@ +#include "../source/strpool.c" diff --git a/tools/qfcc/test/typedef.r b/tools/qfcc/test/typedef.r new file mode 100644 index 000000000..9dbd7f40b --- /dev/null +++ b/tools/qfcc/test/typedef.r @@ -0,0 +1,66 @@ +#include + +// can't link against libr.a (may not be built) +void *PR_FindGlobal (string name) = #0; +void printf (string fmt, ...) = #0; + +qfot_type_encodings_t *encodings; + +typedef int *foo; +typedef int *bar; + +foo baz; +bar snafu; + +qfot_type_t * +next_type (qfot_type_t *type) +{ + int size = type.size; + if (!size) + size = 4; + return (qfot_type_t *) ((int *) type + size); +} + +int +check_alias (string name, qfot_type_t *alias) +{ + if (alias.meta != ty_basic || alias.type != ev_pointer + || alias.fldptr.aux_type.meta != ty_basic + || alias.fldptr.aux_type.type != ev_integer) { + printf ("%s is not a *int alias\n", name); + return 0; + } + return 1; +} + +int +main (void) +{ + baz = snafu; + + int found_foo = 0; + int found_bar = 0; + qfot_type_t *type; + + encodings = PR_FindGlobal (".type_encodings"); + + for (type = encodings.types; + ((int *)type - (int *) encodings.types) < encodings.size; + type = next_type (type)) { + if (type.meta == ty_alias) { + if (type.alias.name == "foo") { + found_foo = check_alias (type.alias.name, + type.alias.aux_type); + } + if (type.alias.name == "bar") { + found_bar = check_alias (type.alias.name, + type.alias.aux_type); + } + } + } + if (!(found_bar && found_foo)) { + printf ("missing typedef: foo: %d bar:%d\n", found_foo, found_bar); + return 1; + } + return 0; +} diff --git a/tools/qfcc/test/typelinker.h b/tools/qfcc/test/typelinker.h new file mode 100644 index 000000000..1968a52cc --- /dev/null +++ b/tools/qfcc/test/typelinker.h @@ -0,0 +1,3 @@ +typedef struct plitem_s *plitem_t; + +@extern plitem_t PL_GetPropertyList (string str); diff --git a/tools/qfcc/test/typelinker_a.r b/tools/qfcc/test/typelinker_a.r new file mode 100644 index 000000000..57c98ca76 --- /dev/null +++ b/tools/qfcc/test/typelinker_a.r @@ -0,0 +1,7 @@ +#include "typelinker.h" + +int main () +{ + PL_GetPropertyList ("{}"); + return 0; +} diff --git a/tools/qfcc/test/typelinker_b.r b/tools/qfcc/test/typelinker_b.r new file mode 100644 index 000000000..54336eae3 --- /dev/null +++ b/tools/qfcc/test/typelinker_b.r @@ -0,0 +1,3 @@ +#include "typelinker.h" + +plitem_t PL_GetPropertyList (string str) = #0; diff --git a/tools/qfcc/test/unaryminus.r b/tools/qfcc/test/unaryminus.r new file mode 100644 index 000000000..5149a224a --- /dev/null +++ b/tools/qfcc/test/unaryminus.r @@ -0,0 +1,13 @@ +int strlen (string s) = #0; + +int foo (string bar) +{ + int len; + len = -strlen (bar); + return len; +} + +int main (void) +{ + return 0; +} diff --git a/tools/qfcc/test/vecaddr.r b/tools/qfcc/test/vecaddr.r new file mode 100644 index 000000000..323d9205c --- /dev/null +++ b/tools/qfcc/test/vecaddr.r @@ -0,0 +1,16 @@ +void printf (string fmt, ...) = #0; + +float foo (vector v, float z) +{ + return v * *(vector*)(&v.y); +} + +int +main (int argc, string *argv) +{ + vector v = [1, 2, 3]; + vector w = [2, 3, 4]; + float f; + printf ("%v %g %g %g\n", v, v*v, v*w, f=foo (v, 4)); + return f != v*w; +} diff --git a/tools/qfcc/test/vecexpr.r b/tools/qfcc/test/vecexpr.r new file mode 100644 index 000000000..0365ed589 --- /dev/null +++ b/tools/qfcc/test/vecexpr.r @@ -0,0 +1,49 @@ +#include "test-harness.h" + +vector t1(); +vector t2(float x); + +vector +t3(float x) +{ + return [x, t2(9).z, x] * 2; +} + +vector +t1() +{ + return [1, 2, 3]; +} + +vector +t2(float x) +{ + return [x, x, x]; +} + +int +main () +{ + int ret = 0; + float x = 4; + float y = 5; + vector v; + + v = t2(5); + if (v != [5, 5, 5]) { + printf("t2(5) = %v\n", v); + ret |= 1; + } + v = t3 (5); + if (v != [10, 18, 10]) { + printf("t3(5) = %v\n", v); + ret |= 1; + } + v = [x, y] / 2; + if (v != [2, 2.5]) { + printf("v = %v\n", v); + ret |= 1; + } + + return ret; +} diff --git a/tools/qfcc/test/vecinit.r b/tools/qfcc/test/vecinit.r index 6503b390d..653f9e25d 100644 --- a/tools/qfcc/test/vecinit.r +++ b/tools/qfcc/test/vecinit.r @@ -8,8 +8,33 @@ foo (float x, float y, float z) return v; } +float w = 2; +float h = 4; + +vector +bar (void) +{ + vector pos; + + pos.x = w; + pos.y = h; + pos.z = 0; + return pos; +} + +vector +baz (float w, float h) +{ + vector p = [w, h, 0] / 2; + return p; +} + int main () { - return 0; + int ret = 0; + ret |= foo(1,2,3) != [1, 2, 3]; + ret |= bar() != [2, 4, 0]; + ret |= baz(5, 6) != [2.5, 3, 0]; + return ret; } diff --git a/tools/qfcc/test/zerolinker.r b/tools/qfcc/test/zerolinker.r new file mode 100644 index 000000000..7b14f4a6e --- /dev/null +++ b/tools/qfcc/test/zerolinker.r @@ -0,0 +1,45 @@ +#include + +// can't link against libr.a (may not be built) +void *PR_FindGlobal (string name) = #0; +void printf (string fmt, ...) = #0; + +qfot_type_encodings_t *encodings; + +qfot_type_t * +next_type (qfot_type_t *type) +{ + int size = type.size; + if (!size) + size = 4; + return (qfot_type_t *) ((int *) type + size); +} + +int +main (void) +{ + int found_param = 0; + int found_zero = 0; + qfot_type_t *type; + + encodings = PR_FindGlobal (".type_encodings"); + + for (type = encodings.types; + ((int *)type - (int *) encodings.types) < encodings.size; + type = next_type (type)) { + if (type.meta == ty_union) { + if (type.strct.tag == "tag @param") { + found_param = 1; + } + if (type.strct.tag == "tag @zero") { + found_zero = 1; + } + } + } + if (!(found_param && found_zero)) { + printf ("missing struct: param: %d zero:%d\n", + found_param, found_zero); + return 1; + } + return 0; +} diff --git a/tools/qflight/Makefile.am b/tools/qflight/Makefile.am deleted file mode 100644 index e4102a7e9..000000000 --- a/tools/qflight/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source - -man_MANS= qflight.1 - -EXTRA_DIST= qflight.1 diff --git a/tools/qflight/Makemodule.am b/tools/qflight/Makemodule.am new file mode 100644 index 000000000..cd4d971c6 --- /dev/null +++ b/tools/qflight/Makemodule.am @@ -0,0 +1,4 @@ +include tools/qflight/include/Makemodule.am +include tools/qflight/source/Makemodule.am + +man_MANS += tools/qflight/qflight.1 diff --git a/tools/qflight/include/Makefile.am b/tools/qflight/include/Makefile.am deleted file mode 100644 index 3d7e10861..000000000 --- a/tools/qflight/include/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST= entities.h light.h noise.h options.h properties.h threads.h diff --git a/tools/qflight/include/Makemodule.am b/tools/qflight/include/Makemodule.am new file mode 100644 index 000000000..747bdca73 --- /dev/null +++ b/tools/qflight/include/Makemodule.am @@ -0,0 +1,7 @@ +EXTRA_DIST += \ + tools/qflight/include/entities.h \ + tools/qflight/include/light.h \ + tools/qflight/include/noise.h \ + tools/qflight/include/options.h \ + tools/qflight/include/properties.h \ + tools/qflight/include/threads.h diff --git a/tools/qflight/include/entities.h b/tools/qflight/include/entities.h index 82bf378cc..6f3d1dd12 100644 --- a/tools/qflight/include/entities.h +++ b/tools/qflight/include/entities.h @@ -34,7 +34,7 @@ /** \defgroup qflight_entities Light entity data. \ingroup qflight */ -//@{ +///@{ #define DEFAULTLIGHTLEVEL 300 #define DEFAULTFALLOFF 1.0f @@ -106,6 +106,6 @@ void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec); void LoadEntities (void); void WriteEntitiesToString (void); -//@} +///@} #endif// __entities_h diff --git a/tools/qflight/include/light.h b/tools/qflight/include/light.h index 0899bc1b8..f558f594d 100644 --- a/tools/qflight/include/light.h +++ b/tools/qflight/include/light.h @@ -37,7 +37,7 @@ /** \defgroup qflight_general General functions \ingroup qflight */ -//@{ +///@{ #define ON_EPSILON 0.1 #define MAXLIGHTS 1024 @@ -97,8 +97,6 @@ extern vec3_t bsp_yvector; extern qboolean extrasamples; -extern float minlights[MAX_MAP_FACES]; - void LoadNodes (const char *file); qboolean TestLine (lightinfo_t *l, const vec3_t start, const vec3_t stop); qboolean TestSky (lightinfo_t *l, const vec3_t start, const vec3_t stop); @@ -128,8 +126,8 @@ extern vec3_t *surfaceorgs; extern struct entity_s **novislights; extern int num_novislights; -const char *get_tex_name (int texindex); +const char *get_tex_name (int texindex) __attribute__((pure)); -//@} +///@} #endif// __light_h diff --git a/tools/qflight/include/noise.h b/tools/qflight/include/noise.h index 0017ab107..0b118d17a 100644 --- a/tools/qflight/include/noise.h +++ b/tools/qflight/include/noise.h @@ -31,12 +31,12 @@ /** \defgroup qflight_noise Light noise functions. \ingroup qflight */ -//@{ +///@{ -float noise3d (vec3_t v, int num); -float noiseXYZ (float x, float y, float z, int num); -float noise_scaled (vec3_t v, float s, int num); -float noise_perlin (vec3_t v, float p, int num); +float noise3d (vec3_t v, int num) __attribute__((pure)); +float noiseXYZ (float x, float y, float z, int num) __attribute__((const)); +float noise_scaled (vec3_t v, float s, int num) __attribute__((pure)); +float noise_perlin (vec3_t v, float p, int num) __attribute__((pure)); void snap_vector (vec3_t v_old, vec3_t v_new, float scale); -//@} +///@} diff --git a/tools/qflight/include/options.h b/tools/qflight/include/options.h index 22443ccae..32c6d6755 100644 --- a/tools/qflight/include/options.h +++ b/tools/qflight/include/options.h @@ -33,7 +33,7 @@ /** \defgroup qflight_options Light command line options. \ingroup qflight */ -//@{ +///@{ typedef struct { int verbosity; // 0=silent @@ -57,8 +57,8 @@ extern struct dstring_s *bspfile; extern const char *this_program; int DecodeArgs (int argc, char **argv); -void usage (int status); +void usage (int status) __attribute__((noreturn)); -//@} +///@} #endif//__options_h diff --git a/tools/qflight/include/properties.h b/tools/qflight/include/properties.h index a6b724d19..8d39361b7 100644 --- a/tools/qflight/include/properties.h +++ b/tools/qflight/include/properties.h @@ -33,7 +33,7 @@ /** \defgroup qflight_properties Lighting properties \ingroup qflight */ -//@{ +///@{ struct plitem_s; @@ -76,7 +76,7 @@ void parse_color (const char *str, vec3_t color); \arg HalfLife "R G B i" where R G & B are 0-255 and i is the same as for normal id lights. The RGB values will be scaled by 1/255 such that 255 becomes 1.0. - \arg RGB "R B B" where R G & B are left as-is and the intensity + \arg RGB "R G B" where R G & B are left as-is and the intensity is set to 1.0. \arg id Standard quake single value light intensity. The color is set to white ([1.0 1.0 1.0]). @@ -124,7 +124,7 @@ int parse_noise (const char *arg); The database is loaded via LoadProperties(). - If a set of properties named "worldspawn" is in the database, the it + If a set of properties named "worldspawn" is in the database, then it will be used for default values, otherwise the database will be ignored. @@ -163,7 +163,7 @@ void set_sun_properties (entity_t *ent, struct plitem_s *dict); Supported properties: \arg \c light see \ref parse_light \arg \c style light style: 0-254 - \arg \c angle spotlight con angle in degress. defaults to 20 + \arg \c angle spotlight cone angle in degress. defaults to 20 \arg \c wait light "falloff". defaults to 1.0 \arg \c lightradius size of light. interacts with falloff for distance clipping (?). defaults to 0 @@ -199,6 +199,6 @@ void set_properties (entity_t *ent, struct plitem_s *dict); */ void LoadProperties (const char *filename); -//@} +///@} #endif//__properties_h diff --git a/tools/qflight/include/threads.h b/tools/qflight/include/threads.h index 30b9cc59f..0fd5c00af 100644 --- a/tools/qflight/include/threads.h +++ b/tools/qflight/include/threads.h @@ -32,7 +32,7 @@ /** \defgroup qflight_threads Light thread handling. \ingroup qflight */ -//@{ +///@{ #if defined (HAVE_PTHREAD_H) && defined (HAVE_PTHREAD) @@ -66,6 +66,6 @@ typedef void *(threadfunc_t) (void *); void InitThreads (void); void RunThreadsOn (threadfunc_t func); -//@} +///@} #endif// __threads_h diff --git a/tools/qflight/source/Makefile.am b/tools/qflight/source/Makefile.am deleted file mode 100644 index cdf5005fb..000000000 --- a/tools/qflight/source/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -QFLIGHT_LIBS=@QFLIGHT_LIBS@ -QFLIGHT_DEPS=@QFLIGHT_DEPS@ -QFLIGHT_INCS=@QFLIGHT_INCS@ -PTHREAD_LDFLAGS=@PTHREAD_LDFLAGS@ -PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFLIGHT_INCS) $(PTHREAD_CFLAGS) - -bin_PROGRAMS= qflight - -qflight_SOURCES=\ - entities.c ltface.c noise.c options.c properties.c qflight.c \ - threads.c trace.c vis.c - - -qflight_LDFLAGS= $(PTHREAD_LDFLAGS) -qflight_LDADD= $(QFLIGHT_LIBS) -qflight_DEPENDENCIES= $(QFLIGHT_DEPS) diff --git a/tools/qflight/source/Makemodule.am b/tools/qflight/source/Makemodule.am new file mode 100644 index 000000000..0913e37a8 --- /dev/null +++ b/tools/qflight/source/Makemodule.am @@ -0,0 +1,20 @@ +QFLIGHT_LIBS=@QFLIGHT_LIBS@ +QFLIGHT_DEPS=@QFLIGHT_DEPS@ +QFLIGHT_INCS=@QFLIGHT_INCS@ + +bin_PROGRAMS += qflight + +qflight_SOURCES=\ + tools/qflight/source/entities.c \ + tools/qflight/source/ltface.c \ + tools/qflight/source/noise.c \ + tools/qflight/source/options.c \ + tools/qflight/source/properties.c \ + tools/qflight/source/qflight.c \ + tools/qflight/source/threads.c \ + tools/qflight/source/trace.c \ + tools/qflight/source/vis.c + +qflight_LDFLAGS= $(PTHREAD_LDFLAGS) +qflight_LDADD= $(QFLIGHT_LIBS) +qflight_DEPENDENCIES= $(QFLIGHT_DEPS) diff --git a/tools/qflight/source/entities.c b/tools/qflight/source/entities.c index 01c36077c..8c2260fcd 100644 --- a/tools/qflight/source/entities.c +++ b/tools/qflight/source/entities.c @@ -47,19 +47,19 @@ #include "QF/bspfile.h" #include "QF/dstring.h" #include "QF/mathlib.h" +#include "QF/plist.h" #include "QF/progs.h" -#include "QF/qfplist.h" #include "QF/qtypes.h" #include "QF/quakefs.h" #include "QF/script.h" #include "QF/sys.h" #include "QF/va.h" -#include "light.h" -#include "threads.h" -#include "entities.h" -#include "options.h" -#include "properties.h" +#include "tools/qflight/include/light.h" +#include "tools/qflight/include/threads.h" +#include "tools/qflight/include/entities.h" +#include "tools/qflight/include/options.h" +#include "tools/qflight/include/properties.h" entity_t *entities; int num_entities; @@ -125,7 +125,8 @@ MatchTargets (void) // set the style on the source ent for switchable lights if (entities[j].style) { entities[i].style = entities[j].style; - SetKeyValue (&entities[i], "style", va ("%i", entities[i].style)); + SetKeyValue (&entities[i], "style", va (0, "%i", + entities[i].style)); } if (entities[i].spotcone >= 0) { @@ -178,12 +179,12 @@ LoadEntities (void) script = Script_New (); Script_Start (script, "ent data", bsp->entdata); - entity_list = ED_ConvertToPlist (script, 1); + entity_list = ED_ConvertToPlist (script, 1, 0); Script_Delete (script); // start parsing num_entities = PL_A_NumObjects (entity_list); - entities = malloc (num_entities * sizeof (entity_t));; + entities = malloc (num_entities * sizeof (entity_t)); // go through all the entities for (i = 0; i < num_entities; i++) { @@ -207,7 +208,7 @@ LoadEntities (void) } entity->dict = PL_ObjectAtIndex (entity_list, i); - dict = PL_NewDictionary (); + dict = PL_NewDictionary (0); // go through all the keys in this entity keys = PL_D_AllKeys (entity->dict); diff --git a/tools/qflight/source/ltface.c b/tools/qflight/source/ltface.c index acb157c36..de947cfff 100644 --- a/tools/qflight/source/ltface.c +++ b/tools/qflight/source/ltface.c @@ -52,11 +52,11 @@ #include "compat.h" -#include "light.h" -#include "entities.h" -#include "noise.h" -#include "options.h" -#include "threads.h" +#include "tools/qflight/include/light.h" +#include "tools/qflight/include/entities.h" +#include "tools/qflight/include/noise.h" +#include "tools/qflight/include/options.h" +#include "tools/qflight/include/threads.h" int c_bad; int c_culldistplane, c_proper; @@ -488,7 +488,6 @@ SkyLightFace (entity_t *ent, int sun, lightinfo_t *l) // Check each point... VectorCopy (sun_dir, incoming); VectorNormalize (incoming); - angle = DotProduct (incoming, l->facenormal); //anglesense = 0.5; //FIXME // FIXME global @@ -499,11 +498,9 @@ SkyLightFace (entity_t *ent, int sun, lightinfo_t *l) if (!TestSky (l, point->v, sun_dir)) continue; + add = sun_light; - continue; - add *= angle; - add *= options.extrascale; sample = &l->sample[mapnum][point->samplepos]; @@ -511,38 +508,6 @@ SkyLightFace (entity_t *ent, int sun, lightinfo_t *l) } } -#if 0 -static void -FixMinlight (lightinfo_t *l) -{ - float minlight; - int i, j; - - minlight = minlights[l->surfnum]; - - // if minlight is set, there must be a style 0 light map - if (!minlight) - return; - - for (i = 0; i < l->numlightstyles; i++) { - if (l->lightstyles[i] == 0) - break; - } - if (i == l->numlightstyles) { - if (l->numlightstyles == MAXLIGHTMAPS) - return; // oh well.. - for (j = 0; j < l->numsurfpt; j++) - l->lightmaps[i][j] = minlight; - l->lightstyles[i] = 0; - l->numlightstyles++; - } else { - for (j = 0; j < l->numsurfpt; j++) - if (l->lightmaps[i][j] < minlight) - l->lightmaps[i][j] = minlight; - } -} -#endif - void LightFace (lightinfo_t *l, int surfnum) { @@ -593,8 +558,6 @@ LightFace (lightinfo_t *l, int surfnum) SkyLightFace (world_entity, i, l); } -// FixMinlight (&l); - for (i = 0; i < MAXLIGHTMAPS; i++) if (l->lightstyles[i] == 255) break; diff --git a/tools/qflight/source/noise.c b/tools/qflight/source/noise.c index 8d8a87758..b34e31ee1 100644 --- a/tools/qflight/source/noise.c +++ b/tools/qflight/source/noise.c @@ -35,7 +35,7 @@ #include "QF/qtypes.h" -#include "noise.h" +#include "tools/qflight/include/noise.h" // returns the 3D noise value for a point in space float diff --git a/tools/qflight/source/options.c b/tools/qflight/source/options.c index 88a3584b9..b50753169 100644 --- a/tools/qflight/source/options.c +++ b/tools/qflight/source/options.c @@ -44,9 +44,9 @@ #include "compat.h" -#include "entities.h" -#include "options.h" -#include "properties.h" +#include "tools/qflight/include/entities.h" +#include "tools/qflight/include/options.h" +#include "tools/qflight/include/properties.h" const char *this_program; diff --git a/tools/qflight/source/properties.c b/tools/qflight/source/properties.c index d9286e268..87229d05d 100644 --- a/tools/qflight/source/properties.c +++ b/tools/qflight/source/properties.c @@ -41,15 +41,15 @@ #include #include "QF/mathlib.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/quakeio.h" #include "compat.h" -#include "entities.h" -#include "light.h" -#include "options.h" -#include "properties.h" +#include "tools/qflight/include/entities.h" +#include "tools/qflight/include/light.h" +#include "tools/qflight/include/options.h" +#include "tools/qflight/include/properties.h" static plitem_t *properties; @@ -237,14 +237,11 @@ set_properties (entity_t *ent, plitem_t *dict) const char *str; if (properties) { - prop = PL_ObjectForKey (properties, ent->classname); if ((p = get_item ("light_name", dict, 0)) && (str = PL_String (p))) prop = PL_ObjectForKey (properties, str); if (!prop) prop = PL_ObjectForKey (properties, ent->classname); - - prop = PL_ObjectForKey (properties, ent->classname); if (!prop) prop = PL_ObjectForKey (properties, "default"); } @@ -337,6 +334,6 @@ LoadProperties (const char *filename) Qread (f, buf, len); Qclose (f); buf[len] = 0; - properties = PL_GetPropertyList (buf); + properties = PL_GetPropertyList (buf, 0); free (buf); } diff --git a/tools/qflight/source/qflight.c b/tools/qflight/source/qflight.c index 62eda9af1..db133a3b4 100644 --- a/tools/qflight/source/qflight.c +++ b/tools/qflight/source/qflight.c @@ -53,11 +53,11 @@ #include "QF/sys.h" #include "QF/va.h" -#include "light.h" -#include "threads.h" -#include "entities.h" -#include "options.h" -#include "properties.h" +#include "tools/qflight/include/light.h" +#include "tools/qflight/include/threads.h" +#include "tools/qflight/include/entities.h" +#include "tools/qflight/include/options.h" +#include "tools/qflight/include/properties.h" options_t options; bsp_t *bsp; @@ -78,9 +78,6 @@ vec3_t bsp_origin; qboolean extrasamples; -float minlights[MAX_MAP_FACES]; - - int GetFileSpace (int size) { @@ -150,7 +147,7 @@ FindFaceOffsets (void) surfaceorgs = (vec3_t *) calloc (bsp->numfaces, sizeof (vec3_t)); for (i = 1; i < bsp->nummodels; i++) { - ent = FindEntityWithKeyPair ("model", name = va ("*%d", i)); + ent = FindEntityWithKeyPair ("model", name = va (0, "*%d", i)); VectorZero (org); if (!ent) Sys_Error ("FindFaceOffsets: Couldn't find entity for model %s.\n", diff --git a/tools/qflight/source/threads.c b/tools/qflight/source/threads.c index 50e2709a0..8438f7b8e 100644 --- a/tools/qflight/source/threads.c +++ b/tools/qflight/source/threads.c @@ -46,9 +46,9 @@ #include "QF/qtypes.h" #include "QF/qendian.h" -#include "light.h" -#include "options.h" -#include "threads.h" +#include "tools/qflight/include/light.h" +#include "tools/qflight/include/options.h" +#include "tools/qflight/include/threads.h" #if defined (HAVE_PTHREAD_H) && defined (HAVE_PTHREAD) pthread_mutex_t *my_mutex; diff --git a/tools/qflight/source/trace.c b/tools/qflight/source/trace.c index 0f9df661e..aa5b4ce19 100644 --- a/tools/qflight/source/trace.c +++ b/tools/qflight/source/trace.c @@ -50,8 +50,8 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "light.h" -#include "options.h" +#include "tools/qflight/include/light.h" +#include "tools/qflight/include/options.h" typedef struct { int type; diff --git a/tools/qflight/source/vis.c b/tools/qflight/source/vis.c index 44ed4ecca..a4f0e1114 100644 --- a/tools/qflight/source/vis.c +++ b/tools/qflight/source/vis.c @@ -47,10 +47,10 @@ #include "QF/bspfile.h" #include "QF/mathlib.h" -#include "entities.h" -#include "light.h" -#include "options.h" -#include "threads.h" +#include "tools/qflight/include/entities.h" +#include "tools/qflight/include/light.h" +#include "tools/qflight/include/options.h" +#include "tools/qflight/include/threads.h" static struct { int empty; @@ -73,7 +73,7 @@ int num_alllights; entity_t **novislights; int num_novislights; -static dleaf_t * +static __attribute__((pure)) dleaf_t * Light_PointInLeaf (vec3_t point) { int num = 0, side; diff --git a/tools/qflmp/Makefile.am b/tools/qflmp/Makefile.am deleted file mode 100644 index b9436172c..000000000 --- a/tools/qflmp/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -QFLMP_LIBS=@QFLMP_LIBS@ -QFLMP_DEPS=@QFLMP_DEPS@ -QFLMP_INCS=@QFLMP_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFLMP_INCS) - -bin_PROGRAMS= qflmp - -#mans=qflmp.1 -man_MANS= $(mans) - -qflmp_SOURCES= lmp.c -qflmp_LDADD= $(QFLMP_LIBS) -qflmp_DEPENDENCIES= $(QFLMP_DEPS) - -EXTRA_DIST= lmp.h #lmp.1 diff --git a/tools/qflmp/Makemodule.am b/tools/qflmp/Makemodule.am new file mode 100644 index 000000000..78dd3a233 --- /dev/null +++ b/tools/qflmp/Makemodule.am @@ -0,0 +1,14 @@ +QFLMP_LIBS=@QFLMP_LIBS@ +QFLMP_DEPS=@QFLMP_DEPS@ +QFLMP_INCS=@QFLMP_INCS@ + +bin_PROGRAMS += qflmp + +#mans=qflmp.1 +man_MANS += $(mans) + +qflmp_SOURCES= tools/qflmp/lmp.c +qflmp_LDADD= $(QFLMP_LIBS) +qflmp_DEPENDENCIES= $(QFLMP_DEPS) + +EXTRA_DIST += tools/qflmp/lmp.h #lmp.1 diff --git a/tools/qflmp/lmp.c b/tools/qflmp/lmp.c index b8021166c..06a77e370 100644 --- a/tools/qflmp/lmp.c +++ b/tools/qflmp/lmp.c @@ -213,7 +213,7 @@ importFile (const char *inpath) if (options.verbosity > 1) Sys_Printf ("PCX file size: %d\n", fsize); - lmp = LoadPCX (infile, false, NULL); + lmp = LoadPCX (infile, false, NULL, 1); if (!lmp) { Sys_Printf ("%s: Failed to load %s as texture.\n", @@ -334,7 +334,7 @@ main (int argc, char **argv) this_program = argv[0]; Sys_Init (); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); decode_args (argc, argv); diff --git a/tools/qfmodelgen/Makefile.am b/tools/qfmodelgen/Makefile.am deleted file mode 100644 index e5b93df89..000000000 --- a/tools/qfmodelgen/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source - -#man_MANS= qfmodelgen.1 - -#EXTRA_DIST= $(man_MANS) diff --git a/tools/qfmodelgen/Makemodule.am b/tools/qfmodelgen/Makemodule.am new file mode 100644 index 000000000..d397b4f91 --- /dev/null +++ b/tools/qfmodelgen/Makemodule.am @@ -0,0 +1,2 @@ +include tools/qfmodelgen/include/Makemodule.am +include tools/qfmodelgen/source/Makemodule.am diff --git a/tools/qfmodelgen/include/Makefile.am b/tools/qfmodelgen/include/Makefile.am deleted file mode 100644 index c4cc81268..000000000 --- a/tools/qfmodelgen/include/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST= lbmlib.h trilib.h diff --git a/tools/qfmodelgen/include/Makemodule.am b/tools/qfmodelgen/include/Makemodule.am new file mode 100644 index 000000000..0a5f0306d --- /dev/null +++ b/tools/qfmodelgen/include/Makemodule.am @@ -0,0 +1,3 @@ +EXTRA_DIST += \ + tools/qfmodelgen/include/lbmlib.h \ + tools/qfmodelgen/include/trilib.h diff --git a/tools/qfmodelgen/source/Makefile.am b/tools/qfmodelgen/source/Makemodule.am similarity index 54% rename from tools/qfmodelgen/source/Makefile.am rename to tools/qfmodelgen/source/Makemodule.am index 4bc3a0bda..9ca6ae7ef 100644 --- a/tools/qfmodelgen/source/Makefile.am +++ b/tools/qfmodelgen/source/Makemodule.am @@ -1,14 +1,13 @@ -AUTOMAKE_OPTIONS= foreign - QFMODELGEN_LIBS=@QFMODELGEN_LIBS@ QFMODELGEN_DEPS=@QFMODELGEN_DEPS@ QFMODELGEN_INCS=@QFMODELGEN_INCS@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFMODELGEN_INCS) +bin_PROGRAMS += qfmodelgen -bin_PROGRAMS= qfmodelgen - -qfmodelgen_SOURCES= lbmlib.c modelgen.c trilib.c +qfmodelgen_SOURCES = \ + tools/qfmodelgen/source/lbmlib.c \ + tools/qfmodelgen/source/modelgen.c \ + tools/qfmodelgen/source/trilib.c qfmodelgen_LDADD= $(QFMODELGEN_LIBS) qfmodelgen_DEPENDENCIES= $(QFMODELGEN_DEPS) diff --git a/tools/qfmodelgen/source/lbmlib.c b/tools/qfmodelgen/source/lbmlib.c index 77af86e92..1650bda86 100644 --- a/tools/qfmodelgen/source/lbmlib.c +++ b/tools/qfmodelgen/source/lbmlib.c @@ -30,7 +30,7 @@ #include "QF/quakeio.h" #include "QF/sys.h" -#include "lbmlib.h" +#include "tools/qfmodelgen/include/lbmlib.h" static int LoadFile (const char *fname, byte **buf) diff --git a/tools/qfmodelgen/source/modelgen.c b/tools/qfmodelgen/source/modelgen.c index 4905ad041..a4b18b1ac 100644 --- a/tools/qfmodelgen/source/modelgen.c +++ b/tools/qfmodelgen/source/modelgen.c @@ -45,10 +45,11 @@ #include "QF/script.h" #include "QF/sys.h" -#include "lbmlib.h" -#include "trilib.h" #include "compat.h" +#include "tools/qfmodelgen/include/lbmlib.h" +#include "tools/qfmodelgen/include/trilib.h" + #define MAXVERTS 2048 #define MAXFRAMES 256 #define MAXSKINS 100 @@ -177,15 +178,17 @@ SetQdirFromPath (char *path) static const char * ExpandPath (const char *path) { - static char full[1024]; + static dstring_t *full; - //FIXME buffer overflow central + if (!full) { + full = dstring_new(); + } //if (!qdir) // Sys_Error ("ExpandPath called without qdir set"); if (path[0] == '/' || path[0] == '\\' || path[1] == ':') return path; - sprintf (full, "%s%s", qdir, path); - return full; + dsprintf (full, "%s%s", qdir, path); + return full->str; } static void diff --git a/tools/qfmodelgen/source/trilib.c b/tools/qfmodelgen/source/trilib.c index 41f6ffd42..a22721192 100644 --- a/tools/qfmodelgen/source/trilib.c +++ b/tools/qfmodelgen/source/trilib.c @@ -31,7 +31,7 @@ #include "QF/quakeio.h" #include "QF/sys.h" -#include "trilib.h" +#include "tools/qfmodelgen/include/trilib.h" // on disk representation of a face diff --git a/tools/qfspritegen/Makefile.am b/tools/qfspritegen/Makemodule.am similarity index 57% rename from tools/qfspritegen/Makefile.am rename to tools/qfspritegen/Makemodule.am index 05f321022..a12777453 100644 --- a/tools/qfspritegen/Makefile.am +++ b/tools/qfspritegen/Makemodule.am @@ -1,14 +1,10 @@ -AUTOMAKE_OPTIONS= foreign - QFSPRITEGEN_LIBS=@QFSPRITEGEN_LIBS@ QFSPRITEGEN_DEPS=@QFSPRITEGEN_DEPS@ QFSPRITEGEN_INCS=@QFSPRITEGEN_INCS@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFSPRITEGEN_INCS) +bin_PROGRAMS += qfspritegen -bin_PROGRAMS= qfspritegen - -qfspritegen_SOURCES= spritegen.c +qfspritegen_SOURCES= tools/qfspritegen/spritegen.c qfspritegen_LDADD= $(QFSPRITEGEN_LIBS) qfspritegen_DEPENDENCIES= $(QFSPRITEGEN_DEPS) diff --git a/tools/qfspritegen/spritegen.c b/tools/qfspritegen/spritegen.c index b209650d4..08ddc86f1 100644 --- a/tools/qfspritegen/spritegen.c +++ b/tools/qfspritegen/spritegen.c @@ -27,6 +27,7 @@ #include #include +#include "QF/dstring.h" #include "QF/image.h" #include "QF/pcx.h" #include "QF/qendian.h" @@ -42,8 +43,8 @@ tex_t *image; dsprite_t sprite; byte *lumpbuffer, *plump; -char spritedir[1024]; -char spriteoutname[1024]; +dstring_t *spritedir; +dstring_t *spriteoutname; int framesmaxs[2]; int framecount; @@ -189,7 +190,7 @@ LoadScreen (const char *name) file = Qopen (name, "rb"); if (!file) Sys_Error ("could not open"); - image = LoadPCX (file, false, 0); + image = LoadPCX (file, false, 0, 1); } @@ -444,7 +445,7 @@ Cmd_Spritename (void) FinishSprite (); Script_GetToken (&scr, false); - sprintf (spriteoutname, "%s%s.spr", spritedir, Script_Token (&scr)); + dsprintf (spriteoutname, "%s%s.spr", spritedir->str, Script_Token (&scr)); memset (&sprite, 0, sizeof(sprite)); framecount = 0; @@ -472,14 +473,14 @@ FinishSprite (void) if (sprite.numframes == 0) Sys_Error ("no frames\n"); - if (!strlen(spriteoutname)) + if (!spriteoutname->str) Sys_Error ("Didn't name sprite file"); if ((plump - lumpbuffer) > MAX_BUFFER_SIZE) Sys_Error ("Sprite package too big; increase MAX_BUFFER_SIZE"); - spriteouthandle = Qopen (spriteoutname, "wb"); - printf ("saving in %s\n", spriteoutname); + spriteouthandle = Qopen (spriteoutname->str, "wb"); + printf ("saving in %s\n", spriteoutname->str); WriteSprite (spriteouthandle); Qclose (spriteouthandle); @@ -487,7 +488,7 @@ FinishSprite (void) printf ("%d frame(s)\n", sprite.numframes); printf ("%d ungrouped frame(s), including group headers\n", framecount); - spriteoutname[0] = 0; // clear for a new sprite + dstring_clearstr (spriteoutname); // clear for a new sprite } /* @@ -505,6 +506,9 @@ int main (int argc, char **argv) if (argc != 2) Sys_Error ("usage: spritegen file.qc"); + spritedir = dstring_newstr (); + spriteoutname = dstring_newstr (); + i = 1; //SetQdirFromPath (argv[i]); diff --git a/tools/qfvis/Makefile.am b/tools/qfvis/Makefile.am deleted file mode 100644 index 52a798c6e..000000000 --- a/tools/qfvis/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -SUBDIRS= include source - -mans=qfvis.1 -man_MANS= $(mans) -EXTRA_DIST= $(mans) diff --git a/tools/qfvis/Makemodule.am b/tools/qfvis/Makemodule.am new file mode 100644 index 000000000..5840ea1f6 --- /dev/null +++ b/tools/qfvis/Makemodule.am @@ -0,0 +1,4 @@ +include tools/qfvis/include/Makemodule.am +include tools/qfvis/source/Makemodule.am + +man_MANS += tools/qfvis/qfvis.1 diff --git a/tools/qfvis/include/Makefile.am b/tools/qfvis/include/Makefile.am deleted file mode 100644 index 0bbb6480b..000000000 --- a/tools/qfvis/include/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -EXTRA_DIST= options.h vis.h diff --git a/tools/qfvis/include/Makemodule.am b/tools/qfvis/include/Makemodule.am new file mode 100644 index 000000000..eec0af5b0 --- /dev/null +++ b/tools/qfvis/include/Makemodule.am @@ -0,0 +1,3 @@ +EXTRA_DIST += \ + tools/qfvis/include/options.h \ + tools/qfvis/include/vis.h diff --git a/tools/qfvis/include/options.h b/tools/qfvis/include/options.h index 0af22f520..521a4ef94 100644 --- a/tools/qfvis/include/options.h +++ b/tools/qfvis/include/options.h @@ -40,7 +40,7 @@ typedef struct { extern options_t options; int DecodeArgs (int argc, char **argv); -void usage (int status); +void usage (int status) __attribute__((noreturn)); extern const char *this_program; #endif//__options_h diff --git a/tools/qfvis/source/Makefile.am b/tools/qfvis/source/Makefile.am deleted file mode 100644 index e0a725ca0..000000000 --- a/tools/qfvis/source/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -QFVIS_LIBS=@QFVIS_LIBS@ -QFVIS_DEPS=@QFVIS_DEPS@ -QFVIS_INCS=@QFVIS_INCS@ -PTHREAD_LDFLAGS=@PTHREAD_LDFLAGS@ -PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(QFVIS_INCS) $(PTHREAD_CFLAGS) - -bin_PROGRAMS= qfvis - -qfvis_SOURCES= base-vis.c flow.c options.c qfvis.c soundphs.c - -qfvis_LDFLAGS= $(PTHREAD_LDFLAGS) -qfvis_LDADD= $(QFVIS_LIBS) -qfvis_DEPENDENCIES= $(QFVIS_DEPS) diff --git a/tools/qfvis/source/Makemodule.am b/tools/qfvis/source/Makemodule.am new file mode 100644 index 000000000..73ccf547e --- /dev/null +++ b/tools/qfvis/source/Makemodule.am @@ -0,0 +1,16 @@ +QFVIS_LIBS=@QFVIS_LIBS@ +QFVIS_DEPS=@QFVIS_DEPS@ +QFVIS_INCS=@QFVIS_INCS@ + +bin_PROGRAMS += qfvis + +qfvis_SOURCES = \ + tools/qfvis/source/base-vis.c \ + tools/qfvis/source/flow.c \ + tools/qfvis/source/options.c \ + tools/qfvis/source/qfvis.c \ + tools/qfvis/source/soundphs.c + +qfvis_LDFLAGS= $(PTHREAD_LDFLAGS) +qfvis_LDADD= $(QFVIS_LIBS) +qfvis_DEPENDENCIES= $(QFVIS_DEPS) diff --git a/tools/qfvis/source/base-vis.c b/tools/qfvis/source/base-vis.c index ca4d912e0..99d5934df 100644 --- a/tools/qfvis/source/base-vis.c +++ b/tools/qfvis/source/base-vis.c @@ -54,8 +54,8 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "vis.h" -#include "options.h" +#include "tools/qfvis/include/vis.h" +#include "tools/qfvis/include/options.h" /* This is a rough first-order aproximation that is used to trivially reject diff --git a/tools/qfvis/source/flow.c b/tools/qfvis/source/flow.c index 15af6524f..030ca7a43 100644 --- a/tools/qfvis/source/flow.c +++ b/tools/qfvis/source/flow.c @@ -55,8 +55,8 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "vis.h" -#include "options.h" +#include "tools/qfvis/include/vis.h" +#include "tools/qfvis/include/options.h" static int CheckStack (cluster_t *cluster, threaddata_t *thread) diff --git a/tools/qfvis/source/options.c b/tools/qfvis/source/options.c index 048f604b0..d9a5e3691 100644 --- a/tools/qfvis/source/options.c +++ b/tools/qfvis/source/options.c @@ -41,8 +41,8 @@ #include "QF/dstring.h" -#include "options.h" -#include "vis.h" +#include "tools/qfvis/include/options.h" +#include "tools/qfvis/include/vis.h" const char *this_program; diff --git a/tools/qfvis/source/qfvis.c b/tools/qfvis/source/qfvis.c index 7ec7e776c..c62eabbcc 100644 --- a/tools/qfvis/source/qfvis.c +++ b/tools/qfvis/source/qfvis.c @@ -57,8 +57,8 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "vis.h" -#include "options.h" +#include "tools/qfvis/include/vis.h" +#include "tools/qfvis/include/options.h" #ifdef USE_PTHREADS pthread_attr_t threads_attrib; @@ -111,6 +111,9 @@ InitThreads (void) stats_lock = malloc (sizeof (pthread_rwlock_t)); if (pthread_rwlock_init (stats_lock, 0)) Sys_Error ("pthread_rwlock_init failed"); +#else + // Unable to run multi-threaded, so force threadcount to 1 + options.threads = 1; #endif } @@ -149,7 +152,7 @@ NewWinding (int points) if (points > MAX_POINTS_ON_WINDING) Sys_Error ("NewWinding: %i points", points); - size = (size_t)(uintptr_t) ((winding_t *) 0)->points[points]; + size = field_offset (winding_t, points[points]); winding = calloc (1, size); return winding; @@ -168,7 +171,7 @@ CopyWinding (const winding_t *w) size_t size; winding_t *copy; - size = (size_t) (uintptr_t) ((winding_t *) 0)->points[w->numpoints]; + size = field_offset (winding_t, points[w->numpoints]); copy = malloc (size); memcpy (copy, w, size); copy->original = false; @@ -610,7 +613,7 @@ void ClusterFlow (int clusternum) { set_t *visclusters; - byte compressed[MAX_MAP_LEAFS / 8]; + byte compressed[MAP_PVS_BYTES]; byte *outbuffer; int numvis, i; cluster_t *cluster; @@ -724,6 +727,7 @@ CalcVis (void) { int i; + printf ("Thread count: %d\n", options.threads); BasePortalVis (); CalcPortalVis (); @@ -1111,14 +1115,14 @@ main (int argc, char **argv) dstring_t *portalfile = dstring_new (); QFile *f; - InitThreads (); - start = Sys_DoubleTime (); this_program = argv[0]; DecodeArgs (argc, argv); + InitThreads (); + if (!options.bspfile) { usage (1); Sys_Error ("%s: no bsp file specified.", this_program); diff --git a/tools/qfvis/source/soundphs.c b/tools/qfvis/source/soundphs.c index 086e453cc..f21a9390d 100644 --- a/tools/qfvis/source/soundphs.c +++ b/tools/qfvis/source/soundphs.c @@ -54,7 +54,7 @@ #include "QF/quakefs.h" #include "QF/sys.h" -#include "vis.h" +#include "tools/qfvis/include/vis.h" /* Some textures (sky, water, slime, lava) are considered ambient sound diff --git a/tools/qwaq/Makefile.am b/tools/qwaq/Makefile.am deleted file mode 100644 index dd34fd9c5..000000000 --- a/tools/qwaq/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -QWAQ_LIBS=@QWAQ_LIBS@ -QWAQ_DEPS=@QWAQ_DEPS@ -QWAQ_INCS=@QWAQ_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(QWAQ_INCS) - -QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QFCC=$(top_builddir)/tools/qfcc/source/qfcc -QCFLAGS=-qq -O -g -Werror --advanced --no-default-paths - -noinst_PROGRAMS=qwaq @QWAQ_TARGETS@ -noinst_DATA=qwaq.dat - -qwaq_dat_src= \ - defs.qc main.qc test.r types.r - -qwaq_SOURCES= main.c builtins.c -qwaq_LDADD= $(QWAQ_LIBS) -qwaq_DEPENDENCIES= $(QWAQ_DEPS) - -cl_plugin_libs= \ - @client_static_plugin_libs@ - -client_libs= \ - $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/video/targets/libQFjs.la \ - $(top_builddir)/libs/audio/libQFcd.la \ - $(top_builddir)/libs/audio/libQFsound.la \ - $(top_builddir)/libs/image/libQFimage.la - -qwaq_x11_libs= \ - $(cl_plugin_libs) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFx11.la \ - $(client_libs) \ - $(top_builddir)/libs/gib/libQFgib.la -qwaq_x11_SOURCES=qwaq.c qwaq-bi.c -qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \ - $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ - $(X_EXTRA_LIBS) $(X_SHM_LIB) $(DL_LIBS) -qwaq_x11_LDFLAGS= -qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) - -qwaq.dat: progs.src $(qwaq_dat_src) $(QFCC_DEP) $(top_srcdir)/ruamoko/lib/Object.r - $(QFCC) $(QCFLAGS) -I$(top_srcdir)/ruamoko/include - -EXTRA_PROGRAMS=qwaq-x11 -EXTRA_DIST=$(qwaq_dat_src) qwaq.h -CLEANFILES= *.dat *.sym diff --git a/tools/qwaq/defs.qc b/tools/qwaq/defs.qc deleted file mode 100644 index e872fb799..000000000 --- a/tools/qwaq/defs.qc +++ /dev/null @@ -1,22 +0,0 @@ -void (string str) print = #0; -int () errno = #0; -string (int err) strerror = #0; -int (...) open = #0; // string path, float flags[, float mode] -int (int handle) close = #0; -string read (int handle, int count, int *result) = #0; -int (int handle, string buffer, int count) write = #0; -int (int handle, int pos, int whence) seek = #0; - -//void() traceon = #0; // turns statment trace on -//void() traceoff = #0; - -void (...) printf = #0; - - -float time; -entity self; - -.float nextthink; -.void() think; -.float frame; -.vector origin; diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c deleted file mode 100644 index edb7c0229..000000000 --- a/tools/qwaq/main.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - #FILENAME# - - #DESCRIPTION# - - Copyright (C) 2001 #AUTHOR# - - Author: #AUTHOR# - Date: #DATE# - - 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: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include -#include -#include -#include -#include "QF/ruamoko.h" -#include -#include "QF/va.h" -#include - -#include "qwaq.h" - -#define MAX_EDICTS 1024 - -static edict_t *edicts; -static int num_edicts; -static int reserved_edicts; -static progs_t pr; - -static QFile * -open_file (const char *path, int *len) -{ - QFile *file = Qopen (path, "rbz"); - - if (!file) { - perror (path); - return 0; - } - *len = Qfilesize (file); - return file; -} - -static void * -load_file (progs_t *pr, const char *name) -{ - QFile *file; - int size; - char *sym; - - file = open_file (name, &size); - if (!file) { - file = open_file (va ("%s.gz", name), &size); - if (!file) { - return 0; - } - } - sym = malloc (size + 1); - sym[size] = 0; - Qread (file, sym, size); - return sym; -} - -static void * -allocate_progs_mem (progs_t *pr, int size) -{ - return malloc (size); -} - -static void -free_progs_mem (progs_t *pr, void *mem) -{ - free (mem); -} - -static void -init_qf (void) -{ - Sys_Init (); - //Cvar_Get ("developer", "128", 0, 0, 0); - - Memory_Init (malloc (1024 * 1024), 1024 * 1024); - - Cvar_Get ("pr_debug", "2", 0, 0, 0); - Cvar_Get ("pr_boundscheck", "0", 0, 0, 0); - - pr.edicts = &edicts; - pr.num_edicts = &num_edicts; - pr.reserved_edicts = &reserved_edicts; - pr.load_file = load_file; - pr.allocate_progs_mem = allocate_progs_mem; - pr.free_progs_mem = free_progs_mem; - pr.no_exec_limit = 1; - - PR_Init_Cvars (); - PR_Init (); - RUA_Init (&pr, 0); - PR_Cmds_Init(&pr); - BI_Init (&pr); -} - -static int -load_progs (const char *name) -{ - QFile *file; - int size; - - file = open_file (name, &size); - if (!file) { - return 0; - } - pr.progs_name = name; - PR_LoadProgsFile (&pr, file, size, 1, 1024 * 1024); - Qclose (file); - if (!PR_RunLoadFuncs (&pr)) - PR_Error (&pr, "unable to load %s", pr.progs_name); - return 1; -} - -int -main (int argc, char **argv) -{ - dfunction_t *dfunc; - func_t main_func = 0; - const char *name = "qwaq.dat"; - string_t *pr_argv; - int pr_argc = 1, i; - - init_qf (); - - if (argc > 1) - name = argv[1]; - - if (!load_progs (name)) - Sys_Error ("couldn't load %s", "qwaq.dat"); - - PR_PushFrame (&pr); - if (argc > 2) - pr_argc = argc - 1; - pr_argv = PR_Zone_Malloc (&pr, (pr_argc + 1) * 4); - pr_argv[0] = PR_SetTempString (&pr, name); - for (i = 1; i < pr_argc; i++) - pr_argv[i] = PR_SetTempString (&pr, argv[1 + i]); - pr_argv[i] = 0; - - if ((dfunc = PR_FindFunction (&pr, ".main")) - || (dfunc = PR_FindFunction (&pr, "main"))) - main_func = dfunc - pr.pr_functions; - else - PR_Undefined (&pr, "function", "main"); - PR_RESET_PARAMS (&pr); - P_INT (&pr, 0) = pr_argc; - P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); - PR_ExecuteProgram (&pr, main_func); - PR_PopFrame (&pr); - return R_INT (&pr); -} diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc deleted file mode 100644 index 1014c1f4d..000000000 --- a/tools/qwaq/main.qc +++ /dev/null @@ -1,113 +0,0 @@ -string read_file (string filename) -{ - local QFile file; - local string data = nil, d; - file = Qopen (filename, "rtz"); - if (!file) { - printf ("Can't open %s for reading." - " Probably a bad hardcoded filename:)\n", filename); - return nil; - } - while ((d = Qgetline (file))) - data = data + d; - //FIXME can't read to a string, can't convert a pointer to a string ... - //Qread (file, data, 1023); - Qclose (file); - d = str_new (); - str_copy (d, data); - return d; -} - -void test_plist (void) -{ - local string data, l; - local plitem_t pl, item, i; - - data = read_file ("/home/bill/.quakeforge/gamedir.conf"); - pl = PL_GetPropertyList ("{" + data + "}"); - l = PL_WritePropertyList (pl); - printf ("%s", data); - printf ("%s", l); - i = PL_ObjectForKey (pl, "QF"); - item = PL_RemoveObjectForKey (pl, "QF"); - l = PL_WritePropertyList (item); - printf ("%s", l); - PL_Free (item); - //Because i and item both point to the same plitem, and item has been, - //freed, freeing i will generate an error - //l = PL_WritePropertyList (i); - PL_Free (pl); - str_free (data); -} - -void test_script (void) -{ - local script_t script; - local string token; - local string data; - - data = read_file ("progs.src"); - script = Script_New (); - token = Script_Start (script, "progs.src", data); - while (Script_GetToken (script, 1)) { - printf ("%s\n", token); - } - Script_Delete (script); - str_free (data); -} - -void () test_str = -{ - local string a,b,c,d; - a = "testing "; - b = "temp "; - c = "strings "; - d = "\n"; - print (a + b + c + d); - printf ("%i \"%.5s\" %3.4f %v\n", 14, "hi there", 3.1415926, '4 1 3'); -}; -void (...) dprint = #0; -int main (int argc, string *argv) -{ - local int i; - local SEL sel; - dprint ("foo", "bar\n"); - for (i = 0; i < argc; i++) { - print (argv[i]); - print ("\n"); - } - local id foo = [[Foo alloc] init]; - [foo run]; - sel = sel_get_uid ("run"); - if (sel) { - print ("found selector for `run'\n"); - if ([foo respondsToSelector:sel]) - print ("foo responds to `run'\n"); - else - print ("foo does not repond to `run'\n"); - } else - print ("did not find selector for `run'\n"); - sel = sel_get_uid ("alloc"); - if (sel) { - print ("found selector for `alloc'\n"); - if ([Object instancesRespondToSelector:sel]) - print ("Object instances respond to `alloc'\n"); - else - print ("Object instances do not repond to `alloc'\n"); - } else - print ("did not find selector for `alloc'\n"); - sel = sel_get_uid ("run:with:me:"); - if (sel) { - print ("found selector for `run:with:me:'\n"); - if ([Object instancesRespondToSelector:sel]) - print ("Object instances respond to `run:with:me:'\n"); - else - print ("Object instances do not repond to `run:with:me:'\n"); - } else - print ("did not find selector for `run:with:me:'\n"); - test_str (); - test_script (); - test_plist (); - test_types (); - return 0; -}; diff --git a/tools/qwaq/progs.src.in b/tools/qwaq/progs.src.in deleted file mode 100644 index c6d4f7070..000000000 --- a/tools/qwaq/progs.src.in +++ /dev/null @@ -1,16 +0,0 @@ -qwaq.dat - -@srcdir@/defs.qc - -@top_srcdir@/ruamoko/lib/plist.r -@top_srcdir@/ruamoko/lib/qfile.r -@top_srcdir@/ruamoko/lib/script.r -@top_srcdir@/ruamoko/lib/string.r -@top_srcdir@/ruamoko/lib/Object.r -@top_srcdir@/ruamoko/lib/Protocol.r -@top_srcdir@/ruamoko/lib/Array.r -@top_srcdir@/ruamoko/lib/Array+Private.r -@top_srcdir@/ruamoko/lib/AutoreleasePool.r -@srcdir@/test.r -@srcdir@/types.r -@srcdir@/main.qc diff --git a/tools/qwaq/qwaq.h b/tools/qwaq/qwaq.h deleted file mode 100644 index 9dbb2c23a..000000000 --- a/tools/qwaq/qwaq.h +++ /dev/null @@ -1,2 +0,0 @@ -void BI_Init (progs_t *pr); -extern struct cbuf_s *qwaq_cbuf; diff --git a/tools/qwaq/test.r b/tools/qwaq/test.r deleted file mode 100644 index 6e0afd6f2..000000000 --- a/tools/qwaq/test.r +++ /dev/null @@ -1,42 +0,0 @@ -@interface Foo : Object -{ - int x; -} --run; -@end - - -@implementation Foo - -+load -{ - print ("+load\n"); - return self; -} - -+alloc -{ - print ("+alloc\n"); - return class_create_instance (self); -} - --init -{ - print ("-init\n"); - return [super init]; -} - -+ (void) initialize -{ - print ("+initialize\n"); -} - --run -{ - print ("Hello world\n"); - printf ("%i %p [%s %s]\n", self, &self.x, [self description], - __PRETTY_FUNCTION__); - return self; -} - -@end diff --git a/tools/qwaq/types.r b/tools/qwaq/types.r deleted file mode 100644 index 82665e20a..000000000 --- a/tools/qwaq/types.r +++ /dev/null @@ -1,174 +0,0 @@ -#include "runtime.h" //FIXME for PR_FindGlobal -typedef enum { - ev_void, - ev_string, - ev_float, - ev_vector, - ev_entity, - ev_field, - ev_func, - ev_pointer, // end of v6 types - ev_quat, - ev_integer, - ev_uinteger, - ev_short, // value is embedded in the opcode - - ev_invalid, // invalid type. used for instruction checking - ev_type_count // not a type, gives number of types -} etype_t; - -typedef enum { - ty_none, ///< func/field/pointer or not used - ty_struct, - ty_union, - ty_enum, - ty_array, - ty_class, -} ty_meta_e; - - -typedef struct qfot_fldptr_s { - etype_t type; - struct qfot_type_s *aux_type; -} qfot_fldptr_t; - -typedef struct qfot_func_s { - etype_t type; - struct qfot_type_s *return_type; - int num_params; - struct qfot_type_s *param_types[1]; -} qfot_func_t; - -typedef struct qfot_var_s { - struct qfot_type_s *type; - string name; - int offset; // value for enum, 0 for union -} qfot_var_t; - -typedef struct qfot_struct_s { - string tag; - int num_fields; - qfot_var_t fields[1]; -} qfot_struct_t; - -typedef struct qfot_array_s { - struct qfot_type_s *type; - int base; - int size; -} qfot_array_t; - -typedef struct qfot_type_s { - ty_meta_e meta; - int size; - string encoding; - union { - etype_t type; - qfot_fldptr_t fldptr; - qfot_func_t func; - qfot_struct_t strct; - qfot_array_t array; - string class; - } t; -} qfot_type_t; - -typedef struct qfot_type_encodings_s { - qfot_type_t *types; - int size; -} qfot_type_encodings_t; - -qfot_type_t * -next_type (qfot_type_t *type) -{ - int size = type.size; - if (!size) - size = 4; - return (qfot_type_t *) ((int *) type + size); -} - -string ty_meta_name[6] = { - "basic", - "struct", - "union", - "enum", - "array", - "class", -}; - -string pr_type_name[ev_type_count] = { - "void", - "string", - "float", - "vector", - "entity", - "field", - "function", - "pointer", - "quaternion", - "integer", - "uinteger", - "short", - "invalid", -}; - -void -test_types (void) -{ - qfot_type_encodings_t *encodings; - qfot_type_t *type; - int i; - - encodings = PR_FindGlobal (".type_encodings"); - if (!encodings) { - printf ("Can't find encodings\n"); - return; - } - for (type = encodings.types; - ((int *)type - (int *) encodings.types) < encodings.size; - type = next_type (type)) { - printf ("%p %-6s %-20s", type, ty_meta_name[type.meta], - type.encoding); - if (!type.size) { - printf ("\n"); - continue; - } - switch (type.meta) { - case ty_none: - printf (" %-10s", pr_type_name[type.t.type]); - if (type.t.type == ev_func) { - int count = type.t.func.num_params; - printf ("%p %d", type.t.func.return_type, count); - if (count < 0) - count = ~count; - for (i = 0; i < count; i++) - printf (" %p", type.t.func.param_types[i]); - } else if (type.t.type == ev_pointer) { - printf (" *%p", type.t.fldptr.aux_type); - } else if (type.t.type == ev_field) { - printf (" .%p", type.t.fldptr.aux_type); - } else { - printf (" %p", type.t.fldptr.aux_type); - } - printf ("\n"); - break; - case ty_struct: - case ty_union: - case ty_enum: - printf (" %s\n", type.t.strct.tag); - for (i = 0; i < type.t.strct.num_fields; i++) { - printf (" %p %4x %s\n", - type.t.strct.fields[i].type, - type.t.strct.fields[i].offset, - type.t.strct.fields[i].name); - } - break; - case ty_array: - printf (" %p %d %d\n", type.t.array.type, - type.t.array.base, type.t.array.size); - break; - case ty_class: - printf (" %s %p\n", type.t.class, - obj_lookup_class (type.t.class)); - break; - } - } -} diff --git a/tools/wad/Makefile.am b/tools/wad/Makefile.am deleted file mode 100644 index 7db82d273..000000000 --- a/tools/wad/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -WAD_LIBS=@WAD_LIBS@ -WAD_DEPS=@WAD_DEPS@ -WAD_INCS=@WAD_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(WAD_INCS) - - -bin_PROGRAMS= wad - -mans=wad.1 -man_MANS= $(mans) - -wad_SOURCES= grab.c script.c wad.c -wad_LDADD= $(WAD_LIBS) -wad_DEPENDENCIES= $(WAD_DEPS) - -EXTRA_DIST= wad.h $(mans) diff --git a/tools/wad/Makemodule.am b/tools/wad/Makemodule.am new file mode 100644 index 000000000..dd68d6842 --- /dev/null +++ b/tools/wad/Makemodule.am @@ -0,0 +1,13 @@ +WAD_LIBS=@WAD_LIBS@ +WAD_DEPS=@WAD_DEPS@ +WAD_INCS=@WAD_INCS@ + +bin_PROGRAMS += wad + +man_MANS += tools/wad/wad.1 + +wad_SOURCES= tools/wad/grab.c tools/wad/script.c tools/wad/wad.c +wad_LDADD= $(WAD_LIBS) +wad_DEPENDENCIES= $(WAD_DEPS) + +EXTRA_DIST += tools/wad/wad.h diff --git a/tools/wad/script.c b/tools/wad/script.c index a9a9dcd5d..43da05360 100644 --- a/tools/wad/script.c +++ b/tools/wad/script.c @@ -92,7 +92,7 @@ load_image (const char *name) if (!(file = Qopen (name, "rb"))) Sys_Error ("couldn't open %s. %s", name, strerror(errno)); - if (!(tex = LoadPNG (file))) + if (!(tex = LoadPNG (file, 1))) Sys_Error ("couldn't read %s as PNG", name); pixels = tex->width * tex->height; @@ -159,7 +159,7 @@ write_file (void) QFile *file; const char *name; - name = va ("%s/%s.lmp", destfile.str, lumpname->str); + name = va (0, "%s/%s.lmp", destfile.str, lumpname->str); if (!(file = Qopen (name, "wb"))) Sys_Error ("couldn't open %s. %s", name, strerror(errno)); Qwrite (file, lumpbuffer, lump_p - lumpbuffer); diff --git a/tools/wad/wad.c b/tools/wad/wad.c index a1caf6fc9..08abf6d81 100644 --- a/tools/wad/wad.c +++ b/tools/wad/wad.c @@ -396,7 +396,7 @@ main (int argc, char **argv) lumpinfo_t *pf; Sys_Init (); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); this_program = argv[0]; diff --git a/tools/wav/Makefile.am b/tools/wav/Makefile.am deleted file mode 100644 index 7e17fe376..000000000 --- a/tools/wav/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -WAV_LIBS=@WAV_LIBS@ -WAV_DEPS=@WAV_DEPS@ -WAV_INCS=@WAV_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(WAV_INCS) - -bin_PROGRAMS= qfwavinfo - -mans=qfwavinfo.1 -man_MANS= #$(mans) - -qfwavinfo_SOURCES= qfwavinfo.c -qfwavinfo_LDADD= $(WAV_LIBS) -qfwavinfo_DEPENDENCIES= $(WAV_DEPS) - -EXTRA_DIST=#$(mans) diff --git a/tools/wav/Makemodule.am b/tools/wav/Makemodule.am new file mode 100644 index 000000000..4a4726809 --- /dev/null +++ b/tools/wav/Makemodule.am @@ -0,0 +1,11 @@ +WAV_LIBS=@WAV_LIBS@ +WAV_DEPS=@WAV_DEPS@ +WAV_INCS=@WAV_INCS@ + +bin_PROGRAMS += qfwavinfo + +#man_MANS += tools/wav/qfwavinfo.1 + +qfwavinfo_SOURCES= tools/wav/qfwavinfo.c +qfwavinfo_LDADD= $(WAV_LIBS) +qfwavinfo_DEPENDENCIES= $(WAV_DEPS) diff --git a/vc2005/Makefile.am b/vc2005/Makefile.am deleted file mode 100644 index 7f616ef19..000000000 --- a/vc2005/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign -EXTRA_DIST = \ - Makefile.am QuakeForge-VS8-Express.sln QuakeForge-VS8.sln \ - bsp2img/bsp2img.vcproj builtins/builtins.vcproj clean.ps1 \ - common/common.vcproj console/console.vcproj \ - console_client/console_client.vcproj console_server/console_server.vcproj \ - engine/engine.vcproj gib/gib.vcproj hw-master/hw-master.vcproj \ - image/image.vcproj include/config.h models-sw/models-sw.vcproj \ - models/models.vcproj modelsgl/modelsgl.vcproj net-main/net-main.vcproj \ - net/net.vcproj nq-common/nq-common.vcproj nq-sdl/nq-sdl.vcproj \ - nq-sdl32/nq-sdl32.vcproj nq-server/nq-server.vcproj nq-sgl/nq-sgl.vcproj \ - nq-wgl/nq-wgl.vcproj nq/nq.vcproj pak/pak.vcproj qfbsp/qfbsp.vcproj \ - qfcc/FlexBison.rules qfcc/qfcc.vcproj qfclient/qfclient.vcproj \ - qflight/qflight.vcproj qfmodelgen/qfmodelgen.vcproj \ - qfprogs/qfprogs.vcproj qfserver/qfserver.vcproj qfvis/qfvis.vcproj \ - qfwavinfo/qfwavinfo.vcproj qtv/qtv.vcproj \ - qw-client-sdl/qw-client-sdl.vcproj qw-client-sdl32/qw-client-sdl32.vcproj \ - qw-client-sgl/qw-client-sgl.vcproj qw-client-wgl/qw-client-wgl.vcproj \ - qw-master/qw-master.vcproj qw/qw.vcproj readme.txt ruamoko/ruamoko.vcproj \ - sound/sound.vcproj util/util.vcproj video-sdl/video-sdl.vcproj \ - video-sgl/video-sgl.vcproj video-sw/video-sw.vcproj \ - video-sw32/video-sw32.vcproj video-wgl/video-wgl.vcproj \ - video/video.vcproj videogl/videogl.vcproj wad/wad.vcproj diff --git a/vc2005/QuakeForge-VS8-Express.sln b/vc2005/QuakeForge-VS8-Express.sln deleted file mode 100644 index 404f35ff4..000000000 --- a/vc2005/QuakeForge-VS8-Express.sln +++ /dev/null @@ -1,935 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client", "qfclient\qfclient.vcproj", "{9A942925-61E6-4975-935A-5D62E8248E64}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw", "qw\qw.vcproj", "{6ADA4322-693A-46BB-897B-17BB5BE9F08C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net-chan", "net\net.vcproj", "{6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ruamoko", "ruamoko\ruamoko.vcproj", "{51028ACF-53D4-4478-8500-55E6B8A81375}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models-gl", "modelsgl\modelsgl.vcproj", "{1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console", "console\console.vcproj", "{ED4AFBF5-C247-4352-966D-048B8998C6A1}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gib", "gib\gib.vcproj", "{01C3B138-9D45-4ED6-A763-893C067262C2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util", "util\util.vcproj", "{ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "engine", "engine\engine.vcproj", "{2626C0E1-6F5C-47D3-B80D-93942D766DD7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "builtins", "builtins\builtins.vcproj", "{04FA9D77-E45F-4917-B972-B353BA6A6FA8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sound", "sound\sound.vcproj", "{BF149D97-7520-4788-9CD1-3D99C5C8150F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "image", "image\image.vcproj", "{5203F034-0047-4EC0-B7E9-D037FAF5D536}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video", "video\video.vcproj", "{E7B3D07D-2FE8-481B-8DAB-6255A412A42F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-common", "common\common.vcproj", "{BC1F021A-1EEC-4A7A-B746-5AA6048E478C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-server", "qfserver\qfserver.vcproj", "{544D097C-9C24-4C57-A171-8C8029421185}" - ProjectSection(ProjectDependencies) = postProject - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models", "models\models.vcproj", "{DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console-client", "console_client\console_client.vcproj", "{226D42CE-5833-444E-94FA-84C1D51892A8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console-server", "console_server\console_server.vcproj", "{B37FE734-01F4-4799-86B2-D084820715BE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfbsp", "qfbsp\qfbsp.vcproj", "{B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qflight", "qflight\qflight.vcproj", "{5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfvis", "qfvis\qfvis.vcproj", "{E5D842C5-669F-4FC7-A5E0-44B562F86435}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-master", "qw-master\qw-master.vcproj", "{445A2500-3BBC-449A-A929-C419C2A16051}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfmodelgen", "qfmodelgen\qfmodelgen.vcproj", "{052C34FE-C9E2-43ED-95DA-FB3F27B44E37}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfprogs", "qfprogs\qfprogs.vcproj", "{5FA27C8E-51B1-445A-A375-FBE74F0984B1}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfwavinfo", "qfwavinfo\qfwavinfo.vcproj", "{56BD559B-1590-4FC4-B441-AB1973BAC2BD}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wad", "wad\wad.vcproj", "{88422448-C5FB-46F3-A0B3-0811F90E537C}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pak", "pak\pak.vcproj", "{9EE8BD4B-47D3-4AD5-A8B9-831329792A05}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsp2img", "bsp2img\bsp2img.vcproj", "{4605418D-2292-470A-AB18-C2119B016F71}" - ProjectSection(ProjectDependencies) = postProject - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtv", "qtv\qtv.vcproj", "{05E68E3B-5901-43A9-981D-CF392C0F5C6C}" - ProjectSection(ProjectDependencies) = postProject - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-common", "nq-common\nq-common.vcproj", "{6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-wgl", "nq-wgl\nq-wgl.vcproj", "{1CD1A18B-95D5-4EA4-917C-34B10066BFCC}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net-main", "net-main\net-main.vcproj", "{053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-server", "nq-server\nq-server.vcproj", "{231C032C-DE16-459A-8E7D-6509C2EC3998}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hw-master", "hw-master\hw-master.vcproj", "{419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}" - ProjectSection(ProjectDependencies) = postProject - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfcc", "qfcc\qfcc.vcproj", "{40639893-4D75-48CD-811F-4B363CC71FFA}" - ProjectSection(ProjectDependencies) = postProject - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-wgl", "qw-client-wgl\qw-client-wgl.vcproj", "{5FD733BF-B3C6-4A96-BED7-35E2484448E1}" - ProjectSection(ProjectDependencies) = postProject - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sgl", "qw-client-sgl\qw-client-sgl.vcproj", "{649C4168-1C65-4E41-818F-85A1C52C1B8F}" - ProjectSection(ProjectDependencies) = postProject - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {7E30C3B1-AEE7-483D-B231-C672365CD2D7} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-gl", "videogl\videogl.vcproj", "{C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sdl", "video-sdl\video-sdl.vcproj", "{44A18410-3AA8-4A64-935B-D20223AD6885}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sdl", "qw-client-sdl\qw-client-sdl.vcproj", "{B44CB3E0-F2FD-4260-A632-C01FB881613E}" - ProjectSection(ProjectDependencies) = postProject - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {66D3A191-E4D5-45F3-86BD-EFBB249CD554} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models-sw", "models-sw\models-sw.vcproj", "{F4A9881E-0EB0-44A1-9664-B6CBDE992861}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sw", "video-sw\video-sw.vcproj", "{66D3A191-E4D5-45F3-86BD-EFBB249CD554}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sdl32", "qw-client-sdl32\qw-client-sdl32.vcproj", "{CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}" - ProjectSection(ProjectDependencies) = postProject - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {D5B9558F-EF25-4167-ACE4-723C7413B390} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sw32", "video-sw32\video-sw32.vcproj", "{D5B9558F-EF25-4167-ACE4-723C7413B390}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq", "nq\nq.vcproj", "{155112B9-A8A9-4E06-90F5-4AAAB32B2F70}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-wgl", "video-wgl\video-wgl.vcproj", "{178D81A7-F2FB-41D7-B300-9D1A4DE5E137}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sgl", "video-sgl\video-sgl.vcproj", "{7E30C3B1-AEE7-483D-B231-C672365CD2D7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sgl", "nq-sgl\nq-sgl.vcproj", "{2E26DB8B-9E37-4072-B397-8A7086E0ACD0}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {7E30C3B1-AEE7-483D-B231-C672365CD2D7} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sdl", "nq-sdl\nq-sdl.vcproj", "{2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}" - ProjectSection(ProjectDependencies) = postProject - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {66D3A191-E4D5-45F3-86BD-EFBB249CD554} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sdl32", "nq-sdl32\nq-sdl32.vcproj", "{2CEB1965-A89C-4422-A9AC-B30FCE7913C3}" - ProjectSection(ProjectDependencies) = postProject - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {D5B9558F-EF25-4167-ACE4-723C7413B390} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release (static)|Win32 = Release (static)|Win32 - Release (static)|x64 = Release (static)|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|Win32.ActiveCfg = Debug|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|Win32.Build.0 = Debug|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|x64.ActiveCfg = Debug|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|x64.Build.0 = Debug|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|x64.Build.0 = Release (static)|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|Win32.ActiveCfg = Release|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|Win32.Build.0 = Release|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|x64.ActiveCfg = Release|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|x64.Build.0 = Release|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|Win32.ActiveCfg = Debug|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|Win32.Build.0 = Debug|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|x64.ActiveCfg = Debug|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|x64.Build.0 = Debug|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|x64.Build.0 = Release (static)|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|Win32.ActiveCfg = Release|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|Win32.Build.0 = Release|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|x64.ActiveCfg = Release|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|x64.Build.0 = Release|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|Win32.ActiveCfg = Debug|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|Win32.Build.0 = Debug|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|x64.ActiveCfg = Debug|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|x64.Build.0 = Debug|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|x64.Build.0 = Release (static)|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|Win32.ActiveCfg = Release|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|Win32.Build.0 = Release|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|x64.ActiveCfg = Release|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|x64.Build.0 = Release|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|Win32.ActiveCfg = Debug|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|Win32.Build.0 = Debug|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|x64.ActiveCfg = Debug|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|x64.Build.0 = Debug|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|x64.Build.0 = Release (static)|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|Win32.ActiveCfg = Release|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|Win32.Build.0 = Release|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|x64.ActiveCfg = Release|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|x64.Build.0 = Release|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|Win32.ActiveCfg = Debug|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|Win32.Build.0 = Debug|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|x64.ActiveCfg = Debug|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|x64.Build.0 = Debug|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|x64.Build.0 = Release (static)|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|Win32.ActiveCfg = Release|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|Win32.Build.0 = Release|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|x64.ActiveCfg = Release|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|x64.Build.0 = Release|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|Win32.ActiveCfg = Debug|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|Win32.Build.0 = Debug|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|x64.ActiveCfg = Debug|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|x64.Build.0 = Debug|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|x64.Build.0 = Release (static)|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|Win32.ActiveCfg = Release|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|Win32.Build.0 = Release|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|x64.ActiveCfg = Release|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|x64.Build.0 = Release|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|Win32.ActiveCfg = Debug|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|Win32.Build.0 = Debug|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|x64.ActiveCfg = Debug|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|x64.Build.0 = Debug|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|x64.Build.0 = Release (static)|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|Win32.ActiveCfg = Release|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|Win32.Build.0 = Release|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|x64.ActiveCfg = Release|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|x64.Build.0 = Release|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|Win32.ActiveCfg = Debug|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|Win32.Build.0 = Debug|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|x64.ActiveCfg = Debug|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|x64.Build.0 = Debug|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|x64.Build.0 = Release (static)|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|Win32.ActiveCfg = Release|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|Win32.Build.0 = Release|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|x64.ActiveCfg = Release|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|x64.Build.0 = Release|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|Win32.ActiveCfg = Debug|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|Win32.Build.0 = Debug|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|x64.ActiveCfg = Debug|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|x64.Build.0 = Debug|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|x64.Build.0 = Release (static)|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|Win32.ActiveCfg = Release|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|Win32.Build.0 = Release|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|x64.ActiveCfg = Release|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|x64.Build.0 = Release|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|Win32.ActiveCfg = Debug|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|Win32.Build.0 = Debug|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|x64.ActiveCfg = Debug|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|x64.Build.0 = Debug|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|x64.Build.0 = Release (static)|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|Win32.ActiveCfg = Release|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|Win32.Build.0 = Release|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|x64.ActiveCfg = Release|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|x64.Build.0 = Release|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|Win32.ActiveCfg = Debug|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|Win32.Build.0 = Debug|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|x64.ActiveCfg = Debug|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|x64.Build.0 = Debug|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|x64.Build.0 = Release (static)|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|Win32.ActiveCfg = Release|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|Win32.Build.0 = Release|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|x64.ActiveCfg = Release|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|x64.Build.0 = Release|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|Win32.ActiveCfg = Debug|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|Win32.Build.0 = Debug|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|x64.ActiveCfg = Debug|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|x64.Build.0 = Debug|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|x64.Build.0 = Release (static)|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|Win32.ActiveCfg = Release|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|Win32.Build.0 = Release|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|x64.ActiveCfg = Release|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|x64.Build.0 = Release|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|Win32.ActiveCfg = Debug|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|Win32.Build.0 = Debug|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|x64.ActiveCfg = Debug|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|x64.Build.0 = Debug|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|x64.Build.0 = Release (static)|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|Win32.ActiveCfg = Release|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|Win32.Build.0 = Release|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|x64.ActiveCfg = Release|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|x64.Build.0 = Release|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|Win32.ActiveCfg = Debug|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|Win32.Build.0 = Debug|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|x64.ActiveCfg = Debug|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|x64.Build.0 = Debug|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|x64.Build.0 = Release (static)|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|Win32.ActiveCfg = Release|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|Win32.Build.0 = Release|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|x64.ActiveCfg = Release|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|x64.Build.0 = Release|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|Win32.ActiveCfg = Debug|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|Win32.Build.0 = Debug|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|x64.ActiveCfg = Debug|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|x64.Build.0 = Debug|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|x64.Build.0 = Release (static)|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|Win32.ActiveCfg = Release|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|Win32.Build.0 = Release|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|x64.ActiveCfg = Release|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|x64.Build.0 = Release|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|Win32.ActiveCfg = Debug|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|Win32.Build.0 = Debug|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|x64.ActiveCfg = Debug|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|x64.Build.0 = Debug|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|x64.Build.0 = Release (static)|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|Win32.ActiveCfg = Release|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|Win32.Build.0 = Release|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|x64.ActiveCfg = Release|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|x64.Build.0 = Release|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|Win32.ActiveCfg = Debug|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|Win32.Build.0 = Debug|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|x64.ActiveCfg = Debug|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|x64.Build.0 = Debug|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|x64.Build.0 = Release (static)|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|Win32.ActiveCfg = Release|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|Win32.Build.0 = Release|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|x64.ActiveCfg = Release|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|x64.Build.0 = Release|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|Win32.Build.0 = Debug|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|x64.ActiveCfg = Debug|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|x64.Build.0 = Debug|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|x64.Build.0 = Release (static)|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|Win32.ActiveCfg = Release|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|Win32.Build.0 = Release|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|x64.ActiveCfg = Release|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|x64.Build.0 = Release|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|Win32.ActiveCfg = Debug|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|Win32.Build.0 = Debug|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|x64.ActiveCfg = Debug|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|x64.Build.0 = Debug|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|x64.Build.0 = Release (static)|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|Win32.ActiveCfg = Release|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|Win32.Build.0 = Release|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|x64.ActiveCfg = Release|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|x64.Build.0 = Release|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|Win32.ActiveCfg = Debug|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|Win32.Build.0 = Debug|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|x64.ActiveCfg = Debug|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|x64.Build.0 = Debug|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|x64.Build.0 = Release (static)|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|Win32.ActiveCfg = Release|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|Win32.Build.0 = Release|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|x64.ActiveCfg = Release|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|x64.Build.0 = Release|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|Win32.ActiveCfg = Debug|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|Win32.Build.0 = Debug|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|x64.ActiveCfg = Debug|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|x64.Build.0 = Debug|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|x64.Build.0 = Release (static)|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|Win32.ActiveCfg = Release|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|Win32.Build.0 = Release|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|x64.ActiveCfg = Release|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|x64.Build.0 = Release|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|Win32.ActiveCfg = Debug|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|Win32.Build.0 = Debug|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|x64.ActiveCfg = Debug|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|x64.Build.0 = Debug|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|x64.Build.0 = Release (static)|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|Win32.ActiveCfg = Release|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|Win32.Build.0 = Release|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|x64.ActiveCfg = Release|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|x64.Build.0 = Release|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|Win32.ActiveCfg = Debug|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|Win32.Build.0 = Debug|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|x64.ActiveCfg = Debug|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|x64.Build.0 = Debug|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|x64.Build.0 = Release (static)|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|Win32.ActiveCfg = Release|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|Win32.Build.0 = Release|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|x64.ActiveCfg = Release|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|x64.Build.0 = Release|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|Win32.ActiveCfg = Debug|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|Win32.Build.0 = Debug|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|x64.ActiveCfg = Debug|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|x64.Build.0 = Debug|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|x64.Build.0 = Release (static)|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|Win32.ActiveCfg = Release|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|Win32.Build.0 = Release|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|x64.ActiveCfg = Release|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|x64.Build.0 = Release|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|Win32.ActiveCfg = Debug|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|Win32.Build.0 = Debug|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|x64.ActiveCfg = Debug|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|x64.Build.0 = Debug|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|x64.Build.0 = Release (static)|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|Win32.ActiveCfg = Release|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|Win32.Build.0 = Release|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|x64.ActiveCfg = Release|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|x64.Build.0 = Release|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|Win32.ActiveCfg = Debug|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|Win32.Build.0 = Debug|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|x64.ActiveCfg = Debug|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|x64.Build.0 = Debug|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|x64.Build.0 = Release (static)|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|Win32.ActiveCfg = Release|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|Win32.Build.0 = Release|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|x64.ActiveCfg = Release|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|x64.Build.0 = Release|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|Win32.ActiveCfg = Debug|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|Win32.Build.0 = Debug|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|x64.ActiveCfg = Debug|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|x64.Build.0 = Debug|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|x64.Build.0 = Release (static)|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|Win32.ActiveCfg = Release|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|Win32.Build.0 = Release|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|x64.ActiveCfg = Release|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|x64.Build.0 = Release|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|Win32.ActiveCfg = Debug|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|Win32.Build.0 = Debug|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|x64.ActiveCfg = Debug|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|x64.Build.0 = Debug|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|x64.Build.0 = Release (static)|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|Win32.ActiveCfg = Release|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|Win32.Build.0 = Release|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|x64.ActiveCfg = Release|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|x64.Build.0 = Release|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|Win32.ActiveCfg = Debug|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|Win32.Build.0 = Debug|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|x64.ActiveCfg = Debug|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|x64.Build.0 = Debug|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|x64.Build.0 = Release (static)|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|Win32.ActiveCfg = Release|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|Win32.Build.0 = Release|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|x64.ActiveCfg = Release|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|x64.Build.0 = Release|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|Win32.ActiveCfg = Debug|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|Win32.Build.0 = Debug|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|x64.ActiveCfg = Debug|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|x64.Build.0 = Debug|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|x64.Build.0 = Release (static)|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|Win32.ActiveCfg = Release|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|Win32.Build.0 = Release|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|x64.ActiveCfg = Release|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|x64.Build.0 = Release|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|Win32.ActiveCfg = Debug|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|Win32.Build.0 = Debug|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|x64.ActiveCfg = Debug|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|x64.Build.0 = Debug|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|x64.Build.0 = Release (static)|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|Win32.ActiveCfg = Release|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|Win32.Build.0 = Release|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|x64.ActiveCfg = Release|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|x64.Build.0 = Release|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|Win32.ActiveCfg = Debug|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|Win32.Build.0 = Debug|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|x64.ActiveCfg = Debug|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|x64.Build.0 = Debug|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|x64.Build.0 = Release (static)|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|Win32.ActiveCfg = Release|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|Win32.Build.0 = Release|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|x64.ActiveCfg = Release|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|x64.Build.0 = Release|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|Win32.ActiveCfg = Debug|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|Win32.Build.0 = Debug|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|x64.ActiveCfg = Debug|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|x64.Build.0 = Debug|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|x64.Build.0 = Release (static)|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|Win32.ActiveCfg = Release|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|Win32.Build.0 = Release|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|x64.ActiveCfg = Release|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|x64.Build.0 = Release|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|Win32.ActiveCfg = Debug|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|Win32.Build.0 = Debug|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|x64.ActiveCfg = Debug|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|x64.Build.0 = Debug|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|x64.Build.0 = Release (static)|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|Win32.ActiveCfg = Release|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|Win32.Build.0 = Release|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|x64.ActiveCfg = Release|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|x64.Build.0 = Release|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|Win32.ActiveCfg = Debug|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|Win32.Build.0 = Debug|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|x64.ActiveCfg = Debug|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|x64.Build.0 = Debug|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|x64.Build.0 = Release (static)|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|Win32.ActiveCfg = Release|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|Win32.Build.0 = Release|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|x64.ActiveCfg = Release|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|x64.Build.0 = Release|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|Win32.ActiveCfg = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|Win32.Build.0 = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|x64.ActiveCfg = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|x64.Build.0 = Release (static)|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|Win32.ActiveCfg = Release|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|Win32.Build.0 = Release|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|x64.ActiveCfg = Release|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|x64.Build.0 = Release|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|Win32.ActiveCfg = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|Win32.Build.0 = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|x64.ActiveCfg = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|x64.Build.0 = Release (static)|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|Win32.ActiveCfg = Release|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|Win32.Build.0 = Release|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|x64.ActiveCfg = Release|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|x64.Build.0 = Release|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|Win32.ActiveCfg = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|Win32.Build.0 = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|x64.ActiveCfg = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|x64.Build.0 = Release (static)|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|Win32.ActiveCfg = Release|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|Win32.Build.0 = Release|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|x64.ActiveCfg = Release|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|x64.Build.0 = Release|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|Win32.ActiveCfg = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|Win32.Build.0 = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|x64.ActiveCfg = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|x64.Build.0 = Release (static)|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|Win32.ActiveCfg = Release|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|Win32.Build.0 = Release|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|x64.ActiveCfg = Release|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|x64.Build.0 = Release|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|Win32.ActiveCfg = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|Win32.Build.0 = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|x64.ActiveCfg = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|x64.Build.0 = Release (static)|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|Win32.ActiveCfg = Release|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|Win32.Build.0 = Release|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|x64.ActiveCfg = Release|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|x64.Build.0 = Release|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|Win32.ActiveCfg = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|Win32.Build.0 = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|x64.ActiveCfg = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|x64.Build.0 = Release (static)|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|Win32.ActiveCfg = Release|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|Win32.Build.0 = Release|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|x64.ActiveCfg = Release|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|x64.Build.0 = Release|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|Win32.ActiveCfg = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|Win32.Build.0 = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|x64.ActiveCfg = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|x64.Build.0 = Release (static)|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|Win32.ActiveCfg = Release|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|Win32.Build.0 = Release|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|x64.ActiveCfg = Release|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|x64.Build.0 = Release|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|Win32.ActiveCfg = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|Win32.Build.0 = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|x64.ActiveCfg = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|x64.Build.0 = Release (static)|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|Win32.ActiveCfg = Release|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|Win32.Build.0 = Release|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|x64.ActiveCfg = Release|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|x64.Build.0 = Release|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|Win32.ActiveCfg = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|Win32.Build.0 = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|x64.ActiveCfg = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|x64.Build.0 = Release (static)|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|Win32.ActiveCfg = Release|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|Win32.Build.0 = Release|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|x64.ActiveCfg = Release|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|x64.Build.0 = Release|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|Win32.ActiveCfg = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|Win32.Build.0 = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|x64.ActiveCfg = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|x64.Build.0 = Release (static)|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|Win32.ActiveCfg = Release|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|Win32.Build.0 = Release|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|x64.ActiveCfg = Release|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|x64.Build.0 = Release|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|Win32.ActiveCfg = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|Win32.Build.0 = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|x64.ActiveCfg = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|x64.Build.0 = Release (static)|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|Win32.ActiveCfg = Release|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|Win32.Build.0 = Release|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|x64.ActiveCfg = Release|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|x64.Build.0 = Release|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|Win32.ActiveCfg = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|Win32.Build.0 = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|x64.ActiveCfg = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|x64.Build.0 = Release (static)|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|Win32.ActiveCfg = Release|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|Win32.Build.0 = Release|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|x64.ActiveCfg = Release|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|x64.Build.0 = Release|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|Win32.ActiveCfg = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|Win32.Build.0 = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|x64.ActiveCfg = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|x64.Build.0 = Release (static)|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|Win32.ActiveCfg = Release|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|Win32.Build.0 = Release|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|x64.ActiveCfg = Release|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|x64.Build.0 = Release|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|Win32.ActiveCfg = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|Win32.Build.0 = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|x64.ActiveCfg = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|x64.Build.0 = Release (static)|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|Win32.ActiveCfg = Release|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|Win32.Build.0 = Release|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|x64.ActiveCfg = Release|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|x64.Build.0 = Release|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|Win32.ActiveCfg = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|Win32.Build.0 = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|x64.ActiveCfg = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|x64.Build.0 = Release (static)|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|Win32.ActiveCfg = Release|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|Win32.Build.0 = Release|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|x64.ActiveCfg = Release|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vc2005/QuakeForge-VS8.sln b/vc2005/QuakeForge-VS8.sln deleted file mode 100644 index de80d166d..000000000 --- a/vc2005/QuakeForge-VS8.sln +++ /dev/null @@ -1,966 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client", "qfclient\qfclient.vcproj", "{9A942925-61E6-4975-935A-5D62E8248E64}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw", "qw\qw.vcproj", "{6ADA4322-693A-46BB-897B-17BB5BE9F08C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net-chan", "net\net.vcproj", "{6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ruamoko", "ruamoko\ruamoko.vcproj", "{51028ACF-53D4-4478-8500-55E6B8A81375}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models-gl", "modelsgl\modelsgl.vcproj", "{1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console", "console\console.vcproj", "{ED4AFBF5-C247-4352-966D-048B8998C6A1}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gib", "gib\gib.vcproj", "{01C3B138-9D45-4ED6-A763-893C067262C2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util", "util\util.vcproj", "{ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "engine", "engine\engine.vcproj", "{2626C0E1-6F5C-47D3-B80D-93942D766DD7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "builtins", "builtins\builtins.vcproj", "{04FA9D77-E45F-4917-B972-B353BA6A6FA8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sound", "sound\sound.vcproj", "{BF149D97-7520-4788-9CD1-3D99C5C8150F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "image", "image\image.vcproj", "{5203F034-0047-4EC0-B7E9-D037FAF5D536}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video", "video\video.vcproj", "{E7B3D07D-2FE8-481B-8DAB-6255A412A42F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-common", "common\common.vcproj", "{BC1F021A-1EEC-4A7A-B746-5AA6048E478C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-server", "qfserver\qfserver.vcproj", "{544D097C-9C24-4C57-A171-8C8029421185}" - ProjectSection(ProjectDependencies) = postProject - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models", "models\models.vcproj", "{DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console-client", "console_client\console_client.vcproj", "{226D42CE-5833-444E-94FA-84C1D51892A8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console-server", "console_server\console_server.vcproj", "{B37FE734-01F4-4799-86B2-D084820715BE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfbsp", "qfbsp\qfbsp.vcproj", "{B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qflight", "qflight\qflight.vcproj", "{5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfvis", "qfvis\qfvis.vcproj", "{E5D842C5-669F-4FC7-A5E0-44B562F86435}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-master", "qw-master\qw-master.vcproj", "{445A2500-3BBC-449A-A929-C419C2A16051}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfmodelgen", "qfmodelgen\qfmodelgen.vcproj", "{052C34FE-C9E2-43ED-95DA-FB3F27B44E37}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfprogs", "qfprogs\qfprogs.vcproj", "{5FA27C8E-51B1-445A-A375-FBE74F0984B1}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfwavinfo", "qfwavinfo\qfwavinfo.vcproj", "{56BD559B-1590-4FC4-B441-AB1973BAC2BD}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wad", "wad\wad.vcproj", "{88422448-C5FB-46F3-A0B3-0811F90E537C}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pak", "pak\pak.vcproj", "{9EE8BD4B-47D3-4AD5-A8B9-831329792A05}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsp2img", "bsp2img\bsp2img.vcproj", "{4605418D-2292-470A-AB18-C2119B016F71}" - ProjectSection(ProjectDependencies) = postProject - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtv", "qtv\qtv.vcproj", "{05E68E3B-5901-43A9-981D-CF392C0F5C6C}" - ProjectSection(ProjectDependencies) = postProject - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-common", "nq-common\nq-common.vcproj", "{6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-wgl", "nq-wgl\nq-wgl.vcproj", "{1CD1A18B-95D5-4EA4-917C-34B10066BFCC}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net-main", "net-main\net-main.vcproj", "{053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-server", "nq-server\nq-server.vcproj", "{231C032C-DE16-459A-8E7D-6509C2EC3998}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hw-master", "hw-master\hw-master.vcproj", "{419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}" - ProjectSection(ProjectDependencies) = postProject - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{3CDA2798-7565-47C5-B972-F9E63DBEFFFA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfcc", "qfcc\qfcc.vcproj", "{40639893-4D75-48CD-811F-4B363CC71FFA}" - ProjectSection(ProjectDependencies) = postProject - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-wgl", "qw-client-wgl\qw-client-wgl.vcproj", "{5FD733BF-B3C6-4A96-BED7-35E2484448E1}" - ProjectSection(ProjectDependencies) = postProject - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sgl", "qw-client-sgl\qw-client-sgl.vcproj", "{649C4168-1C65-4E41-818F-85A1C52C1B8F}" - ProjectSection(ProjectDependencies) = postProject - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {7E30C3B1-AEE7-483D-B231-C672365CD2D7} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-gl", "videogl\videogl.vcproj", "{C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sdl", "video-sdl\video-sdl.vcproj", "{44A18410-3AA8-4A64-935B-D20223AD6885}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sdl", "qw-client-sdl\qw-client-sdl.vcproj", "{B44CB3E0-F2FD-4260-A632-C01FB881613E}" - ProjectSection(ProjectDependencies) = postProject - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {66D3A191-E4D5-45F3-86BD-EFBB249CD554} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models-sw", "models-sw\models-sw.vcproj", "{F4A9881E-0EB0-44A1-9664-B6CBDE992861}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sw", "video-sw\video-sw.vcproj", "{66D3A191-E4D5-45F3-86BD-EFBB249CD554}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sdl32", "qw-client-sdl32\qw-client-sdl32.vcproj", "{CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}" - ProjectSection(ProjectDependencies) = postProject - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {D5B9558F-EF25-4167-ACE4-723C7413B390} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sw32", "video-sw32\video-sw32.vcproj", "{D5B9558F-EF25-4167-ACE4-723C7413B390}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq", "nq\nq.vcproj", "{155112B9-A8A9-4E06-90F5-4AAAB32B2F70}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-wgl", "video-wgl\video-wgl.vcproj", "{178D81A7-F2FB-41D7-B300-9D1A4DE5E137}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sgl", "video-sgl\video-sgl.vcproj", "{7E30C3B1-AEE7-483D-B231-C672365CD2D7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sgl", "nq-sgl\nq-sgl.vcproj", "{2E26DB8B-9E37-4072-B397-8A7086E0ACD0}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {7E30C3B1-AEE7-483D-B231-C672365CD2D7} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sdl", "nq-sdl\nq-sdl.vcproj", "{2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}" - ProjectSection(ProjectDependencies) = postProject - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {66D3A191-E4D5-45F3-86BD-EFBB249CD554} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sdl32", "nq-sdl32\nq-sdl32.vcproj", "{2CEB1965-A89C-4422-A9AC-B30FCE7913C3}" - ProjectSection(ProjectDependencies) = postProject - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {D5B9558F-EF25-4167-ACE4-723C7413B390} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release (static)|Win32 = Release (static)|Win32 - Release (static)|x64 = Release (static)|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|Win32.ActiveCfg = Debug|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|Win32.Build.0 = Debug|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|x64.ActiveCfg = Debug|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|x64.Build.0 = Debug|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|x64.Build.0 = Release (static)|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|Win32.ActiveCfg = Release|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|Win32.Build.0 = Release|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|x64.ActiveCfg = Release|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|x64.Build.0 = Release|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|Win32.ActiveCfg = Debug|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|Win32.Build.0 = Debug|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|x64.ActiveCfg = Debug|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|x64.Build.0 = Debug|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|x64.Build.0 = Release (static)|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|Win32.ActiveCfg = Release|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|Win32.Build.0 = Release|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|x64.ActiveCfg = Release|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|x64.Build.0 = Release|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|Win32.ActiveCfg = Debug|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|Win32.Build.0 = Debug|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|x64.ActiveCfg = Debug|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|x64.Build.0 = Debug|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|x64.Build.0 = Release (static)|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|Win32.ActiveCfg = Release|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|Win32.Build.0 = Release|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|x64.ActiveCfg = Release|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|x64.Build.0 = Release|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|Win32.ActiveCfg = Debug|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|Win32.Build.0 = Debug|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|x64.ActiveCfg = Debug|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|x64.Build.0 = Debug|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|x64.Build.0 = Release (static)|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|Win32.ActiveCfg = Release|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|Win32.Build.0 = Release|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|x64.ActiveCfg = Release|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|x64.Build.0 = Release|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|Win32.ActiveCfg = Debug|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|Win32.Build.0 = Debug|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|x64.ActiveCfg = Debug|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|x64.Build.0 = Debug|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|x64.Build.0 = Release (static)|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|Win32.ActiveCfg = Release|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|Win32.Build.0 = Release|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|x64.ActiveCfg = Release|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|x64.Build.0 = Release|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|Win32.ActiveCfg = Debug|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|Win32.Build.0 = Debug|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|x64.ActiveCfg = Debug|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|x64.Build.0 = Debug|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|x64.Build.0 = Release (static)|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|Win32.ActiveCfg = Release|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|Win32.Build.0 = Release|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|x64.ActiveCfg = Release|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|x64.Build.0 = Release|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|Win32.ActiveCfg = Debug|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|Win32.Build.0 = Debug|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|x64.ActiveCfg = Debug|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|x64.Build.0 = Debug|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|x64.Build.0 = Release (static)|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|Win32.ActiveCfg = Release|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|Win32.Build.0 = Release|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|x64.ActiveCfg = Release|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|x64.Build.0 = Release|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|Win32.ActiveCfg = Debug|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|Win32.Build.0 = Debug|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|x64.ActiveCfg = Debug|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|x64.Build.0 = Debug|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|x64.Build.0 = Release (static)|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|Win32.ActiveCfg = Release|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|Win32.Build.0 = Release|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|x64.ActiveCfg = Release|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|x64.Build.0 = Release|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|Win32.ActiveCfg = Debug|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|Win32.Build.0 = Debug|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|x64.ActiveCfg = Debug|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|x64.Build.0 = Debug|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|x64.Build.0 = Release (static)|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|Win32.ActiveCfg = Release|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|Win32.Build.0 = Release|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|x64.ActiveCfg = Release|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|x64.Build.0 = Release|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|Win32.ActiveCfg = Debug|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|Win32.Build.0 = Debug|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|x64.ActiveCfg = Debug|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|x64.Build.0 = Debug|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|x64.Build.0 = Release (static)|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|Win32.ActiveCfg = Release|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|Win32.Build.0 = Release|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|x64.ActiveCfg = Release|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|x64.Build.0 = Release|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|Win32.ActiveCfg = Debug|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|Win32.Build.0 = Debug|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|x64.ActiveCfg = Debug|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|x64.Build.0 = Debug|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|x64.Build.0 = Release (static)|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|Win32.ActiveCfg = Release|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|Win32.Build.0 = Release|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|x64.ActiveCfg = Release|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|x64.Build.0 = Release|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|Win32.ActiveCfg = Debug|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|Win32.Build.0 = Debug|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|x64.ActiveCfg = Debug|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|x64.Build.0 = Debug|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|x64.Build.0 = Release (static)|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|Win32.ActiveCfg = Release|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|Win32.Build.0 = Release|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|x64.ActiveCfg = Release|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|x64.Build.0 = Release|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|Win32.ActiveCfg = Debug|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|Win32.Build.0 = Debug|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|x64.ActiveCfg = Debug|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|x64.Build.0 = Debug|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|x64.Build.0 = Release (static)|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|Win32.ActiveCfg = Release|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|Win32.Build.0 = Release|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|x64.ActiveCfg = Release|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|x64.Build.0 = Release|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|Win32.ActiveCfg = Debug|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|Win32.Build.0 = Debug|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|x64.ActiveCfg = Debug|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|x64.Build.0 = Debug|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|x64.Build.0 = Release (static)|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|Win32.ActiveCfg = Release|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|Win32.Build.0 = Release|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|x64.ActiveCfg = Release|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|x64.Build.0 = Release|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|Win32.ActiveCfg = Debug|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|Win32.Build.0 = Debug|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|x64.ActiveCfg = Debug|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|x64.Build.0 = Debug|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|x64.Build.0 = Release (static)|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|Win32.ActiveCfg = Release|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|Win32.Build.0 = Release|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|x64.ActiveCfg = Release|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|x64.Build.0 = Release|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|Win32.ActiveCfg = Debug|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|Win32.Build.0 = Debug|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|x64.ActiveCfg = Debug|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|x64.Build.0 = Debug|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|x64.Build.0 = Release (static)|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|Win32.ActiveCfg = Release|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|Win32.Build.0 = Release|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|x64.ActiveCfg = Release|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|x64.Build.0 = Release|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|Win32.ActiveCfg = Debug|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|Win32.Build.0 = Debug|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|x64.ActiveCfg = Debug|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|x64.Build.0 = Debug|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|x64.Build.0 = Release (static)|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|Win32.ActiveCfg = Release|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|Win32.Build.0 = Release|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|x64.ActiveCfg = Release|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|x64.Build.0 = Release|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|Win32.Build.0 = Debug|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|x64.ActiveCfg = Debug|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|x64.Build.0 = Debug|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|x64.Build.0 = Release (static)|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|Win32.ActiveCfg = Release|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|Win32.Build.0 = Release|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|x64.ActiveCfg = Release|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|x64.Build.0 = Release|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|Win32.ActiveCfg = Debug|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|Win32.Build.0 = Debug|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|x64.ActiveCfg = Debug|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|x64.Build.0 = Debug|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|x64.Build.0 = Release (static)|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|Win32.ActiveCfg = Release|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|Win32.Build.0 = Release|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|x64.ActiveCfg = Release|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|x64.Build.0 = Release|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|Win32.ActiveCfg = Debug|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|Win32.Build.0 = Debug|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|x64.ActiveCfg = Debug|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|x64.Build.0 = Debug|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|x64.Build.0 = Release (static)|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|Win32.ActiveCfg = Release|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|Win32.Build.0 = Release|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|x64.ActiveCfg = Release|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|x64.Build.0 = Release|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|Win32.ActiveCfg = Debug|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|Win32.Build.0 = Debug|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|x64.ActiveCfg = Debug|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|x64.Build.0 = Debug|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|x64.Build.0 = Release (static)|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|Win32.ActiveCfg = Release|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|Win32.Build.0 = Release|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|x64.ActiveCfg = Release|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|x64.Build.0 = Release|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|Win32.ActiveCfg = Debug|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|Win32.Build.0 = Debug|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|x64.ActiveCfg = Debug|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|x64.Build.0 = Debug|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|x64.Build.0 = Release (static)|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|Win32.ActiveCfg = Release|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|Win32.Build.0 = Release|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|x64.ActiveCfg = Release|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|x64.Build.0 = Release|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|Win32.ActiveCfg = Debug|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|Win32.Build.0 = Debug|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|x64.ActiveCfg = Debug|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|x64.Build.0 = Debug|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|x64.Build.0 = Release (static)|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|Win32.ActiveCfg = Release|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|Win32.Build.0 = Release|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|x64.ActiveCfg = Release|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|x64.Build.0 = Release|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|Win32.ActiveCfg = Debug|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|Win32.Build.0 = Debug|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|x64.ActiveCfg = Debug|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|x64.Build.0 = Debug|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|x64.Build.0 = Release (static)|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|Win32.ActiveCfg = Release|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|Win32.Build.0 = Release|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|x64.ActiveCfg = Release|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|x64.Build.0 = Release|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|Win32.ActiveCfg = Debug|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|Win32.Build.0 = Debug|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|x64.ActiveCfg = Debug|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|x64.Build.0 = Debug|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|x64.Build.0 = Release (static)|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|Win32.ActiveCfg = Release|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|Win32.Build.0 = Release|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|x64.ActiveCfg = Release|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|x64.Build.0 = Release|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|Win32.ActiveCfg = Debug|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|Win32.Build.0 = Debug|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|x64.ActiveCfg = Debug|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|x64.Build.0 = Debug|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|x64.Build.0 = Release (static)|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|Win32.ActiveCfg = Release|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|Win32.Build.0 = Release|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|x64.ActiveCfg = Release|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|x64.Build.0 = Release|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|Win32.ActiveCfg = Debug|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|Win32.Build.0 = Debug|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|x64.ActiveCfg = Debug|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|x64.Build.0 = Debug|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|x64.Build.0 = Release (static)|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|Win32.ActiveCfg = Release|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|Win32.Build.0 = Release|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|x64.ActiveCfg = Release|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|x64.Build.0 = Release|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|Win32.ActiveCfg = Debug|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|Win32.Build.0 = Debug|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|x64.ActiveCfg = Debug|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|x64.Build.0 = Debug|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|x64.Build.0 = Release (static)|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|Win32.ActiveCfg = Release|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|Win32.Build.0 = Release|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|x64.ActiveCfg = Release|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|x64.Build.0 = Release|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|Win32.ActiveCfg = Debug|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|Win32.Build.0 = Debug|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|x64.ActiveCfg = Debug|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|x64.Build.0 = Debug|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|x64.Build.0 = Release (static)|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|Win32.ActiveCfg = Release|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|Win32.Build.0 = Release|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|x64.ActiveCfg = Release|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|x64.Build.0 = Release|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|Win32.ActiveCfg = Debug|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|Win32.Build.0 = Debug|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|x64.ActiveCfg = Debug|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|x64.Build.0 = Debug|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|x64.Build.0 = Release (static)|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|Win32.ActiveCfg = Release|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|Win32.Build.0 = Release|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|x64.ActiveCfg = Release|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|x64.Build.0 = Release|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|Win32.ActiveCfg = Debug|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|Win32.Build.0 = Debug|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|x64.ActiveCfg = Debug|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|x64.Build.0 = Debug|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|x64.Build.0 = Release (static)|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|Win32.ActiveCfg = Release|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|Win32.Build.0 = Release|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|x64.ActiveCfg = Release|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|x64.Build.0 = Release|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|Win32.ActiveCfg = Debug|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|Win32.Build.0 = Debug|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|x64.ActiveCfg = Debug|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|x64.Build.0 = Debug|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|x64.Build.0 = Release (static)|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|Win32.ActiveCfg = Release|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|Win32.Build.0 = Release|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|x64.ActiveCfg = Release|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|x64.Build.0 = Release|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|Win32.ActiveCfg = Debug|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|Win32.Build.0 = Debug|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|x64.ActiveCfg = Debug|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|x64.Build.0 = Debug|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|x64.Build.0 = Release (static)|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|Win32.ActiveCfg = Release|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|Win32.Build.0 = Release|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|x64.ActiveCfg = Release|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|x64.Build.0 = Release|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|Win32.ActiveCfg = Debug|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|Win32.Build.0 = Debug|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|x64.ActiveCfg = Debug|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|x64.Build.0 = Debug|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|x64.Build.0 = Release (static)|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|Win32.ActiveCfg = Release|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|Win32.Build.0 = Release|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|x64.ActiveCfg = Release|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|x64.Build.0 = Release|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|Win32.ActiveCfg = Debug|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|Win32.Build.0 = Debug|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|x64.ActiveCfg = Debug|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|x64.Build.0 = Debug|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|x64.Build.0 = Release (static)|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|Win32.ActiveCfg = Release|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|Win32.Build.0 = Release|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|x64.ActiveCfg = Release|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|x64.Build.0 = Release|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|Win32.ActiveCfg = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|Win32.Build.0 = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|x64.ActiveCfg = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|x64.Build.0 = Release (static)|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|Win32.ActiveCfg = Release|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|Win32.Build.0 = Release|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|x64.ActiveCfg = Release|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|x64.Build.0 = Release|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|Win32.ActiveCfg = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|Win32.Build.0 = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|x64.ActiveCfg = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|x64.Build.0 = Release (static)|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|Win32.ActiveCfg = Release|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|Win32.Build.0 = Release|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|x64.ActiveCfg = Release|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|x64.Build.0 = Release|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|Win32.ActiveCfg = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|Win32.Build.0 = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|x64.ActiveCfg = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|x64.Build.0 = Release (static)|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|Win32.ActiveCfg = Release|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|Win32.Build.0 = Release|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|x64.ActiveCfg = Release|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|x64.Build.0 = Release|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|Win32.ActiveCfg = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|Win32.Build.0 = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|x64.ActiveCfg = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|x64.Build.0 = Release (static)|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|Win32.ActiveCfg = Release|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|Win32.Build.0 = Release|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|x64.ActiveCfg = Release|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|x64.Build.0 = Release|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|Win32.ActiveCfg = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|Win32.Build.0 = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|x64.ActiveCfg = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|x64.Build.0 = Release (static)|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|Win32.ActiveCfg = Release|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|Win32.Build.0 = Release|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|x64.ActiveCfg = Release|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|x64.Build.0 = Release|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|Win32.ActiveCfg = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|Win32.Build.0 = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|x64.ActiveCfg = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|x64.Build.0 = Release (static)|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|Win32.ActiveCfg = Release|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|Win32.Build.0 = Release|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|x64.ActiveCfg = Release|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|x64.Build.0 = Release|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|Win32.ActiveCfg = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|Win32.Build.0 = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|x64.ActiveCfg = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|x64.Build.0 = Release (static)|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|Win32.ActiveCfg = Release|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|Win32.Build.0 = Release|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|x64.ActiveCfg = Release|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|x64.Build.0 = Release|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|Win32.ActiveCfg = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|Win32.Build.0 = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|x64.ActiveCfg = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|x64.Build.0 = Release (static)|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|Win32.ActiveCfg = Release|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|Win32.Build.0 = Release|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|x64.ActiveCfg = Release|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|x64.Build.0 = Release|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|Win32.ActiveCfg = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|Win32.Build.0 = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|x64.ActiveCfg = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|x64.Build.0 = Release (static)|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|Win32.ActiveCfg = Release|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|Win32.Build.0 = Release|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|x64.ActiveCfg = Release|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|x64.Build.0 = Release|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|Win32.ActiveCfg = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|Win32.Build.0 = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|x64.ActiveCfg = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|x64.Build.0 = Release (static)|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|Win32.ActiveCfg = Release|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|Win32.Build.0 = Release|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|x64.ActiveCfg = Release|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|x64.Build.0 = Release|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|Win32.ActiveCfg = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|Win32.Build.0 = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|x64.ActiveCfg = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|x64.Build.0 = Release (static)|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|Win32.ActiveCfg = Release|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|Win32.Build.0 = Release|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|x64.ActiveCfg = Release|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|x64.Build.0 = Release|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|Win32.ActiveCfg = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|Win32.Build.0 = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|x64.ActiveCfg = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|x64.Build.0 = Release (static)|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|Win32.ActiveCfg = Release|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|Win32.Build.0 = Release|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|x64.ActiveCfg = Release|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|x64.Build.0 = Release|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|Win32.ActiveCfg = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|Win32.Build.0 = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|x64.ActiveCfg = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|x64.Build.0 = Release (static)|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|Win32.ActiveCfg = Release|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|Win32.Build.0 = Release|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|x64.ActiveCfg = Release|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|x64.Build.0 = Release|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|Win32.ActiveCfg = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|Win32.Build.0 = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|x64.ActiveCfg = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|x64.Build.0 = Release (static)|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|Win32.ActiveCfg = Release|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|Win32.Build.0 = Release|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|x64.ActiveCfg = Release|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|x64.Build.0 = Release|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|Win32.ActiveCfg = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|Win32.Build.0 = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|x64.ActiveCfg = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|x64.Build.0 = Release (static)|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|Win32.ActiveCfg = Release|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|Win32.Build.0 = Release|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|x64.ActiveCfg = Release|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {B37FE734-01F4-4799-86B2-D084820715BE} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {9A942925-61E6-4975-935A-5D62E8248E64} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - EndGlobalSection -EndGlobal diff --git a/vc2005/bsp2img/bsp2img.vcproj b/vc2005/bsp2img/bsp2img.vcproj deleted file mode 100644 index 49beb4a45..000000000 --- a/vc2005/bsp2img/bsp2img.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/builtins/builtins.vcproj b/vc2005/builtins/builtins.vcproj deleted file mode 100644 index 63e384c61..000000000 --- a/vc2005/builtins/builtins.vcproj +++ /dev/null @@ -1,473 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/clean.ps1 b/vc2005/clean.ps1 deleted file mode 100644 index b1e75f990..000000000 --- a/vc2005/clean.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -ls -recurse -include 'win32','x64','*.user' | rm -recurse -if(test-path QuakeForge.suo) { rm QuakeForge.suo -force } -if(test-path QuakeForge.ncb) { rm QuakeForge.ncb } \ No newline at end of file diff --git a/vc2005/common/common.vcproj b/vc2005/common/common.vcproj deleted file mode 100644 index e473c7cce..000000000 --- a/vc2005/common/common.vcproj +++ /dev/null @@ -1,489 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/console/console.vcproj b/vc2005/console/console.vcproj deleted file mode 100644 index b71cf236e..000000000 --- a/vc2005/console/console.vcproj +++ /dev/null @@ -1,493 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/console_client/console_client.vcproj b/vc2005/console_client/console_client.vcproj deleted file mode 100644 index b6ae66820..000000000 --- a/vc2005/console_client/console_client.vcproj +++ /dev/null @@ -1,481 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/console_server/console_server.vcproj b/vc2005/console_server/console_server.vcproj deleted file mode 100644 index 4c3347b3a..000000000 --- a/vc2005/console_server/console_server.vcproj +++ /dev/null @@ -1,469 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/engine/engine.vcproj b/vc2005/engine/engine.vcproj deleted file mode 100644 index f3b7665ff..000000000 --- a/vc2005/engine/engine.vcproj +++ /dev/null @@ -1,509 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/gib/gib.vcproj b/vc2005/gib/gib.vcproj deleted file mode 100644 index 4039956cb..000000000 --- a/vc2005/gib/gib.vcproj +++ /dev/null @@ -1,537 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/hw-master/hw-master.vcproj b/vc2005/hw-master/hw-master.vcproj deleted file mode 100644 index 133d54777..000000000 --- a/vc2005/hw-master/hw-master.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/image/image.vcproj b/vc2005/image/image.vcproj deleted file mode 100644 index e32ffd958..000000000 --- a/vc2005/image/image.vcproj +++ /dev/null @@ -1,481 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/include/config.h b/vc2005/include/config.h deleted file mode 100644 index 1b787db16..000000000 --- a/vc2005/include/config.h +++ /dev/null @@ -1,740 +0,0 @@ -/* include/config.h. Generated from config.h.in by configure. */ -/* include/config.h.in. Generated from configure.ac by autoheader. */ - -/* list of cd plugins */ -#define CD_PLUGIN_LIST {"cd_win", cd_win_PluginInfo},{0, 0} - -/* list of cd prototypes */ -#define CD_PLUGIN_PROTOS extern plugin_t *cd_win_PluginInfo (void); - -/* list of client plugins */ -#define CLIENT_PLUGIN_LIST {"console_client", console_client_PluginInfo},{0, 0} - -/* list of client prototypes */ -#define CLIENT_PLUGIN_PROTOS extern plugin_t *console_client_PluginInfo (void); - -/* Define this to the command line for the C preprocessor */ -#define CPP_NAME "wave --c99 %d -o %o %i" - -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -/* #undef CRAY_STACKSEG_END */ - -/* Define to 1 if using `alloca.c'. */ -/* #undef C_ALLOCA */ - -/* Define this to the location of the global config file */ -#define FS_GLOBALCFG "~/quakeforge.conf" - -/* Define this to the path from which to load plugins */ -#define FS_PLUGINPATH "/usr/local/lib/quakeforge" - -/* Define this to the shared game directory root */ -#define FS_SHAREPATH "." - -/* Define this to the location of the user config file */ -#define FS_USERCFG "~/quakeforgerc" - -/* Define this to the unshared game directory root */ -#define FS_USERPATH "." - -/* Define this to the default GL dynamic lib */ -#define GL_DRIVER "OPENGL32.DLL" - -/* Define to 1 if you have the `access' function. */ -#define HAVE_ACCESS 1 - -/* Define to 1 if you have `alloca', as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -/* #undef HAVE_ALLOCA_H */ - -/* Define this if alloca is prototyped */ -/* #undef HAVE_ALLOCA_PROTO */ -#ifndef HAVE_ALLOCA_PROTO -#ifndef QFASM -void *alloca (int size); -#endif -#endif - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ALSA_ASOUNDLIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ARPA_INET_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ASM_IO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CONIO_H 1 - -/* Define to 1 if you have the `connect' function. */ -#define HAVE_CONNECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CURSES_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DDRAW_H 1 - -/* Define if you have the XFree86 DGA extension */ -/* #undef HAVE_DGA */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DINPUT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRECT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRENT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLFCN_H */ - -/* Define if you have the dlopen function. */ -/* #undef HAVE_DLOPEN */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DMEDIA_AUDIO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DMEDIA_CDAUDIO_H */ - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DPMI_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DSOUND_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXECINFO_H */ - -/* Define this if you have FB_AUX_VGA_PLANES_CFB4 */ -/* #undef HAVE_FB_AUX_VGA_PLANES_CFB4 */ - -/* Define this if you have FB_AUX_VGA_PLANES_CFB4 */ -/* #undef HAVE_FB_AUX_VGA_PLANES_CFB8 */ - -/* Define this if you have FB_AUX_VGA_PLANES_VGA4 */ -/* #undef HAVE_FB_AUX_VGA_PLANES_VGA4 */ - -/* Define to 1 if you have the `fcntl' function. */ -/* #undef HAVE_FCNTL */ - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* define this if you have flac libs */ -/* #undef HAVE_FLAC */ - -/* Define to 1 if you have the header file. */ -#define HAVE_FNMATCH_H 1 - -/* Define this if fnmatch is prototyped in fnmatch.h */ -/* #undef HAVE_FNMATCH_PROTO */ - -/* Define this if FPOS_T is a struct */ -/* #undef HAVE_FPOS_T_STRUCT */ - -/* Define to 1 if you have the `ftime' function. */ -#define HAVE_FTIME 1 - -/* Define to 1 if you have the `getaddrinfo' function. */ -#define HAVE_GETADDRINFO 1 - -/* Define to 1 if you have the `gethostbyname' function. */ -#define HAVE_GETHOSTBYNAME 1 - -/* Define to 1 if you have the `gethostname' function. */ -#define HAVE_GETHOSTNAME 1 - -/* Define to 1 if you have the `getnameinfo' function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to 1 if you have the `getpagesize' function. */ -/* #undef HAVE_GETPAGESIZE */ - -/* Define to 1 if you have the `gettimeofday' function. */ -/* #undef HAVE_GETTIMEOFDAY */ - -/* Define to 1 if you have the `getwd' function. */ -/* #undef HAVE_GETWD */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_INTTYPES_H */ - -/* Define this if your system has struct in_pktinfo */ -/* #undef HAVE_IN_PKTINFO */ - -/* Define to 1 if you have the header file. */ -#define HAVE_IO_H 1 - -/* Define this if you want IPv6 support */ -/* #undef HAVE_IPV6 */ - -/* Define if you have libjack */ -/* #undef HAVE_JACK */ - -/* Define to 1 if you have a functional curl library. */ -#define HAVE_LIBCURL 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBC_H */ - -/* Define to 1 if you have the `db' library (-ldb). */ -/* #undef HAVE_LIBDB */ - -/* Define to 1 if you have the `efence' library (-lefence). */ -/* #undef HAVE_LIBEFENCE */ - -/* Define to 1 if you have the `m' library (-lm). */ -/* #undef HAVE_LIBM */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_CDROM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_JOYSTICK_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_SOUNDCARD_H */ - -/* Define to 1 if you support file names longer than 14 characters. */ -#define HAVE_LONG_FILE_NAMES 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MACHINE_SOUNDCARD_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MALLOC_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MATH_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MGRAPH_H */ - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have a working `mmap' system call. */ -/* #undef HAVE_MMAP */ - -/* Define to 1 if you have the `mprotect' function. */ -/* #undef HAVE_MPROTECT */ - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETDB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETINET_IN_H */ - -/* Define if you have libpng */ -/* #undef HAVE_PNG */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PROCESS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PTHREAD_H */ - -/* Define to 1 if you have the `putenv' function. */ -#define HAVE_PUTENV 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PWD_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RPC_TYPES_H */ - -/* Define this if you have sa_len member in struct sockaddr (BSD) */ -/* #undef HAVE_SA_LEN */ - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SETJMP_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define this if you have sin6_len member in struct sockaddr_in6 (BSD) */ -/* #undef HAVE_SIN6_LEN */ - -/* Define this if your system has size_t */ -#define HAVE_SIZE_T 1 - -/* Define to 1 if you have the `snprintf' function. */ -#define HAVE_SNPRINTF 1 - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define this if your system has socklen_t */ -/* #undef HAVE_SOCKLEN_T */ - -/* Define this if you have ss_len member in struct sockaddr_storage (BSD) */ -/* #undef HAVE_SS_LEN */ - -/* Define to 1 if you have the `stat' function. */ -#define HAVE_STAT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strcasestr' function. */ -/* #undef HAVE_STRCASESTR */ - -/* Define this if strcasestr is prototyped in string.h */ -/* #undef HAVE_STRCASESTR_PROTO */ - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STRINGS_H 1 */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strnlen' function. */ -#define HAVE_STRNLEN 1 - -/* Define this if strnlen is prototyped in string.h */ -#define HAVE_STRNLEN_PROTO 1 - -/* Define to 1 if you have the `strsep' function. */ -/* #undef HAVE_STRSEP */ - -/* Define to 1 if you have the `strstr' function. */ -#define HAVE_STRSTR 1 - -/* Define to 1 if `st_blksize' is member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */ - -/* Define to 1 if your `struct stat' has `st_blksize'. Deprecated, use - `HAVE_STRUCT_STAT_ST_BLKSIZE' instead. */ -/* #undef HAVE_ST_BLKSIZE */ - -/* Define this if C symbols are prefixed with an underscore */ -#define HAVE_SYM_PREFIX_UNDERSCORE 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_ASOUNDLIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_AUDIOIO_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_FILIO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IOCTL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IPC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MMAN_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_PARAM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SHM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SIGNAL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOCKET_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOUNDCARD_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_TIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UIO_H */ - -/* Define to 1 if you have that is POSIX.1 compatible. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define this if you have tchar.h */ -#define HAVE_TCHAR_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TERMIOS_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_UNISTD_H */ - -/* Define to 1 if you have the `usleep' function. */ -/* #undef HAVE_USLEEP */ - -/* Define if va_copy is available */ -/* #undef HAVE_VA_COPY */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_VGAKEYBOARD_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_VGAMOUSE_H */ - -/* Define if you have the XFree86 VIDMODE extension */ -/* #undef HAVE_VIDMODE */ - -/* define this if you have ogg/vorbis libs */ -/* #undef HAVE_VORBIS */ - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the `vsnprintf' function. */ -#define HAVE_VSNPRINTF 1 - -/* Define if you have WildMidi */ -/* #undef HAVE_WILDMIDI */ - -/* Define to 1 if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WINSOCK_H 1 - -/* Define if you have XMMS */ -/* #undef HAVE_XMMS */ - -/* Define if you have zlib */ -#define HAVE_ZLIB 1 - -/* Define to 1 if you have the `_access' function. */ -#define HAVE__ACCESS 1 - -/* Define to 1 if you have the `_ftime' function. */ -#define HAVE__FTIME 1 - -/* Define to 1 if you have the <_mingw.h> header file. */ -/* #undef HAVE__MINGW_H */ - -/* Define to 1 if you have the `_mkdir' function. */ -#define HAVE__MKDIR 1 - -/* Define this if you have _SC_PAGESIZE */ -/* #undef HAVE__SC_PAGESIZE */ - -/* Define to 1 if you have the `_snprintf' function. */ -#define HAVE__SNPRINTF 1 - -/* Define if __va_copy is available */ -/* #undef HAVE__VA_COPY */ - -/* Define to 1 if you have the `_vsnprintf' function. */ -#define HAVE__VSNPRINTF 1 - -/* Define this if the GCC __attribute__ keyword is available */ -/* #undef HAVE___ATTRIBUTE__ */ - -#ifndef HAVE___ATTRIBUTE__ -# define __attribute__(x) -#endif - -/* Define this if the GCC __attribute__ keyword is available */ -/* #undef HAVE___ATTRIBUTE__VISIBILITY */ - -#ifdef HAVE___ATTRIBUTE__VISIBILITY -# define VISIBLE __attribute__((visibility ("default"))) -#else -# define VISIBLE -#endif - -/* Define this if the GCC __builtin_expect keyword is available */ -/* #undef HAVE___BUILTIN_EXPECT */ - -#ifndef HAVE___BUILTIN_EXPECT -# define __builtin_expect(x,c) x -#endif - -/* Defined if libcurl supports AsynchDNS */ -/* #undef LIBCURL_FEATURE_ASYNCHDNS */ - -/* Defined if libcurl supports IDN */ -#define LIBCURL_FEATURE_IDN 1 - -/* Defined if libcurl supports IPv6 */ -#define LIBCURL_FEATURE_IPV6 1 - -/* Defined if libcurl supports KRB4 */ -/* #undef LIBCURL_FEATURE_KRB4 */ - -/* Defined if libcurl supports libz */ -#define LIBCURL_FEATURE_LIBZ 1 - -/* Defined if libcurl supports NTLM */ -#define LIBCURL_FEATURE_NTLM 1 - -/* Defined if libcurl supports SSL */ -/* #undef LIBCURL_FEATURE_SSL */ - -/* Defined if libcurl supports SSPI */ -#define LIBCURL_FEATURE_SSPI 1 - -/* Defined if libcurl supports DICT */ -/* #undef LIBCURL_PROTOCOL_DICT */ - -/* Defined if libcurl supports FILE */ -/* #undef LIBCURL_PROTOCOL_FILE */ - -/* Defined if libcurl supports FTP */ -#define LIBCURL_PROTOCOL_FTP 1 - -/* Defined if libcurl supports FTPS */ -/* #undef LIBCURL_PROTOCOL_FTPS */ - -/* Defined if libcurl supports HTTP */ -#define LIBCURL_PROTOCOL_HTTP 1 - -/* Defined if libcurl supports HTTPS */ -/* #undef LIBCURL_PROTOCOL_HTTPS */ - -/* Defined if libcurl supports LDAP */ -/* #undef LIBCURL_PROTOCOL_LDAP */ - -/* Defined if libcurl supports TELNET */ -/* #undef LIBCURL_PROTOCOL_TELNET */ - -/* Defined if libcurl supports TFTP */ -/* #undef LIBCURL_PROTOCOL_TFTP */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -/* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define this to the QSG standard version you support in NetQuake */ -#define NQ_QSG_VERSION "1.0" - -/* Define this to the NetQuake standard version you support */ -#define NQ_VERSION "1.09" - -/* Name of package */ -#define PACKAGE "quakeforge" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "" - -/* Define this to your operating system's path separator character */ -#define PATH_SEPARATOR '/' - -/* "Proper" package name */ -#define PROGRAM "QuakeForge" - -/* Define this to where qfcc should look for header files */ -#define QFCC_INCLUDE_PATH "/usr/local/include/QF/ruamoko" - -/* Define this to where qfcc should look for lib files */ -#define QFCC_LIB_PATH "/usr/local/lib/ruamoko" - -/* Define this to the QSG standard version you support in QuakeWorld */ -#define QW_QSG_VERSION "2.0" - -/* Define this to the QuakeWorld standard version you support */ -#define QW_VERSION "2.40" - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* list of server plugins */ -#define SERVER_PLUGIN_LIST {"console_server", console_server_PluginInfo},{0, 0} - -/* list of server prototypes */ -#define SERVER_PLUGIN_PROTOS extern plugin_t *console_server_PluginInfo (void); - -/* Define this to the default sound output driver. */ -#define SND_OUTPUT_DEFAULT "win" - -/* list of sound output plugins */ -#define SND_OUTPUT_LIST {"snd_output_win", snd_output_win_PluginInfo},{0, 0} - -/* list of sound output prototypes */ -#define SND_OUTPUT_PROTOS extern plugin_t *snd_output_win_PluginInfo (void); - -/* list of sound render plugins */ -#define SND_RENDER_LIST {"snd_render_default", snd_render_default_PluginInfo},{0, 0} - -/* list of sound render prototypes */ -#define SND_RENDER_PROTOS extern plugin_t *snd_render_default_PluginInfo (void); - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -/* #undef STACK_DIRECTION */ - -/* Define this if you are building static plugins */ -#define STATIC_PLUGINS 1 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Define to 1 if your declares `struct tm'. */ -/* #undef TM_IN_SYS_TIME */ - -/* Define this if you want progs typechecking */ -/* #undef TYPECHECK_PROGS */ - -/* Define this if you want to use Intel assembly optimizations */ -/* #undef USE_INTEL_ASM */ - -/* Define if va_list is an array */ -/* #undef VA_LIST_IS_ARRAY */ - -/* Version number of package */ -#define VERSION "0.5.5-SVN" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define to 1 if the X Window System is missing or not being used. */ -/* #undef X_DISPLAY_MISSING */ - -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ -/* #undef YYTEXT_POINTER */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define curl_free() as free() if our version of curl lacks curl_free. */ -/* #undef curl_free */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#define inline __inline -/* #undef inline */ -#endif - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define strcasecmp as stricmp if you have one but not the other */ -#define strcasecmp stricmp - -/* new stuff, for VC2005 compatibility (phrosty) */ - -#define _CRT_SECURE_NO_WARNINGS -#define _CRT_NONSTDC_NO_WARNINGS - -/* used in qfcc. should #define to _ReturnAddress()? */ -#define __builtin_return_address(x) (0) - -#define _WIN32_WINNT 0x0500 -#define DIRECTINPUT_VERSION 0x0600 - -#define INITGUID - -#define snprintf _snprintf -#define strncasecmp strnicmp - -#define ssize_t ptrdiff_t -#define S_ISDIR(mode) (mode & _S_IFDIR) - -/* used in access() */ -#define R_OK 04 - -/* - disable silent conversion warnings for fixing later.. - - 4047: 'operator' : 'identifier1' differs in levels of indirection from 'identifier2' - 4244: 'argument' : conversion from 'type1' to 'type2', possible loss of data - 4267: 'var' : conversion from 'size_t' to 'type', possible loss of data (/Wp64 warning) - 4305: 'identifier' : truncation from 'type1' to 'type2' - 4311: 'variable' : pointer truncation from 'type' to 'type' (/Wp64 warning) - 4312: 'operation' : conversion from 'type1' to 'type2' of greater size (/Wp64 warning) -*/ -#pragma warning(disable:4047 4244 4267 4305 4311 4312) diff --git a/vc2005/models-sw/models-sw.vcproj b/vc2005/models-sw/models-sw.vcproj deleted file mode 100644 index 6eb490b83..000000000 --- a/vc2005/models-sw/models-sw.vcproj +++ /dev/null @@ -1,511 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/models/models.vcproj b/vc2005/models/models.vcproj deleted file mode 100644 index 06c14ed04..000000000 --- a/vc2005/models/models.vcproj +++ /dev/null @@ -1,489 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/modelsgl/modelsgl.vcproj b/vc2005/modelsgl/modelsgl.vcproj deleted file mode 100644 index 4f455edbe..000000000 --- a/vc2005/modelsgl/modelsgl.vcproj +++ /dev/null @@ -1,521 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/net-main/net-main.vcproj b/vc2005/net-main/net-main.vcproj deleted file mode 100644 index d986b743a..000000000 --- a/vc2005/net-main/net-main.vcproj +++ /dev/null @@ -1,487 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/net/net.vcproj b/vc2005/net/net.vcproj deleted file mode 100644 index 5b43da9e5..000000000 --- a/vc2005/net/net.vcproj +++ /dev/null @@ -1,473 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/nq-common/nq-common.vcproj b/vc2005/nq-common/nq-common.vcproj deleted file mode 100644 index 0dccdd9a4..000000000 --- a/vc2005/nq-common/nq-common.vcproj +++ /dev/null @@ -1,515 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/nq-sdl/nq-sdl.vcproj b/vc2005/nq-sdl/nq-sdl.vcproj deleted file mode 100644 index f4813f262..000000000 --- a/vc2005/nq-sdl/nq-sdl.vcproj +++ /dev/null @@ -1,561 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/nq-sdl32/nq-sdl32.vcproj b/vc2005/nq-sdl32/nq-sdl32.vcproj deleted file mode 100644 index 9c46d06f4..000000000 --- a/vc2005/nq-sdl32/nq-sdl32.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/nq-server/nq-server.vcproj b/vc2005/nq-server/nq-server.vcproj deleted file mode 100644 index 2b89d7bbe..000000000 --- a/vc2005/nq-server/nq-server.vcproj +++ /dev/null @@ -1,571 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/nq-sgl/nq-sgl.vcproj b/vc2005/nq-sgl/nq-sgl.vcproj deleted file mode 100644 index 3e61b1f10..000000000 --- a/vc2005/nq-sgl/nq-sgl.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/nq-wgl/nq-wgl.vcproj b/vc2005/nq-wgl/nq-wgl.vcproj deleted file mode 100644 index a789c0871..000000000 --- a/vc2005/nq-wgl/nq-wgl.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/nq/nq.vcproj b/vc2005/nq/nq.vcproj deleted file mode 100644 index 82cf3e55f..000000000 --- a/vc2005/nq/nq.vcproj +++ /dev/null @@ -1,543 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/pak/pak.vcproj b/vc2005/pak/pak.vcproj deleted file mode 100644 index 0daa6d627..000000000 --- a/vc2005/pak/pak.vcproj +++ /dev/null @@ -1,571 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfbsp/qfbsp.vcproj b/vc2005/qfbsp/qfbsp.vcproj deleted file mode 100644 index 461d6734b..000000000 --- a/vc2005/qfbsp/qfbsp.vcproj +++ /dev/null @@ -1,637 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfcc/FlexBison.rules b/vc2005/qfcc/FlexBison.rules deleted file mode 100644 index 0e4c1e3dc..000000000 --- a/vc2005/qfcc/FlexBison.rules +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfcc/qfcc.vcproj b/vc2005/qfcc/qfcc.vcproj deleted file mode 100644 index 786974fe1..000000000 --- a/vc2005/qfcc/qfcc.vcproj +++ /dev/null @@ -1,970 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfclient/qfclient.vcproj b/vc2005/qfclient/qfclient.vcproj deleted file mode 100644 index 19d1fac4d..000000000 --- a/vc2005/qfclient/qfclient.vcproj +++ /dev/null @@ -1,625 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qflight/qflight.vcproj b/vc2005/qflight/qflight.vcproj deleted file mode 100644 index 820cbc14a..000000000 --- a/vc2005/qflight/qflight.vcproj +++ /dev/null @@ -1,625 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfmodelgen/qfmodelgen.vcproj b/vc2005/qfmodelgen/qfmodelgen.vcproj deleted file mode 100644 index 24436bea5..000000000 --- a/vc2005/qfmodelgen/qfmodelgen.vcproj +++ /dev/null @@ -1,583 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfprogs/qfprogs.vcproj b/vc2005/qfprogs/qfprogs.vcproj deleted file mode 100644 index d77e43a2e..000000000 --- a/vc2005/qfprogs/qfprogs.vcproj +++ /dev/null @@ -1,595 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfserver/qfserver.vcproj b/vc2005/qfserver/qfserver.vcproj deleted file mode 100644 index 2852ccec3..000000000 --- a/vc2005/qfserver/qfserver.vcproj +++ /dev/null @@ -1,677 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfvis/qfvis.vcproj b/vc2005/qfvis/qfvis.vcproj deleted file mode 100644 index 4e34daab8..000000000 --- a/vc2005/qfvis/qfvis.vcproj +++ /dev/null @@ -1,593 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qfwavinfo/qfwavinfo.vcproj b/vc2005/qfwavinfo/qfwavinfo.vcproj deleted file mode 100644 index 9e2ead0d5..000000000 --- a/vc2005/qfwavinfo/qfwavinfo.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qtv/qtv.vcproj b/vc2005/qtv/qtv.vcproj deleted file mode 100644 index 127035507..000000000 --- a/vc2005/qtv/qtv.vcproj +++ /dev/null @@ -1,599 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qw-client-sdl/qw-client-sdl.vcproj b/vc2005/qw-client-sdl/qw-client-sdl.vcproj deleted file mode 100644 index 188d11f88..000000000 --- a/vc2005/qw-client-sdl/qw-client-sdl.vcproj +++ /dev/null @@ -1,563 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qw-client-sdl32/qw-client-sdl32.vcproj b/vc2005/qw-client-sdl32/qw-client-sdl32.vcproj deleted file mode 100644 index ccbdb9c89..000000000 --- a/vc2005/qw-client-sdl32/qw-client-sdl32.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qw-client-sgl/qw-client-sgl.vcproj b/vc2005/qw-client-sgl/qw-client-sgl.vcproj deleted file mode 100644 index 22adf9217..000000000 --- a/vc2005/qw-client-sgl/qw-client-sgl.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qw-client-wgl/qw-client-wgl.vcproj b/vc2005/qw-client-wgl/qw-client-wgl.vcproj deleted file mode 100644 index 96fb8c16a..000000000 --- a/vc2005/qw-client-wgl/qw-client-wgl.vcproj +++ /dev/null @@ -1,563 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qw-master/qw-master.vcproj b/vc2005/qw-master/qw-master.vcproj deleted file mode 100644 index a8605e358..000000000 --- a/vc2005/qw-master/qw-master.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/qw/qw.vcproj b/vc2005/qw/qw.vcproj deleted file mode 100644 index d73566194..000000000 --- a/vc2005/qw/qw.vcproj +++ /dev/null @@ -1,473 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/readme.txt b/vc2005/readme.txt deleted file mode 100644 index 8c50717db..000000000 --- a/vc2005/readme.txt +++ /dev/null @@ -1,27 +0,0 @@ -Requirements -============= -- Visual C++ 2005 SP1 -- Windows Vista SDK (previous RC compilers won't recognize the - high-resolution Vista icon) -- DirectX SDK (for DirectInput) -- SDL (required for sdl, sdl32, and sgl builds) -- bison/flex (required for qfcc, needs to be in your compiler path) - -Optional -========= -- zlib (#undef HAVE_ZLIB from vc2005/include/config.h if you don't want - this). Expects zlib.lib and zlib.dll for Debug/Release builds, and - libzlib.lib for Release (static) build. -- libcurl (#undef HAVE_LIBCURL from vc2005/include/config.h if you don't - want this). Expects curl.lib and curl.dll for Debug/Release builds, - and libcurl.lib for Release (static) build. - -Notes -====== -By default, qfcc is configured to use the Boost Wave preprocessor. You -can get this from http://www.boost.org, or change the CPP_NAME #define in -vc2005/include/config.h to whatever preprocessor you want. If you have -GCC, you can simply replace "wave --c99" with "gcc" in the define and it -should work. - -clean.ps1 is a Windows Powershell script that cleans up any build files. diff --git a/vc2005/ruamoko/ruamoko.vcproj b/vc2005/ruamoko/ruamoko.vcproj deleted file mode 100644 index 93fd48673..000000000 --- a/vc2005/ruamoko/ruamoko.vcproj +++ /dev/null @@ -1,517 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/sound/sound.vcproj b/vc2005/sound/sound.vcproj deleted file mode 100644 index 50c25ce4c..000000000 --- a/vc2005/sound/sound.vcproj +++ /dev/null @@ -1,513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/util/util.vcproj b/vc2005/util/util.vcproj deleted file mode 100644 index 021e3d655..000000000 --- a/vc2005/util/util.vcproj +++ /dev/null @@ -1,617 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/video-sdl/video-sdl.vcproj b/vc2005/video-sdl/video-sdl.vcproj deleted file mode 100644 index 5efd89c56..000000000 --- a/vc2005/video-sdl/video-sdl.vcproj +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/video-sgl/video-sgl.vcproj b/vc2005/video-sgl/video-sgl.vcproj deleted file mode 100644 index 94be99a3a..000000000 --- a/vc2005/video-sgl/video-sgl.vcproj +++ /dev/null @@ -1,467 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/video-sw/video-sw.vcproj b/vc2005/video-sw/video-sw.vcproj deleted file mode 100644 index 9158369bf..000000000 --- a/vc2005/video-sw/video-sw.vcproj +++ /dev/null @@ -1,595 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/video-sw32/video-sw32.vcproj b/vc2005/video-sw32/video-sw32.vcproj deleted file mode 100644 index fd4ed7caa..000000000 --- a/vc2005/video-sw32/video-sw32.vcproj +++ /dev/null @@ -1,571 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/video-wgl/video-wgl.vcproj b/vc2005/video-wgl/video-wgl.vcproj deleted file mode 100644 index 0087c8b78..000000000 --- a/vc2005/video-wgl/video-wgl.vcproj +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/video/video.vcproj b/vc2005/video/video.vcproj deleted file mode 100644 index 44213b2a4..000000000 --- a/vc2005/video/video.vcproj +++ /dev/null @@ -1,537 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/videogl/videogl.vcproj b/vc2005/videogl/videogl.vcproj deleted file mode 100644 index cfd456dc5..000000000 --- a/vc2005/videogl/videogl.vcproj +++ /dev/null @@ -1,555 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2005/wad/wad.vcproj b/vc2005/wad/wad.vcproj deleted file mode 100644 index 044bff20a..000000000 --- a/vc2005/wad/wad.vcproj +++ /dev/null @@ -1,579 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/Makefile.am b/vc2008/Makefile.am deleted file mode 100644 index 04c53f194..000000000 --- a/vc2008/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign -EXTRA_DIST = \ - Makefile.am QuakeForge.sln bsp2img/bsp2img.vcproj \ - builtins/builtins.vcproj clean.ps1 common/common.vcproj \ - console/console.vcproj console_client/console_client.vcproj \ - console_server/console_server.vcproj engine/engine.vcproj gib/gib.vcproj \ - hw-master/hw-master.vcproj image/image.vcproj include/config.h \ - models-sw/models-sw.vcproj models/models.vcproj modelsgl/modelsgl.vcproj \ - net-main/net-main.vcproj net/net.vcproj nq-common/nq-common.vcproj \ - nq-sdl/nq-sdl.vcproj nq-sdl32/nq-sdl32.vcproj nq-server/nq-server.vcproj \ - nq-sgl/nq-sgl.vcproj nq-wgl/nq-wgl.vcproj nq/nq.vcproj pak/pak.vcproj \ - qfbsp/qfbsp.vcproj qfcc/FlexBison.rules qfcc/qfcc.vcproj \ - qfclient/qfclient.vcproj qflight/qflight.vcproj \ - qfmodelgen/qfmodelgen.vcproj qfprogs/qfprogs.vcproj \ - qfserver/qfserver.vcproj qfvis/qfvis.vcproj qfwavinfo/qfwavinfo.vcproj \ - qtv/qtv.vcproj qw-client-sdl/qw-client-sdl.vcproj \ - qw-client-sdl32/qw-client-sdl32.vcproj qw-client-sgl/qw-client-sgl.vcproj \ - qw-client-wgl/qw-client-wgl.vcproj qw-master/qw-master.vcproj \ - qw/qw.vcproj readme.txt ruamoko/ruamoko.vcproj sound/sound.vcproj \ - util/util.vcproj video-sdl/video-sdl.vcproj video-sgl/video-sgl.vcproj \ - video-sw/video-sw.vcproj video-sw32/video-sw32.vcproj \ - video-wgl/video-wgl.vcproj video/video.vcproj videogl/videogl.vcproj \ - wad/wad.vcproj diff --git a/vc2008/QuakeForge.sln b/vc2008/QuakeForge.sln deleted file mode 100644 index 296484c89..000000000 --- a/vc2008/QuakeForge.sln +++ /dev/null @@ -1,966 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{3CDA2798-7565-47C5-B972-F9E63DBEFFFA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client", "qfclient\qfclient.vcproj", "{9A942925-61E6-4975-935A-5D62E8248E64}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw", "qw\qw.vcproj", "{6ADA4322-693A-46BB-897B-17BB5BE9F08C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net-chan", "net\net.vcproj", "{6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ruamoko", "ruamoko\ruamoko.vcproj", "{51028ACF-53D4-4478-8500-55E6B8A81375}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models-gl", "modelsgl\modelsgl.vcproj", "{1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console", "console\console.vcproj", "{ED4AFBF5-C247-4352-966D-048B8998C6A1}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gib", "gib\gib.vcproj", "{01C3B138-9D45-4ED6-A763-893C067262C2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util", "util\util.vcproj", "{ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "engine", "engine\engine.vcproj", "{2626C0E1-6F5C-47D3-B80D-93942D766DD7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "builtins", "builtins\builtins.vcproj", "{04FA9D77-E45F-4917-B972-B353BA6A6FA8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sound", "sound\sound.vcproj", "{BF149D97-7520-4788-9CD1-3D99C5C8150F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "image", "image\image.vcproj", "{5203F034-0047-4EC0-B7E9-D037FAF5D536}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video", "video\video.vcproj", "{E7B3D07D-2FE8-481B-8DAB-6255A412A42F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-common", "common\common.vcproj", "{BC1F021A-1EEC-4A7A-B746-5AA6048E478C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-server", "qfserver\qfserver.vcproj", "{544D097C-9C24-4C57-A171-8C8029421185}" - ProjectSection(ProjectDependencies) = postProject - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models", "models\models.vcproj", "{DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console-client", "console_client\console_client.vcproj", "{226D42CE-5833-444E-94FA-84C1D51892A8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console-server", "console_server\console_server.vcproj", "{B37FE734-01F4-4799-86B2-D084820715BE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfbsp", "qfbsp\qfbsp.vcproj", "{B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qflight", "qflight\qflight.vcproj", "{5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfvis", "qfvis\qfvis.vcproj", "{E5D842C5-669F-4FC7-A5E0-44B562F86435}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-master", "qw-master\qw-master.vcproj", "{445A2500-3BBC-449A-A929-C419C2A16051}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfmodelgen", "qfmodelgen\qfmodelgen.vcproj", "{052C34FE-C9E2-43ED-95DA-FB3F27B44E37}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfprogs", "qfprogs\qfprogs.vcproj", "{5FA27C8E-51B1-445A-A375-FBE74F0984B1}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfwavinfo", "qfwavinfo\qfwavinfo.vcproj", "{56BD559B-1590-4FC4-B441-AB1973BAC2BD}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wad", "wad\wad.vcproj", "{88422448-C5FB-46F3-A0B3-0811F90E537C}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pak", "pak\pak.vcproj", "{9EE8BD4B-47D3-4AD5-A8B9-831329792A05}" - ProjectSection(ProjectDependencies) = postProject - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsp2img", "bsp2img\bsp2img.vcproj", "{4605418D-2292-470A-AB18-C2119B016F71}" - ProjectSection(ProjectDependencies) = postProject - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtv", "qtv\qtv.vcproj", "{05E68E3B-5901-43A9-981D-CF392C0F5C6C}" - ProjectSection(ProjectDependencies) = postProject - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-common", "nq-common\nq-common.vcproj", "{6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-wgl", "nq-wgl\nq-wgl.vcproj", "{1CD1A18B-95D5-4EA4-917C-34B10066BFCC}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net-main", "net-main\net-main.vcproj", "{053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-server", "nq-server\nq-server.vcproj", "{231C032C-DE16-459A-8E7D-6509C2EC3998}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hw-master", "hw-master\hw-master.vcproj", "{419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}" - ProjectSection(ProjectDependencies) = postProject - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qfcc", "qfcc\qfcc.vcproj", "{40639893-4D75-48CD-811F-4B363CC71FFA}" - ProjectSection(ProjectDependencies) = postProject - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-wgl", "qw-client-wgl\qw-client-wgl.vcproj", "{5FD733BF-B3C6-4A96-BED7-35E2484448E1}" - ProjectSection(ProjectDependencies) = postProject - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sgl", "qw-client-sgl\qw-client-sgl.vcproj", "{649C4168-1C65-4E41-818F-85A1C52C1B8F}" - ProjectSection(ProjectDependencies) = postProject - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {7E30C3B1-AEE7-483D-B231-C672365CD2D7} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-gl", "videogl\videogl.vcproj", "{C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sdl", "video-sdl\video-sdl.vcproj", "{44A18410-3AA8-4A64-935B-D20223AD6885}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sdl", "qw-client-sdl\qw-client-sdl.vcproj", "{B44CB3E0-F2FD-4260-A632-C01FB881613E}" - ProjectSection(ProjectDependencies) = postProject - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {66D3A191-E4D5-45F3-86BD-EFBB249CD554} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models-sw", "models-sw\models-sw.vcproj", "{F4A9881E-0EB0-44A1-9664-B6CBDE992861}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sw", "video-sw\video-sw.vcproj", "{66D3A191-E4D5-45F3-86BD-EFBB249CD554}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qw-client-sdl32", "qw-client-sdl32\qw-client-sdl32.vcproj", "{CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}" - ProjectSection(ProjectDependencies) = postProject - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {6ADA4322-693A-46BB-897B-17BB5BE9F08C} - {9A942925-61E6-4975-935A-5D62E8248E64} = {9A942925-61E6-4975-935A-5D62E8248E64} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {D5B9558F-EF25-4167-ACE4-723C7413B390} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sw32", "video-sw32\video-sw32.vcproj", "{D5B9558F-EF25-4167-ACE4-723C7413B390}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq", "nq\nq.vcproj", "{155112B9-A8A9-4E06-90F5-4AAAB32B2F70}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-wgl", "video-wgl\video-wgl.vcproj", "{178D81A7-F2FB-41D7-B300-9D1A4DE5E137}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "video-sgl", "video-sgl\video-sgl.vcproj", "{7E30C3B1-AEE7-483D-B231-C672365CD2D7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sgl", "nq-sgl\nq-sgl.vcproj", "{2E26DB8B-9E37-4072-B397-8A7086E0ACD0}" - ProjectSection(ProjectDependencies) = postProject - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {7E30C3B1-AEE7-483D-B231-C672365CD2D7} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sdl", "nq-sdl\nq-sdl.vcproj", "{2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}" - ProjectSection(ProjectDependencies) = postProject - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {66D3A191-E4D5-45F3-86BD-EFBB249CD554} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nq-sdl32", "nq-sdl32\nq-sdl32.vcproj", "{2CEB1965-A89C-4422-A9AC-B30FCE7913C3}" - ProjectSection(ProjectDependencies) = postProject - {44A18410-3AA8-4A64-935B-D20223AD6885} = {44A18410-3AA8-4A64-935B-D20223AD6885} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {F4A9881E-0EB0-44A1-9664-B6CBDE992861} - {B37FE734-01F4-4799-86B2-D084820715BE} = {B37FE734-01F4-4799-86B2-D084820715BE} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {5203F034-0047-4EC0-B7E9-D037FAF5D536} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {01C3B138-9D45-4ED6-A763-893C067262C2} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {04FA9D77-E45F-4917-B972-B353BA6A6FA8} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {D5B9558F-EF25-4167-ACE4-723C7413B390} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {BF149D97-7520-4788-9CD1-3D99C5C8150F} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {226D42CE-5833-444E-94FA-84C1D51892A8} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {51028ACF-53D4-4478-8500-55E6B8A81375} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {2626C0E1-6F5C-47D3-B80D-93942D766DD7} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {ED4AFBF5-C247-4352-966D-048B8998C6A1} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release (static)|Win32 = Release (static)|Win32 - Release (static)|x64 = Release (static)|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|Win32.ActiveCfg = Debug|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|Win32.Build.0 = Debug|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|x64.ActiveCfg = Debug|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Debug|x64.Build.0 = Debug|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release (static)|x64.Build.0 = Release (static)|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|Win32.ActiveCfg = Release|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|Win32.Build.0 = Release|Win32 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|x64.ActiveCfg = Release|x64 - {9A942925-61E6-4975-935A-5D62E8248E64}.Release|x64.Build.0 = Release|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|Win32.ActiveCfg = Debug|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|Win32.Build.0 = Debug|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|x64.ActiveCfg = Debug|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Debug|x64.Build.0 = Debug|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release (static)|x64.Build.0 = Release (static)|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|Win32.ActiveCfg = Release|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|Win32.Build.0 = Release|Win32 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|x64.ActiveCfg = Release|x64 - {6ADA4322-693A-46BB-897B-17BB5BE9F08C}.Release|x64.Build.0 = Release|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|Win32.ActiveCfg = Debug|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|Win32.Build.0 = Debug|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|x64.ActiveCfg = Debug|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Debug|x64.Build.0 = Debug|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release (static)|x64.Build.0 = Release (static)|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|Win32.ActiveCfg = Release|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|Win32.Build.0 = Release|Win32 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|x64.ActiveCfg = Release|x64 - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0}.Release|x64.Build.0 = Release|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|Win32.ActiveCfg = Debug|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|Win32.Build.0 = Debug|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|x64.ActiveCfg = Debug|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Debug|x64.Build.0 = Debug|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release (static)|x64.Build.0 = Release (static)|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|Win32.ActiveCfg = Release|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|Win32.Build.0 = Release|Win32 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|x64.ActiveCfg = Release|x64 - {51028ACF-53D4-4478-8500-55E6B8A81375}.Release|x64.Build.0 = Release|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|Win32.ActiveCfg = Debug|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|Win32.Build.0 = Debug|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|x64.ActiveCfg = Debug|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Debug|x64.Build.0 = Debug|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release (static)|x64.Build.0 = Release (static)|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|Win32.ActiveCfg = Release|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|Win32.Build.0 = Release|Win32 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|x64.ActiveCfg = Release|x64 - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7}.Release|x64.Build.0 = Release|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|Win32.ActiveCfg = Debug|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|Win32.Build.0 = Debug|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|x64.ActiveCfg = Debug|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Debug|x64.Build.0 = Debug|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release (static)|x64.Build.0 = Release (static)|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|Win32.ActiveCfg = Release|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|Win32.Build.0 = Release|Win32 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|x64.ActiveCfg = Release|x64 - {ED4AFBF5-C247-4352-966D-048B8998C6A1}.Release|x64.Build.0 = Release|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|Win32.ActiveCfg = Debug|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|Win32.Build.0 = Debug|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|x64.ActiveCfg = Debug|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Debug|x64.Build.0 = Debug|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release (static)|x64.Build.0 = Release (static)|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|Win32.ActiveCfg = Release|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|Win32.Build.0 = Release|Win32 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|x64.ActiveCfg = Release|x64 - {01C3B138-9D45-4ED6-A763-893C067262C2}.Release|x64.Build.0 = Release|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|Win32.ActiveCfg = Debug|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|Win32.Build.0 = Debug|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|x64.ActiveCfg = Debug|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Debug|x64.Build.0 = Debug|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release (static)|x64.Build.0 = Release (static)|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|Win32.ActiveCfg = Release|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|Win32.Build.0 = Release|Win32 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|x64.ActiveCfg = Release|x64 - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB}.Release|x64.Build.0 = Release|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|Win32.ActiveCfg = Debug|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|Win32.Build.0 = Debug|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|x64.ActiveCfg = Debug|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Debug|x64.Build.0 = Debug|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release (static)|x64.Build.0 = Release (static)|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|Win32.ActiveCfg = Release|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|Win32.Build.0 = Release|Win32 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|x64.ActiveCfg = Release|x64 - {2626C0E1-6F5C-47D3-B80D-93942D766DD7}.Release|x64.Build.0 = Release|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|Win32.ActiveCfg = Debug|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|Win32.Build.0 = Debug|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|x64.ActiveCfg = Debug|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Debug|x64.Build.0 = Debug|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release (static)|x64.Build.0 = Release (static)|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|Win32.ActiveCfg = Release|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|Win32.Build.0 = Release|Win32 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|x64.ActiveCfg = Release|x64 - {04FA9D77-E45F-4917-B972-B353BA6A6FA8}.Release|x64.Build.0 = Release|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|Win32.ActiveCfg = Debug|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|Win32.Build.0 = Debug|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|x64.ActiveCfg = Debug|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Debug|x64.Build.0 = Debug|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release (static)|x64.Build.0 = Release (static)|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|Win32.ActiveCfg = Release|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|Win32.Build.0 = Release|Win32 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|x64.ActiveCfg = Release|x64 - {BF149D97-7520-4788-9CD1-3D99C5C8150F}.Release|x64.Build.0 = Release|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|Win32.ActiveCfg = Debug|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|Win32.Build.0 = Debug|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|x64.ActiveCfg = Debug|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Debug|x64.Build.0 = Debug|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release (static)|x64.Build.0 = Release (static)|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|Win32.ActiveCfg = Release|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|Win32.Build.0 = Release|Win32 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|x64.ActiveCfg = Release|x64 - {5203F034-0047-4EC0-B7E9-D037FAF5D536}.Release|x64.Build.0 = Release|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|Win32.ActiveCfg = Debug|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|Win32.Build.0 = Debug|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|x64.ActiveCfg = Debug|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Debug|x64.Build.0 = Debug|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release (static)|x64.Build.0 = Release (static)|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|Win32.ActiveCfg = Release|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|Win32.Build.0 = Release|Win32 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|x64.ActiveCfg = Release|x64 - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F}.Release|x64.Build.0 = Release|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|Win32.ActiveCfg = Debug|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|Win32.Build.0 = Debug|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|x64.ActiveCfg = Debug|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Debug|x64.Build.0 = Debug|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release (static)|x64.Build.0 = Release (static)|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|Win32.ActiveCfg = Release|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|Win32.Build.0 = Release|Win32 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|x64.ActiveCfg = Release|x64 - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C}.Release|x64.Build.0 = Release|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|Win32.ActiveCfg = Debug|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|Win32.Build.0 = Debug|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|x64.ActiveCfg = Debug|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Debug|x64.Build.0 = Debug|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release (static)|x64.Build.0 = Release (static)|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|Win32.ActiveCfg = Release|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|Win32.Build.0 = Release|Win32 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|x64.ActiveCfg = Release|x64 - {544D097C-9C24-4C57-A171-8C8029421185}.Release|x64.Build.0 = Release|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|Win32.ActiveCfg = Debug|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|Win32.Build.0 = Debug|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|x64.ActiveCfg = Debug|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Debug|x64.Build.0 = Debug|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release (static)|x64.Build.0 = Release (static)|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|Win32.ActiveCfg = Release|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|Win32.Build.0 = Release|Win32 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|x64.ActiveCfg = Release|x64 - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A}.Release|x64.Build.0 = Release|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|Win32.ActiveCfg = Debug|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|Win32.Build.0 = Debug|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|x64.ActiveCfg = Debug|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Debug|x64.Build.0 = Debug|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release (static)|x64.Build.0 = Release (static)|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|Win32.ActiveCfg = Release|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|Win32.Build.0 = Release|Win32 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|x64.ActiveCfg = Release|x64 - {226D42CE-5833-444E-94FA-84C1D51892A8}.Release|x64.Build.0 = Release|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|Win32.Build.0 = Debug|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|x64.ActiveCfg = Debug|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Debug|x64.Build.0 = Debug|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release (static)|x64.Build.0 = Release (static)|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|Win32.ActiveCfg = Release|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|Win32.Build.0 = Release|Win32 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|x64.ActiveCfg = Release|x64 - {B37FE734-01F4-4799-86B2-D084820715BE}.Release|x64.Build.0 = Release|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|Win32.ActiveCfg = Debug|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|Win32.Build.0 = Debug|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|x64.ActiveCfg = Debug|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Debug|x64.Build.0 = Debug|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release (static)|x64.Build.0 = Release (static)|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|Win32.ActiveCfg = Release|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|Win32.Build.0 = Release|Win32 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|x64.ActiveCfg = Release|x64 - {B00D4025-0437-4FF2-BD0E-D2AE6CF82AC2}.Release|x64.Build.0 = Release|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|Win32.ActiveCfg = Debug|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|Win32.Build.0 = Debug|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|x64.ActiveCfg = Debug|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Debug|x64.Build.0 = Debug|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release (static)|x64.Build.0 = Release (static)|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|Win32.ActiveCfg = Release|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|Win32.Build.0 = Release|Win32 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|x64.ActiveCfg = Release|x64 - {5E7E6110-89E8-4797-A8E3-EBEF0EF5CAF2}.Release|x64.Build.0 = Release|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|Win32.ActiveCfg = Debug|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|Win32.Build.0 = Debug|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|x64.ActiveCfg = Debug|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Debug|x64.Build.0 = Debug|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release (static)|x64.Build.0 = Release (static)|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|Win32.ActiveCfg = Release|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|Win32.Build.0 = Release|Win32 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|x64.ActiveCfg = Release|x64 - {E5D842C5-669F-4FC7-A5E0-44B562F86435}.Release|x64.Build.0 = Release|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|Win32.ActiveCfg = Debug|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|Win32.Build.0 = Debug|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|x64.ActiveCfg = Debug|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Debug|x64.Build.0 = Debug|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release (static)|x64.Build.0 = Release (static)|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|Win32.ActiveCfg = Release|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|Win32.Build.0 = Release|Win32 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|x64.ActiveCfg = Release|x64 - {445A2500-3BBC-449A-A929-C419C2A16051}.Release|x64.Build.0 = Release|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|Win32.ActiveCfg = Debug|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|Win32.Build.0 = Debug|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|x64.ActiveCfg = Debug|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Debug|x64.Build.0 = Debug|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release (static)|x64.Build.0 = Release (static)|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|Win32.ActiveCfg = Release|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|Win32.Build.0 = Release|Win32 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|x64.ActiveCfg = Release|x64 - {052C34FE-C9E2-43ED-95DA-FB3F27B44E37}.Release|x64.Build.0 = Release|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|Win32.ActiveCfg = Debug|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|Win32.Build.0 = Debug|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|x64.ActiveCfg = Debug|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Debug|x64.Build.0 = Debug|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release (static)|x64.Build.0 = Release (static)|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|Win32.ActiveCfg = Release|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|Win32.Build.0 = Release|Win32 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|x64.ActiveCfg = Release|x64 - {5FA27C8E-51B1-445A-A375-FBE74F0984B1}.Release|x64.Build.0 = Release|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|Win32.ActiveCfg = Debug|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|Win32.Build.0 = Debug|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|x64.ActiveCfg = Debug|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Debug|x64.Build.0 = Debug|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release (static)|x64.Build.0 = Release (static)|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|Win32.ActiveCfg = Release|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|Win32.Build.0 = Release|Win32 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|x64.ActiveCfg = Release|x64 - {56BD559B-1590-4FC4-B441-AB1973BAC2BD}.Release|x64.Build.0 = Release|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|Win32.ActiveCfg = Debug|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|Win32.Build.0 = Debug|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|x64.ActiveCfg = Debug|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Debug|x64.Build.0 = Debug|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release (static)|x64.Build.0 = Release (static)|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|Win32.ActiveCfg = Release|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|Win32.Build.0 = Release|Win32 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|x64.ActiveCfg = Release|x64 - {88422448-C5FB-46F3-A0B3-0811F90E537C}.Release|x64.Build.0 = Release|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|Win32.ActiveCfg = Debug|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|Win32.Build.0 = Debug|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|x64.ActiveCfg = Debug|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Debug|x64.Build.0 = Debug|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release (static)|x64.Build.0 = Release (static)|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|Win32.ActiveCfg = Release|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|Win32.Build.0 = Release|Win32 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|x64.ActiveCfg = Release|x64 - {9EE8BD4B-47D3-4AD5-A8B9-831329792A05}.Release|x64.Build.0 = Release|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|Win32.ActiveCfg = Debug|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|Win32.Build.0 = Debug|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|x64.ActiveCfg = Debug|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Debug|x64.Build.0 = Debug|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release (static)|x64.Build.0 = Release (static)|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|Win32.ActiveCfg = Release|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|Win32.Build.0 = Release|Win32 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|x64.ActiveCfg = Release|x64 - {4605418D-2292-470A-AB18-C2119B016F71}.Release|x64.Build.0 = Release|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|Win32.ActiveCfg = Debug|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|Win32.Build.0 = Debug|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|x64.ActiveCfg = Debug|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Debug|x64.Build.0 = Debug|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release (static)|x64.Build.0 = Release (static)|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|Win32.ActiveCfg = Release|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|Win32.Build.0 = Release|Win32 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|x64.ActiveCfg = Release|x64 - {05E68E3B-5901-43A9-981D-CF392C0F5C6C}.Release|x64.Build.0 = Release|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|Win32.ActiveCfg = Debug|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|Win32.Build.0 = Debug|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|x64.ActiveCfg = Debug|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Debug|x64.Build.0 = Debug|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release (static)|x64.Build.0 = Release (static)|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|Win32.ActiveCfg = Release|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|Win32.Build.0 = Release|Win32 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|x64.ActiveCfg = Release|x64 - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80}.Release|x64.Build.0 = Release|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|Win32.ActiveCfg = Debug|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|Win32.Build.0 = Debug|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|x64.ActiveCfg = Debug|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Debug|x64.Build.0 = Debug|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release (static)|x64.Build.0 = Release (static)|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|Win32.ActiveCfg = Release|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|Win32.Build.0 = Release|Win32 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|x64.ActiveCfg = Release|x64 - {1CD1A18B-95D5-4EA4-917C-34B10066BFCC}.Release|x64.Build.0 = Release|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|Win32.ActiveCfg = Debug|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|Win32.Build.0 = Debug|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|x64.ActiveCfg = Debug|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Debug|x64.Build.0 = Debug|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release (static)|x64.Build.0 = Release (static)|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|Win32.ActiveCfg = Release|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|Win32.Build.0 = Release|Win32 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|x64.ActiveCfg = Release|x64 - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5}.Release|x64.Build.0 = Release|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|Win32.ActiveCfg = Debug|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|Win32.Build.0 = Debug|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|x64.ActiveCfg = Debug|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Debug|x64.Build.0 = Debug|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release (static)|x64.Build.0 = Release (static)|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|Win32.ActiveCfg = Release|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|Win32.Build.0 = Release|Win32 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|x64.ActiveCfg = Release|x64 - {231C032C-DE16-459A-8E7D-6509C2EC3998}.Release|x64.Build.0 = Release|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|Win32.ActiveCfg = Debug|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|Win32.Build.0 = Debug|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|x64.ActiveCfg = Debug|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Debug|x64.Build.0 = Debug|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release (static)|x64.Build.0 = Release (static)|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|Win32.ActiveCfg = Release|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|Win32.Build.0 = Release|Win32 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|x64.ActiveCfg = Release|x64 - {419FEFBE-D9D5-4149-974B-0FFFC8D0D93F}.Release|x64.Build.0 = Release|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|Win32.ActiveCfg = Debug|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|Win32.Build.0 = Debug|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|x64.ActiveCfg = Debug|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Debug|x64.Build.0 = Debug|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release (static)|x64.Build.0 = Release (static)|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|Win32.ActiveCfg = Release|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|Win32.Build.0 = Release|Win32 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|x64.ActiveCfg = Release|x64 - {40639893-4D75-48CD-811F-4B363CC71FFA}.Release|x64.Build.0 = Release|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|Win32.ActiveCfg = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|Win32.Build.0 = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Debug|x64.ActiveCfg = Debug|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release (static)|x64.Build.0 = Release (static)|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|Win32.ActiveCfg = Release|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|Win32.Build.0 = Release|Win32 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|x64.ActiveCfg = Release|x64 - {5FD733BF-B3C6-4A96-BED7-35E2484448E1}.Release|x64.Build.0 = Release|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|Win32.ActiveCfg = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|Win32.Build.0 = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Debug|x64.ActiveCfg = Debug|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release (static)|x64.Build.0 = Release (static)|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|Win32.ActiveCfg = Release|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|Win32.Build.0 = Release|Win32 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|x64.ActiveCfg = Release|x64 - {649C4168-1C65-4E41-818F-85A1C52C1B8F}.Release|x64.Build.0 = Release|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|Win32.ActiveCfg = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|Win32.Build.0 = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Debug|x64.ActiveCfg = Debug|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release (static)|x64.Build.0 = Release (static)|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|Win32.ActiveCfg = Release|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|Win32.Build.0 = Release|Win32 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|x64.ActiveCfg = Release|x64 - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F}.Release|x64.Build.0 = Release|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|Win32.ActiveCfg = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|Win32.Build.0 = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Debug|x64.ActiveCfg = Debug|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release (static)|x64.Build.0 = Release (static)|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|Win32.ActiveCfg = Release|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|Win32.Build.0 = Release|Win32 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|x64.ActiveCfg = Release|x64 - {44A18410-3AA8-4A64-935B-D20223AD6885}.Release|x64.Build.0 = Release|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|Win32.ActiveCfg = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|Win32.Build.0 = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Debug|x64.ActiveCfg = Debug|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release (static)|x64.Build.0 = Release (static)|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|Win32.ActiveCfg = Release|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|Win32.Build.0 = Release|Win32 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|x64.ActiveCfg = Release|x64 - {B44CB3E0-F2FD-4260-A632-C01FB881613E}.Release|x64.Build.0 = Release|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|Win32.ActiveCfg = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|Win32.Build.0 = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Debug|x64.ActiveCfg = Debug|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release (static)|x64.Build.0 = Release (static)|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|Win32.ActiveCfg = Release|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|Win32.Build.0 = Release|Win32 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|x64.ActiveCfg = Release|x64 - {F4A9881E-0EB0-44A1-9664-B6CBDE992861}.Release|x64.Build.0 = Release|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|Win32.ActiveCfg = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|Win32.Build.0 = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Debug|x64.ActiveCfg = Debug|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release (static)|x64.Build.0 = Release (static)|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|Win32.ActiveCfg = Release|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|Win32.Build.0 = Release|Win32 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|x64.ActiveCfg = Release|x64 - {66D3A191-E4D5-45F3-86BD-EFBB249CD554}.Release|x64.Build.0 = Release|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|Win32.ActiveCfg = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|Win32.Build.0 = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Debug|x64.ActiveCfg = Debug|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release (static)|x64.Build.0 = Release (static)|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|Win32.ActiveCfg = Release|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|Win32.Build.0 = Release|Win32 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|x64.ActiveCfg = Release|x64 - {CBD0DD82-4DC7-4398-AF32-FD7BFFA3C2D5}.Release|x64.Build.0 = Release|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|Win32.ActiveCfg = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|Win32.Build.0 = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Debug|x64.ActiveCfg = Debug|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release (static)|x64.Build.0 = Release (static)|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|Win32.ActiveCfg = Release|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|Win32.Build.0 = Release|Win32 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|x64.ActiveCfg = Release|x64 - {D5B9558F-EF25-4167-ACE4-723C7413B390}.Release|x64.Build.0 = Release|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|Win32.ActiveCfg = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|Win32.Build.0 = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Debug|x64.ActiveCfg = Debug|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release (static)|x64.Build.0 = Release (static)|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|Win32.ActiveCfg = Release|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|Win32.Build.0 = Release|Win32 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|x64.ActiveCfg = Release|x64 - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70}.Release|x64.Build.0 = Release|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|Win32.ActiveCfg = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|Win32.Build.0 = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Debug|x64.ActiveCfg = Debug|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release (static)|x64.Build.0 = Release (static)|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|Win32.ActiveCfg = Release|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|Win32.Build.0 = Release|Win32 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|x64.ActiveCfg = Release|x64 - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137}.Release|x64.Build.0 = Release|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|Win32.ActiveCfg = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|Win32.Build.0 = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Debug|x64.ActiveCfg = Debug|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release (static)|x64.Build.0 = Release (static)|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|Win32.ActiveCfg = Release|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|Win32.Build.0 = Release|Win32 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|x64.ActiveCfg = Release|x64 - {7E30C3B1-AEE7-483D-B231-C672365CD2D7}.Release|x64.Build.0 = Release|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|Win32.ActiveCfg = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|Win32.Build.0 = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Debug|x64.ActiveCfg = Debug|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release (static)|x64.Build.0 = Release (static)|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|Win32.ActiveCfg = Release|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|Win32.Build.0 = Release|Win32 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|x64.ActiveCfg = Release|x64 - {2E26DB8B-9E37-4072-B397-8A7086E0ACD0}.Release|x64.Build.0 = Release|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|Win32.ActiveCfg = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|Win32.Build.0 = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Debug|x64.ActiveCfg = Debug|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release (static)|x64.Build.0 = Release (static)|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|Win32.ActiveCfg = Release|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|Win32.Build.0 = Release|Win32 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|x64.ActiveCfg = Release|x64 - {2736D4F9-EA8B-4ADF-B2D9-B705FF288A8A}.Release|x64.Build.0 = Release|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|Win32.ActiveCfg = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|Win32.Build.0 = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Debug|x64.ActiveCfg = Debug|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|Win32.ActiveCfg = Release (static)|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|Win32.Build.0 = Release (static)|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|x64.ActiveCfg = Release (static)|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release (static)|x64.Build.0 = Release (static)|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|Win32.ActiveCfg = Release|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|Win32.Build.0 = Release|Win32 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|x64.ActiveCfg = Release|x64 - {2CEB1965-A89C-4422-A9AC-B30FCE7913C3}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9A942925-61E6-4975-935A-5D62E8248E64} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {6ADA4322-693A-46BB-897B-17BB5BE9F08C} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {6540C00F-C5EF-4C8B-824D-F2B7B302F0E0} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {51028ACF-53D4-4478-8500-55E6B8A81375} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {1311DEDF-B04C-4E96-BFDC-5D9FA0B05AC7} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {ED4AFBF5-C247-4352-966D-048B8998C6A1} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {01C3B138-9D45-4ED6-A763-893C067262C2} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {ACCC6F49-7E06-4395-AAF4-3C03A68F49EB} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {2626C0E1-6F5C-47D3-B80D-93942D766DD7} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {04FA9D77-E45F-4917-B972-B353BA6A6FA8} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {BF149D97-7520-4788-9CD1-3D99C5C8150F} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {5203F034-0047-4EC0-B7E9-D037FAF5D536} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {E7B3D07D-2FE8-481B-8DAB-6255A412A42F} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {BC1F021A-1EEC-4A7A-B746-5AA6048E478C} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {DE7E8FF8-0F5D-4062-A5C0-CFA3502E7A5A} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {226D42CE-5833-444E-94FA-84C1D51892A8} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {B37FE734-01F4-4799-86B2-D084820715BE} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {6BA39648-5BD0-4B8D-A8DD-8202FBA1AE80} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {053E1EE2-75B4-4D9A-B8AE-89600BCB60A5} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {C55D5FBF-43A0-4F6C-BCF6-BAE5705C121F} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {44A18410-3AA8-4A64-935B-D20223AD6885} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {F4A9881E-0EB0-44A1-9664-B6CBDE992861} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {66D3A191-E4D5-45F3-86BD-EFBB249CD554} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {D5B9558F-EF25-4167-ACE4-723C7413B390} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {155112B9-A8A9-4E06-90F5-4AAAB32B2F70} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {178D81A7-F2FB-41D7-B300-9D1A4DE5E137} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - {7E30C3B1-AEE7-483D-B231-C672365CD2D7} = {3CDA2798-7565-47C5-B972-F9E63DBEFFFA} - EndGlobalSection -EndGlobal diff --git a/vc2008/bsp2img/bsp2img.vcproj b/vc2008/bsp2img/bsp2img.vcproj deleted file mode 100644 index b4608c799..000000000 --- a/vc2008/bsp2img/bsp2img.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/builtins/builtins.vcproj b/vc2008/builtins/builtins.vcproj deleted file mode 100644 index 43fa081df..000000000 --- a/vc2008/builtins/builtins.vcproj +++ /dev/null @@ -1,474 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/clean.ps1 b/vc2008/clean.ps1 deleted file mode 100644 index b1e75f990..000000000 --- a/vc2008/clean.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -ls -recurse -include 'win32','x64','*.user' | rm -recurse -if(test-path QuakeForge.suo) { rm QuakeForge.suo -force } -if(test-path QuakeForge.ncb) { rm QuakeForge.ncb } \ No newline at end of file diff --git a/vc2008/common/common.vcproj b/vc2008/common/common.vcproj deleted file mode 100644 index 7c1404ac7..000000000 --- a/vc2008/common/common.vcproj +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/console/console.vcproj b/vc2008/console/console.vcproj deleted file mode 100644 index f93f3975f..000000000 --- a/vc2008/console/console.vcproj +++ /dev/null @@ -1,494 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/console_client/console_client.vcproj b/vc2008/console_client/console_client.vcproj deleted file mode 100644 index 0e2a378b0..000000000 --- a/vc2008/console_client/console_client.vcproj +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/console_server/console_server.vcproj b/vc2008/console_server/console_server.vcproj deleted file mode 100644 index 33a611997..000000000 --- a/vc2008/console_server/console_server.vcproj +++ /dev/null @@ -1,470 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/engine/engine.vcproj b/vc2008/engine/engine.vcproj deleted file mode 100644 index 203710bf7..000000000 --- a/vc2008/engine/engine.vcproj +++ /dev/null @@ -1,510 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/gib/gib.vcproj b/vc2008/gib/gib.vcproj deleted file mode 100644 index 3fbb039b6..000000000 --- a/vc2008/gib/gib.vcproj +++ /dev/null @@ -1,538 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/hw-master/hw-master.vcproj b/vc2008/hw-master/hw-master.vcproj deleted file mode 100644 index 0e7273e3b..000000000 --- a/vc2008/hw-master/hw-master.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/image/image.vcproj b/vc2008/image/image.vcproj deleted file mode 100644 index 73970fb11..000000000 --- a/vc2008/image/image.vcproj +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/include/config.h b/vc2008/include/config.h deleted file mode 100644 index 1b787db16..000000000 --- a/vc2008/include/config.h +++ /dev/null @@ -1,740 +0,0 @@ -/* include/config.h. Generated from config.h.in by configure. */ -/* include/config.h.in. Generated from configure.ac by autoheader. */ - -/* list of cd plugins */ -#define CD_PLUGIN_LIST {"cd_win", cd_win_PluginInfo},{0, 0} - -/* list of cd prototypes */ -#define CD_PLUGIN_PROTOS extern plugin_t *cd_win_PluginInfo (void); - -/* list of client plugins */ -#define CLIENT_PLUGIN_LIST {"console_client", console_client_PluginInfo},{0, 0} - -/* list of client prototypes */ -#define CLIENT_PLUGIN_PROTOS extern plugin_t *console_client_PluginInfo (void); - -/* Define this to the command line for the C preprocessor */ -#define CPP_NAME "wave --c99 %d -o %o %i" - -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -/* #undef CRAY_STACKSEG_END */ - -/* Define to 1 if using `alloca.c'. */ -/* #undef C_ALLOCA */ - -/* Define this to the location of the global config file */ -#define FS_GLOBALCFG "~/quakeforge.conf" - -/* Define this to the path from which to load plugins */ -#define FS_PLUGINPATH "/usr/local/lib/quakeforge" - -/* Define this to the shared game directory root */ -#define FS_SHAREPATH "." - -/* Define this to the location of the user config file */ -#define FS_USERCFG "~/quakeforgerc" - -/* Define this to the unshared game directory root */ -#define FS_USERPATH "." - -/* Define this to the default GL dynamic lib */ -#define GL_DRIVER "OPENGL32.DLL" - -/* Define to 1 if you have the `access' function. */ -#define HAVE_ACCESS 1 - -/* Define to 1 if you have `alloca', as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -/* #undef HAVE_ALLOCA_H */ - -/* Define this if alloca is prototyped */ -/* #undef HAVE_ALLOCA_PROTO */ -#ifndef HAVE_ALLOCA_PROTO -#ifndef QFASM -void *alloca (int size); -#endif -#endif - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ALSA_ASOUNDLIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ARPA_INET_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ASM_IO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CONIO_H 1 - -/* Define to 1 if you have the `connect' function. */ -#define HAVE_CONNECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CURSES_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DDRAW_H 1 - -/* Define if you have the XFree86 DGA extension */ -/* #undef HAVE_DGA */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DINPUT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRECT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRENT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLFCN_H */ - -/* Define if you have the dlopen function. */ -/* #undef HAVE_DLOPEN */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DMEDIA_AUDIO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DMEDIA_CDAUDIO_H */ - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DPMI_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DSOUND_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXECINFO_H */ - -/* Define this if you have FB_AUX_VGA_PLANES_CFB4 */ -/* #undef HAVE_FB_AUX_VGA_PLANES_CFB4 */ - -/* Define this if you have FB_AUX_VGA_PLANES_CFB4 */ -/* #undef HAVE_FB_AUX_VGA_PLANES_CFB8 */ - -/* Define this if you have FB_AUX_VGA_PLANES_VGA4 */ -/* #undef HAVE_FB_AUX_VGA_PLANES_VGA4 */ - -/* Define to 1 if you have the `fcntl' function. */ -/* #undef HAVE_FCNTL */ - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* define this if you have flac libs */ -/* #undef HAVE_FLAC */ - -/* Define to 1 if you have the header file. */ -#define HAVE_FNMATCH_H 1 - -/* Define this if fnmatch is prototyped in fnmatch.h */ -/* #undef HAVE_FNMATCH_PROTO */ - -/* Define this if FPOS_T is a struct */ -/* #undef HAVE_FPOS_T_STRUCT */ - -/* Define to 1 if you have the `ftime' function. */ -#define HAVE_FTIME 1 - -/* Define to 1 if you have the `getaddrinfo' function. */ -#define HAVE_GETADDRINFO 1 - -/* Define to 1 if you have the `gethostbyname' function. */ -#define HAVE_GETHOSTBYNAME 1 - -/* Define to 1 if you have the `gethostname' function. */ -#define HAVE_GETHOSTNAME 1 - -/* Define to 1 if you have the `getnameinfo' function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to 1 if you have the `getpagesize' function. */ -/* #undef HAVE_GETPAGESIZE */ - -/* Define to 1 if you have the `gettimeofday' function. */ -/* #undef HAVE_GETTIMEOFDAY */ - -/* Define to 1 if you have the `getwd' function. */ -/* #undef HAVE_GETWD */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_INTTYPES_H */ - -/* Define this if your system has struct in_pktinfo */ -/* #undef HAVE_IN_PKTINFO */ - -/* Define to 1 if you have the header file. */ -#define HAVE_IO_H 1 - -/* Define this if you want IPv6 support */ -/* #undef HAVE_IPV6 */ - -/* Define if you have libjack */ -/* #undef HAVE_JACK */ - -/* Define to 1 if you have a functional curl library. */ -#define HAVE_LIBCURL 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBC_H */ - -/* Define to 1 if you have the `db' library (-ldb). */ -/* #undef HAVE_LIBDB */ - -/* Define to 1 if you have the `efence' library (-lefence). */ -/* #undef HAVE_LIBEFENCE */ - -/* Define to 1 if you have the `m' library (-lm). */ -/* #undef HAVE_LIBM */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_CDROM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_FB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_JOYSTICK_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_SOUNDCARD_H */ - -/* Define to 1 if you support file names longer than 14 characters. */ -#define HAVE_LONG_FILE_NAMES 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MACHINE_SOUNDCARD_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MALLOC_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MATH_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MGRAPH_H */ - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have a working `mmap' system call. */ -/* #undef HAVE_MMAP */ - -/* Define to 1 if you have the `mprotect' function. */ -/* #undef HAVE_MPROTECT */ - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETDB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETINET_IN_H */ - -/* Define if you have libpng */ -/* #undef HAVE_PNG */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PROCESS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PTHREAD_H */ - -/* Define to 1 if you have the `putenv' function. */ -#define HAVE_PUTENV 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PWD_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_RPC_TYPES_H */ - -/* Define this if you have sa_len member in struct sockaddr (BSD) */ -/* #undef HAVE_SA_LEN */ - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SETJMP_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define this if you have sin6_len member in struct sockaddr_in6 (BSD) */ -/* #undef HAVE_SIN6_LEN */ - -/* Define this if your system has size_t */ -#define HAVE_SIZE_T 1 - -/* Define to 1 if you have the `snprintf' function. */ -#define HAVE_SNPRINTF 1 - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define this if your system has socklen_t */ -/* #undef HAVE_SOCKLEN_T */ - -/* Define this if you have ss_len member in struct sockaddr_storage (BSD) */ -/* #undef HAVE_SS_LEN */ - -/* Define to 1 if you have the `stat' function. */ -#define HAVE_STAT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strcasestr' function. */ -/* #undef HAVE_STRCASESTR */ - -/* Define this if strcasestr is prototyped in string.h */ -/* #undef HAVE_STRCASESTR_PROTO */ - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STRINGS_H 1 */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strnlen' function. */ -#define HAVE_STRNLEN 1 - -/* Define this if strnlen is prototyped in string.h */ -#define HAVE_STRNLEN_PROTO 1 - -/* Define to 1 if you have the `strsep' function. */ -/* #undef HAVE_STRSEP */ - -/* Define to 1 if you have the `strstr' function. */ -#define HAVE_STRSTR 1 - -/* Define to 1 if `st_blksize' is member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */ - -/* Define to 1 if your `struct stat' has `st_blksize'. Deprecated, use - `HAVE_STRUCT_STAT_ST_BLKSIZE' instead. */ -/* #undef HAVE_ST_BLKSIZE */ - -/* Define this if C symbols are prefixed with an underscore */ -#define HAVE_SYM_PREFIX_UNDERSCORE 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_ASOUNDLIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_AUDIOIO_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_FILIO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IOCTL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IPC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MMAN_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_PARAM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SHM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SIGNAL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOCKET_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOUNDCARD_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_TIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UIO_H */ - -/* Define to 1 if you have that is POSIX.1 compatible. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define this if you have tchar.h */ -#define HAVE_TCHAR_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TERMIOS_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_UNISTD_H */ - -/* Define to 1 if you have the `usleep' function. */ -/* #undef HAVE_USLEEP */ - -/* Define if va_copy is available */ -/* #undef HAVE_VA_COPY */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_VGAKEYBOARD_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_VGAMOUSE_H */ - -/* Define if you have the XFree86 VIDMODE extension */ -/* #undef HAVE_VIDMODE */ - -/* define this if you have ogg/vorbis libs */ -/* #undef HAVE_VORBIS */ - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the `vsnprintf' function. */ -#define HAVE_VSNPRINTF 1 - -/* Define if you have WildMidi */ -/* #undef HAVE_WILDMIDI */ - -/* Define to 1 if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WINSOCK_H 1 - -/* Define if you have XMMS */ -/* #undef HAVE_XMMS */ - -/* Define if you have zlib */ -#define HAVE_ZLIB 1 - -/* Define to 1 if you have the `_access' function. */ -#define HAVE__ACCESS 1 - -/* Define to 1 if you have the `_ftime' function. */ -#define HAVE__FTIME 1 - -/* Define to 1 if you have the <_mingw.h> header file. */ -/* #undef HAVE__MINGW_H */ - -/* Define to 1 if you have the `_mkdir' function. */ -#define HAVE__MKDIR 1 - -/* Define this if you have _SC_PAGESIZE */ -/* #undef HAVE__SC_PAGESIZE */ - -/* Define to 1 if you have the `_snprintf' function. */ -#define HAVE__SNPRINTF 1 - -/* Define if __va_copy is available */ -/* #undef HAVE__VA_COPY */ - -/* Define to 1 if you have the `_vsnprintf' function. */ -#define HAVE__VSNPRINTF 1 - -/* Define this if the GCC __attribute__ keyword is available */ -/* #undef HAVE___ATTRIBUTE__ */ - -#ifndef HAVE___ATTRIBUTE__ -# define __attribute__(x) -#endif - -/* Define this if the GCC __attribute__ keyword is available */ -/* #undef HAVE___ATTRIBUTE__VISIBILITY */ - -#ifdef HAVE___ATTRIBUTE__VISIBILITY -# define VISIBLE __attribute__((visibility ("default"))) -#else -# define VISIBLE -#endif - -/* Define this if the GCC __builtin_expect keyword is available */ -/* #undef HAVE___BUILTIN_EXPECT */ - -#ifndef HAVE___BUILTIN_EXPECT -# define __builtin_expect(x,c) x -#endif - -/* Defined if libcurl supports AsynchDNS */ -/* #undef LIBCURL_FEATURE_ASYNCHDNS */ - -/* Defined if libcurl supports IDN */ -#define LIBCURL_FEATURE_IDN 1 - -/* Defined if libcurl supports IPv6 */ -#define LIBCURL_FEATURE_IPV6 1 - -/* Defined if libcurl supports KRB4 */ -/* #undef LIBCURL_FEATURE_KRB4 */ - -/* Defined if libcurl supports libz */ -#define LIBCURL_FEATURE_LIBZ 1 - -/* Defined if libcurl supports NTLM */ -#define LIBCURL_FEATURE_NTLM 1 - -/* Defined if libcurl supports SSL */ -/* #undef LIBCURL_FEATURE_SSL */ - -/* Defined if libcurl supports SSPI */ -#define LIBCURL_FEATURE_SSPI 1 - -/* Defined if libcurl supports DICT */ -/* #undef LIBCURL_PROTOCOL_DICT */ - -/* Defined if libcurl supports FILE */ -/* #undef LIBCURL_PROTOCOL_FILE */ - -/* Defined if libcurl supports FTP */ -#define LIBCURL_PROTOCOL_FTP 1 - -/* Defined if libcurl supports FTPS */ -/* #undef LIBCURL_PROTOCOL_FTPS */ - -/* Defined if libcurl supports HTTP */ -#define LIBCURL_PROTOCOL_HTTP 1 - -/* Defined if libcurl supports HTTPS */ -/* #undef LIBCURL_PROTOCOL_HTTPS */ - -/* Defined if libcurl supports LDAP */ -/* #undef LIBCURL_PROTOCOL_LDAP */ - -/* Defined if libcurl supports TELNET */ -/* #undef LIBCURL_PROTOCOL_TELNET */ - -/* Defined if libcurl supports TFTP */ -/* #undef LIBCURL_PROTOCOL_TFTP */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -/* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define this to the QSG standard version you support in NetQuake */ -#define NQ_QSG_VERSION "1.0" - -/* Define this to the NetQuake standard version you support */ -#define NQ_VERSION "1.09" - -/* Name of package */ -#define PACKAGE "quakeforge" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "" - -/* Define this to your operating system's path separator character */ -#define PATH_SEPARATOR '/' - -/* "Proper" package name */ -#define PROGRAM "QuakeForge" - -/* Define this to where qfcc should look for header files */ -#define QFCC_INCLUDE_PATH "/usr/local/include/QF/ruamoko" - -/* Define this to where qfcc should look for lib files */ -#define QFCC_LIB_PATH "/usr/local/lib/ruamoko" - -/* Define this to the QSG standard version you support in QuakeWorld */ -#define QW_QSG_VERSION "2.0" - -/* Define this to the QuakeWorld standard version you support */ -#define QW_VERSION "2.40" - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* list of server plugins */ -#define SERVER_PLUGIN_LIST {"console_server", console_server_PluginInfo},{0, 0} - -/* list of server prototypes */ -#define SERVER_PLUGIN_PROTOS extern plugin_t *console_server_PluginInfo (void); - -/* Define this to the default sound output driver. */ -#define SND_OUTPUT_DEFAULT "win" - -/* list of sound output plugins */ -#define SND_OUTPUT_LIST {"snd_output_win", snd_output_win_PluginInfo},{0, 0} - -/* list of sound output prototypes */ -#define SND_OUTPUT_PROTOS extern plugin_t *snd_output_win_PluginInfo (void); - -/* list of sound render plugins */ -#define SND_RENDER_LIST {"snd_render_default", snd_render_default_PluginInfo},{0, 0} - -/* list of sound render prototypes */ -#define SND_RENDER_PROTOS extern plugin_t *snd_render_default_PluginInfo (void); - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -/* #undef STACK_DIRECTION */ - -/* Define this if you are building static plugins */ -#define STATIC_PLUGINS 1 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Define to 1 if your declares `struct tm'. */ -/* #undef TM_IN_SYS_TIME */ - -/* Define this if you want progs typechecking */ -/* #undef TYPECHECK_PROGS */ - -/* Define this if you want to use Intel assembly optimizations */ -/* #undef USE_INTEL_ASM */ - -/* Define if va_list is an array */ -/* #undef VA_LIST_IS_ARRAY */ - -/* Version number of package */ -#define VERSION "0.5.5-SVN" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define to 1 if the X Window System is missing or not being used. */ -/* #undef X_DISPLAY_MISSING */ - -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ -/* #undef YYTEXT_POINTER */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define curl_free() as free() if our version of curl lacks curl_free. */ -/* #undef curl_free */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#define inline __inline -/* #undef inline */ -#endif - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define strcasecmp as stricmp if you have one but not the other */ -#define strcasecmp stricmp - -/* new stuff, for VC2005 compatibility (phrosty) */ - -#define _CRT_SECURE_NO_WARNINGS -#define _CRT_NONSTDC_NO_WARNINGS - -/* used in qfcc. should #define to _ReturnAddress()? */ -#define __builtin_return_address(x) (0) - -#define _WIN32_WINNT 0x0500 -#define DIRECTINPUT_VERSION 0x0600 - -#define INITGUID - -#define snprintf _snprintf -#define strncasecmp strnicmp - -#define ssize_t ptrdiff_t -#define S_ISDIR(mode) (mode & _S_IFDIR) - -/* used in access() */ -#define R_OK 04 - -/* - disable silent conversion warnings for fixing later.. - - 4047: 'operator' : 'identifier1' differs in levels of indirection from 'identifier2' - 4244: 'argument' : conversion from 'type1' to 'type2', possible loss of data - 4267: 'var' : conversion from 'size_t' to 'type', possible loss of data (/Wp64 warning) - 4305: 'identifier' : truncation from 'type1' to 'type2' - 4311: 'variable' : pointer truncation from 'type' to 'type' (/Wp64 warning) - 4312: 'operation' : conversion from 'type1' to 'type2' of greater size (/Wp64 warning) -*/ -#pragma warning(disable:4047 4244 4267 4305 4311 4312) diff --git a/vc2008/models-sw/models-sw.vcproj b/vc2008/models-sw/models-sw.vcproj deleted file mode 100644 index e8aa3d541..000000000 --- a/vc2008/models-sw/models-sw.vcproj +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/models/models.vcproj b/vc2008/models/models.vcproj deleted file mode 100644 index cacad0007..000000000 --- a/vc2008/models/models.vcproj +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/modelsgl/modelsgl.vcproj b/vc2008/modelsgl/modelsgl.vcproj deleted file mode 100644 index 128903bd5..000000000 --- a/vc2008/modelsgl/modelsgl.vcproj +++ /dev/null @@ -1,522 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/net-main/net-main.vcproj b/vc2008/net-main/net-main.vcproj deleted file mode 100644 index 8f33ca46c..000000000 --- a/vc2008/net-main/net-main.vcproj +++ /dev/null @@ -1,488 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/net/net.vcproj b/vc2008/net/net.vcproj deleted file mode 100644 index b79e2718b..000000000 --- a/vc2008/net/net.vcproj +++ /dev/null @@ -1,474 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/nq-common/nq-common.vcproj b/vc2008/nq-common/nq-common.vcproj deleted file mode 100644 index f5e82ed15..000000000 --- a/vc2008/nq-common/nq-common.vcproj +++ /dev/null @@ -1,516 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/nq-sdl/nq-sdl.vcproj b/vc2008/nq-sdl/nq-sdl.vcproj deleted file mode 100644 index 73f38ada0..000000000 --- a/vc2008/nq-sdl/nq-sdl.vcproj +++ /dev/null @@ -1,556 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/nq-sdl32/nq-sdl32.vcproj b/vc2008/nq-sdl32/nq-sdl32.vcproj deleted file mode 100644 index 1e9ffcae2..000000000 --- a/vc2008/nq-sdl32/nq-sdl32.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/nq-server/nq-server.vcproj b/vc2008/nq-server/nq-server.vcproj deleted file mode 100644 index 202f9b6f2..000000000 --- a/vc2008/nq-server/nq-server.vcproj +++ /dev/null @@ -1,566 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/nq-sgl/nq-sgl.vcproj b/vc2008/nq-sgl/nq-sgl.vcproj deleted file mode 100644 index f6e9bc3b1..000000000 --- a/vc2008/nq-sgl/nq-sgl.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/nq-wgl/nq-wgl.vcproj b/vc2008/nq-wgl/nq-wgl.vcproj deleted file mode 100644 index 6453a12bd..000000000 --- a/vc2008/nq-wgl/nq-wgl.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/nq/nq.vcproj b/vc2008/nq/nq.vcproj deleted file mode 100644 index 220f0ff7a..000000000 --- a/vc2008/nq/nq.vcproj +++ /dev/null @@ -1,544 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/pak/pak.vcproj b/vc2008/pak/pak.vcproj deleted file mode 100644 index b5cd0bec8..000000000 --- a/vc2008/pak/pak.vcproj +++ /dev/null @@ -1,566 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfbsp/qfbsp.vcproj b/vc2008/qfbsp/qfbsp.vcproj deleted file mode 100644 index 97462b79e..000000000 --- a/vc2008/qfbsp/qfbsp.vcproj +++ /dev/null @@ -1,632 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfcc/FlexBison.rules b/vc2008/qfcc/FlexBison.rules deleted file mode 100644 index 0e4c1e3dc..000000000 --- a/vc2008/qfcc/FlexBison.rules +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfcc/qfcc.vcproj b/vc2008/qfcc/qfcc.vcproj deleted file mode 100644 index 59bc03f84..000000000 --- a/vc2008/qfcc/qfcc.vcproj +++ /dev/null @@ -1,965 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfclient/qfclient.vcproj b/vc2008/qfclient/qfclient.vcproj deleted file mode 100644 index 8739a5098..000000000 --- a/vc2008/qfclient/qfclient.vcproj +++ /dev/null @@ -1,626 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qflight/qflight.vcproj b/vc2008/qflight/qflight.vcproj deleted file mode 100644 index 3fc0ab1d6..000000000 --- a/vc2008/qflight/qflight.vcproj +++ /dev/null @@ -1,620 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfmodelgen/qfmodelgen.vcproj b/vc2008/qfmodelgen/qfmodelgen.vcproj deleted file mode 100644 index 893da110a..000000000 --- a/vc2008/qfmodelgen/qfmodelgen.vcproj +++ /dev/null @@ -1,578 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfprogs/qfprogs.vcproj b/vc2008/qfprogs/qfprogs.vcproj deleted file mode 100644 index 5141f8959..000000000 --- a/vc2008/qfprogs/qfprogs.vcproj +++ /dev/null @@ -1,590 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfserver/qfserver.vcproj b/vc2008/qfserver/qfserver.vcproj deleted file mode 100644 index 909324104..000000000 --- a/vc2008/qfserver/qfserver.vcproj +++ /dev/null @@ -1,672 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfvis/qfvis.vcproj b/vc2008/qfvis/qfvis.vcproj deleted file mode 100644 index 479049560..000000000 --- a/vc2008/qfvis/qfvis.vcproj +++ /dev/null @@ -1,588 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qfwavinfo/qfwavinfo.vcproj b/vc2008/qfwavinfo/qfwavinfo.vcproj deleted file mode 100644 index 40df9c014..000000000 --- a/vc2008/qfwavinfo/qfwavinfo.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qtv/qtv.vcproj b/vc2008/qtv/qtv.vcproj deleted file mode 100644 index 0e2bb2d4b..000000000 --- a/vc2008/qtv/qtv.vcproj +++ /dev/null @@ -1,594 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qw-client-sdl/qw-client-sdl.vcproj b/vc2008/qw-client-sdl/qw-client-sdl.vcproj deleted file mode 100644 index 983be0451..000000000 --- a/vc2008/qw-client-sdl/qw-client-sdl.vcproj +++ /dev/null @@ -1,558 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qw-client-sdl32/qw-client-sdl32.vcproj b/vc2008/qw-client-sdl32/qw-client-sdl32.vcproj deleted file mode 100644 index 33a31293d..000000000 --- a/vc2008/qw-client-sdl32/qw-client-sdl32.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qw-client-sgl/qw-client-sgl.vcproj b/vc2008/qw-client-sgl/qw-client-sgl.vcproj deleted file mode 100644 index 2842872d1..000000000 --- a/vc2008/qw-client-sgl/qw-client-sgl.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qw-client-wgl/qw-client-wgl.vcproj b/vc2008/qw-client-wgl/qw-client-wgl.vcproj deleted file mode 100644 index 0a2c37256..000000000 --- a/vc2008/qw-client-wgl/qw-client-wgl.vcproj +++ /dev/null @@ -1,558 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qw-master/qw-master.vcproj b/vc2008/qw-master/qw-master.vcproj deleted file mode 100644 index 4d7961feb..000000000 --- a/vc2008/qw-master/qw-master.vcproj +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/qw/qw.vcproj b/vc2008/qw/qw.vcproj deleted file mode 100644 index e5cb0be82..000000000 --- a/vc2008/qw/qw.vcproj +++ /dev/null @@ -1,474 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/readme.txt b/vc2008/readme.txt deleted file mode 100644 index b4ad78741..000000000 --- a/vc2008/readme.txt +++ /dev/null @@ -1,25 +0,0 @@ -Requirements -============= -- Visual C++ 2008 SP1 -- DirectX SDK (for DirectInput) -- SDL (required for sdl, sdl32, and sgl builds) -- bison/flex (required for qfcc, needs to be in your compiler path) - -Optional -========= -- zlib (#undef HAVE_ZLIB from vc2008/include/config.h if you don't want - this). Expects zlib.lib and zlib.dll for Debug/Release builds, and - libzlib.lib for Release (static) build. -- libcurl (#undef HAVE_LIBCURL from vc2008/include/config.h if you don't - want this). Expects curl.lib and curl.dll for Debug/Release builds, - and libcurl.lib for Release (static) build. - -Notes -====== -By default, qfcc is configured to use the Boost Wave preprocessor. You -can get this from http://www.boost.org, or change the CPP_NAME #define in -vc2008/include/config.h to whatever preprocessor you want. If you have -GCC, you can simply replace "wave --c99" with "gcc" in the define and it -should work. - -clean.ps1 is a Windows Powershell script that cleans up any build files. diff --git a/vc2008/ruamoko/ruamoko.vcproj b/vc2008/ruamoko/ruamoko.vcproj deleted file mode 100644 index 924c02f7c..000000000 --- a/vc2008/ruamoko/ruamoko.vcproj +++ /dev/null @@ -1,518 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/sound/sound.vcproj b/vc2008/sound/sound.vcproj deleted file mode 100644 index fe681171d..000000000 --- a/vc2008/sound/sound.vcproj +++ /dev/null @@ -1,514 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/util/util.vcproj b/vc2008/util/util.vcproj deleted file mode 100644 index e680f491d..000000000 --- a/vc2008/util/util.vcproj +++ /dev/null @@ -1,618 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/video-sdl/video-sdl.vcproj b/vc2008/video-sdl/video-sdl.vcproj deleted file mode 100644 index 2b03f2566..000000000 --- a/vc2008/video-sdl/video-sdl.vcproj +++ /dev/null @@ -1,472 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/video-sgl/video-sgl.vcproj b/vc2008/video-sgl/video-sgl.vcproj deleted file mode 100644 index 920a06e47..000000000 --- a/vc2008/video-sgl/video-sgl.vcproj +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/video-sw/video-sw.vcproj b/vc2008/video-sw/video-sw.vcproj deleted file mode 100644 index 75f419ae0..000000000 --- a/vc2008/video-sw/video-sw.vcproj +++ /dev/null @@ -1,596 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/video-sw32/video-sw32.vcproj b/vc2008/video-sw32/video-sw32.vcproj deleted file mode 100644 index fc6bc6054..000000000 --- a/vc2008/video-sw32/video-sw32.vcproj +++ /dev/null @@ -1,572 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/video-wgl/video-wgl.vcproj b/vc2008/video-wgl/video-wgl.vcproj deleted file mode 100644 index a0b315c7c..000000000 --- a/vc2008/video-wgl/video-wgl.vcproj +++ /dev/null @@ -1,472 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/video/video.vcproj b/vc2008/video/video.vcproj deleted file mode 100644 index 737ecfe59..000000000 --- a/vc2008/video/video.vcproj +++ /dev/null @@ -1,538 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/videogl/videogl.vcproj b/vc2008/videogl/videogl.vcproj deleted file mode 100644 index 44d30c3fc..000000000 --- a/vc2008/videogl/videogl.vcproj +++ /dev/null @@ -1,556 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vc2008/wad/wad.vcproj b/vc2008/wad/wad.vcproj deleted file mode 100644 index 11fc5737d..000000000 --- a/vc2008/wad/wad.vcproj +++ /dev/null @@ -1,574 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -