diff --git a/engine/sw/adivtab.h b/engine/sw/adivtab.h new file mode 100644 index 000000000..5d556e4b0 --- /dev/null +++ b/engine/sw/adivtab.h @@ -0,0 +1,1074 @@ +/* +Copyright (C) 1999, 2000 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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +// table of quotients and remainders for [-15...16] / [-15...16] + +// numerator = -15 +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{1, -7}, +{2, -1}, +{2, -3}, +{3, 0}, +{3, -3}, +{5, 0}, +{7, -1}, +{15, 0}, +{0, 0}, +{-15, 0}, +{-8, 1}, +{-5, 0}, +{-4, 1}, +{-3, 0}, +{-3, 3}, +{-3, 6}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-2, 11}, +{-2, 13}, +{-1, 0}, +{-1, 1}, +// numerator = -14 +{0, -14}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{2, 0}, +{2, -2}, +{2, -4}, +{3, -2}, +{4, -2}, +{7, 0}, +{14, 0}, +{0, 0}, +{-14, 0}, +{-7, 0}, +{-5, 1}, +{-4, 2}, +{-3, 1}, +{-3, 4}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-2, 10}, +{-2, 12}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +// numerator = -13 +{0, -13}, +{0, -13}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{2, -1}, +{2, -3}, +{3, -1}, +{4, -1}, +{6, -1}, +{13, 0}, +{0, 0}, +{-13, 0}, +{-7, 1}, +{-5, 2}, +{-4, 3}, +{-3, 2}, +{-3, 5}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-2, 11}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +// numerator = -12 +{0, -12}, +{0, -12}, +{0, -12}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{2, 0}, +{2, -2}, +{3, 0}, +{4, 0}, +{6, 0}, +{12, 0}, +{0, 0}, +{-12, 0}, +{-6, 0}, +{-4, 0}, +{-3, 0}, +{-3, 3}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-2, 10}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +// numerator = -11 +{0, -11}, +{0, -11}, +{0, -11}, +{0, -11}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{2, -1}, +{2, -3}, +{3, -2}, +{5, -1}, +{11, 0}, +{0, 0}, +{-11, 0}, +{-6, 1}, +{-4, 1}, +{-3, 1}, +{-3, 4}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +// numerator = -10 +{0, -10}, +{0, -10}, +{0, -10}, +{0, -10}, +{0, -10}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{2, 0}, +{2, -2}, +{3, -1}, +{5, 0}, +{10, 0}, +{0, 0}, +{-10, 0}, +{-5, 0}, +{-4, 2}, +{-3, 2}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +// numerator = -9 +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{2, -1}, +{3, 0}, +{4, -1}, +{9, 0}, +{0, 0}, +{-9, 0}, +{-5, 1}, +{-3, 0}, +{-3, 3}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +// numerator = -8 +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{2, 0}, +{2, -2}, +{4, 0}, +{8, 0}, +{0, 0}, +{-8, 0}, +{-4, 0}, +{-3, 1}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +// numerator = -7 +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{2, -1}, +{3, -1}, +{7, 0}, +{0, 0}, +{-7, 0}, +{-4, 1}, +{-3, 2}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +// numerator = -6 +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{1, 0}, +{1, -1}, +{1, -2}, +{2, 0}, +{3, 0}, +{6, 0}, +{0, 0}, +{-6, 0}, +{-3, 0}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +// numerator = -5 +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{1, 0}, +{1, -1}, +{1, -2}, +{2, -1}, +{5, 0}, +{0, 0}, +{-5, 0}, +{-3, 1}, +{-2, 1}, +{-2, 3}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +// numerator = -4 +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{1, 0}, +{1, -1}, +{2, 0}, +{4, 0}, +{0, 0}, +{-4, 0}, +{-2, 0}, +{-2, 2}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +// numerator = -3 +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{1, 0}, +{1, -1}, +{3, 0}, +{0, 0}, +{-3, 0}, +{-2, 1}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +// numerator = -2 +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{1, 0}, +{2, 0}, +{0, 0}, +{-2, 0}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +{-1, 14}, +// numerator = -1 +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{1, 0}, +{0, 0}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +{-1, 14}, +{-1, 15}, +// numerator = 0 +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +// numerator = 1 +{-1, -14}, +{-1, -13}, +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{0, 0}, +{1, 0}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +// numerator = 2 +{-1, -13}, +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, 0}, +{0, 0}, +{2, 0}, +{1, 0}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +// numerator = 3 +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -1}, +{-3, 0}, +{0, 0}, +{3, 0}, +{1, 1}, +{1, 0}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +// numerator = 4 +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -2}, +{-2, 0}, +{-4, 0}, +{0, 0}, +{4, 0}, +{2, 0}, +{1, 1}, +{1, 0}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +// numerator = 5 +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -3}, +{-2, -1}, +{-3, -1}, +{-5, 0}, +{0, 0}, +{5, 0}, +{2, 1}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +// numerator = 6 +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, 0}, +{-6, 0}, +{0, 0}, +{6, 0}, +{3, 0}, +{2, 0}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +// numerator = 7 +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -2}, +{-4, -1}, +{-7, 0}, +{0, 0}, +{7, 0}, +{3, 1}, +{2, 1}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +// numerator = 8 +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -1}, +{-4, 0}, +{-8, 0}, +{0, 0}, +{8, 0}, +{4, 0}, +{2, 2}, +{2, 0}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +// numerator = 9 +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -3}, +{-3, 0}, +{-5, -1}, +{-9, 0}, +{0, 0}, +{9, 0}, +{4, 1}, +{3, 0}, +{2, 1}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +// numerator = 10 +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -2}, +{-4, -2}, +{-5, 0}, +{-10, 0}, +{0, 0}, +{10, 0}, +{5, 0}, +{3, 1}, +{2, 2}, +{2, 0}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +// numerator = 11 +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -4}, +{-3, -1}, +{-4, -1}, +{-6, -1}, +{-11, 0}, +{0, 0}, +{11, 0}, +{5, 1}, +{3, 2}, +{2, 3}, +{2, 1}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 11}, +{0, 11}, +{0, 11}, +{0, 11}, +{0, 11}, +// numerator = 12 +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -3}, +{-3, 0}, +{-4, 0}, +{-6, 0}, +{-12, 0}, +{0, 0}, +{12, 0}, +{6, 0}, +{4, 0}, +{3, 0}, +{2, 2}, +{2, 0}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 12}, +{0, 12}, +{0, 12}, +{0, 12}, +// numerator = 13 +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -11}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -5}, +{-3, -2}, +{-4, -3}, +{-5, -2}, +{-7, -1}, +{-13, 0}, +{0, 0}, +{13, 0}, +{6, 1}, +{4, 1}, +{3, 1}, +{2, 3}, +{2, 1}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 13}, +{0, 13}, +{0, 13}, +// numerator = 14 +{-1, -1}, +{-1, 0}, +{-2, -12}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -4}, +{-3, -1}, +{-4, -2}, +{-5, -1}, +{-7, 0}, +{-14, 0}, +{0, 0}, +{14, 0}, +{7, 0}, +{4, 2}, +{3, 2}, +{2, 4}, +{2, 2}, +{2, 0}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 14}, +{0, 14}, +// numerator = 15 +{-1, 0}, +{-2, -13}, +{-2, -11}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -6}, +{-3, -3}, +{-3, 0}, +{-4, -1}, +{-5, 0}, +{-8, -1}, +{-15, 0}, +{0, 0}, +{15, 0}, +{7, 1}, +{5, 0}, +{3, 3}, +{3, 0}, +{2, 3}, +{2, 1}, +{1, 7}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 15}, +// numerator = 16 +{-2, -14}, +{-2, -12}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -5}, +{-3, -2}, +{-4, -4}, +{-4, 0}, +{-6, -2}, +{-8, 0}, +{-16, 0}, +{0, 0}, +{16, 0}, +{8, 0}, +{5, 1}, +{4, 0}, +{3, 1}, +{2, 4}, +{2, 2}, +{2, 0}, +{1, 7}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, diff --git a/engine/sw/asm_draw.h b/engine/sw/asm_draw.h new file mode 100644 index 000000000..6adc6897d --- /dev/null +++ b/engine/sw/asm_draw.h @@ -0,0 +1,154 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// asm_draw.h +// +// Include file for asm drawing routines. +// + +// +// !!! note that this file must match the corresponding C structures at all +// times !!! +// + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define NEAR_CLIP 0.01 + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define CYCLE 128 + +// espan_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define espan_t_u 0 +#define espan_t_v 4 +#define espan_t_count 8 +#define espan_t_pnext 12 +#define espan_t_size 16 + +// sspan_t structure +// !!! if this is changed, it must be changed in d_local.h too !!! +#define sspan_t_u 0 +#define sspan_t_v 4 +#define sspan_t_count 8 +#define sspan_t_size 12 + +// spanpackage_t structure +// !!! if this is changed, it must be changed in d_polyset.c too !!! +#define spanpackage_t_pdest 0 +#define spanpackage_t_pz 4 +#define spanpackage_t_count 8 +#define spanpackage_t_ptex 12 +#define spanpackage_t_sfrac 16 +#define spanpackage_t_tfrac 20 +#define spanpackage_t_light 24 +#define spanpackage_t_zi 28 +#define spanpackage_t_size 32 + +// edge_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define et_u 0 +#define et_u_step 4 +#define et_prev 8 +#define et_next 12 +#define et_surfs 16 +#define et_nextremove 20 +#define et_nearzi 24 +#define et_owner 28 +#define et_size 32 + +// surf_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define SURF_T_SHIFT 6 +#define st_next 0 +#define st_prev 4 +#define st_spans 8 +#define st_key 12 +#define st_last_u 16 +#define st_spanstate 20 +#define st_flags 24 +#define st_data 28 +#define st_entity 32 +#define st_nearzi 36 +#define st_insubmodel 40 +#define st_d_ziorigin 44 +#define st_d_zistepu 48 +#define st_d_zistepv 52 +#define st_pad 56 +#define st_size 64 + +// clipplane_t structure +// !!! if this is changed, it must be changed in r_local.h too !!! +#define cp_normal 0 +#define cp_dist 12 +#define cp_next 16 +#define cp_leftedge 20 +#define cp_rightedge 21 +#define cp_reserved 22 +#define cp_size 24 + +// medge_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define me_v 0 +#define me_cachededgeoffset 4 +#define me_size 8 + +// mvertex_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mv_position 0 +#define mv_size 12 + +// refdef_t structure +// !!! if this is changed, it must be changed in render.h too !!! +#define rd_vrect 0 +#define rd_aliasvrect 20 +#define rd_vrectright 40 +#define rd_vrectbottom 44 +#define rd_aliasvrectright 48 +#define rd_aliasvrectbottom 52 +#define rd_vrectrightedge 56 +#define rd_fvrectx 60 +#define rd_fvrecty 64 +#define rd_fvrectx_adj 68 +#define rd_fvrecty_adj 72 +#define rd_vrect_x_adj_shift20 76 +#define rd_vrectright_adj_shift20 80 +#define rd_fvrectright_adj 84 +#define rd_fvrectbottom_adj 88 +#define rd_fvrectright 92 +#define rd_fvrectbottom 96 +#define rd_horizontalFieldOfView 100 +#define rd_xOrigin 104 +#define rd_yOrigin 108 +#define rd_vieworg 112 +#define rd_viewangles 124 +#define rd_ambientlight 136 +#define rd_flags 140 +#define rd_currentplayernum 144 +#define rd_size 148 + +// mtriangle_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mtri_facesfront 0 +#define mtri_vertindex 4 +#define mtri_stindex 16 +#define mtri_size 28 // !!! if this changes, array indexing in !!! + // !!! d_polysa.s must be changed to match !!! +#define mtri_shift 4 + diff --git a/engine/sw/block16.h b/engine/sw/block16.h new file mode 100644 index 000000000..98a1cf707 --- /dev/null +++ b/engine/sw/block16.h @@ -0,0 +1,123 @@ +LEnter16_16: + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch0: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch1: + movw %cx,2(%edi) + addl $0x4,%edi + + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch2: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch3: + movw %cx,2(%edi) + addl $0x4,%edi + + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch4: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch5: + movw %cx,2(%edi) + addl $0x4,%edi + + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch6: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch7: + movw %cx,2(%edi) + addl $0x4,%edi + +LEnter8_16: + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch8: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch9: + movw %cx,2(%edi) + addl $0x4,%edi + + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch10: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch11: + movw %cx,2(%edi) + addl $0x4,%edi + +LEnter4_16: + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch12: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch13: + movw %cx,2(%edi) + addl $0x4,%edi + +LEnter2_16: + movb (%esi),%al + movb (%esi,%ebx,),%cl + movb %dh,%ah + addl %ebp,%edx + movb %dh,%ch + leal (%esi,%ebx,2),%esi + movw 0x12345678(,%eax,2),%ax +LBPatch14: + addl %ebp,%edx + movw %ax,(%edi) + movw 0x12345678(,%ecx,2),%cx +LBPatch15: + movw %cx,2(%edi) + addl $0x4,%edi diff --git a/engine/sw/d_draw.s b/engine/sw/d_draw.s new file mode 100644 index 000000000..f0a6e2aaf --- /dev/null +++ b/engine/sw/d_draw.s @@ -0,0 +1,1037 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// d_draw.s +// x86 assembly-language horizontal 8-bpp span-drawing code. +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" +#include "d_ifacea.h" + +#if id386 + +//---------------------------------------------------------------------- +// 8-bpp horizontal span drawing code for polygons, with no transparency. +// +// Assumes there is at least one span in pspans, and that every span +// contains at least one pixel +//---------------------------------------------------------------------- + + .text + +// out-of-line, rarely-needed clamping code + +LClampHigh0: + movl C(bbextents),%esi + jmp LClampReentry0 +LClampHighOrLow0: + jg LClampHigh0 + xorl %esi,%esi + jmp LClampReentry0 + +LClampHigh1: + movl C(bbextentt),%edx + jmp LClampReentry1 +LClampHighOrLow1: + jg LClampHigh1 + xorl %edx,%edx + jmp LClampReentry1 + +LClampLow2: + movl $2048,%ebp + jmp LClampReentry2 +LClampHigh2: + movl C(bbextents),%ebp + jmp LClampReentry2 + +LClampLow3: + movl $2048,%ecx + jmp LClampReentry3 +LClampHigh3: + movl C(bbextentt),%ecx + jmp LClampReentry3 + +LClampLow4: + movl $2048,%eax + jmp LClampReentry4 +LClampHigh4: + movl C(bbextents),%eax + jmp LClampReentry4 + +LClampLow5: + movl $2048,%ebx + jmp LClampReentry5 +LClampHigh5: + movl C(bbextentt),%ebx + jmp LClampReentry5 + + +#define pspans 4+16 + + .align 4 +.globl C(D_DrawSpans8) +C(D_DrawSpans8): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// +// set up scaled-by-8 steps, for 8-long segments; also set up cacheblock +// and span list pointers +// +// TODO: any overlap from rearranging? + flds C(d_sdivzstepu) + fmuls fp_8 + movl C(cacheblock),%edx + flds C(d_tdivzstepu) + fmuls fp_8 + movl pspans(%esp),%ebx // point to the first span descriptor + flds C(d_zistepu) + fmuls fp_8 + movl %edx,pbase // pbase = cacheblock + fstps zi8stepu + fstps tdivz8stepu + fstps sdivz8stepu + +LSpanLoop: +// +// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the +// initial s and t values +// +// FIXME: pipeline FILD? + fildl espan_t_v(%ebx) + fildl espan_t_u(%ebx) + + fld %st(1) // dv | du | dv + fmuls C(d_sdivzstepv) // dv*d_sdivzstepv | du | dv + fld %st(1) // du | dv*d_sdivzstepv | du | dv + fmuls C(d_sdivzstepu) // du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fld %st(2) // du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fmuls C(d_tdivzstepu) // du*d_tdivzstepu | du*d_sdivzstepu | + // dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu | du*d_tdivzstepu | + // dv*d_sdivzstepv | du | dv + faddp %st(0),%st(2) // du*d_tdivzstepu | + // du*d_sdivzstepu + dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fld %st(3) // dv | du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fmuls C(d_tdivzstepv) // dv*d_tdivzstepv | + // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // dv*d_tdivzstepv | du*d_tdivzstepu | du | dv + fadds C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv + + // du*d_sdivzstepu; stays in %st(2) at end + fxch %st(4) // dv | dv*d_tdivzstepv | du*d_tdivzstepu | du | + // s/z + fmuls C(d_zistepv) // dv*d_zistepv | dv*d_tdivzstepv | + // du*d_tdivzstepu | du | s/z + fxch %st(1) // dv*d_tdivzstepv | dv*d_zistepv | + // du*d_tdivzstepu | du | s/z + faddp %st(0),%st(2) // dv*d_zistepv | + // dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z + fxch %st(2) // du | dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fmuls C(d_zistepu) // du*d_zistepu | + // dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fxch %st(1) // dv*d_tdivzstepv + du*d_tdivzstepu | + // du*d_zistepu | dv*d_zistepv | s/z + fadds C(d_tdivzorigin) // tdivz = d_tdivzorigin + dv*d_tdivzstepv + + // du*d_tdivzstepu; stays in %st(1) at end + fxch %st(2) // dv*d_zistepv | du*d_zistepu | t/z | s/z + faddp %st(0),%st(1) // dv*d_zistepv + du*d_zistepu | t/z | s/z + + flds fp_64k // fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z + fxch %st(1) // dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z + fadds C(d_ziorigin) // zi = d_ziorigin + dv*d_zistepv + + // du*d_zistepu; stays in %st(0) at end + // 1/z | fp_64k | t/z | s/z +// +// calculate and clamp s & t +// + fdivr %st(0),%st(1) // 1/z | z*64k | t/z | s/z + +// +// point %edi to the first pixel in the span +// + movl C(d_viewbuffer),%ecx + movl espan_t_v(%ebx),%eax + movl %ebx,pspantemp // preserve spans pointer + + movl C(tadjust),%edx + movl C(sadjust),%esi + movl C(d_scantable)(,%eax,4),%edi // v * screenwidth + addl %ecx,%edi + movl espan_t_u(%ebx),%ecx + addl %ecx,%edi // pdest = &pdestspan[scans->u]; + movl espan_t_count(%ebx),%ecx + +// +// now start the FDIV for the end of the span +// + cmpl $8,%ecx + ja LSetupNotLast1 + + decl %ecx + jz LCleanup1 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fildl spancountminus1 + + flds C(d_tdivzstepu) // C(d_tdivzstepu) | spancountminus1 + flds C(d_zistepu) // C(d_zistepu) | C(d_tdivzstepu) | spancountminus1 + fmul %st(2),%st(0) // C(d_zistepu)*scm1 | C(d_tdivzstepu) | scm1 + fxch %st(1) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch %st(2) // scm1 | C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 + fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_zistepu)*scm1 | + // C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_zistepu)*scm1 | C(d_sdivzstepu)*scm1 | + // C(d_tdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) + + flds fp_64k + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight1 + +LCleanup1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + jmp LFDIVInFlight1 + + .align 4 +LSetupNotLast1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fadds zi8stepu + fxch %st(2) + fadds sdivz8stepu + fxch %st(2) + flds tdivz8stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight1: + + addl s,%esi + addl t,%edx + movl C(bbextents),%ebx + movl C(bbextentt),%ebp + cmpl %ebx,%esi + ja LClampHighOrLow0 +LClampReentry0: + movl %esi,s + movl pbase,%ebx + shll $16,%esi + cmpl %ebp,%edx + movl %esi,sfracf + ja LClampHighOrLow1 +LClampReentry1: + movl %edx,t + movl s,%esi // sfrac = scans->sfrac; + shll $16,%edx + movl t,%eax // tfrac = scans->tfrac; + sarl $16,%esi + movl %edx,tfracf + +// +// calculate the texture starting address +// + sarl $16,%eax + movl C(cachewidth),%edx + imull %edx,%eax // (tfrac >> 16) * cachewidth + addl %ebx,%esi + addl %eax,%esi // psource = pbase + (sfrac >> 16) + + // ((tfrac >> 16) * cachewidth); + +// +// determine whether last span or not +// + cmpl $8,%ecx + jna LLastSegment + +// +// not the last segment; do full 8-wide segment +// +LNotLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there +// + +// pick up after the FDIV that was left in flight previously + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + movl snext,%eax + movl tnext,%edx + + movb (%esi),%bl // get first source texel + subl $8,%ecx // count off this segments' pixels + movl C(sadjust),%ebp + movl %ecx,counttemp // remember count of remaining pixels + + movl C(tadjust),%ecx + movb %bl,(%edi) // store first dest pixel + + addl %eax,%ebp + addl %edx,%ecx + + movl C(bbextents),%eax + movl C(bbextentt),%edx + + cmpl $2048,%ebp + jl LClampLow2 + cmpl %eax,%ebp + ja LClampHigh2 +LClampReentry2: + + cmpl $2048,%ecx + jl LClampLow3 + cmpl %edx,%ecx + ja LClampHigh3 +LClampReentry3: + + movl %ebp,snext + movl %ecx,tnext + + subl s,%ebp + subl t,%ecx + +// +// set up advancetable +// + movl %ecx,%eax + movl %ebp,%edx + sarl $19,%eax // tstep >>= 16; + jz LZero + sarl $19,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + imull %ebx,%eax + jmp LSetUp1 + +LZero: + sarl $19,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + +LSetUp1: + + addl %edx,%eax // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%edx + movl %eax,advancetable+4 // advance base in t + addl %ebx,%eax // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $13,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $13,%ecx // left-justify tstep fractional part + movl %eax,advancetable // advance extra in t + + movl %ecx,tstep + addl %ecx,%edx // advance tfrac fractional part by tstep frac + + sbbl %ecx,%ecx // turn tstep carry into -1 (0 if none) + addl %ebp,%ebx // advance sfrac fractional part by sstep frac + adcl advancetable+4(,%ecx,4),%esi // point to next source texel + + addl tstep,%edx + sbbl %ecx,%ecx + movb (%esi),%al + addl %ebp,%ebx + movb %al,1(%edi) + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,2(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,3(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + +// +// start FDIV for end of next segment in flight, so it can overlap +// + movl counttemp,%ecx + cmpl $8,%ecx // more than one segment after this? + ja LSetupNotLast2 // yes + + decl %ecx + jz LFDIVInFlight2 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + fildl spancountminus1 + + flds C(d_zistepu) // C(d_zistepu) | spancountminus1 + fmul %st(1),%st(0) // C(d_zistepu)*scm1 | scm1 + flds C(d_tdivzstepu) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch %st(1) // C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 | scm1 + faddp %st(0),%st(3) // C(d_tdivzstepu)*scm1 | scm1 + fxch %st(1) // scm1 | C(d_tdivzstepu)*scm1 + fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 + flds fp_64k // 64k | C(d_sdivzstepu)*scm1 + fxch %st(1) // C(d_sdivzstepu)*scm1 | 64k + faddp %st(0),%st(4) // 64k + + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight2 + + .align 4 +LSetupNotLast2: + fadds zi8stepu + fxch %st(2) + fadds sdivz8stepu + fxch %st(2) + flds tdivz8stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight2: + movl %ecx,counttemp + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,4(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,5(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,6(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl $8,%edi + movl %edx,tfracf + movl snext,%edx + movl %ebx,sfracf + movl tnext,%ebx + movl %edx,s + movl %ebx,t + + movl counttemp,%ecx // retrieve count + +// +// determine whether last span or not +// + cmpl $8,%ecx // are there multiple segments remaining? + movb %al,-1(%edi) + ja LNotLastSegment // yes + +// +// last segment of scan +// +LLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there. The number of pixels left is variable, and we want to land on the +// last pixel, not step one past it, so we can't run into arithmetic problems +// + testl %ecx,%ecx + jz LNoSteps // just draw the last pixel and we're done + +// pick up after the FDIV that was left in flight previously + + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + + movb (%esi),%al // load first texel in segment + movl C(tadjust),%ebx + movb %al,(%edi) // store first pixel in segment + movl C(sadjust),%eax + + addl snext,%eax + addl tnext,%ebx + + movl C(bbextents),%ebp + movl C(bbextentt),%edx + + cmpl $2048,%eax + jl LClampLow4 + cmpl %ebp,%eax + ja LClampHigh4 +LClampReentry4: + movl %eax,snext + + cmpl $2048,%ebx + jl LClampLow5 + cmpl %edx,%ebx + ja LClampHigh5 +LClampReentry5: + + cmpl $1,%ecx // don't bother + je LOnlyOneStep // if two pixels in segment, there's only one step, + // of the segment length + subl s,%eax + subl t,%ebx + + addl %eax,%eax // convert to 15.17 format so multiply by 1.31 + addl %ebx,%ebx // reciprocal yields 16.48 + + imull reciprocal_table-8(,%ecx,4) // sstep = (snext - s) / (spancount-1) + movl %edx,%ebp + + movl %ebx,%eax + imull reciprocal_table-8(,%ecx,4) // tstep = (tnext - t) / (spancount-1) + +LSetEntryvec: +// +// set up advancetable +// + movl entryvec_table(,%ecx,4),%ebx + movl %edx,%eax + movl %ebx,jumptemp // entry point into code for RET later + movl %ebp,%ecx + sarl $16,%edx // tstep >>= 16; + movl C(cachewidth),%ebx + sarl $16,%ecx // sstep >>= 16; + imull %ebx,%edx + + addl %ecx,%edx // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%ecx + movl %edx,advancetable+4 // advance base in t + addl %ebx,%edx // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $16,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $16,%eax // left-justify tstep fractional part + movl %edx,advancetable // advance extra in t + + movl %eax,tstep + movl %ecx,%edx + addl %eax,%edx + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + + jmp *jumptemp // jump to the number-of-pixels handler + +//---------------------------------------- + +LNoSteps: + movb (%esi),%al // load first texel in segment + subl $7,%edi // adjust for hardwired offset + jmp LEndSpan + + +LOnlyOneStep: + subl s,%eax + subl t,%ebx + movl %eax,%ebp + movl %ebx,%edx + jmp LSetEntryvec + +//---------------------------------------- + +.globl Entry2_8 +Entry2_8: + subl $6,%edi // adjust for hardwired offsets + movb (%esi),%al + jmp LLEntry2_8 + +//---------------------------------------- + +.globl Entry3_8 +Entry3_8: + subl $5,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + jmp LLEntry3_8 + +//---------------------------------------- + +.globl Entry4_8 +Entry4_8: + subl $4,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LLEntry4_8 + +//---------------------------------------- + +.globl Entry5_8 +Entry5_8: + subl $3,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LLEntry5_8 + +//---------------------------------------- + +.globl Entry6_8 +Entry6_8: + subl $2,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LLEntry6_8 + +//---------------------------------------- + +.globl Entry7_8 +Entry7_8: + decl %edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LLEntry7_8 + +//---------------------------------------- + +.globl Entry8_8 +Entry8_8: + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,1(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LLEntry7_8: + sbbl %ecx,%ecx + movb %al,2(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LLEntry6_8: + sbbl %ecx,%ecx + movb %al,3(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LLEntry5_8: + sbbl %ecx,%ecx + movb %al,4(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LLEntry4_8: + sbbl %ecx,%ecx + movb %al,5(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi +LLEntry3_8: + movb %al,6(%edi) + movb (%esi),%al +LLEntry2_8: + +LEndSpan: + +// +// clear s/z, t/z, 1/z from FP stack +// + fstp %st(0) + fstp %st(0) + fstp %st(0) + + movl pspantemp,%ebx // restore spans pointer + movl espan_t_pnext(%ebx),%ebx // point to next span + testl %ebx,%ebx // any more spans? + movb %al,7(%edi) + jnz LSpanLoop // more spans + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +//---------------------------------------------------------------------- +// 8-bpp horizontal span z drawing codefor polygons, with no transparency. +// +// Assumes there is at least one span in pzspans, and that every span +// contains at least one pixel +//---------------------------------------------------------------------- + + .text + +// z-clamp on a non-negative gradient span +LClamp: + movl $0x40000000,%edx + xorl %ebx,%ebx + fstp %st(0) + jmp LZDraw + +// z-clamp on a negative gradient span +LClampNeg: + movl $0x40000000,%edx + xorl %ebx,%ebx + fstp %st(0) + jmp LZDrawNeg + + +#define pzspans 4+16 + +.globl C(D_DrawZSpans) +C(D_DrawZSpans): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + + flds C(d_zistepu) + movl C(d_zistepu),%eax + movl pzspans(%esp),%esi + testl %eax,%eax + jz LFNegSpan + + fmuls Float2ToThe31nd + fistpl izistep // note: we are relying on FP exceptions being turned + // off here to avoid range problems + movl izistep,%ebx // remains loaded for all spans + +LFSpanLoop: +// set up the initial 1/z value + fildl espan_t_v(%esi) + fildl espan_t_u(%esi) + movl espan_t_v(%esi),%ecx + movl C(d_pzbuffer),%edi + fmuls C(d_zistepu) + fxch %st(1) + fmuls C(d_zistepv) + fxch %st(1) + fadds C(d_ziorigin) + imull C(d_zrowbytes),%ecx + faddp %st(0),%st(1) + +// clamp if z is nearer than 2 (1/z > 0.5) + fcoms float_point5 + addl %ecx,%edi + movl espan_t_u(%esi),%edx + addl %edx,%edx // word count + movl espan_t_count(%esi),%ecx + addl %edx,%edi // pdest = &pdestspan[scans->u]; + pushl %esi // preserve spans pointer + fnstsw %ax + testb $0x45,%ah + jz LClamp + + fmuls Float2ToThe31nd + fistpl izi // note: we are relying on FP exceptions being turned + // off here to avoid problems when the span is closer + // than 1/(2**31) + movl izi,%edx + +// at this point: +// %ebx = izistep +// %ecx = count +// %edx = izi +// %edi = pdest + +LZDraw: + +// do a single pixel up front, if necessary to dword align the destination + testl $2,%edi + jz LFMiddle + movl %edx,%eax + addl %ebx,%edx + shrl $16,%eax + decl %ecx + movw %ax,(%edi) + addl $2,%edi + +// do middle a pair of aligned dwords at a time +LFMiddle: + pushl %ecx + shrl $1,%ecx // count / 2 + jz LFLast // no aligned dwords to do + shrl $1,%ecx // (count / 2) / 2 + jnc LFMiddleLoop // even number of aligned dwords to do + + movl %edx,%eax + addl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + addl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %eax,(%edi) + addl $4,%edi + andl %ecx,%ecx + jz LFLast + +LFMiddleLoop: + movl %edx,%eax + addl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + addl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %edx,%ebp + movl %eax,(%edi) + addl %ebx,%edx + shrl $16,%ebp + movl %edx,%esi + addl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%ebp + movl %ebp,4(%edi) // FIXME: eliminate register contention + addl $8,%edi + + decl %ecx + jnz LFMiddleLoop + +LFLast: + popl %ecx // retrieve count + popl %esi // retrieve span pointer + +// do the last, unaligned pixel, if there is one + andl $1,%ecx // is there an odd pixel left to do? + jz LFSpanDone // no + shrl $16,%edx + movw %dx,(%edi) // do the final pixel's z + +LFSpanDone: + movl espan_t_pnext(%esi),%esi + testl %esi,%esi + jnz LFSpanLoop + + jmp LFDone + +LFNegSpan: + fmuls FloatMinus2ToThe31nd + fistpl izistep // note: we are relying on FP exceptions being turned + // off here to avoid range problems + movl izistep,%ebx // remains loaded for all spans + +LFNegSpanLoop: +// set up the initial 1/z value + fildl espan_t_v(%esi) + fildl espan_t_u(%esi) + movl espan_t_v(%esi),%ecx + movl C(d_pzbuffer),%edi + fmuls C(d_zistepu) + fxch %st(1) + fmuls C(d_zistepv) + fxch %st(1) + fadds C(d_ziorigin) + imull C(d_zrowbytes),%ecx + faddp %st(0),%st(1) + +// clamp if z is nearer than 2 (1/z > 0.5) + fcoms float_point5 + addl %ecx,%edi + movl espan_t_u(%esi),%edx + addl %edx,%edx // word count + movl espan_t_count(%esi),%ecx + addl %edx,%edi // pdest = &pdestspan[scans->u]; + pushl %esi // preserve spans pointer + fnstsw %ax + testb $0x45,%ah + jz LClampNeg + + fmuls Float2ToThe31nd + fistpl izi // note: we are relying on FP exceptions being turned + // off here to avoid problems when the span is closer + // than 1/(2**31) + movl izi,%edx + +// at this point: +// %ebx = izistep +// %ecx = count +// %edx = izi +// %edi = pdest + +LZDrawNeg: + +// do a single pixel up front, if necessary to dword align the destination + testl $2,%edi + jz LFNegMiddle + movl %edx,%eax + subl %ebx,%edx + shrl $16,%eax + decl %ecx + movw %ax,(%edi) + addl $2,%edi + +// do middle a pair of aligned dwords at a time +LFNegMiddle: + pushl %ecx + shrl $1,%ecx // count / 2 + jz LFNegLast // no aligned dwords to do + shrl $1,%ecx // (count / 2) / 2 + jnc LFNegMiddleLoop // even number of aligned dwords to do + + movl %edx,%eax + subl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + subl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %eax,(%edi) + addl $4,%edi + andl %ecx,%ecx + jz LFNegLast + +LFNegMiddleLoop: + movl %edx,%eax + subl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + subl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %edx,%ebp + movl %eax,(%edi) + subl %ebx,%edx + shrl $16,%ebp + movl %edx,%esi + subl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%ebp + movl %ebp,4(%edi) // FIXME: eliminate register contention + addl $8,%edi + + decl %ecx + jnz LFNegMiddleLoop + +LFNegLast: + popl %ecx // retrieve count + popl %esi // retrieve span pointer + +// do the last, unaligned pixel, if there is one + andl $1,%ecx // is there an odd pixel left to do? + jz LFNegSpanDone // no + shrl $16,%edx + movw %dx,(%edi) // do the final pixel's z + +LFNegSpanDone: + movl espan_t_pnext(%esi),%esi + testl %esi,%esi + jnz LFNegSpanLoop + +LFDone: + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +#endif // id386 diff --git a/engine/sw/d_draw16.s b/engine/sw/d_draw16.s new file mode 100644 index 000000000..de2b72f30 --- /dev/null +++ b/engine/sw/d_draw16.s @@ -0,0 +1,974 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// d_draw16.s +// x86 assembly-language horizontal 16-bpp span-drawing code, with 16-pixel +// subdivision. +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" +#include "d_ifacea.h" + +#if id386 + +//---------------------------------------------------------------------- +// 8-bpp horizontal span drawing code for polygons, with no transparency and +// 16-pixel subdivision. +// +// Assumes there is at least one span in pspans, and that every span +// contains at least one pixel +//---------------------------------------------------------------------- + + .data + + .text + +// out-of-line, rarely-needed clamping code + +LClampHigh0: + movl C(bbextents),%esi + jmp LClampReentry0 +LClampHighOrLow0: + jg LClampHigh0 + xorl %esi,%esi + jmp LClampReentry0 + +LClampHigh1: + movl C(bbextentt),%edx + jmp LClampReentry1 +LClampHighOrLow1: + jg LClampHigh1 + xorl %edx,%edx + jmp LClampReentry1 + +LClampLow2: + movl $4096,%ebp + jmp LClampReentry2 +LClampHigh2: + movl C(bbextents),%ebp + jmp LClampReentry2 + +LClampLow3: + movl $4096,%ecx + jmp LClampReentry3 +LClampHigh3: + movl C(bbextentt),%ecx + jmp LClampReentry3 + +LClampLow4: + movl $4096,%eax + jmp LClampReentry4 +LClampHigh4: + movl C(bbextents),%eax + jmp LClampReentry4 + +LClampLow5: + movl $4096,%ebx + jmp LClampReentry5 +LClampHigh5: + movl C(bbextentt),%ebx + jmp LClampReentry5 + + +#define pspans 4+16 + + .align 4 +.globl C(D_DrawSpans8SubDiv16) +C(D_DrawSpans8SubDiv16): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// +// set up scaled-by-16 steps, for 16-long segments; also set up cacheblock +// and span list pointers +// +// TODO: any overlap from rearranging? + flds C(d_sdivzstepu) + fmuls fp_16 + movl C(cacheblock),%edx + flds C(d_tdivzstepu) + fmuls fp_16 + movl pspans(%esp),%ebx // point to the first span descriptor + flds C(d_zistepu) + fmuls fp_16 + movl %edx,pbase // pbase = cacheblock + fstps zi16stepu + fstps tdivz16stepu + fstps sdivz16stepu + +LSpanLoop: +// +// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the +// initial s and t values +// +// FIXME: pipeline FILD? + fildl espan_t_v(%ebx) + fildl espan_t_u(%ebx) + + fld %st(1) // dv | du | dv + fmuls C(d_sdivzstepv) // dv*d_sdivzstepv | du | dv + fld %st(1) // du | dv*d_sdivzstepv | du | dv + fmuls C(d_sdivzstepu) // du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fld %st(2) // du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fmuls C(d_tdivzstepu) // du*d_tdivzstepu | du*d_sdivzstepu | + // dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu | du*d_tdivzstepu | + // dv*d_sdivzstepv | du | dv + faddp %st(0),%st(2) // du*d_tdivzstepu | + // du*d_sdivzstepu + dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fld %st(3) // dv | du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fmuls C(d_tdivzstepv) // dv*d_tdivzstepv | + // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // dv*d_tdivzstepv | du*d_tdivzstepu | du | dv + fadds C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv + + // du*d_sdivzstepu; stays in %st(2) at end + fxch %st(4) // dv | dv*d_tdivzstepv | du*d_tdivzstepu | du | + // s/z + fmuls C(d_zistepv) // dv*d_zistepv | dv*d_tdivzstepv | + // du*d_tdivzstepu | du | s/z + fxch %st(1) // dv*d_tdivzstepv | dv*d_zistepv | + // du*d_tdivzstepu | du | s/z + faddp %st(0),%st(2) // dv*d_zistepv | + // dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z + fxch %st(2) // du | dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fmuls C(d_zistepu) // du*d_zistepu | + // dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fxch %st(1) // dv*d_tdivzstepv + du*d_tdivzstepu | + // du*d_zistepu | dv*d_zistepv | s/z + fadds C(d_tdivzorigin) // tdivz = d_tdivzorigin + dv*d_tdivzstepv + + // du*d_tdivzstepu; stays in %st(1) at end + fxch %st(2) // dv*d_zistepv | du*d_zistepu | t/z | s/z + faddp %st(0),%st(1) // dv*d_zistepv + du*d_zistepu | t/z | s/z + + flds fp_64k // fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z + fxch %st(1) // dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z + fadds C(d_ziorigin) // zi = d_ziorigin + dv*d_zistepv + + // du*d_zistepu; stays in %st(0) at end + // 1/z | fp_64k | t/z | s/z +// +// calculate and clamp s & t +// + fdivr %st(0),%st(1) // 1/z | z*64k | t/z | s/z + +// +// point %edi to the first pixel in the span +// + movl C(d_viewbuffer),%ecx + movl espan_t_v(%ebx),%eax + movl %ebx,pspantemp // preserve spans pointer + + movl C(tadjust),%edx + movl C(sadjust),%esi + movl C(d_scantable)(,%eax,4),%edi // v * screenwidth + addl %ecx,%edi + movl espan_t_u(%ebx),%ecx + addl %ecx,%edi // pdest = &pdestspan[scans->u]; + movl espan_t_count(%ebx),%ecx + +// +// now start the FDIV for the end of the span +// + cmpl $16,%ecx + ja LSetupNotLast1 + + decl %ecx + jz LCleanup1 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fildl spancountminus1 + + flds C(d_tdivzstepu) // C(d_tdivzstepu) | spancountminus1 + flds C(d_zistepu) // C(d_zistepu) | C(d_tdivzstepu) | spancountminus1 + fmul %st(2),%st(0) // C(d_zistepu)*scm1 | C(d_tdivzstepu) | scm1 + fxch %st(1) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch %st(2) // scm1 | C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 + fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_zistepu)*scm1 | + // C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_zistepu)*scm1 | C(d_sdivzstepu)*scm1 | + // C(d_tdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) + + flds fp_64k + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight1 + +LCleanup1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + jmp LFDIVInFlight1 + + .align 4 +LSetupNotLast1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fadds zi16stepu + fxch %st(2) + fadds sdivz16stepu + fxch %st(2) + flds tdivz16stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight1: + + addl s,%esi + addl t,%edx + movl C(bbextents),%ebx + movl C(bbextentt),%ebp + cmpl %ebx,%esi + ja LClampHighOrLow0 +LClampReentry0: + movl %esi,s + movl pbase,%ebx + shll $16,%esi + cmpl %ebp,%edx + movl %esi,sfracf + ja LClampHighOrLow1 +LClampReentry1: + movl %edx,t + movl s,%esi // sfrac = scans->sfrac; + shll $16,%edx + movl t,%eax // tfrac = scans->tfrac; + sarl $16,%esi + movl %edx,tfracf + +// +// calculate the texture starting address +// + sarl $16,%eax + movl C(cachewidth),%edx + imull %edx,%eax // (tfrac >> 16) * cachewidth + addl %ebx,%esi + addl %eax,%esi // psource = pbase + (sfrac >> 16) + + // ((tfrac >> 16) * cachewidth); +// +// determine whether last span or not +// + cmpl $16,%ecx + jna LLastSegment + +// +// not the last segment; do full 16-wide segment +// +LNotLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there +// + +// pick up after the FDIV that was left in flight previously + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + movl snext,%eax + movl tnext,%edx + + movb (%esi),%bl // get first source texel + subl $16,%ecx // count off this segments' pixels + movl C(sadjust),%ebp + movl %ecx,counttemp // remember count of remaining pixels + + movl C(tadjust),%ecx + movb %bl,(%edi) // store first dest pixel + + addl %eax,%ebp + addl %edx,%ecx + + movl C(bbextents),%eax + movl C(bbextentt),%edx + + cmpl $4096,%ebp + jl LClampLow2 + cmpl %eax,%ebp + ja LClampHigh2 +LClampReentry2: + + cmpl $4096,%ecx + jl LClampLow3 + cmpl %edx,%ecx + ja LClampHigh3 +LClampReentry3: + + movl %ebp,snext + movl %ecx,tnext + + subl s,%ebp + subl t,%ecx + +// +// set up advancetable +// + movl %ecx,%eax + movl %ebp,%edx + sarl $20,%eax // tstep >>= 16; + jz LZero + sarl $20,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + imull %ebx,%eax + jmp LSetUp1 + +LZero: + sarl $20,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + +LSetUp1: + + addl %edx,%eax // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%edx + movl %eax,advancetable+4 // advance base in t + addl %ebx,%eax // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $12,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $12,%ecx // left-justify tstep fractional part + movl %eax,advancetable // advance extra in t + + movl %ecx,tstep + addl %ecx,%edx // advance tfrac fractional part by tstep frac + + sbbl %ecx,%ecx // turn tstep carry into -1 (0 if none) + addl %ebp,%ebx // advance sfrac fractional part by sstep frac + adcl advancetable+4(,%ecx,4),%esi // point to next source texel + + addl tstep,%edx + sbbl %ecx,%ecx + movb (%esi),%al + addl %ebp,%ebx + movb %al,1(%edi) + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,2(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,3(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,4(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,5(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,6(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,7(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + +// +// start FDIV for end of next segment in flight, so it can overlap +// + movl counttemp,%ecx + cmpl $16,%ecx // more than one segment after this? + ja LSetupNotLast2 // yes + + decl %ecx + jz LFDIVInFlight2 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + fildl spancountminus1 + + flds C(d_zistepu) // C(d_zistepu) | spancountminus1 + fmul %st(1),%st(0) // C(d_zistepu)*scm1 | scm1 + flds C(d_tdivzstepu) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch %st(1) // C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 | scm1 + faddp %st(0),%st(3) // C(d_tdivzstepu)*scm1 | scm1 + fxch %st(1) // scm1 | C(d_tdivzstepu)*scm1 + fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 + flds fp_64k // 64k | C(d_sdivzstepu)*scm1 + fxch %st(1) // C(d_sdivzstepu)*scm1 | 64k + faddp %st(0),%st(4) // 64k + + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight2 + + .align 4 +LSetupNotLast2: + fadds zi16stepu + fxch %st(2) + fadds sdivz16stepu + fxch %st(2) + flds tdivz16stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight2: + movl %ecx,counttemp + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,8(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,9(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,10(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,11(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,12(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,13(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,14(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl $16,%edi + movl %edx,tfracf + movl snext,%edx + movl %ebx,sfracf + movl tnext,%ebx + movl %edx,s + movl %ebx,t + + movl counttemp,%ecx // retrieve count + +// +// determine whether last span or not +// + cmpl $16,%ecx // are there multiple segments remaining? + movb %al,-1(%edi) + ja LNotLastSegment // yes + +// +// last segment of scan +// +LLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there. The number of pixels left is variable, and we want to land on the +// last pixel, not step one past it, so we can't run into arithmetic problems +// + testl %ecx,%ecx + jz LNoSteps // just draw the last pixel and we're done + +// pick up after the FDIV that was left in flight previously + + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + + movb (%esi),%al // load first texel in segment + movl C(tadjust),%ebx + movb %al,(%edi) // store first pixel in segment + movl C(sadjust),%eax + + addl snext,%eax + addl tnext,%ebx + + movl C(bbextents),%ebp + movl C(bbextentt),%edx + + cmpl $4096,%eax + jl LClampLow4 + cmpl %ebp,%eax + ja LClampHigh4 +LClampReentry4: + movl %eax,snext + + cmpl $4096,%ebx + jl LClampLow5 + cmpl %edx,%ebx + ja LClampHigh5 +LClampReentry5: + + cmpl $1,%ecx // don't bother + je LOnlyOneStep // if two pixels in segment, there's only one step, + // of the segment length + subl s,%eax + subl t,%ebx + + addl %eax,%eax // convert to 15.17 format so multiply by 1.31 + addl %ebx,%ebx // reciprocal yields 16.48 + + imull reciprocal_table_16-8(,%ecx,4) // sstep = (snext - s) / + // (spancount-1) + movl %edx,%ebp + + movl %ebx,%eax + imull reciprocal_table_16-8(,%ecx,4) // tstep = (tnext - t) / + // (spancount-1) +LSetEntryvec: +// +// set up advancetable +// + movl entryvec_table_16(,%ecx,4),%ebx + movl %edx,%eax + movl %ebx,jumptemp // entry point into code for RET later + movl %ebp,%ecx + sarl $16,%edx // tstep >>= 16; + movl C(cachewidth),%ebx + sarl $16,%ecx // sstep >>= 16; + imull %ebx,%edx + + addl %ecx,%edx // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%ecx + movl %edx,advancetable+4 // advance base in t + addl %ebx,%edx // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $16,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $16,%eax // left-justify tstep fractional part + movl %edx,advancetable // advance extra in t + + movl %eax,tstep + movl %ecx,%edx + addl %eax,%edx + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + + jmp *jumptemp // jump to the number-of-pixels handler + +//---------------------------------------- + +LNoSteps: + movb (%esi),%al // load first texel in segment + subl $15,%edi // adjust for hardwired offset + jmp LEndSpan + + +LOnlyOneStep: + subl s,%eax + subl t,%ebx + movl %eax,%ebp + movl %ebx,%edx + jmp LSetEntryvec + +//---------------------------------------- + +.globl Entry2_16, Entry3_16, Entry4_16, Entry5_16 +.globl Entry6_16, Entry7_16, Entry8_16, Entry9_16 +.globl Entry10_16, Entry11_16, Entry12_16, Entry13_16 +.globl Entry14_16, Entry15_16, Entry16_16 + +Entry2_16: + subl $14,%edi // adjust for hardwired offsets + movb (%esi),%al + jmp LEntry2_16 + +//---------------------------------------- + +Entry3_16: + subl $13,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + jmp LEntry3_16 + +//---------------------------------------- + +Entry4_16: + subl $12,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry4_16 + +//---------------------------------------- + +Entry5_16: + subl $11,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry5_16 + +//---------------------------------------- + +Entry6_16: + subl $10,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry6_16 + +//---------------------------------------- + +Entry7_16: + subl $9,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry7_16 + +//---------------------------------------- + +Entry8_16: + subl $8,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry8_16 + +//---------------------------------------- + +Entry9_16: + subl $7,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry9_16 + +//---------------------------------------- + +Entry10_16: + subl $6,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry10_16 + +//---------------------------------------- + +Entry11_16: + subl $5,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry11_16 + +//---------------------------------------- + +Entry12_16: + subl $4,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry12_16 + +//---------------------------------------- + +Entry13_16: + subl $3,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry13_16 + +//---------------------------------------- + +Entry14_16: + subl $2,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry14_16 + +//---------------------------------------- + +Entry15_16: + decl %edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry15_16 + +//---------------------------------------- + +Entry16_16: + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,1(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry15_16: + sbbl %ecx,%ecx + movb %al,2(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry14_16: + sbbl %ecx,%ecx + movb %al,3(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry13_16: + sbbl %ecx,%ecx + movb %al,4(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry12_16: + sbbl %ecx,%ecx + movb %al,5(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry11_16: + sbbl %ecx,%ecx + movb %al,6(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry10_16: + sbbl %ecx,%ecx + movb %al,7(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry9_16: + sbbl %ecx,%ecx + movb %al,8(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry8_16: + sbbl %ecx,%ecx + movb %al,9(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry7_16: + sbbl %ecx,%ecx + movb %al,10(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry6_16: + sbbl %ecx,%ecx + movb %al,11(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry5_16: + sbbl %ecx,%ecx + movb %al,12(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry4_16: + sbbl %ecx,%ecx + movb %al,13(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi +LEntry3_16: + movb %al,14(%edi) + movb (%esi),%al +LEntry2_16: + +LEndSpan: + +// +// clear s/z, t/z, 1/z from FP stack +// + fstp %st(0) + fstp %st(0) + fstp %st(0) + + movl pspantemp,%ebx // restore spans pointer + movl espan_t_pnext(%ebx),%ebx // point to next span + testl %ebx,%ebx // any more spans? + movb %al,15(%edi) + jnz LSpanLoop // more spans + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +#endif // id386 diff --git a/engine/sw/d_edge.c b/engine/sw/d_edge.c new file mode 100644 index 000000000..3a38b87c4 --- /dev/null +++ b/engine/sw/d_edge.c @@ -0,0 +1,435 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_edge.c + +#include "quakedef.h" +#include "d_local.h" + +static int miplevel; + +float scale_for_mip; +int screenwidth; +int ubasestep, errorterm, erroradjustup, erroradjustdown; +int vstartscan; + +// FIXME: should go away +extern void R_RotateBmodel (void); +extern void R_TransformFrustum (void); + +vec3_t transformed_modelorg; + +/* +============== +D_DrawPoly + +============== +*/ +void D_DrawPoly (void) +{ +// this driver takes spans, not polygons +} + + +/* +============= +D_MipLevelForScale +============= +*/ +int D_MipLevelForScale (float scale) +{ + int lmiplevel; + + if (scale >= d_scalemip[0] ) + lmiplevel = 0; + else if (scale >= d_scalemip[1] ) + lmiplevel = 1; + else if (scale >= d_scalemip[2] ) + lmiplevel = 2; + else + lmiplevel = 3; + + if (lmiplevel < d_minmip) + lmiplevel = d_minmip; + + return lmiplevel; +} + + +/* +============== +D_DrawSolidSurface +============== +*/ + +// FIXME: clean this up + +void D_DrawSolidSurface (surf_t *surf, int color) +{ + espan_t *span; + qbyte *pdest; + int u, u2, pix; + + if (r_pixbytes == 4) + { + unsigned int *p32dest; + pix = d_8to32table[color]; + for (span=surf->spans ; span ; span=span->pnext) + { + p32dest = (unsigned int *)d_viewbuffer + screenwidth*span->v; + u = span->u; + u2 = span->u + span->count - 1; + p32dest[u] = pix; + + for ( ; u <= u2 ; u++) + p32dest[u] = pix; + } + } + else + { + pix = (color<<24) | (color<<16) | (color<<8) | color; + for (span=surf->spans ; span ; span=span->pnext) + { + pdest = (qbyte *)d_viewbuffer + screenwidth*span->v; + u = span->u; + u2 = span->u + span->count - 1; + ((qbyte *)pdest)[u] = pix; + + if (u2 - u < 8) + { + for (u++ ; u <= u2 ; u++) + ((qbyte *)pdest)[u] = pix; + } + else + { + for (u++ ; u & 3 ; u++) + ((qbyte *)pdest)[u] = pix; + + u2 -= 3; + for ( ; u <= u2 ; u+=4) + *(int *)((qbyte *)pdest + u) = pix; + u2 += 3; + for ( ; u <= u2 ; u++) + ((qbyte *)pdest)[u] = pix; + } + } + } +} + + +/* +============== +D_CalcGradients +============== +*/ +void D_CalcGradients (msurface_t *pface) +{ + mplane_t *pplane; + float mipscale; + vec3_t p_temp1; + vec3_t p_saxis, p_taxis; + float t; + + pplane = pface->plane; + + mipscale = 1.0 / (float)(1 << miplevel); + + TransformVector (pface->texinfo->vecs[0], p_saxis); + TransformVector (pface->texinfo->vecs[1], p_taxis); + + t = xscaleinv * mipscale; + d_sdivzstepu = p_saxis[0] * t; + d_tdivzstepu = p_taxis[0] * t; + + t = yscaleinv * mipscale; + d_sdivzstepv = -p_saxis[1] * t; + d_tdivzstepv = -p_taxis[1] * t; + + d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu - + ycenter * d_sdivzstepv; + d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu - + ycenter * d_tdivzstepv; + + VectorScale (transformed_modelorg, mipscale, p_temp1); + + t = 0x10000*mipscale; + sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) - + ((pface->texturemins[0] << 16) >> miplevel) + + pface->texinfo->vecs[0][3]*t; + tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) - + ((pface->texturemins[1] << 16) >> miplevel) + + pface->texinfo->vecs[1][3]*t; + +// +// -1 (-epsilon) so we never wander off the edge of the texture +// + bbextents = ((pface->extents[0] << 16) >> miplevel) - 1; + bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1; +} + + +/* +============== +D_DrawSurfaces +============== +*/ +void D_DrawSurfaces (void) +{ + void D_DrawSpans32 (espan_t *pspan); + surf_t *s; + msurface_t *pface; + surfcache_t *pcurrentcache; + vec3_t world_transformed_modelorg; + vec3_t local_modelorg; + extern int r_dosirds; + + currententity = &r_worldentity; + TransformVector (modelorg, transformed_modelorg); + VectorCopy (transformed_modelorg, world_transformed_modelorg); + + if (r_dosirds) //depth only + { + for (s = &surfaces[1] ; sspans) + continue; + + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + D_DrawZSpans (s->spans); + } + } +// TODO: could preset a lot of this at mode set time + else if (r_drawflat.value) + { + for (s = &surfaces[1] ; sspans) + continue; + + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + +#ifdef __alpha__ + D_DrawSolidSurface (s, (int)((long)s->data & 0xFF)); +#else + D_DrawSolidSurface (s, (int)s->data & 0xFF); +#endif + D_DrawZSpans (s->spans); + } + } + else + { + for (s = &surfaces[1] ; sspans) + continue; + + r_drawnpolycount++; + + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + + if (s->flags & SURF_DRAWSKY) + { + if (r_worldentity.model->fromgame == fg_halflife) + continue; + if (!r_skymade) + { + R_MakeSky (); + } + + if (r_pixbytes == 4) + D_DrawSkyScans32 (s->spans); + else if (r_pixbytes == 2) + D_DrawSkyScans16 (s->spans); + else + D_DrawSkyScans8 (s->spans); + D_DrawZSpans (s->spans); + } + else if (s->flags & SURF_DRAWSKYBOX) + { + pface = s->data; + miplevel = 0; + if (!pface->texinfo->texture) + { + d_zistepu = 0; + d_zistepv = 0; + d_ziorigin = -0.9; + + D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF); + D_DrawZSpans (s->spans); + continue; + } + cacheblock = (qbyte *)pface->texinfo->texture + pface->texinfo->texture->offsets[0]; + cachewidth = 256; + + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + + D_CalcGradients (pface); + + if (r_pixbytes == 2) + D_DrawSpans16From8(s->spans); + else + (*d_drawspans) (s->spans); +// D_DrawSolidSurface (s, (int)15); + + // set up a gradient for the background surface that places it + // effectively at infinity distance from the viewpoint + d_zistepu = 0; + d_zistepv = 0; + d_ziorigin = -0.9; + + D_DrawZSpans (s->spans); + } + else if (s->flags & SURF_DRAWBACKGROUND) + { + // set up a gradient for the background surface that places it + // effectively at infinity distance from the viewpoint + d_zistepu = 0; + d_zistepv = 0; + d_ziorigin = -0.9; + + D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF); + D_DrawZSpans (s->spans); + } + else if (s->flags & SURF_DRAWTURB) + { + pface = s->data; + miplevel = 0; + cacheblock = (pixel_t *) + ((qbyte *)pface->texinfo->texture + + pface->texinfo->texture->offsets[0]); + cachewidth = 64; + cacheheight = 64; + + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, + local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + + D_CalcGradients (pface); + + if (r_pixbytes == 4) + Turbulent32 (s->spans); + else if (r_pixbytes == 2) + Turbulent16 (s->spans); + else + Turbulent8 (s->spans); + D_DrawZSpans (s->spans); + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + currententity = &r_worldentity; + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + R_TransformFrustum (); + } + } + else + { + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + + pface = s->data; + + if (pface->flags & SURF_BULLETEN) + { + miplevel = 0; + if (pface->cachespots[miplevel]) + pface->cachespots[miplevel]->texture = NULL; + } + else + { + miplevel = D_MipLevelForScale (s->nearzi * scale_for_mip + * pface->texinfo->mipadjust); + } + + // FIXME: make this passed in to D_CacheSurface + pcurrentcache = D_CacheSurface (pface, miplevel); + + cacheblock = (pixel_t *)pcurrentcache->data; + cachewidth = pcurrentcache->width; + + cacheheight = pcurrentcache->height; + + +// if (s->entity == &r_worldentity) //temporary +// { + D_CalcGradients (pface); + (*d_drawspans) (s->spans); + + if (d_drawspans != D_DrawSpans32) + D_DrawZSpans (s->spans); +// } + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + R_TransformFrustum (); + currententity = &r_worldentity; + } + } + } + } +} + diff --git a/engine/sw/d_fill.c b/engine/sw/d_fill.c new file mode 100644 index 000000000..25a9e7242 --- /dev/null +++ b/engine/sw/d_fill.c @@ -0,0 +1,88 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_clear: clears a specified rectangle to the specified color + +#include "quakedef.h" + + +/* +================ +D_FillRect +================ +*/ +void D_FillRect (vrect_t *rect, int color) +{ + int rx, ry, rwidth, rheight; + unsigned char *dest; + unsigned *ldest; + + rx = rect->x; + ry = rect->y; + rwidth = rect->width; + rheight = rect->height; + + if (rx < 0) + { + rwidth += rx; + rx = 0; + } + if (ry < 0) + { + rheight += ry; + ry = 0; + } + if (rx+rwidth > vid.width) + rwidth = vid.width - rx; + if (ry+rheight > vid.height) + rheight = vid.height - rx; + + if (rwidth < 1 || rheight < 1) + return; + + dest = ((qbyte *)vid.buffer + ry*vid.rowbytes + rx); + + if (((rwidth & 0x03) == 0) && (((long)dest & 0x03) == 0)) + { + // faster aligned dword clear + ldest = (unsigned *)dest; + color += color << 16; + + rwidth >>= 2; + color += color << 8; + + for (ry=0 ; ry 3) + d_minmip = 3; + else if (d_minmip < 0) + d_minmip = 0; + + for (i=0 ; i<(NUM_MIPS-1) ; i++) + d_scalemip[i] = basemip[i] * d_mipscale.value; + +#if id386 + if (r_pixbytes == 4) + d_drawspans = d_smooth.value?D_DrawSpans32_Smooth:D_DrawSpans32; + else if (r_pixbytes == 2) + d_drawspans = D_DrawSpans16; + else if (d_smooth.value)//override's subdiv16 (bigger impact) + d_drawspans = D_DrawSpans8_Smooth; + else if (d_subdiv16.value) + d_drawspans = D_DrawSpans8SubDiv16; + else + d_drawspans = D_DrawSpans8; +#else + if (r_pixbytes == 4) + { + if (r_usinglits) + d_drawspans = d_smooth.value?D_DrawSpans32_Smooth:D_DrawSpans32; + else + d_drawspans = D_DrawSpans32From8; + } + else if (r_pixbytes == 2) + d_drawspans = D_DrawSpans16; + else + d_drawspans = d_smooth.value?D_DrawSpans8_Smooth:D_DrawSpans8; +#endif + + d_aflatcolor = 0; +} + + +/* +=============== +D_UpdateRects +=============== +*/ +void D_UpdateRects (vrect_t *prect) +{ + +// the software driver draws these directly to the vid buffer + + UNUSED(prect); +} + diff --git a/engine/sw/d_local.h b/engine/sw/d_local.h new file mode 100644 index 000000000..eeed04456 --- /dev/null +++ b/engine/sw/d_local.h @@ -0,0 +1,136 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_local.h: private rasterization driver defs + +#include "r_shared.h" + +// +// TODO: fine-tune this; it's based on providing some overage even if there +// is a 2k-wide scan, with subdivision every 8, for 256 spans of 12 bytes each +// +#define SCANBUFFERPAD 0x1000 + +#define R_SKY_SMASK 0x007F0000 +#define R_SKY_TMASK 0x007F0000 + +#define DS_SPAN_LIST_END -128 + +#define SURFCACHE_SIZE_AT_320X200 600*1024 + +typedef struct surfcache_s +{ + struct surfcache_s *next; + struct surfcache_s **owner; // NULL is an empty chunk of memory + int lightadj[MAXLIGHTMAPS]; // checked for strobe flush + int dlight; + int size; // including header + unsigned width; + unsigned height; // DEBUG only needed for debug + float mipscale; + struct texture_s *texture; // checked for animating textures + int bytesperpix; + int fcache; + qbyte data[4]; // width*height elements +} surfcache_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct sspan_s +{ + int u, v, count; +} sspan_t; + +extern cvar_t d_subdiv16; + +extern float scale_for_mip; + +extern qboolean d_roverwrapped; +extern surfcache_t *sc_rover; +extern surfcache_t *d_initial_rover; + +extern float d_sdivzstepu, d_tdivzstepu, d_zistepu; +extern float d_sdivzstepv, d_tdivzstepv, d_zistepv; +extern float d_sdivzorigin, d_tdivzorigin, d_ziorigin; + +fixed16_t sadjust, tadjust; +fixed16_t bbextents, bbextentt; + + +void D_DrawSpans8_Smooth (espan_t *pspan); +void D_DrawSpans8 (espan_t *pspans); +void D_DrawSpans16 (espan_t *pspans); +void D_DrawSpans8SubDiv16 (espan_t *pspans); +void D_DrawSpans16From8 (espan_t *pspan); //skybox in 16 bit renderer (fixme - load tgas with more colourdepth). +void D_DrawZSpans (espan_t *pspans); +void Turbulent8 (espan_t *pspan); +void Turbulent16 (espan_t *pspan); +void Turbulent32 (espan_t *pspan); +void D_SpriteDrawSpans (sspan_t *pspan); + +void D_DrawSkyScans8 (espan_t *pspan); +void D_DrawSkyScans16 (espan_t *pspan); +void D_DrawSkyScans32 (espan_t *pspan); + +void R_ShowSubDiv (void); +void (*prealspandrawer)(void); +surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel); + +extern int D_MipLevelForScale (float scale); + +#if id386 +extern void D_PolysetAff8Start (void); +extern void D_PolysetAff8End (void); +#endif + +extern short *d_pzbuffer; +extern unsigned int d_zrowbytes, d_zwidth; + +extern int *d_pscantable; +extern int d_scantable[MAXHEIGHT]; + +extern int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; + +extern int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift; + +extern pixel_t *d_viewbuffer; + +extern short *zspantable[MAXHEIGHT]; + +extern int d_minmip; +extern float d_scalemip[3]; + +extern void (*d_drawspans) (espan_t *pspan); + + + +#ifdef PEXT_TRANS +typedef qbyte tlookup[256][256]; +typedef qbyte tlookupp[256]; +extern tlookup *t_lookup; +extern tlookupp *t_curlookupp; +extern int t_curtable; +extern int t_numtables; +extern int t_numtablesinv;//65546/numtables + +void D_InitTrans(void); +#define Trans(p, p2) (t_curlookupp[p][p2]) +void Set_TransLevelI(int level); +void Set_TransLevelF(float level); +#endif + diff --git a/engine/sw/d_modech.c b/engine/sw/d_modech.c new file mode 100644 index 000000000..1447eb1a3 --- /dev/null +++ b/engine/sw/d_modech.c @@ -0,0 +1,115 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_modech.c: called when mode has just changed + +//the id made assembler cannot cope with the changes made to the triangle data type. +#ifndef NOASM +#define NOASM +#endif + +#include "quakedef.h" +#include "d_local.h" + +int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; + +int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift; + +int d_scantable[MAXHEIGHT]; +short *zspantable[MAXHEIGHT]; + +/* +================ +D_Patch +================ +*/ +void D_Patch (void) +{ +#if id386 + + static qboolean protectset8 = false; + + if (!protectset8) + { + Sys_MakeCodeWriteable ((int)D_PolysetAff8Start, + (int)D_PolysetAff8End - (int)D_PolysetAff8Start); + protectset8 = true; + } + +#endif // id386 +} + + +/* +================ +D_ViewChanged +================ +*/ +void D_ViewChanged (void) +{ + int rowbytes; + + if (r_dowarp) + rowbytes = WARP_WIDTH; + else + rowbytes = vid.rowbytes; + + scale_for_mip = xscale; + if (yscale > xscale) + scale_for_mip = yscale; + + d_zrowbytes = vid.width * 2; + d_zwidth = vid.width; + + d_pix_min = r_refdef.vrect.width / 320; + if (d_pix_min < 1) + d_pix_min = 1; + + d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5); +d_pix_max*=2; + d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5); + if (d_pix_max < 1) + d_pix_max = 1; + + if (pixelAspect > 1.4) + d_y_aspect_shift = 1; + else + d_y_aspect_shift = 0; + + d_vrectx = r_refdef.vrect.x; + d_vrecty = r_refdef.vrect.y; + d_vrectright_particle = r_refdef.vrectright - d_pix_max; + d_vrectbottom_particle = + r_refdef.vrectbottom - (d_pix_max << d_y_aspect_shift); + + { + int i; + + for (i=0 ; iorg, r_origin, local); + + transformed[0] = DotProduct(local, r_pright); + transformed[1] = DotProduct(local, r_pup); + transformed[2] = DotProduct(local, r_ppn); + + if (transformed[2] < PARTICLE_Z_CLIP) + return; + +// project the point +// FIXME: preadjust xcenter and ycenter + zi = 1.0 / transformed[2]; + u = (int)(xcenter + zi * transformed[0] + 0.5); + v = (int)(ycenter - zi * transformed[1] + 0.5); + + if ((v > d_vrectbottom_particle) || + (u > d_vrectright_particle) || + (v < d_vrecty) || + (u < d_vrectx)) + { + return; + } + + pz = d_pzbuffer + (d_zwidth * v) + u; + pdest = d_viewbuffer + d_scantable[v] + u; + izi = (int)(zi * 0x8000); + + pix = izi >> d_pix_shift; + pix *= pparticle->scale; + + if (pix < d_pix_min) + pix = d_pix_min; + else if (pix > d_pix_max) + pix = d_pix_max; + + switch (pix) + { + case 1: + count = 1 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + pdest[0] = pparticle->color; + } + } + break; + + case 2: + count = 2 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + pdest[0] = pparticle->color; + } + + if (pz[1] <= izi) + { +// pz[1] = izi; + pdest[1] = pparticle->color; + } + } + break; + + case 3: + count = 3 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + pdest[0] = pparticle->color; + } + + if (pz[1] <= izi) + { +// pz[1] = izi; + pdest[1] = pparticle->color; + } + + if (pz[2] <= izi) + { +// pz[2] = izi; + pdest[2] = pparticle->color; + } + } + break; + + case 4: + count = 4 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + pdest[0] = pparticle->color; + } + + if (pz[1] <= izi) + { +// pz[1] = izi; + pdest[1] = pparticle->color; + } + + if (pz[2] <= izi) + { +// pz[2] = izi; + pdest[2] = pparticle->color; + } + + if (pz[3] <= izi) + { +// pz[3] = izi; + pdest[3] = pparticle->color; + } + } + break; + + default: + count = pix << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + for (i=0 ; icolor; + } + } + } + break; + } +} + +#endif // !id386 + +void D_DrawParticle16 (particle_t *pparticle) +{ + vec3_t local, transformed; + float zi; + unsigned short *pdest; + int a; + short *pz; + int i, izi, pix, count, u, v; + + if (pparticle->alpha <= 0.2) + return; + +// transform point + VectorSubtract (pparticle->org, r_origin, local); + + transformed[0] = DotProduct(local, r_pright); + transformed[1] = DotProduct(local, r_pup); + transformed[2] = DotProduct(local, r_ppn); + + if (transformed[2] < PARTICLE_Z_CLIP) + return; + +// project the point +// FIXME: preadjust xcenter and ycenter + zi = 1.0 / transformed[2]; + u = (int)(xcenter + zi * transformed[0] + 0.5); + v = (int)(ycenter - zi * transformed[1] + 0.5); + + if ((v > d_vrectbottom_particle) || + (u > d_vrectright_particle) || + (v < d_vrecty) || + (u < d_vrectx)) + { + return; + } + + pz = d_pzbuffer + (d_zwidth * v) + u; + izi = (int)(zi * 0x8000); + + pix = ((int)(izi*pparticle->scale)) >> d_pix_shift; + + if (pix < d_pix_min) + pix = d_pix_min; + else if (pix > d_pix_max) + pix = d_pix_max; + + u -= pix/2; + v -= pix/2; + if (u < 0) u = 0; + if (v < 0) v = 0; + pdest = (unsigned short *)d_viewbuffer + ((d_scantable[v] + u)); + + a = 255*pparticle->alpha; + + switch (pix) + { + default: + count = pix << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + for (i=0 ; icolor]; + } + } + } + break; + } +} + +void D_DrawParticle32 (particle_t *pparticle) +{ + vec3_t local, transformed; + float zi; + qbyte *pdest; + qbyte *pal; + int a; + short *pz; + int i, izi, pix, count, u, v; + + if (pparticle->alpha <= 0.0) + return; + +// transform point + VectorSubtract (pparticle->org, r_origin, local); + + transformed[0] = DotProduct(local, r_pright); + transformed[1] = DotProduct(local, r_pup); + transformed[2] = DotProduct(local, r_ppn); + + if (transformed[2] < PARTICLE_Z_CLIP) + return; + +// project the point +// FIXME: preadjust xcenter and ycenter + zi = 1.0 / transformed[2]; + u = (int)(xcenter + zi * transformed[0] + 0.5); + v = (int)(ycenter - zi * transformed[1] + 0.5); + + if ((v > d_vrectbottom_particle) || + (u > d_vrectright_particle) || + (v < d_vrecty) || + (u < d_vrectx)) + { + return; + } + + pz = d_pzbuffer + (d_zwidth * v) + u; + izi = (int)(zi * 0x8000); + + pix = ((int)(izi*pparticle->scale)) >> d_pix_shift; + + if (pix < d_pix_min) + pix = d_pix_min; + else if (pix > d_pix_max) + pix = d_pix_max; + + u -= pix/2; + v -= pix/2; + if (u < 0) u = 0; + if (v < 0) v = 0; + pdest = d_viewbuffer + ((d_scantable[v] + u)<<2); + pal = (qbyte *)&d_8to32table[(int)pparticle->color]; + + a = 255*pparticle->alpha; + + switch (pix) + { + default: + count = pix << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth<<2) + { + for (i=0 ; ialpha <= 0.0) + return; + + + if (pparticle->alpha >= 0.9) + { + D_DrawParticle(pparticle); + return; + } + + Set_TransLevelF(pparticle->alpha); + +// transform point + VectorSubtract (pparticle->org, r_origin, local); + + transformed[0] = DotProduct(local, r_pright); + transformed[1] = DotProduct(local, r_pup); + transformed[2] = DotProduct(local, r_ppn); + + if (transformed[2] < PARTICLE_Z_CLIP) + return; + +// project the point +// FIXME: preadjust xcenter and ycenter + zi = 1.0 / transformed[2]; + u = (int)(xcenter + zi * transformed[0] + 0.5); + v = (int)(ycenter - zi * transformed[1] + 0.5); + + if ((v > d_vrectbottom_particle) || + (u > d_vrectright_particle) || + (v < d_vrecty) || + (u < d_vrectx)) + { + return; + } + + pz = d_pzbuffer + (d_zwidth * v) + u; + izi = (int)(zi * 0x8000); + + pix = ((int)(izi*pparticle->scale)) >> d_pix_shift; + + if (pix < d_pix_min) + pix = d_pix_min; + else if (pix > d_pix_max) + pix = d_pix_max; + + u -= pix/2; + v -= pix/2; + if (u < 0) u = 0; + if (v < 0) v = 0; + pdest = d_viewbuffer + d_scantable[v] + u; + + switch (pix) + { + case 1: + count = 1 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + draw(pdest[0], pparticle->color); + } + } + break; + + case 2: + count = 2 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + draw(pdest[0], pparticle->color); + } + + if (pz[1] <= izi) + { +// pz[1] = izi; + draw(pdest[1], pparticle->color); + } + } + break; + + case 3: + count = 3 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + draw(pdest[0], pparticle->color); + } + + if (pz[1] <= izi) + { +// pz[1] = izi; + draw(pdest[1], pparticle->color); + } + + if (pz[2] <= izi) + { +// pz[2] = izi; + draw(pdest[2], pparticle->color); + } + } + break; + + case 4: + count = 4 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { +// pz[0] = izi; + draw(pdest[0], pparticle->color); + } + + if (pz[1] <= izi) + { +// pz[1] = izi; + draw(pdest[1], pparticle->color); + } + + if (pz[2] <= izi) + { +// pz[2] = izi; + draw(pdest[2], pparticle->color); + } + + if (pz[3] <= izi) + { +// pz[3] = izi; + draw(pdest[3], pparticle->color); + } + } + break; + + default: + count = pix << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + for (i=0 ; icolor); + } + } + } + break; + } +} + +void D_2dPos(vec3_t pos, int *u, int *v, int *z) +{ + float zi; + vec3_t local, transformed; + + // transform point + VectorSubtract (pos, r_origin, local); + + transformed[2] = DotProduct(local, r_ppn); + + if (transformed[2] < PARTICLE_Z_CLIP) //near clip + { + *u = -1; //send it off the side intentionally. + return; + } + + transformed[0] = DotProduct(local, r_pright); + transformed[1] = DotProduct(local, r_pup); + +// project the point + zi = 1.0 / transformed[2]; + *u = (int)(xcenter + zi * transformed[0] + 0.5); + *v = (int)(ycenter - zi * transformed[1] + 0.5); + + *z = (int)(zi * 0x8000); +} +vec_t VI2Length(int x, int y) +{ + float length; + length = (float)x*x + (float)y*y; + length = sqrt (length); + return length; +} +void D_DrawSparkTrans32 (particle_t *pparticle) //draw a line in 3d space +{ + /* + Finds 2d coords for the points, then draws a line between them with an appropriate alpha + */ + vec3_t delta; + unsigned char *pdest; + unsigned char *pal; + short *pz; + int count, u1, v1, z1, a1, a, ia; + int u2, v2, z2; + float speed; + + int du, dv, dz, da; + + if (pparticle->alpha <= 0.0) + return; + + speed = Length(pparticle->vel); + if ((speed) < 1) + { + D_2dPos(pparticle->org, &u1, &v1, &z1); + D_2dPos(pparticle->org, &u2, &v2, &z2); + } + else + { //causes flickers with lower vels (due to bouncing in physics) + if (speed < 50) + speed *= 50/speed; + VectorMA(pparticle->org, 5/(speed), pparticle->vel, delta); + D_2dPos(delta, &u1, &v1, &z1); + VectorMA(pparticle->org, -5/(speed), pparticle->vel, delta); + D_2dPos(delta, &u2, &v2, &z2); + } + + if ((v1 > d_vrectbottom_particle) || + (u1 > d_vrectright_particle) || + (v1 < d_vrecty) || + (u1 < d_vrectx)) + { + return; + } + + if ((v2 > d_vrectbottom_particle) || + (u2 > d_vrectright_particle) || + (v2 < d_vrecty) || + (u2 < d_vrectx)) + { + return; + } +pal = (qbyte *)(d_8to32table + (int)pparticle->color); + a1 = 255 * pparticle->alpha; + + du = u2 - u1; + dv = v2 - v1; + dz = z2 - z1; + da = 0 - a1; + + if (!du && !dv) + count = 1; + else + { + count = VI2Length(du, dv); + if (!count) + count = 1; + } + + du *= 256*256; + dv *= 256*256; + dz *= 256*256; + da *= 256*256; + u1 = u1<<16; + v1 = v1<<16; + z1 = z1<<16; + a1 = a1<<16; + { + du /= count; + dv /= count; + dz /= count; + da /= count; + } + do + { + pz = d_pzbuffer + (d_zwidth * (v1>>16)) + (u1>>16); + + if (*pz <= z1>>16) + { +// *pz = z1>>16; + + a = a1>>16; + ia = 255-a; + pdest = (qbyte *)((unsigned int *)d_viewbuffer + ((d_scantable[v1>>16] + (u1>>16)))); + pdest[0] = (pdest[0]*((ia)) + pal[0]*(a))/255; + pdest[1] = (pdest[1]*((ia)) + pal[1]*(a))/255; + pdest[2] = (pdest[2]*((ia)) + pal[2]*(a))/255; + } + + u1 += du; + v1 += dv; + z1 += dz; + a1 += da; + } while (count--); +} + +void D_DrawSparkTrans16 (particle_t *pparticle) //draw a line in 3d space, 8bpp +{ + vec3_t delta; + unsigned short *pdest; + short *pz; + int count, u1, v1, z1; + int u2, v2, z2; + float speed; + + int du, dv, dz; + + if (pparticle->alpha <= 0.0) + return; + + speed = Length(pparticle->vel); + if ((speed) < 1) + { + D_2dPos(pparticle->org, &u1, &v1, &z1); + D_2dPos(pparticle->org, &u2, &v2, &z2); + } + else + { //causes flickers with lower vels (due to bouncing in physics) + if (speed < 50) + speed *= 50/speed; + VectorMA(pparticle->org, 2.5/(speed), pparticle->vel, delta); + D_2dPos(delta, &u1, &v1, &z1); + VectorMA(pparticle->org, -2.5/(speed), pparticle->vel, delta); + D_2dPos(delta, &u2, &v2, &z2); + } + + if ((v1 > d_vrectbottom_particle) || + (u1 > d_vrectright_particle) || + (v1 < d_vrecty) || + (u1 < d_vrectx)) + { + return; + } + + if ((v2 > d_vrectbottom_particle) || + (u2 > d_vrectright_particle) || + (v2 < d_vrecty) || + (u2 < d_vrectx)) + { + return; + } + + du = u2 - u1; + dv = v2 - v1; + dz = z2 - z1; + + if (!du && !dv) + count = 1; + else + { + count = VI2Length(du, dv); + if (!count) + count = 1; + } + + du *= 256*256; + dv *= 256*256; + dz *= 256*256; + u1 = u1<<16; + v1 = v1<<16; + z1 = z1<<16; + { + du /= count; + dv /= count; + dz /= count; + } + do + { + pz = d_pzbuffer + (d_zwidth * (v1>>16)) + (u1>>16); + + if (*pz <= z1>>16) + { +// *pz = z1>>16; + + pdest = (unsigned short*)d_viewbuffer + d_scantable[v1>>16] + (u1>>16); + *pdest = d_8to16table[(int)pparticle->color]; + } + + u1 += du; + v1 += dv; + z1 += dz; + } while (count--); +} + +void D_DrawSparkTrans (particle_t *pparticle) //draw a line in 3d space, 8bpp +{ + vec3_t delta; + qbyte *pdest; + short *pz; + int count, u1, v1, z1; + int u2, v2, z2; + float speed; + + int du, dv, dz; +/* + D_DrawParticleTrans(pparticle); + return; +*/ + if (r_pixbytes == 4) + { + D_DrawSparkTrans32(pparticle); + return; + } + if (r_pixbytes == 2) + { + D_DrawSparkTrans16(pparticle); + return; + } + + if (pparticle->alpha <= 0.0) + return; + + Set_TransLevelF(pparticle->alpha); + + speed = Length(pparticle->vel); + if ((speed) < 1) + { + D_2dPos(pparticle->org, &u1, &v1, &z1); + D_2dPos(pparticle->org, &u2, &v2, &z2); + } + else + { //causes flickers with lower vels (due to bouncing in physics) + if (speed < 50) + speed *= 50/speed; + VectorMA(pparticle->org, 2.5/(speed), pparticle->vel, delta); + D_2dPos(delta, &u1, &v1, &z1); + VectorMA(pparticle->org, -2.5/(speed), pparticle->vel, delta); + D_2dPos(delta, &u2, &v2, &z2); + } + + if ((v1 > d_vrectbottom_particle) || + (u1 > d_vrectright_particle) || + (v1 < d_vrecty) || + (u1 < d_vrectx)) + { + return; + } + + if ((v2 > d_vrectbottom_particle) || + (u2 > d_vrectright_particle) || + (v2 < d_vrecty) || + (u2 < d_vrectx)) + { + return; + } + + du = u2 - u1; + dv = v2 - v1; + dz = z2 - z1; + + if (!du && !dv) + count = 1; + else + { + count = VI2Length(du, dv); + if (!count) + count = 1; + } + + du *= 256*256; + dv *= 256*256; + dz *= 256*256; + u1 = u1<<16; + v1 = v1<<16; + z1 = z1<<16; + { + du /= count; + dv /= count; + dz /= count; + } + do + { + pz = d_pzbuffer + (d_zwidth * (v1>>16)) + (u1>>16); + + if (*pz <= z1>>16) + { +// *pz = z1>>16; + + pdest = d_viewbuffer + d_scantable[v1>>16] + (u1>>16); + draw(*pdest, pparticle->color); + } + + u1 += du; + v1 += dv; + z1 += dz; + } while (count--); +} diff --git a/engine/sw/d_parta.s b/engine/sw/d_parta.s new file mode 100644 index 000000000..b32f1bcb6 --- /dev/null +++ b/engine/sw/d_parta.s @@ -0,0 +1,477 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// d_parta.s +// x86 assembly-language 8-bpp particle-drawing code. +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "d_ifacea.h" +#include "asm_draw.h" + +#if id386 + +//---------------------------------------------------------------------- +// 8-bpp particle drawing code. +//---------------------------------------------------------------------- + +//FIXME: comments, full optimization + +//---------------------------------------------------------------------- +// 8-bpp particle queueing code. +//---------------------------------------------------------------------- + + .text + +#define P 12+4 + + .align 4 +.globl C(D_DrawParticle) +C(D_DrawParticle): + pushl %ebp // preserve caller's stack frame + pushl %edi // preserve register variables + pushl %ebx + + movl P(%esp),%edi + +// FIXME: better FP overlap in general here + +// transform point +// VectorSubtract (p->org, r_origin, local); + flds C(r_origin) + fsubrs pt_org(%edi) + flds pt_org+4(%edi) + fsubs C(r_origin)+4 + flds pt_org+8(%edi) + fsubs C(r_origin)+8 + fxch %st(2) // local[0] | local[1] | local[2] + +// transformed[2] = DotProduct(local, r_ppn); + flds C(r_ppn) // r_ppn[0] | local[0] | local[1] | local[2] + fmul %st(1),%st(0) // dot0 | local[0] | local[1] | local[2] + flds C(r_ppn)+4 // r_ppn[1] | dot0 | local[0] | local[1] | local[2] + fmul %st(3),%st(0) // dot1 | dot0 | local[0] | local[1] | local[2] + flds C(r_ppn)+8 // r_ppn[2] | dot1 | dot0 | local[0] | + // local[1] | local[2] + fmul %st(5),%st(0) // dot2 | dot1 | dot0 | local[0] | local[1] | local[2] + fxch %st(2) // dot0 | dot1 | dot2 | local[0] | local[1] | local[2] + faddp %st(0),%st(1) // dot0 + dot1 | dot2 | local[0] | local[1] | + // local[2] + faddp %st(0),%st(1) // z | local[0] | local[1] | local[2] + fld %st(0) // z | z | local[0] | local[1] | + // local[2] + fdivrs float_1 // 1/z | z | local[0] | local[1] | local[2] + fxch %st(1) // z | 1/z | local[0] | local[1] | local[2] + +// if (transformed[2] < PARTICLE_Z_CLIP) +// return; + fcomps float_particle_z_clip // 1/z | local[0] | local[1] | local[2] + fxch %st(3) // local[2] | local[0] | local[1] | 1/z + + flds C(r_pup) // r_pup[0] | local[2] | local[0] | local[1] | 1/z + fmul %st(2),%st(0) // dot0 | local[2] | local[0] | local[1] | 1/z + flds C(r_pup)+4 // r_pup[1] | dot0 | local[2] | local[0] | + // local[1] | 1/z + + fnstsw %ax + testb $1,%ah + jnz LPop6AndDone + +// transformed[1] = DotProduct(local, r_pup); + fmul %st(4),%st(0) // dot1 | dot0 | local[2] | local[0] | local[1] | 1/z + flds C(r_pup)+8 // r_pup[2] | dot1 | dot0 | local[2] | + // local[0] | local[1] | 1/z + fmul %st(3),%st(0) // dot2 | dot1 | dot0 | local[2] | local[0] | + // local[1] | 1/z + fxch %st(2) // dot0 | dot1 | dot2 | local[2] | local[0] | + // local[1] | 1/z + faddp %st(0),%st(1) // dot0 + dot1 | dot2 | local[2] | local[0] | + // local[1] | 1/z + faddp %st(0),%st(1) // y | local[2] | local[0] | local[1] | 1/z + fxch %st(3) // local[1] | local[2] | local[0] | y | 1/z + +// transformed[0] = DotProduct(local, r_pright); + fmuls C(r_pright)+4 // dot1 | local[2] | local[0] | y | 1/z + fxch %st(2) // local[0] | local[2] | dot1 | y | 1/z + fmuls C(r_pright) // dot0 | local[2] | dot1 | y | 1/z + fxch %st(1) // local[2] | dot0 | dot1 | y | 1/z + fmuls C(r_pright)+8 // dot2 | dot0 | dot1 | y | 1/z + fxch %st(2) // dot1 | dot0 | dot2 | y | 1/z + faddp %st(0),%st(1) // dot1 + dot0 | dot2 | y | 1/z + + faddp %st(0),%st(1) // x | y | 1/z + fxch %st(1) // y | x | 1/z + +// project the point + fmul %st(2),%st(0) // y/z | x | 1/z + fxch %st(1) // x | y/z | 1/z + fmul %st(2),%st(0) // x/z | y/z | 1/z + fxch %st(1) // y/z | x/z | 1/z + fsubrs C(ycenter) // v | x/z | 1/z + fxch %st(1) // x/z | v | 1/z + fadds C(xcenter) // u | v | 1/z +// FIXME: preadjust xcenter and ycenter + fxch %st(1) // v | u | 1/z + fadds float_point5 // v | u | 1/z + fxch %st(1) // u | v | 1/z + fadds float_point5 // u | v | 1/z + fxch %st(2) // 1/z | v | u + fmuls DP_32768 // 1/z * 0x8000 | v | u + fxch %st(2) // u | v | 1/z * 0x8000 + +// FIXME: use Terje's fp->int trick here? +// FIXME: check we're getting proper rounding here + fistpl DP_u // v | 1/z * 0x8000 + fistpl DP_v // 1/z * 0x8000 + + movl DP_u,%eax + movl DP_v,%edx + +// if ((v > d_vrectbottom_particle) || +// (u > d_vrectright_particle) || +// (v < d_vrecty) || +// (u < d_vrectx)) +// { +// continue; +// } + + movl C(d_vrectbottom_particle),%ebx + movl C(d_vrectright_particle),%ecx + cmpl %ebx,%edx + jg LPop1AndDone + cmpl %ecx,%eax + jg LPop1AndDone + movl C(d_vrecty),%ebx + movl C(d_vrectx),%ecx + cmpl %ebx,%edx + jl LPop1AndDone + + cmpl %ecx,%eax + jl LPop1AndDone + + flds pt_color(%edi) // color | 1/z * 0x8000 +// FIXME: use Terje's fast fp->int trick? + fistpl DP_Color // 1/z * 0x8000 + + movl C(d_viewbuffer),%ebx + + addl %eax,%ebx + movl C(d_scantable)(,%edx,4),%edi // point to the pixel + + imull C(d_zrowbytes),%edx // point to the z pixel + + leal (%edx,%eax,2),%edx + movl C(d_pzbuffer),%eax + + fistpl izi + + addl %ebx,%edi + addl %eax,%edx + +// pix = izi >> d_pix_shift; + + movl izi,%eax + movl C(d_pix_shift),%ecx + shrl %cl,%eax + movl izi,%ebp + +// if (pix < d_pix_min) +// pix = d_pix_min; +// else if (pix > d_pix_max) +// pix = d_pix_max; + + movl C(d_pix_min),%ebx + movl C(d_pix_max),%ecx + cmpl %ebx,%eax + jnl LTestPixMax + movl %ebx,%eax + jmp LTestDone + +LTestPixMax: + cmpl %ecx,%eax + jng LTestDone + movl %ecx,%eax +LTestDone: + + movb DP_Color,%ch + + movl C(d_y_aspect_shift),%ebx + testl %ebx,%ebx + jnz LDefault + + cmpl $4,%eax + ja LDefault + + jmp DP_EntryTable-4(,%eax,4) + +// 1x1 +.globl DP_1x1 +DP_1x1: + cmpw %bp,(%edx) // just one pixel to do + jg LDone + movw %bp,(%edx) + movb %ch,(%edi) + jmp LDone + +// 2x2 +.globl DP_2x2 +DP_2x2: + pushl %esi + movl C(screenwidth),%ebx + movl C(d_zrowbytes),%esi + + cmpw %bp,(%edx) + jg L2x2_1 + movw %bp,(%edx) + movb %ch,(%edi) +L2x2_1: + cmpw %bp,2(%edx) + jg L2x2_2 + movw %bp,2(%edx) + movb %ch,1(%edi) +L2x2_2: + cmpw %bp,(%edx,%esi,1) + jg L2x2_3 + movw %bp,(%edx,%esi,1) + movb %ch,(%edi,%ebx,1) +L2x2_3: + cmpw %bp,2(%edx,%esi,1) + jg L2x2_4 + movw %bp,2(%edx,%esi,1) + movb %ch,1(%edi,%ebx,1) +L2x2_4: + + popl %esi + jmp LDone + +// 3x3 +.globl DP_3x3 +DP_3x3: + pushl %esi + movl C(screenwidth),%ebx + movl C(d_zrowbytes),%esi + + cmpw %bp,(%edx) + jg L3x3_1 + movw %bp,(%edx) + movb %ch,(%edi) +L3x3_1: + cmpw %bp,2(%edx) + jg L3x3_2 + movw %bp,2(%edx) + movb %ch,1(%edi) +L3x3_2: + cmpw %bp,4(%edx) + jg L3x3_3 + movw %bp,4(%edx) + movb %ch,2(%edi) +L3x3_3: + + cmpw %bp,(%edx,%esi,1) + jg L3x3_4 + movw %bp,(%edx,%esi,1) + movb %ch,(%edi,%ebx,1) +L3x3_4: + cmpw %bp,2(%edx,%esi,1) + jg L3x3_5 + movw %bp,2(%edx,%esi,1) + movb %ch,1(%edi,%ebx,1) +L3x3_5: + cmpw %bp,4(%edx,%esi,1) + jg L3x3_6 + movw %bp,4(%edx,%esi,1) + movb %ch,2(%edi,%ebx,1) +L3x3_6: + + cmpw %bp,(%edx,%esi,2) + jg L3x3_7 + movw %bp,(%edx,%esi,2) + movb %ch,(%edi,%ebx,2) +L3x3_7: + cmpw %bp,2(%edx,%esi,2) + jg L3x3_8 + movw %bp,2(%edx,%esi,2) + movb %ch,1(%edi,%ebx,2) +L3x3_8: + cmpw %bp,4(%edx,%esi,2) + jg L3x3_9 + movw %bp,4(%edx,%esi,2) + movb %ch,2(%edi,%ebx,2) +L3x3_9: + + popl %esi + jmp LDone + + +// 4x4 +.globl DP_4x4 +DP_4x4: + pushl %esi + movl C(screenwidth),%ebx + movl C(d_zrowbytes),%esi + + cmpw %bp,(%edx) + jg L4x4_1 + movw %bp,(%edx) + movb %ch,(%edi) +L4x4_1: + cmpw %bp,2(%edx) + jg L4x4_2 + movw %bp,2(%edx) + movb %ch,1(%edi) +L4x4_2: + cmpw %bp,4(%edx) + jg L4x4_3 + movw %bp,4(%edx) + movb %ch,2(%edi) +L4x4_3: + cmpw %bp,6(%edx) + jg L4x4_4 + movw %bp,6(%edx) + movb %ch,3(%edi) +L4x4_4: + + cmpw %bp,(%edx,%esi,1) + jg L4x4_5 + movw %bp,(%edx,%esi,1) + movb %ch,(%edi,%ebx,1) +L4x4_5: + cmpw %bp,2(%edx,%esi,1) + jg L4x4_6 + movw %bp,2(%edx,%esi,1) + movb %ch,1(%edi,%ebx,1) +L4x4_6: + cmpw %bp,4(%edx,%esi,1) + jg L4x4_7 + movw %bp,4(%edx,%esi,1) + movb %ch,2(%edi,%ebx,1) +L4x4_7: + cmpw %bp,6(%edx,%esi,1) + jg L4x4_8 + movw %bp,6(%edx,%esi,1) + movb %ch,3(%edi,%ebx,1) +L4x4_8: + + leal (%edx,%esi,2),%edx + leal (%edi,%ebx,2),%edi + + cmpw %bp,(%edx) + jg L4x4_9 + movw %bp,(%edx) + movb %ch,(%edi) +L4x4_9: + cmpw %bp,2(%edx) + jg L4x4_10 + movw %bp,2(%edx) + movb %ch,1(%edi) +L4x4_10: + cmpw %bp,4(%edx) + jg L4x4_11 + movw %bp,4(%edx) + movb %ch,2(%edi) +L4x4_11: + cmpw %bp,6(%edx) + jg L4x4_12 + movw %bp,6(%edx) + movb %ch,3(%edi) +L4x4_12: + + cmpw %bp,(%edx,%esi,1) + jg L4x4_13 + movw %bp,(%edx,%esi,1) + movb %ch,(%edi,%ebx,1) +L4x4_13: + cmpw %bp,2(%edx,%esi,1) + jg L4x4_14 + movw %bp,2(%edx,%esi,1) + movb %ch,1(%edi,%ebx,1) +L4x4_14: + cmpw %bp,4(%edx,%esi,1) + jg L4x4_15 + movw %bp,4(%edx,%esi,1) + movb %ch,2(%edi,%ebx,1) +L4x4_15: + cmpw %bp,6(%edx,%esi,1) + jg L4x4_16 + movw %bp,6(%edx,%esi,1) + movb %ch,3(%edi,%ebx,1) +L4x4_16: + + popl %esi + jmp LDone + +// default case, handling any size particle +LDefault: + +// count = pix << d_y_aspect_shift; + + movl %eax,%ebx + movl %eax,DP_Pix + movb C(d_y_aspect_shift),%cl + shll %cl,%ebx + +// for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) +// { +// for (i=0 ; i> 16) + +// (r_sstepx >> 16); + + movl C(r_sstepx),%eax + movl C(r_tstepx),%edx + shll $16,%eax + shll $16,%edx + movl %eax,C(a_sstepxfrac) + movl %edx,C(a_tstepxfrac) + + movl C(r_sstepx),%ecx + movl C(r_tstepx),%eax + sarl $16,%ecx + sarl $16,%eax + imull skinwidth(%esp) + addl %ecx,%eax + movl %eax,C(a_ststepxwhole) + + ret + + +//---------------------------------------------------------------------- +// recursive subdivision affine triangle drawing code +// +// not C-callable because of stdcall return +//---------------------------------------------------------------------- + +#define lp1 4+16 +#define lp2 8+16 +#define lp3 12+16 + +.globl C(D_PolysetRecursiveTriangle) +C(D_PolysetRecursiveTriangle): + pushl %ebp // preserve caller stack frame pointer + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + +// int *temp; +// int d; +// int new[6]; +// int i; +// int z; +// short *zbuf; + movl lp2(%esp),%esi + movl lp1(%esp),%ebx + movl lp3(%esp),%edi + +// d = lp2[0] - lp1[0]; +// if (d < -1 || d > 1) +// goto split; + movl 0(%esi),%eax + + movl 0(%ebx),%edx + movl 4(%esi),%ebp + + subl %edx,%eax + movl 4(%ebx),%ecx + + subl %ecx,%ebp + incl %eax + + cmpl $2,%eax + ja LSplit + +// d = lp2[1] - lp1[1]; +// if (d < -1 || d > 1) +// goto split; + movl 0(%edi),%eax + incl %ebp + + cmpl $2,%ebp + ja LSplit + +// d = lp3[0] - lp2[0]; +// if (d < -1 || d > 1) +// goto split2; + movl 0(%esi),%edx + movl 4(%edi),%ebp + + subl %edx,%eax + movl 4(%esi),%ecx + + subl %ecx,%ebp + incl %eax + + cmpl $2,%eax + ja LSplit2 + +// d = lp3[1] - lp2[1]; +// if (d < -1 || d > 1) +// goto split2; + movl 0(%ebx),%eax + incl %ebp + + cmpl $2,%ebp + ja LSplit2 + +// d = lp1[0] - lp3[0]; +// if (d < -1 || d > 1) +// goto split3; + movl 0(%edi),%edx + movl 4(%ebx),%ebp + + subl %edx,%eax + movl 4(%edi),%ecx + + subl %ecx,%ebp + incl %eax + + incl %ebp + movl %ebx,%edx + + cmpl $2,%eax + ja LSplit3 + +// d = lp1[1] - lp3[1]; +// if (d < -1 || d > 1) +// { +//split3: +// temp = lp1; +// lp3 = lp2; +// lp1 = lp3; +// lp2 = temp; +// goto split; +// } +// +// return; // entire tri is filled +// + cmpl $2,%ebp + jna LDone + +LSplit3: + movl %edi,%ebx + movl %esi,%edi + movl %edx,%esi + jmp LSplit + +//split2: +LSplit2: + +// temp = lp1; +// lp1 = lp2; +// lp2 = lp3; +// lp3 = temp; + movl %ebx,%eax + movl %esi,%ebx + movl %edi,%esi + movl %eax,%edi + +//split: +LSplit: + + subl $24,%esp // allocate space for a new vertex + +//// split this edge +// new[0] = (lp1[0] + lp2[0]) >> 1; +// new[1] = (lp1[1] + lp2[1]) >> 1; +// new[2] = (lp1[2] + lp2[2]) >> 1; +// new[3] = (lp1[3] + lp2[3]) >> 1; +// new[5] = (lp1[5] + lp2[5]) >> 1; + movl 8(%ebx),%eax + + movl 8(%esi),%edx + movl 12(%ebx),%ecx + + addl %edx,%eax + movl 12(%esi),%edx + + sarl $1,%eax + addl %edx,%ecx + + movl %eax,8(%esp) + movl 20(%ebx),%eax + + sarl $1,%ecx + movl 20(%esi),%edx + + movl %ecx,12(%esp) + addl %edx,%eax + + movl 0(%ebx),%ecx + movl 0(%esi),%edx + + sarl $1,%eax + addl %ecx,%edx + + movl %eax,20(%esp) + movl 4(%ebx),%eax + + sarl $1,%edx + movl 4(%esi),%ebp + + movl %edx,0(%esp) + addl %eax,%ebp + + sarl $1,%ebp + movl %ebp,4(%esp) + +//// draw the point if splitting a leading edge +// if (lp2[1] > lp1[1]) +// goto nodraw; + cmpl %eax,4(%esi) + jg LNoDraw + +// if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) +// goto nodraw; + movl 0(%esi),%edx + jnz LDraw + + cmpl %ecx,%edx + jl LNoDraw + +LDraw: + +// z = new[5] >> 16; + movl 20(%esp),%edx + movl 4(%esp),%ecx + + sarl $16,%edx + movl 0(%esp),%ebp + +// zbuf = zspantable[new[1]] + new[0]; + movl C(zspantable)(,%ecx,4),%eax + +// if (z >= *zbuf) +// { + cmpw (%eax,%ebp,2),%dx + jnge LNoDraw + +// int pix; +// +// *zbuf = z; + movw %dx,(%eax,%ebp,2) + +// pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]]; + movl 12(%esp),%eax + + sarl $16,%eax + movl 8(%esp),%edx + + sarl $16,%edx + subl %ecx,%ecx + + movl C(skintable)(,%eax,4),%eax + movl 4(%esp),%ebp + + movb (%eax,%edx,),%cl + movl C(d_pcolormap),%edx + + movb (%edx,%ecx,),%dl + movl 0(%esp),%ecx + +// d_viewbuffer[d_scantable[new[1]] + new[0]] = pix; + movl C(d_scantable)(,%ebp,4),%eax + addl %eax,%ecx + movl C(d_viewbuffer),%eax + movb %dl,(%eax,%ecx,1) + +// } +// +//nodraw: +LNoDraw: + +//// recursively continue +// D_PolysetRecursiveTriangle (lp3, lp1, new); + pushl %esp + pushl %ebx + pushl %edi + call C(D_PolysetRecursiveTriangle) + +// D_PolysetRecursiveTriangle (lp3, new, lp2); + movl %esp,%ebx + pushl %esi + pushl %ebx + pushl %edi + call C(D_PolysetRecursiveTriangle) + addl $24,%esp + +LDone: + popl %ebx // restore register variables + popl %edi + popl %esi + popl %ebp // restore caller stack frame pointer + ret $12 + + +//---------------------------------------------------------------------- +// 8-bpp horizontal span drawing code for affine polygons, with smooth +// shading and no transparency +//---------------------------------------------------------------------- + +#define pspans 4+8 + +.globl C(D_PolysetAff8Start) +C(D_PolysetAff8Start): + +.globl C(D_PolysetDrawSpans8) +C(D_PolysetDrawSpans8): + pushl %esi // preserve register variables + pushl %ebx + + movl pspans(%esp),%esi // point to the first span descriptor + movl C(r_zistepx),%ecx + + pushl %ebp // preserve caller's stack frame + pushl %edi + + rorl $16,%ecx // put high 16 bits of 1/z step in low word + movl spanpackage_t_count(%esi),%edx + + movl %ecx,lzistepx + +LSpanLoop: + +// lcount = d_aspancount - pspanpackage->count; +// +// errorterm += erroradjustup; +// if (errorterm >= 0) +// { +// d_aspancount += d_countextrastep; +// errorterm -= erroradjustdown; +// } +// else +// { +// d_aspancount += ubasestep; +// } + movl C(d_aspancount),%eax + subl %edx,%eax + + movl C(erroradjustup),%edx + movl C(errorterm),%ebx + addl %edx,%ebx + js LNoTurnover + + movl C(erroradjustdown),%edx + movl C(d_countextrastep),%edi + subl %edx,%ebx + movl C(d_aspancount),%ebp + movl %ebx,C(errorterm) + addl %edi,%ebp + movl %ebp,C(d_aspancount) + jmp LRightEdgeStepped + +LNoTurnover: + movl C(d_aspancount),%edi + movl C(ubasestep),%edx + movl %ebx,C(errorterm) + addl %edx,%edi + movl %edi,C(d_aspancount) + +LRightEdgeStepped: + cmpl $1,%eax + + jl LNextSpan + jz LExactlyOneLong + +// +// set up advancetable +// + movl C(a_ststepxwhole),%ecx + movl C(r_affinetridesc)+atd_skinwidth,%edx + + movl %ecx,advancetable+4 // advance base in t + addl %edx,%ecx + + movl %ecx,advancetable // advance extra in t + movl C(a_tstepxfrac),%ecx + + movw C(r_lstepx),%cx + movl %eax,%edx // count + + movl %ecx,tstep + addl $7,%edx + + shrl $3,%edx // count of full and partial loops + movl spanpackage_t_sfrac(%esi),%ebx + + movw %dx,%bx + movl spanpackage_t_pz(%esi),%ecx + + negl %eax + + movl spanpackage_t_pdest(%esi),%edi + andl $7,%eax // 0->0, 1->7, 2->6, ... , 7->1 + + subl %eax,%edi // compensate for hardwired offsets + subl %eax,%ecx + + subl %eax,%ecx + movl spanpackage_t_tfrac(%esi),%edx + + movw spanpackage_t_light(%esi),%dx + movl spanpackage_t_zi(%esi),%ebp + + rorl $16,%ebp // put high 16 bits of 1/z in low word + pushl %esi + + movl spanpackage_t_ptex(%esi),%esi + jmp aff8entryvec_table(,%eax,4) + +// %bx = count of full and partial loops +// %ebx high word = sfrac +// %ecx = pz +// %dx = light +// %edx high word = tfrac +// %esi = ptex +// %edi = pdest +// %ebp = 1/z +// tstep low word = C(r_lstepx) +// tstep high word = C(a_tstepxfrac) +// C(a_sstepxfrac) low word = 0 +// C(a_sstepxfrac) high word = C(a_sstepxfrac) + +LDrawLoop: + +// FIXME: do we need to clamp light? We may need at least a buffer bit to +// keep it from poking into tfrac and causing problems + +LDraw8: + cmpw (%ecx),%bp + jl Lp1 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,(%ecx) + movb 0x12345678(%eax),%al +LPatch8: + movb %al,(%edi) +Lp1: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + +LDraw7: + cmpw 2(%ecx),%bp + jl Lp2 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,2(%ecx) + movb 0x12345678(%eax),%al +LPatch7: + movb %al,1(%edi) +Lp2: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + +LDraw6: + cmpw 4(%ecx),%bp + jl Lp3 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,4(%ecx) + movb 0x12345678(%eax),%al +LPatch6: + movb %al,2(%edi) +Lp3: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + +LDraw5: + cmpw 6(%ecx),%bp + jl Lp4 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,6(%ecx) + movb 0x12345678(%eax),%al +LPatch5: + movb %al,3(%edi) +Lp4: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + +LDraw4: + cmpw 8(%ecx),%bp + jl Lp5 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,8(%ecx) + movb 0x12345678(%eax),%al +LPatch4: + movb %al,4(%edi) +Lp5: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + +LDraw3: + cmpw 10(%ecx),%bp + jl Lp6 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,10(%ecx) + movb 0x12345678(%eax),%al +LPatch3: + movb %al,5(%edi) +Lp6: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + +LDraw2: + cmpw 12(%ecx),%bp + jl Lp7 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,12(%ecx) + movb 0x12345678(%eax),%al +LPatch2: + movb %al,6(%edi) +Lp7: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + +LDraw1: + cmpw 14(%ecx),%bp + jl Lp8 + xorl %eax,%eax + movb %dh,%ah + movb (%esi),%al + movw %bp,14(%ecx) + movb 0x12345678(%eax),%al +LPatch1: + movb %al,7(%edi) +Lp8: + addl tstep,%edx + sbbl %eax,%eax + addl lzistepx,%ebp + adcl $0,%ebp + addl C(a_sstepxfrac),%ebx + adcl advancetable+4(,%eax,4),%esi + + addl $8,%edi + addl $16,%ecx + + decw %bx + jnz LDrawLoop + + popl %esi // restore spans pointer +LNextSpan: + addl $(spanpackage_t_size),%esi // point to next span +LNextSpanESISet: + movl spanpackage_t_count(%esi),%edx + cmpl $-999999,%edx // any more spans? + jnz LSpanLoop // yes + + popl %edi + popl %ebp // restore the caller's stack frame + popl %ebx // restore register variables + popl %esi + ret + + +// draw a one-long span + +LExactlyOneLong: + + movl spanpackage_t_pz(%esi),%ecx + movl spanpackage_t_zi(%esi),%ebp + + rorl $16,%ebp // put high 16 bits of 1/z in low word + movl spanpackage_t_ptex(%esi),%ebx + + cmpw (%ecx),%bp + jl LNextSpan + xorl %eax,%eax + movl spanpackage_t_pdest(%esi),%edi + movb spanpackage_t_light+1(%esi),%ah + addl $(spanpackage_t_size),%esi // point to next span + movb (%ebx),%al + movw %bp,(%ecx) + movb 0x12345678(%eax),%al +LPatch9: + movb %al,(%edi) + + jmp LNextSpanESISet + +.globl C(D_PolysetAff8End) +C(D_PolysetAff8End): + + +#define pcolormap 4 + +.globl C(D_Aff8Patch) +C(D_Aff8Patch): + movl pcolormap(%esp),%eax + movl %eax,LPatch1-4 + movl %eax,LPatch2-4 + movl %eax,LPatch3-4 + movl %eax,LPatch4-4 + movl %eax,LPatch5-4 + movl %eax,LPatch6-4 + movl %eax,LPatch7-4 + movl %eax,LPatch8-4 + movl %eax,LPatch9-4 + + ret + + +//---------------------------------------------------------------------- +// Alias model polygon dispatching code, combined with subdivided affine +// triangle drawing code +//---------------------------------------------------------------------- + +.globl C(D_PolysetDraw) +C(D_PolysetDraw): + +// spanpackage_t spans[DPS_MAXSPANS + 1 + +// ((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1]; +// // one extra because of cache line pretouching +// +// a_spans = (spanpackage_t *) +// (((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + subl $(SPAN_SIZE),%esp + movl %esp,%eax + addl $(CACHE_SIZE - 1),%eax + andl $(~(CACHE_SIZE - 1)),%eax + movl %eax,C(a_spans) + +// if (r_affinetridesc.drawtype) +// D_DrawSubdiv (); +// else +// D_DrawNonSubdiv (); + movl C(r_affinetridesc)+atd_drawtype,%eax + testl %eax,%eax + jz C(D_DrawNonSubdiv) + + pushl %ebp // preserve caller stack frame pointer + +// lnumtriangles = r_affinetridesc.numtriangles; + movl C(r_affinetridesc)+atd_numtriangles,%ebp + + pushl %esi // preserve register variables + shll $4,%ebp + + pushl %ebx +// ptri = r_affinetridesc.ptriangles; + movl C(r_affinetridesc)+atd_ptriangles,%ebx + + pushl %edi + +// mtriangle_t *ptri; +// finalvert_t *pfv, *index0, *index1, *index2; +// int i; +// int lnumtriangles; +// int s0, s1, s2; + +// pfv = r_affinetridesc.pfinalverts; + movl C(r_affinetridesc)+atd_pfinalverts,%edi + +// for (i=0 ; iv[1]-index1->v[1]) * +// (index0->v[0]-index2->v[0]) - +// (index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1])) >= 0) +// { +// continue; +// } +// +// d_pcolormap = &((byte *)acolormap)[index0->v[4] & 0xFF00]; + fildl fv_v+4(%ecx) // i0v1 + fildl fv_v+4(%esi) // i1v1 | i0v1 + fildl fv_v+0(%ecx) // i0v0 | i1v1 | i0v1 + fildl fv_v+0(%edx) // i2v0 | i0v0 | i1v1 | i0v1 + fxch %st(2) // i1v1 | i0v0 | i2v0 | i0v1 + fsubr %st(3),%st(0) // i0v1-i1v1 | i0v0 | i2v0 | i0v1 + fildl fv_v+0(%esi) // i1v0 | i0v1-i1v1 | i0v0 | i2v0 | i0v1 + fxch %st(2) // i0v0 | i0v1-i1v1 | i1v0 | i2v0 | i0v1 + fsub %st(0),%st(3) // i0v0 | i0v1-i1v1 | i1v0 | i0v0-i2v0 | i0v1 + fildl fv_v+4(%edx) // i2v1 | i0v0 | i0v1-i1v1 | i1v0 | i0v0-i2v0| i0v1 + fxch %st(1) // i0v0 | i2v1 | i0v1-i1v1 | i1v0 | i0v0-i2v0| i0v1 + fsubp %st(0),%st(3) // i2v1 | i0v1-i1v1 | i0v0-i1v0 | i0v0-i2v0 | i0v1 + fxch %st(1) // i0v1-i1v1 | i2v1 | i0v0-i1v0 | i0v0-i2v0 | i0v1 + fmulp %st(0),%st(3) // i2v1 | i0v0-i1v0 | i0v1-i1v1*i0v0-i2v0 | i0v1 + fsubrp %st(0),%st(3) // i0v0-i1v0 | i0v1-i1v1*i0v0-i2v0 | i0v1-i2v1 + movl fv_v+16(%ecx),%eax + andl $0xFF00,%eax + fmulp %st(0),%st(2) // i0v1-i1v1*i0v0-i2v0 | i0v0-i1v0*i0v1-i2v1 + addl C(acolormap),%eax + fsubp %st(0),%st(1) // (i0v1-i1v1)*(i0v0-i2v0)-(i0v0-i1v0)*(i0v1-i2v1) + movl %eax,C(d_pcolormap) + fstps Ltemp + movl Ltemp,%eax + subl $0x80000001,%eax + jc Lskip + +#if 0 +// if (ptri[i].facesfront) +// { +// D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v); + + movl mtri_facesfront-16(%ebx,%ebp,),%eax + testl %eax,%eax + jz Lfacesback +#endif + pushl %edx + pushl %esi + pushl %ecx + call C(D_PolysetRecursiveTriangle) + + subl $16,%ebp + jnz Llooptop + jmp Ldone2 +#if 0 +// } +// else +// { +Lfacesback: + +// s0 = index0->v[2]; +// s1 = index1->v[2]; +// s2 = index2->v[2]; + movl fv_v+8(%ecx),%eax + pushl %eax + movl fv_v+8(%esi),%eax + pushl %eax + movl fv_v+8(%edx),%eax + pushl %eax + pushl %ecx + pushl %edx + +// if (index0->flags & ALIAS_ONSEAM) +// index0->v[2] += r_affinetridesc.seamfixupX16; + movl C(r_affinetridesc)+atd_seamfixupX16,%eax + testl $(ALIAS_ONSEAM),fv_flags(%ecx) + jz Lp11 + addl %eax,fv_v+8(%ecx) +Lp11: + +// if (index1->flags & ALIAS_ONSEAM) +// index1->v[2] += r_affinetridesc.seamfixupX16; + testl $(ALIAS_ONSEAM),fv_flags(%esi) + jz Lp12 + addl %eax,fv_v+8(%esi) +Lp12: + +// if (index2->flags & ALIAS_ONSEAM) +// index2->v[2] += r_affinetridesc.seamfixupX16; + testl $(ALIAS_ONSEAM),fv_flags(%edx) + jz Lp13 + addl %eax,fv_v+8(%edx) +Lp13: + +// D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v); + pushl %edx + pushl %esi + pushl %ecx + call C(D_PolysetRecursiveTriangle) + +// index0->v[2] = s0; +// index1->v[2] = s1; +// index2->v[2] = s2; + popl %edx + popl %ecx + popl %eax + movl %eax,fv_v+8(%edx) + popl %eax + movl %eax,fv_v+8(%esi) + popl %eax + movl %eax,fv_v+8(%ecx) + +// } + +#endif + +// } +Lskip: + subl $16,%ebp + jnz Llooptop + +Ldone2: + popl %edi // restore the caller's stack frame + popl %ebx + popl %esi // restore register variables + popl %ebp + + addl $(SPAN_SIZE),%esp + + ret + + +//---------------------------------------------------------------------- +// Alias model triangle left-edge scanning code +//---------------------------------------------------------------------- + +#define height 4+16 + +.globl C(D_PolysetScanLeftEdge) +C(D_PolysetScanLeftEdge): + pushl %ebp // preserve caller stack frame pointer + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + + movl height(%esp),%eax + movl C(d_sfrac),%ecx + andl $0xFFFF,%eax + movl C(d_ptex),%ebx + orl %eax,%ecx + movl C(d_pedgespanpackage),%esi + movl C(d_tfrac),%edx + movl C(d_light),%edi + movl C(d_zi),%ebp + +// %eax: scratch +// %ebx: d_ptex +// %ecx: d_sfrac in high word, count in low word +// %edx: d_tfrac +// %esi: d_pedgespanpackage, errorterm, scratch alternately +// %edi: d_light +// %ebp: d_zi + +// do +// { + +LScanLoop: + +// d_pedgespanpackage->ptex = ptex; +// d_pedgespanpackage->pdest = d_pdest; +// d_pedgespanpackage->pz = d_pz; +// d_pedgespanpackage->count = d_aspancount; +// d_pedgespanpackage->light = d_light; +// d_pedgespanpackage->zi = d_zi; +// d_pedgespanpackage->sfrac = d_sfrac << 16; +// d_pedgespanpackage->tfrac = d_tfrac << 16; + movl %ebx,spanpackage_t_ptex(%esi) + movl C(d_pdest),%eax + movl %eax,spanpackage_t_pdest(%esi) + movl C(d_pz),%eax + movl %eax,spanpackage_t_pz(%esi) + movl C(d_aspancount),%eax + movl %eax,spanpackage_t_count(%esi) + movl %edi,spanpackage_t_light(%esi) + movl %ebp,spanpackage_t_zi(%esi) + movl %ecx,spanpackage_t_sfrac(%esi) + movl %edx,spanpackage_t_tfrac(%esi) + +// pretouch the next cache line + movb spanpackage_t_size(%esi),%al + +// d_pedgespanpackage++; + addl $(spanpackage_t_size),%esi + movl C(erroradjustup),%eax + movl %esi,C(d_pedgespanpackage) + +// errorterm += erroradjustup; + movl C(errorterm),%esi + addl %eax,%esi + movl C(d_pdest),%eax + +// if (errorterm >= 0) +// { + js LNoLeftEdgeTurnover + +// errorterm -= erroradjustdown; +// d_pdest += d_pdestextrastep; + subl C(erroradjustdown),%esi + addl C(d_pdestextrastep),%eax + movl %esi,C(errorterm) + movl %eax,C(d_pdest) + +// d_pz += d_pzextrastep; +// d_aspancount += d_countextrastep; +// d_ptex += d_ptexextrastep; +// d_sfrac += d_sfracextrastep; +// d_ptex += d_sfrac >> 16; +// d_sfrac &= 0xFFFF; +// d_tfrac += d_tfracextrastep; + movl C(d_pz),%eax + movl C(d_aspancount),%esi + addl C(d_pzextrastep),%eax + addl C(d_sfracextrastep),%ecx + adcl C(d_ptexextrastep),%ebx + addl C(d_countextrastep),%esi + movl %eax,C(d_pz) + movl C(d_tfracextrastep),%eax + movl %esi,C(d_aspancount) + addl %eax,%edx + +// if (d_tfrac & 0x10000) +// { + jnc LSkip1 + +// d_ptex += r_affinetridesc.skinwidth; +// d_tfrac &= 0xFFFF; + addl C(r_affinetridesc)+atd_skinwidth,%ebx + +// } + +LSkip1: + +// d_light += d_lightextrastep; +// d_zi += d_ziextrastep; + addl C(d_lightextrastep),%edi + addl C(d_ziextrastep),%ebp + +// } + movl C(d_pedgespanpackage),%esi + decl %ecx + testl $0xFFFF,%ecx + jnz LScanLoop + + popl %ebx + popl %edi + popl %esi + popl %ebp + ret + +// else +// { + +LNoLeftEdgeTurnover: + movl %esi,C(errorterm) + +// d_pdest += d_pdestbasestep; + addl C(d_pdestbasestep),%eax + movl %eax,C(d_pdest) + +// d_pz += d_pzbasestep; +// d_aspancount += ubasestep; +// d_ptex += d_ptexbasestep; +// d_sfrac += d_sfracbasestep; +// d_ptex += d_sfrac >> 16; +// d_sfrac &= 0xFFFF; + movl C(d_pz),%eax + movl C(d_aspancount),%esi + addl C(d_pzbasestep),%eax + addl C(d_sfracbasestep),%ecx + adcl C(d_ptexbasestep),%ebx + addl C(ubasestep),%esi + movl %eax,C(d_pz) + movl %esi,C(d_aspancount) + +// d_tfrac += d_tfracbasestep; + movl C(d_tfracbasestep),%esi + addl %esi,%edx + +// if (d_tfrac & 0x10000) +// { + jnc LSkip2 + +// d_ptex += r_affinetridesc.skinwidth; +// d_tfrac &= 0xFFFF; + addl C(r_affinetridesc)+atd_skinwidth,%ebx + +// } + +LSkip2: + +// d_light += d_lightbasestep; +// d_zi += d_zibasestep; + addl C(d_lightbasestep),%edi + addl C(d_zibasestep),%ebp + +// } +// } while (--height); + movl C(d_pedgespanpackage),%esi + decl %ecx + testl $0xFFFF,%ecx + jnz LScanLoop + + popl %ebx + popl %edi + popl %esi + popl %ebp + ret + + +//---------------------------------------------------------------------- +// Alias model vertex drawing code +//---------------------------------------------------------------------- + +#define fv 4+8 +#define numverts 8+8 + +.globl C(D_PolysetDrawFinalVerts) +C(D_PolysetDrawFinalVerts): + pushl %ebp // preserve caller stack frame pointer + pushl %ebx + +// int i, z; +// short *zbuf; + + movl numverts(%esp),%ecx + movl fv(%esp),%ebx + + pushl %esi // preserve register variables + pushl %edi + +LFVLoop: + +// for (i=0 ; iv[0] < r_refdef.vrectright) && +// (fv->v[1] < r_refdef.vrectbottom)) +// { + movl fv_v+0(%ebx),%eax + movl C(r_refdef)+rd_vrectright,%edx + cmpl %edx,%eax + jge LNextVert + movl fv_v+4(%ebx),%esi + movl C(r_refdef)+rd_vrectbottom,%edx + cmpl %edx,%esi + jge LNextVert + +// zbuf = zspantable[fv->v[1]] + fv->v[0]; + movl C(zspantable)(,%esi,4),%edi + +// z = fv->v[5]>>16; + movl fv_v+20(%ebx),%edx + shrl $16,%edx + +// if (z >= *zbuf) +// { +// int pix; + cmpw (%edi,%eax,2),%dx + jl LNextVert + +// *zbuf = z; + movw %dx,(%edi,%eax,2) + +// pix = skintable[fv->v[3]>>16][fv->v[2]>>16]; + movl fv_v+12(%ebx),%edi + shrl $16,%edi + movl C(skintable)(,%edi,4),%edi + movl fv_v+8(%ebx),%edx + shrl $16,%edx + movb (%edi,%edx),%dl + +// pix = ((byte *)acolormap)[pix + (fv->v[4] & 0xFF00)]; + movl fv_v+16(%ebx),%edi + andl $0xFF00,%edi + andl $0x00FF,%edx + addl %edx,%edi + movl C(acolormap),%edx + movb (%edx,%edi,1),%dl + +// d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = pix; + movl C(d_scantable)(,%esi,4),%edi + movl C(d_viewbuffer),%esi + addl %eax,%edi + movb %dl,(%esi,%edi) + +// } +// } +// } +LNextVert: + addl $(fv_size),%ebx + decl %ecx + jnz LFVLoop + + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + + +//---------------------------------------------------------------------- +// Alias model non-subdivided polygon dispatching code +// +// not C-callable because of stack buffer cleanup +//---------------------------------------------------------------------- + +.globl C(D_DrawNonSubdiv) +C(D_DrawNonSubdiv): + pushl %ebp // preserve caller stack frame pointer + movl C(r_affinetridesc)+atd_numtriangles,%ebp + pushl %ebx + shll $(mtri_shift),%ebp + pushl %esi // preserve register variables + movl C(r_affinetridesc)+atd_ptriangles,%esi + pushl %edi + +// mtriangle_t *ptri; +// finalvert_t *pfv, *index0, *index1, *index2; +// int i; +// int lnumtriangles; + +// pfv = r_affinetridesc.pfinalverts; +// ptri = r_affinetridesc.ptriangles; +// lnumtriangles = r_affinetridesc.numtriangles; + +LNDLoop: + +// for (i=0 ; ivertindex[0]; +// index1 = pfv + ptri->vertindex[1]; +// index2 = pfv + ptri->vertindex[2]; + movl C(r_affinetridesc)+atd_pfinalverts,%edi + movl mtri_vertindex+0-mtri_size(%esi,%ebp,1),%ecx + shll $(fv_shift),%ecx + movl mtri_vertindex+4-mtri_size(%esi,%ebp,1),%edx + shll $(fv_shift),%edx + movl mtri_vertindex+8-mtri_size(%esi,%ebp,1),%ebx + shll $(fv_shift),%ebx + addl %edi,%ecx + addl %edi,%edx + addl %edi,%ebx + +// d_xdenom = (index0->v[1]-index1->v[1]) * +// (index0->v[0]-index2->v[0]) - +// (index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1]); + movl fv_v+4(%ecx),%eax + movl fv_v+0(%ecx),%esi + subl fv_v+4(%edx),%eax + subl fv_v+0(%ebx),%esi + imull %esi,%eax + movl fv_v+0(%ecx),%esi + movl fv_v+4(%ecx),%edi + subl fv_v+0(%edx),%esi + subl fv_v+4(%ebx),%edi + imull %esi,%edi + subl %edi,%eax + +// if (d_xdenom >= 0) +// { +// continue; + jns LNextTri + +// } + + movl %eax,C(d_xdenom) + fildl C(d_xdenom) + +// r_p0[0] = index0->v[0]; // u +// r_p0[1] = index0->v[1]; // v +// r_p0[2] = index0->v[2]; // s +// r_p0[3] = index0->v[3]; // t +// r_p0[4] = index0->v[4]; // light +// r_p0[5] = index0->v[5]; // iz + movl fv_v+0(%ecx),%eax + movl fv_v+4(%ecx),%esi + movl %eax,C(r_p0)+0 + movl %esi,C(r_p0)+4 + movl fv_v+8(%ecx),%eax + movl fv_v+12(%ecx),%esi + movl %eax,C(r_p0)+8 + movl %esi,C(r_p0)+12 + movl fv_v+16(%ecx),%eax + movl fv_v+20(%ecx),%esi + movl %eax,C(r_p0)+16 + movl %esi,C(r_p0)+20 + + fdivrs float_1 + +// r_p1[0] = index1->v[0]; +// r_p1[1] = index1->v[1]; +// r_p1[2] = index1->v[2]; +// r_p1[3] = index1->v[3]; +// r_p1[4] = index1->v[4]; +// r_p1[5] = index1->v[5]; + movl fv_v+0(%edx),%eax + movl fv_v+4(%edx),%esi + movl %eax,C(r_p1)+0 + movl %esi,C(r_p1)+4 + movl fv_v+8(%edx),%eax + movl fv_v+12(%edx),%esi + movl %eax,C(r_p1)+8 + movl %esi,C(r_p1)+12 + movl fv_v+16(%edx),%eax + movl fv_v+20(%edx),%esi + movl %eax,C(r_p1)+16 + movl %esi,C(r_p1)+20 + +// r_p2[0] = index2->v[0]; +// r_p2[1] = index2->v[1]; +// r_p2[2] = index2->v[2]; +// r_p2[3] = index2->v[3]; +// r_p2[4] = index2->v[4]; +// r_p2[5] = index2->v[5]; + movl fv_v+0(%ebx),%eax + movl fv_v+4(%ebx),%esi + movl %eax,C(r_p2)+0 + movl %esi,C(r_p2)+4 + movl fv_v+8(%ebx),%eax + movl fv_v+12(%ebx),%esi + movl %eax,C(r_p2)+8 + movl %esi,C(r_p2)+12 + movl fv_v+16(%ebx),%eax + movl fv_v+20(%ebx),%esi + movl %eax,C(r_p2)+16 +#if 0 + movl C(r_affinetridesc)+atd_ptriangles,%edi +#endif + movl %esi,C(r_p2)+20 + +#if 0 + movl mtri_facesfront-mtri_size(%edi,%ebp,1),%eax + +// if (!ptri->facesfront) +// { + testl %eax,%eax + jnz LFacesFront + +// if (index0->flags & ALIAS_ONSEAM) +// r_p0[2] += r_affinetridesc.seamfixupX16; + movl fv_flags(%ecx),%eax + movl fv_flags(%edx),%esi + movl fv_flags(%ebx),%edi + testl $(ALIAS_ONSEAM),%eax + movl C(r_affinetridesc)+atd_seamfixupX16,%eax + jz LOnseamDone0 + addl %eax,C(r_p0)+8 +LOnseamDone0: + +// if (index1->flags & ALIAS_ONSEAM) +// r_p1[2] += r_affinetridesc.seamfixupX16; + testl $(ALIAS_ONSEAM),%esi + jz LOnseamDone1 + addl %eax,C(r_p1)+8 +LOnseamDone1: + +// if (index2->flags & ALIAS_ONSEAM) +// r_p2[2] += r_affinetridesc.seamfixupX16; + testl $(ALIAS_ONSEAM),%edi + jz LOnseamDone2 + addl %eax,C(r_p2)+8 +LOnseamDone2: + +// } + +LFacesFront: +#endif + + fstps C(d_xdenom) + +// D_PolysetSetEdgeTable (); +// D_RasterizeAliasPolySmooth8 (); + call C(D_PolysetSetEdgeTable) + call C(D_RasterizeAliasPolySmooth8) + +LNextTri: + movl C(r_affinetridesc)+atd_ptriangles,%esi + subl $16,%ebp + jnz LNDLoop +// } + + popl %edi + popl %esi + popl %ebx + popl %ebp + + addl $(SPAN_SIZE),%esp + + ret + + +#endif // id386 + diff --git a/engine/sw/d_polyse.c b/engine/sw/d_polyse.c new file mode 100644 index 000000000..221f58a1e --- /dev/null +++ b/engine/sw/d_polyse.c @@ -0,0 +1,2446 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_polyset.c: routines for drawing sets of polygons sharing the same +// texture (used for Alias models) + +//changes include stvertexes now being seperatly number from the triangles. +//this allows q2 models to be supported. +#define NOASM + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + +// TODO: put in span spilling to shrink list size +// !!! if this is changed, it must be changed in d_polysa.s too !!! +#define DPS_MAXSPANS MAXHEIGHT+1 + // 1 extra for spanpackage that marks end + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct { + void *pdest; + short *pz; + int count; + qbyte *ptex; + int sfrac, tfrac, light, zi; +} spanpackage_t; + +typedef struct { + int isflattop; + int numleftedges; + int *pleftedgevert0; + int *pleftedgevert1; + int *pleftedgevert2; + int numrightedges; + int *prightedgevert0; + int *prightedgevert1; + int *prightedgevert2; +} edgetable; + +int r_p0[6], r_p1[6], r_p2[6]; + +qbyte *d_pcolormap; + +int d_aflatcolor; +int d_xdenom; + +edgetable *pedgetable; + +edgetable edgetables[12] = { + {0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 }, + {0, 2, r_p1, r_p0, r_p2, 1, r_p1, r_p2, NULL}, + {1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL}, + {0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 }, + {0, 2, r_p0, r_p2, r_p1, 1, r_p0, r_p1, NULL}, + {0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL}, + {0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 }, + {0, 2, r_p2, r_p1, r_p0, 1, r_p2, r_p0, NULL}, + {0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL}, + {1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL}, + {1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL}, + {0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL}, +}; + +// FIXME: some of these can become statics +int a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole; +int r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy; +int r_zistepx, r_zistepy; +int d_aspancount, d_countextrastep; + +spanpackage_t *a_spans; +spanpackage_t *d_pedgespanpackage; +static int ystart; +qbyte *d_pdest, *d_ptex; +short *d_pz; +int d_sfrac, d_tfrac, d_light, d_zi; +int d_ptexextrastep, d_sfracextrastep; +int d_tfracextrastep, d_lightextrastep, d_pdestextrastep; +int d_lightbasestep, d_pdestbasestep, d_ptexbasestep; +int d_sfracbasestep, d_tfracbasestep; +int d_ziextrastep, d_zibasestep; +int d_pzextrastep, d_pzbasestep; + +typedef struct { + int quotient; + int remainder; +} adivtab_t; + +static adivtab_t adivtab[32*32] = { +#include "adivtab.h" +}; + +qbyte *skintable[MAX_LBM_HEIGHT]; +int skinwidth; +qbyte *skinstart; + +qbyte transfactor; +qbyte transbackfac; + +#if id386 +#define D_PolysetScanLeftEdge D_PolysetScanLeftEdge +#define D_PolysetScanLeftEdge32 D_PolysetScanLeftEdgeC + + +void D_PolysetScanLeftEdge (int height); +#else +#define D_PolysetScanLeftEdge D_PolysetScanLeftEdgeC +#define D_PolysetScanLeftEdge32 D_PolysetScanLeftEdgeC + +#define D_PolysetSetUpForLineScan D_PolysetSetUpForLineScanC +#define D_PolysetSetUpForLineScan32 D_PolysetSetUpForLineScanC +#endif + +void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage); +void D_PolysetCalcGradients (int skinwidth); +void D_PolysetCalcGradients32 (int skinwidth); +void D_DrawSubdiv (void); +void D_DrawSubdiv32 (void); +void D_DrawNonSubdiv (void); +void D_DrawNonSubdiv32 (void); +void D_PolysetRecursiveTriangle (int *p1, int *p2, int *p3); +void D_PolysetSetEdgeTable (void); +void D_RasterizeAliasPolySmooth8 (void); +void D_PolysetScanLeftEdgeC (int height); + +void D_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, + fixed8_t endvertu, fixed8_t endvertv); + + +#ifdef PEXT_TRANS +void D_PolysetDrawFinalVertsTrans (finalvert_t *fv, int numverts) +{ + int i, z; + short *zbuf; + + for (i=0 ; iv[0] < r_refdef.vrectright) && + (fv->v[1] < r_refdef.vrectbottom)) + { + z = fv->v[5]>>16; + zbuf = zspantable[fv->v[1]] + fv->v[0]; + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = skintable[fv->v[3]>>16][fv->v[2]>>16]; + pix = ((qbyte *)acolormap)[pix + (fv->v[4] & 0xFF00) ]; + d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = Trans(d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]], pix); + } + } + } +} + +void D_PolysetDrawFinalVerts32Trans (finalvert_t *fv, int numverts) +{ + int i, z; + short *zbuf; + + for (i=0 ; iv[0] < r_refdef.vrectright) && + (fv->v[1] < r_refdef.vrectbottom)) + { + z = fv->v[5]>>16; + if (fv->v[1] < 0 || fv->v[0] < 0) //FIXME: temp + continue; + zbuf = zspantable[fv->v[1]] + fv->v[0]; + if (z >= *zbuf) + { + qbyte *pix; + qbyte *out; + + *zbuf = z; + pix = (qbyte *)(((unsigned int *)((unsigned int **)skintable)[fv->v[3]>>16]) + (fv->v[2]>>16)); +// pix = ((qbyte *)acolormap)[pix + (fv->v[4] & 0xFF00) ]; + out = d_viewbuffer + ((d_scantable[fv->v[1]] + fv->v[0])<<2); + out[0] = (out[0]*transbackfac + pix[0] * transfactor)/255; + out[1] = (out[1]*transbackfac + pix[1] * transfactor)/255; + out[2] = (out[2]*transbackfac + pix[2] * transfactor)/255; + } + } + } +} + +void D_PolysetDrawFinalVerts32 (finalvert_t *fv, int numverts) +{ + int i, z; + short *zbuf; + + for (i=0 ; iv[0] < r_refdef.vrectright) && + (fv->v[1] < r_refdef.vrectbottom)) + { + z = fv->v[5]>>16; + if (fv->v[1] < 0 || fv->v[0] < 0) //FIXME: temp + continue; + zbuf = zspantable[fv->v[1]] + fv->v[0]; + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = ((unsigned int *)((unsigned int **)skintable)[fv->v[3]>>16])[fv->v[2]>>16]; +// pix = ((qbyte *)acolormap)[pix + (fv->v[4] & 0xFF00) ]; + ((unsigned int *)d_viewbuffer)[d_scantable[fv->v[1]] + fv->v[0]] = pix; + } + } + } +} + +void D_PolysetRecursiveTriangleTrans (int *lp1, int *lp2, int *lp3) +{ + int *temp; + int d; + int new[6]; + int z; + short *zbuf; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + d = lp3[0] - lp2[0]; + if (d < -1 || d > 1) + goto split2; + d = lp3[1] - lp2[1]; + if (d < -1 || d > 1) + goto split2; + + d = lp1[0] - lp3[0]; + if (d < -1 || d > 1) + goto split3; + d = lp1[1] - lp3[1]; + if (d < -1 || d > 1) + { +split3: + temp = lp1; + lp1 = lp3; + lp3 = lp2; + lp2 = temp; + + goto split; + } + + return; // entire tri is filled + +split2: + temp = lp1; + lp1 = lp2; + lp2 = lp3; + lp3 = temp; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + +// draw the point if splitting a leading edge + if (lp2[1] > lp1[1]) + goto nodraw; + if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) + goto nodraw; + + + z = new[5]>>16; + zbuf = zspantable[new[1]] + new[0]; + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]]; + d_viewbuffer[d_scantable[new[1]] + new[0]] = Trans(d_viewbuffer[d_scantable[new[1]] + new[0]], pix); + } + +nodraw: +// recursively continue + D_PolysetRecursiveTriangleTrans (lp3, lp1, new); + D_PolysetRecursiveTriangleTrans (lp3, new, lp2); +} + +void D_PolysetRecursiveTriangle32Trans (int *lp1, int *lp2, int *lp3) +{ + int *temp; + int d; + int new[6]; + int z; + short *zbuf; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + d = lp3[0] - lp2[0]; + if (d < -1 || d > 1) + goto split2; + d = lp3[1] - lp2[1]; + if (d < -1 || d > 1) + goto split2; + + d = lp1[0] - lp3[0]; + if (d < -1 || d > 1) + goto split3; + d = lp1[1] - lp3[1]; + if (d < -1 || d > 1) + { +split3: + temp = lp1; + lp1 = lp3; + lp3 = lp2; + lp2 = temp; + + goto split; + } + + return; // entire tri is filled + +split2: + temp = lp1; + lp1 = lp2; + lp2 = lp3; + lp3 = temp; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + +// draw the point if splitting a leading edge + if (lp2[1] > lp1[1]) + goto nodraw; + if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) + goto nodraw; + + + z = new[5]>>16; + if ((new[1]>=vid.height|| new[1] < 0 || new[0] >= vid.width || new[0]<0)) //fixme: temp + return; + zbuf = zspantable[new[1]] + new[0]; + + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = ((unsigned int *)((unsigned int **)skintable)[new[3]>>16])[new[2]>>16]; +// pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]]; + ((unsigned int *)d_viewbuffer)[d_scantable[new[1]] + new[0]] = pix;//d_8to32table[pix]; + } + +nodraw: +// recursively continue + D_PolysetRecursiveTriangle32Trans (lp3, lp1, new); + D_PolysetRecursiveTriangle32Trans (lp3, new, lp2); +} + +void D_PolysetRecursiveTriangle16 (int *lp1, int *lp2, int *lp3) +{ + int *temp; + int d; + int new[6]; + int z; + short *zbuf; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + d = lp3[0] - lp2[0]; + if (d < -1 || d > 1) + goto split2; + d = lp3[1] - lp2[1]; + if (d < -1 || d > 1) + goto split2; + + d = lp1[0] - lp3[0]; + if (d < -1 || d > 1) + goto split3; + d = lp1[1] - lp3[1]; + if (d < -1 || d > 1) + { +split3: + temp = lp1; + lp1 = lp3; + lp3 = lp2; + lp2 = temp; + + goto split; + } + + return; // entire tri is filled + +split2: + temp = lp1; + lp1 = lp2; + lp2 = lp3; + lp3 = temp; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + +// draw the point if splitting a leading edge + if (lp2[1] > lp1[1]) + goto nodraw; + if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) + goto nodraw; + + + z = new[5]>>16; + if ((new[1]>=vid.height|| new[1] < 0 || new[0] >= vid.width || new[0]<0)) //fixme: temp + return; + zbuf = zspantable[new[1]] + new[0]; + + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]]; + ((unsigned short *)d_viewbuffer)[d_scantable[new[1]] + new[0]] = pix;//d_8to32table[pix]; + } + +nodraw: +// recursively continue + D_PolysetRecursiveTriangle16 (lp3, lp1, new); + D_PolysetRecursiveTriangle16 (lp3, new, lp2); +} + + +void D_PolysetDrawSpans8Trans (spanpackage_t *pspanpackage) +{ + int lcount; + qbyte *lpdest; + qbyte *lptex; + int lsfrac, ltfrac; + int llight; + int lzi; + short *lpz; + + do + { + lcount = d_aspancount - pspanpackage->count; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_aspancount += d_countextrastep; + errorterm -= erroradjustdown; + } + else + { + d_aspancount += ubasestep; + } + + if (lcount) + { + lpdest = pspanpackage->pdest; + lptex = pspanpackage->ptex; + lpz = pspanpackage->pz; + lsfrac = pspanpackage->sfrac; + ltfrac = pspanpackage->tfrac; + llight = pspanpackage->light; + lzi = pspanpackage->zi; + + do + { + if ((lzi >> 16) >= *lpz) + { + *lpdest = Trans(*lpdest, ((qbyte *)acolormap)[*lptex + (llight & 0xFF00)]); +// gel mapping *lpdest = gelmap[*lpdest]; + *lpz = lzi >> 16; + } + lpdest++; + lzi += r_zistepx; + lpz++; + llight += r_lstepx; + lptex += a_ststepxwhole; + lsfrac += a_sstepxfrac; + lptex += lsfrac >> 16; + lsfrac &= 0xFFFF; + ltfrac += a_tstepxfrac; + if (ltfrac & 0x10000) + { + lptex += r_affinetridesc.skinwidth; + ltfrac &= 0xFFFF; + } + } while (--lcount); + } + + pspanpackage++; + } while (pspanpackage->count != -999999); +} + +void D_PolysetDrawSpans32Trans (spanpackage_t *pspanpackage) +{ + int lcount; + qbyte *lpdest; + qbyte *lptex; + int tex; + int lsfrac, ltfrac; + int llight; + int lzi; + short *lpz; + + do + { + lcount = d_aspancount - pspanpackage->count; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_aspancount += d_countextrastep; + errorterm -= erroradjustdown; + } + else + { + d_aspancount += ubasestep; + } + + if (lcount) + { + lpdest = pspanpackage->pdest; + tex = pspanpackage->ptex-(qbyte *)r_affinetridesc.pskin; + lpz = pspanpackage->pz; + lsfrac = pspanpackage->sfrac; + ltfrac = pspanpackage->tfrac; + llight = pspanpackage->light; + lzi = pspanpackage->zi; + + do + { + if ((lzi >> 16) >= *lpz) + { + extern qbyte gammatable[256]; +// ((qbyte *)acolormap)[*lptex + (llight & 0xFF00)]; + lptex = (qbyte *)((unsigned int *)r_affinetridesc.pskin+tex); +#if 0 + lpdest[0] = ((qbyte *)acolormap)[lptex[0] + (llight & 0xFF00)]; + lpdest[1] = ((qbyte *)acolormap)[lptex[1] + (llight & 0xFF00)]; + lpdest[2] = ((qbyte *)acolormap)[lptex[2] + (llight & 0xFF00)]; +#else + lpdest[0] = (lpdest[0]*transbackfac + gammatable[(lptex[0]*(llight>>8))/(256)]*transfactor)/255; + lpdest[1] = (lpdest[1]*transbackfac + gammatable[(lptex[1]*(llight>>8))/(256)]*transfactor)/255; + lpdest[2] = (lpdest[2]*transbackfac + gammatable[(lptex[2]*(llight>>8))/(256)]*transfactor)/255; +#endif + *lpz = lzi >> 16; + } + lpdest+=4; + lzi += r_zistepx; + lpz++; + llight += r_lstepx; + tex += a_ststepxwhole; + lsfrac += a_sstepxfrac; + tex += lsfrac >> 16; + lsfrac &= 0xFFFF; + ltfrac += a_tstepxfrac; + if (ltfrac & 0x10000) + { + tex += r_affinetridesc.skinwidth; + ltfrac &= 0xFFFF; + } + } while (--lcount); + } + + pspanpackage++; + } while (pspanpackage->count != -999999); +} +void D_PolysetDrawSpans32 (spanpackage_t *pspanpackage) +{ + int lcount; + qbyte *lpdest; + qbyte *lptex; + int tex; + int lsfrac, ltfrac; + int llight; + int lzi; + short *lpz; + + do + { + lcount = d_aspancount - pspanpackage->count; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_aspancount += d_countextrastep; + errorterm -= erroradjustdown; + } + else + { + d_aspancount += ubasestep; + } + + if (lcount) + { + lpdest = pspanpackage->pdest; + tex = pspanpackage->ptex-(qbyte *)r_affinetridesc.pskin; + lpz = pspanpackage->pz; + lsfrac = pspanpackage->sfrac; + ltfrac = pspanpackage->tfrac; + llight = pspanpackage->light; + lzi = pspanpackage->zi; + + do + { + if ((lzi >> 16) >= *lpz) + { + extern qbyte gammatable[256]; +// ((qbyte *)acolormap)[*lptex + (llight & 0xFF00)]; + lptex = (qbyte *)((unsigned int *)r_affinetridesc.pskin+tex); +#if 0 + lpdest[0] = ((qbyte *)acolormap)[lptex[0] + (llight & 0xFF00)]; + lpdest[1] = ((qbyte *)acolormap)[lptex[1] + (llight & 0xFF00)]; + lpdest[2] = ((qbyte *)acolormap)[lptex[2] + (llight & 0xFF00)]; +#else + lpdest[0] = gammatable[(lptex[0]*(llight>>8))/(256)]; + lpdest[1] = gammatable[(lptex[1]*(llight>>8))/(256)]; + lpdest[2] = gammatable[(lptex[2]*(llight>>8))/(256)]; +#endif + *lpz = lzi >> 16; + } + lpdest+=4; + lzi += r_zistepx; + lpz++; + llight += r_lstepx; + tex += a_ststepxwhole; + lsfrac += a_sstepxfrac; + tex += lsfrac >> 16; + lsfrac &= 0xFFFF; + ltfrac += a_tstepxfrac; + if (ltfrac & 0x10000) + { + tex += r_affinetridesc.skinwidth; + ltfrac &= 0xFFFF; + } + } while (--lcount); + } + + pspanpackage++; + } while (pspanpackage->count != -999999); +} + +void D_PolysetDrawSpans16 (spanpackage_t *pspanpackage) +{ + int lcount; + unsigned short *lpdest; + qbyte *lptex; + int tex; + int lsfrac, ltfrac; + int llight; + int lzi; + short *lpz; + + do + { + lcount = d_aspancount - pspanpackage->count; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_aspancount += d_countextrastep; + errorterm -= erroradjustdown; + } + else + { + d_aspancount += ubasestep; + } + + if (lcount) + { + lpdest = pspanpackage->pdest; + tex = pspanpackage->ptex-(qbyte *)r_affinetridesc.pskin; + lpz = pspanpackage->pz; + lsfrac = pspanpackage->sfrac; + ltfrac = pspanpackage->tfrac; + llight = pspanpackage->light; + lzi = pspanpackage->zi; + + do + { + if ((lzi >> 16) >= *lpz) + { +// ((qbyte *)acolormap)[*lptex + (llight & 0xFF00)]; + lptex = (qbyte *)((unsigned char *)r_affinetridesc.pskin+tex); + lpdest[0] = ((unsigned short *)acolormap)[*lptex + (llight & 0xFF00)]; + *lpz = lzi >> 16; + } + lpdest++; + lzi += r_zistepx; + lpz++; + llight += r_lstepx; + tex += a_ststepxwhole; + lsfrac += a_sstepxfrac; + tex += lsfrac >> 16; + lsfrac &= 0xFFFF; + ltfrac += a_tstepxfrac; + if (ltfrac & 0x10000) + { + tex += r_affinetridesc.skinwidth; + ltfrac &= 0xFFFF; + } + } while (--lcount); + } + + pspanpackage++; + } while (pspanpackage->count != -999999); +} + +/* +================ +D_PolysetFillSpans8 +================ +*/ +void D_PolysetFillSpans8Trans (spanpackage_t *pspanpackage) +{ + int color; + +// FIXME: do z buffering + + color = d_aflatcolor++; + + while (1) + { + int lcount; + qbyte *lpdest; + + lcount = pspanpackage->count; + + if (lcount == -1) + return; + + if (lcount) + { + lpdest = pspanpackage->pdest; + + do + { + *lpdest = Trans(*lpdest, color); + lpdest++; + } while (--lcount); + } + + pspanpackage++; + } +} + + + + +void D_RasterizeAliasPolySmoothTrans (void) +{ + int initialleftheight, initialrightheight; + int *plefttop, *prighttop, *pleftbottom, *prightbottom; + int working_lstepx, originalcount; + + plefttop = pedgetable->pleftedgevert0; + prighttop = pedgetable->prightedgevert0; + + pleftbottom = pedgetable->pleftedgevert1; + prightbottom = pedgetable->prightedgevert1; + + initialleftheight = pleftbottom[1] - plefttop[1]; + initialrightheight = prightbottom[1] - prighttop[1]; + +// +// set the s, t, and light gradients, which are consistent across the triangle +// because being a triangle, things are affine +// + D_PolysetCalcGradients32 (r_affinetridesc.skinwidth); //D_PolysetCalcGradients32 but not with asm possibilities + +// +// rasterize the polygon +// + +// +// scan out the top (and possibly only) part of the left edge +// + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + d_pedgespanpackage = a_spans; + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + + d_ptex = (qbyte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; + + d_sfrac = plefttop[2] & 0xFFFF; + d_tfrac = plefttop[3] & 0xFFFF; + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; + + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdestbasestep = (screenwidth + ubasestep)*r_pixbytes; + d_pdestextrastep = d_pdestbasestep + r_pixbytes; + d_pdest = (qbyte *)d_viewbuffer + (ystart * screenwidth + plefttop[0])*r_pixbytes; + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + +// TODO: can reuse partial expressions here + +// for negative steps in x along left edge, bias toward overflow rather than +// underflow (sort of turning the floor () we did in the gradient calcs into +// ceil (), but plus a little bit) + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; + + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; + + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; + + d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF; + + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdgeC (initialleftheight); + +// +// scan out the bottom part of the left edge, if it exists +// + if (pedgetable->numleftedges == 2) + { + int height; + + plefttop = pleftbottom; + pleftbottom = pedgetable->pleftedgevert2; + + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + height = pleftbottom[1] - plefttop[1]; + +// TODO: make this a function; modularize this function in general + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + d_ptex = (qbyte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; + d_sfrac = 0; + d_tfrac = 0; + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdestbasestep = (screenwidth + ubasestep)*r_pixbytes; + d_pdestextrastep = d_pdestbasestep + r_pixbytes; + d_pdest = (qbyte *)d_viewbuffer + (ystart * screenwidth + plefttop[0])*r_pixbytes; + + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; + + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; + + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; + + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; + + d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF; + + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdgeC (height); + } + +// scan out the top (and possibly only) part of the right edge, updating the +// count field + d_pedgespanpackage = a_spans; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + d_aspancount = 0; + d_countextrastep = ubasestep + 1; + originalcount = a_spans[initialrightheight].count; + a_spans[initialrightheight].count = -999999; // mark end of the spanpackages + + if (r_pixbytes == 4) + { + if (transbackfac) + D_PolysetDrawSpans32Trans (a_spans); + else + D_PolysetDrawSpans32 (a_spans); + } + else if (r_pixbytes == 2) + D_PolysetDrawSpans16 (a_spans); + else + D_PolysetDrawSpans8Trans (a_spans); + +// scan out the bottom part of the right edge, if it exists + if (pedgetable->numrightedges == 2) + { + int height; + spanpackage_t *pstart; + + pstart = a_spans + initialrightheight; + pstart->count = originalcount; + + d_aspancount = prightbottom[0] - prighttop[0]; + + prighttop = prightbottom; + prightbottom = pedgetable->prightedgevert2; + + height = prightbottom[1] - prighttop[1]; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + + d_countextrastep = ubasestep + 1; + a_spans[initialrightheight + height].count = -999999; + // mark end of the spanpackages + if (r_pixbytes == 4) + { + if (transbackfac) + D_PolysetDrawSpans32Trans (pstart); + else + D_PolysetDrawSpans32 (pstart); + } + else if (r_pixbytes == 2) + D_PolysetDrawSpans16 (pstart); + else + D_PolysetDrawSpans8Trans (pstart); + } +} + + + + + +#endif + +void D_PolysetDraw32 (void) +{ + spanpackage_t spans[DPS_MAXSPANS + 1 + + ((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1]; + // one extra because of cache line pretouching + + a_spans = (spanpackage_t *) + (((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + + if (r_affinetridesc.drawtype) + { + D_DrawSubdiv32 (); + } + else + { + D_DrawNonSubdiv32 (); + } +} + +void D_PolysetDraw16 (void) +{ + spanpackage_t spans[DPS_MAXSPANS + 1 + + ((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1]; + // one extra because of cache line pretouching + + a_spans = (spanpackage_t *) + (((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + +#if !id386 + if (r_affinetridesc.drawtype) + { + D_DrawSubdiv (); + } + else +#endif + { + D_DrawNonSubdiv (); + } +} + + +#if !id386 + +/* +================ +D_PolysetDraw +================ +*/ +void D_PolysetDraw (void) +{ + spanpackage_t spans[DPS_MAXSPANS + 1 + + ((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1]; + // one extra because of cache line pretouching + + a_spans = (spanpackage_t *) + (((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + + if (r_affinetridesc.drawtype) + { + D_DrawSubdiv (); + } + else + { + D_DrawNonSubdiv (); + } +} + + +/* +================ +D_PolysetDrawFinalVerts +================ +*/ +void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts) +{ + int i, z; + short *zbuf; + + for (i=0 ; iv[0] < r_refdef.vrectright) && + (fv->v[1] < r_refdef.vrectbottom)) + { + z = fv->v[5]>>16; + zbuf = zspantable[fv->v[1]] + fv->v[0]; + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = skintable[fv->v[3]>>16][fv->v[2]>>16]; + pix = ((qbyte *)acolormap)[pix + (fv->v[4] & 0xFF00) ]; + d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = pix; + } + } + } +} + + +/* +================ +D_DrawSubdiv +================ +*/ +void D_DrawSubdiv (void) +{ + mtriangle_t *ptri; + finalvert_t *pfv, *index0, *index1, *index2; + int i; + int lnumtriangles; + + pfv = r_affinetridesc.pfinalverts; + ptri = r_affinetridesc.ptriangles; + lnumtriangles = r_affinetridesc.numtriangles; + +#ifdef PEXT_TRANS + if (r_pixbytes == 4) + { + for (i=0 ; iv[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0]) * + (index0->v[1]-index2->v[1])) >= 0) + { + continue; + } + + d_pcolormap = &((qbyte *)acolormap)[index0->v[4] & 0xFF00]; + + D_PolysetRecursiveTriangle32Trans(index0->v, index1->v, index2->v); + } + return; + } + if (currententity->alpha != 1) + { + Set_TransLevelF(currententity->alpha); + for (i=0 ; iv[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0]) * + (index0->v[1]-index2->v[1])) >= 0) + { + continue; + } + + d_pcolormap = &((qbyte *)acolormap)[index0->v[4] & 0xFF00]; + + D_PolysetRecursiveTriangleTrans(index0->v, index1->v, index2->v); + } + return; + } +#endif + + for (i=0 ; iv[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0]) * + (index0->v[1]-index2->v[1])) >= 0) + { + continue; + } + + d_pcolormap = &((qbyte *)acolormap)[index0->v[4] & 0xFF00]; + + D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v); + } +} +#endif +void D_DrawSubdiv32 (void) +{ + mtriangle_t *ptri; + finalvert_t *pfv, *index0, *index1, *index2; + mstvert_t *pst, *st0, *st1, *st2; + int i; + int lnumtriangles; + + pst = r_affinetridesc.pstverts; + pfv = r_affinetridesc.pfinalverts; + ptri = r_affinetridesc.ptriangles; + lnumtriangles = r_affinetridesc.numtriangles; + + for (i=0 ; iv[1]-index1->v[1]) * //is this back face culling? + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0]) * + (index0->v[1]-index2->v[1])) >= 0) + { + continue; + } + + st0 = pst + ptri[i].st_index[0]; + st1 = pst + ptri[i].st_index[1]; + st2 = pst + ptri[i].st_index[2]; + + index0->v[2] = st0->s; + index0->v[3] = st0->t; + + index1->v[2] = st1->s; + index1->v[3] = st1->t; + + index2->v[2] = st2->s; + index2->v[3] = st2->t; + + d_pcolormap = &((qbyte *)acolormap)[index0->v[4] & 0xFF00]; + + D_PolysetRecursiveTriangle32Trans(index0->v, index1->v, index2->v); + } +} + +#if !id386 +/* +================ +D_DrawNonSubdiv +================ +*/ +void D_DrawNonSubdiv (void) +{ + mtriangle_t *ptri; + finalvert_t *pfv, *index0, *index1, *index2; + int i; + int lnumtriangles; + + pfv = r_affinetridesc.pfinalverts; + ptri = r_affinetridesc.ptriangles; + lnumtriangles = r_affinetridesc.numtriangles; + +#ifdef PEXT_TRANS + if (currententity->alpha != 1) + { + Set_TransLevelF(currententity->alpha); + for (i=0 ; ixyz_index[0]; + index1 = pfv + ptri->xyz_index[1]; + index2 = pfv + ptri->xyz_index[2]; + + d_xdenom = (index0->v[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1]); + + if (d_xdenom >= 0) + { + continue; + } + + r_p0[0] = index0->v[0]; // u + r_p0[1] = index0->v[1]; // v + r_p0[2] = index0->v[2]; // s + r_p0[3] = index0->v[3]; // t + r_p0[4] = index0->v[4]; // light + r_p0[5] = index0->v[5]; // iz + + r_p1[0] = index1->v[0]; + r_p1[1] = index1->v[1]; + r_p1[2] = index1->v[2]; + r_p1[3] = index1->v[3]; + r_p1[4] = index1->v[4]; + r_p1[5] = index1->v[5]; + + r_p2[0] = index2->v[0]; + r_p2[1] = index2->v[1]; + r_p2[2] = index2->v[2]; + r_p2[3] = index2->v[3]; + r_p2[4] = index2->v[4]; + r_p2[5] = index2->v[5]; + + D_PolysetSetEdgeTable (); + D_RasterizeAliasPolySmoothTrans (); + } + return; + } +#endif + + for (i=0 ; ixyz_index[0]; + index1 = pfv + ptri->xyz_index[1]; + index2 = pfv + ptri->xyz_index[2]; + + d_xdenom = (index0->v[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1]); + + if (d_xdenom >= 0) + { + continue; + } + + r_p0[0] = index0->v[0]; // u + r_p0[1] = index0->v[1]; // v + r_p0[2] = index0->v[2]; // s + r_p0[3] = index0->v[3]; // t + r_p0[4] = index0->v[4]; // light + r_p0[5] = index0->v[5]; // iz + + r_p1[0] = index1->v[0]; + r_p1[1] = index1->v[1]; + r_p1[2] = index1->v[2]; + r_p1[3] = index1->v[3]; + r_p1[4] = index1->v[4]; + r_p1[5] = index1->v[5]; + + r_p2[0] = index2->v[0]; + r_p2[1] = index2->v[1]; + r_p2[2] = index2->v[2]; + r_p2[3] = index2->v[3]; + r_p2[4] = index2->v[4]; + r_p2[5] = index2->v[5]; + + D_PolysetSetEdgeTable (); + D_RasterizeAliasPolySmooth8 (); + } +} +#endif + +void D_DrawNonSubdiv32 (void) +{ + mtriangle_t *ptri; + finalvert_t *pfv, *index0, *index1, *index2; + + int i; + int lnumtriangles; +#if 0 + stvert_t *pst, *st0, *st1, *st2; + pst = r_affinetridesc.pstverts; +#endif + pfv = r_affinetridesc.pfinalverts; + ptri = r_affinetridesc.ptriangles; + lnumtriangles = r_affinetridesc.numtriangles; + + for (i=0 ; ixyz_index[0]; + index1 = pfv + ptri->xyz_index[1]; + index2 = pfv + ptri->xyz_index[2]; + + d_xdenom = (index0->v[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1]); + + if (d_xdenom >= 0) + { + continue; + } +#if 0 + st0 = pfv + ptri->st_index[0]; + st1 = pfv + ptri->st_index[1]; + st2 = pfv + ptri->st_index[2]; + + r_p0[0] = index0->v[0]; // u + r_p0[1] = index0->v[1]; // v + r_p0[2] = st0->s;//index0->v[2]; // s + r_p0[3] = st0->t;//index0->v[3]; // t + r_p0[4] = index0->v[4]; // light + r_p0[5] = index0->v[5]; // iz + + r_p1[0] = index1->v[0]; + r_p1[1] = index1->v[1]; + r_p1[2] = st1->s;//index1->v[2]; + r_p1[3] = st1->t;//index1->v[3]; + r_p1[4] = index1->v[4]; + r_p1[5] = index1->v[5]; + + r_p2[0] = index2->v[0]; + r_p2[1] = index2->v[1]; + r_p2[2] = st2->s;//index2->v[2]; + r_p2[3] = st2->t;//index2->v[3]; + r_p2[4] = index2->v[4]; + r_p2[5] = index2->v[5]; +#else + r_p0[0] = index0->v[0]; // u + r_p0[1] = index0->v[1]; // v + r_p0[2] = index0->v[2]; // s + r_p0[3] = index0->v[3]; // t + r_p0[4] = index0->v[4]; // light + r_p0[5] = index0->v[5]; // iz + + r_p1[0] = index1->v[0]; + r_p1[1] = index1->v[1]; + r_p1[2] = index1->v[2]; + r_p1[3] = index1->v[3]; + r_p1[4] = index1->v[4]; + r_p1[5] = index1->v[5]; + + r_p2[0] = index2->v[0]; + r_p2[1] = index2->v[1]; + r_p2[2] = index2->v[2]; + r_p2[3] = index2->v[3]; + r_p2[4] = index2->v[4]; + r_p2[5] = index2->v[5]; +#endif + + D_PolysetSetEdgeTable (); + D_RasterizeAliasPolySmoothTrans (); + } +} + +#if !id386 +/* +================ +D_PolysetRecursiveTriangle +================ +*/ +void D_PolysetRecursiveTriangle (int *lp1, int *lp2, int *lp3) +{ + int *temp; + int d; + int new[6]; + int z; + short *zbuf; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + d = lp3[0] - lp2[0]; + if (d < -1 || d > 1) + goto split2; + d = lp3[1] - lp2[1]; + if (d < -1 || d > 1) + goto split2; + + d = lp1[0] - lp3[0]; + if (d < -1 || d > 1) + goto split3; + d = lp1[1] - lp3[1]; + if (d < -1 || d > 1) + { +split3: + temp = lp1; + lp1 = lp3; + lp3 = lp2; + lp2 = temp; + + goto split; + } + + return; // entire tri is filled + +split2: + temp = lp1; + lp1 = lp2; + lp2 = lp3; + lp3 = temp; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + +// draw the point if splitting a leading edge + if (lp2[1] > lp1[1]) + goto nodraw; + if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) + goto nodraw; + + + z = new[5]>>16; + zbuf = zspantable[new[1]] + new[0]; + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]]; + d_viewbuffer[d_scantable[new[1]] + new[0]] = pix; + } + +nodraw: +// recursively continue + D_PolysetRecursiveTriangle (lp3, lp1, new); + D_PolysetRecursiveTriangle (lp3, new, lp2); +} + +#endif // !id386 + + +/* +================ +D_PolysetUpdateTables +================ +*/ +void D_PolysetUpdateTables (void) +{ + int i; + qbyte *s; + + if (r_affinetridesc.skinwidth*r_pixbytes != skinwidth || + r_affinetridesc.pskin != skinstart) + { + skinwidth = r_affinetridesc.skinwidth*r_pixbytes; + skinstart = r_affinetridesc.pskin; + s = skinstart; + for (i=0 ; ipdest = d_pdest; + d_pedgespanpackage->pz = d_pz; + d_pedgespanpackage->count = d_aspancount; + d_pedgespanpackage->ptex = d_ptex; + + d_pedgespanpackage->sfrac = d_sfrac; + d_pedgespanpackage->tfrac = d_tfrac; + + // FIXME: need to clamp l, s, t, at both ends? + d_pedgespanpackage->light = d_light; + d_pedgespanpackage->zi = d_zi; + + d_pedgespanpackage++; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_pdest += d_pdestextrastep; + d_pz += d_pzextrastep; + d_aspancount += d_countextrastep; + d_ptex += d_ptexextrastep; + d_sfrac += d_sfracextrastep; + d_ptex += d_sfrac >> 16; + + d_sfrac &= 0xFFFF; + d_tfrac += d_tfracextrastep; + if (d_tfrac & 0x10000) + { + d_ptex += r_affinetridesc.skinwidth; + d_tfrac &= 0xFFFF; + } + d_light += d_lightextrastep; + d_zi += d_ziextrastep; + errorterm -= erroradjustdown; + } + else + { + d_pdest += d_pdestbasestep; + d_pz += d_pzbasestep; + d_aspancount += ubasestep; + d_ptex += d_ptexbasestep; + d_sfrac += d_sfracbasestep; + d_ptex += d_sfrac >> 16; + d_sfrac &= 0xFFFF; + d_tfrac += d_tfracbasestep; + if (d_tfrac & 0x10000) + { + d_ptex += r_affinetridesc.skinwidth; + d_tfrac &= 0xFFFF; + } + d_light += d_lightbasestep; + d_zi += d_zibasestep; + } + } while (--height); +} + +/* +=================== +D_PolysetSetUpForLineScan +==================== +*/ +void D_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, + fixed8_t endvertu, fixed8_t endvertv) +{ + double dm, dn; + int tm, tn; + adivtab_t *ptemp; + +// TODO: implement x86 version + + errorterm = -1; + + tm = endvertu - startvertu; + tn = endvertv - startvertv; + + if (((tm <= 16) && (tm >= -15)) && + ((tn <= 16) && (tn >= -15))) + { + ptemp = &adivtab[((tm+15) << 5) + (tn+15)]; + ubasestep = ptemp->quotient; + erroradjustup = ptemp->remainder; + erroradjustdown = tn; + } + else + { + dm = (double)tm; + dn = (double)tn; + + FloorDivMod (dm, dn, &ubasestep, &erroradjustup); + + erroradjustdown = dn; + } +} + + +#if !id386 + +/* +================ +D_PolysetCalcGradients +================ +*/ +void D_PolysetCalcGradients (int skinwidth) +{ + float xstepdenominv, ystepdenominv, t0, t1; + float p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20; + + p00_minus_p20 = r_p0[0] - r_p2[0]; + p01_minus_p21 = r_p0[1] - r_p2[1]; + p10_minus_p20 = r_p1[0] - r_p2[0]; + p11_minus_p21 = r_p1[1] - r_p2[1]; + + xstepdenominv = 1.0 / (float)d_xdenom; + + ystepdenominv = -xstepdenominv; + +// ceil () for light so positive steps are exaggerated, negative steps +// diminished, pushing us away from underflow toward overflow. Underflow is +// very visible, overflow is very unlikely, because of ambient lighting + t0 = r_p0[4] - r_p2[4]; + t1 = r_p1[4] - r_p2[4]; + r_lstepx = (int) + ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + r_lstepy = (int) + ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + + t0 = r_p0[2] - r_p2[2]; + t1 = r_p1[2] - r_p2[2]; + r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * + xstepdenominv); + r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) * + ystepdenominv); + + t0 = r_p0[3] - r_p2[3]; + t1 = r_p1[3] - r_p2[3]; + r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * + xstepdenominv); + r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * + ystepdenominv); + + t0 = r_p0[5] - r_p2[5]; + t1 = r_p1[5] - r_p2[5]; + r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * + xstepdenominv); + r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * + ystepdenominv); + +#if id386 + a_sstepxfrac = r_sstepx << 16; + a_tstepxfrac = r_tstepx << 16; +#else + a_sstepxfrac = r_sstepx & 0xFFFF; + a_tstepxfrac = r_tstepx & 0xFFFF; +#endif + + a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16); +} + +#endif // !id386 + +void D_PolysetCalcGradients32 (int skinwidth) +{ + float xstepdenominv, ystepdenominv, t0, t1; + float p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20; + + p00_minus_p20 = r_p0[0] - r_p2[0]; + p01_minus_p21 = r_p0[1] - r_p2[1]; + p10_minus_p20 = r_p1[0] - r_p2[0]; + p11_minus_p21 = r_p1[1] - r_p2[1]; + + xstepdenominv = 1.0 / (float)d_xdenom; + + ystepdenominv = -xstepdenominv; + +// ceil () for light so positive steps are exaggerated, negative steps +// diminished, pushing us away from underflow toward overflow. Underflow is +// very visible, overflow is very unlikely, because of ambient lighting + t0 = r_p0[4] - r_p2[4]; + t1 = r_p1[4] - r_p2[4]; + r_lstepx = (int) + /*ceil*/((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + r_lstepy = (int) + /*ceil*/((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + + t0 = r_p0[2] - r_p2[2]; + t1 = r_p1[2] - r_p2[2]; + r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * + xstepdenominv); + r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) * + ystepdenominv); + + t0 = r_p0[3] - r_p2[3]; + t1 = r_p1[3] - r_p2[3]; + r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * + xstepdenominv); + r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * + ystepdenominv); + + t0 = r_p0[5] - r_p2[5]; + t1 = r_p1[5] - r_p2[5]; + r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * + xstepdenominv); + r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * + ystepdenominv); + + a_sstepxfrac = r_sstepx & 0xFFFF; + a_tstepxfrac = r_tstepx & 0xFFFF; + + a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16); +} + +#if 0 +qbyte gelmap[256]; +void InitGel (qbyte *palette) +{ + int i; + int r; + + for (i=0 ; i<256 ; i++) + { +// r = (palette[i*3]>>4); + r = (palette[i*3] + palette[i*3+1] + palette[i*3+2])/(16*3); + gelmap[i] = /* 64 */ 0 + r; + } +} +#endif + +#if !id386 + +/* +================ +D_PolysetDrawSpans8 +================ +*/ +void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage) +{ + int lcount; + qbyte *lpdest; + qbyte *lptex; + int lsfrac, ltfrac; + int llight; + int lzi; + short *lpz; + + do + { + lcount = d_aspancount - pspanpackage->count; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_aspancount += d_countextrastep; + errorterm -= erroradjustdown; + } + else + { + d_aspancount += ubasestep; + } + + if (lcount) + { + lpdest = pspanpackage->pdest; + lptex = pspanpackage->ptex; + lpz = pspanpackage->pz; + lsfrac = pspanpackage->sfrac; + ltfrac = pspanpackage->tfrac; + llight = pspanpackage->light; + lzi = pspanpackage->zi; + + do + { + if ((lzi >> 16) >= *lpz) + { + *lpdest = ((qbyte *)acolormap)[*lptex + (llight & 0xFF00)]; +// gel mapping *lpdest = gelmap[*lpdest]; + *lpz = lzi >> 16; + } + lpdest++; + lzi += r_zistepx; + lpz++; + llight += r_lstepx; + lptex += a_ststepxwhole; + lsfrac += a_sstepxfrac; + lptex += lsfrac >> 16; + lsfrac &= 0xFFFF; + ltfrac += a_tstepxfrac; + if (ltfrac & 0x10000) + { + lptex += r_affinetridesc.skinwidth; + ltfrac &= 0xFFFF; + } + } while (--lcount); + } + + pspanpackage++; + } while (pspanpackage->count != -999999); +} +#endif // !id386 + + +/* +================ +D_PolysetFillSpans8 +================ +*/ +void D_PolysetFillSpans8 (spanpackage_t *pspanpackage) +{ + int color; + +// FIXME: do z buffering + + color = d_aflatcolor++; + + while (1) + { + int lcount; + qbyte *lpdest; + + lcount = pspanpackage->count; + + if (lcount == -1) + return; + + if (lcount) + { + lpdest = pspanpackage->pdest; + + do + { + *lpdest++ = color; + } while (--lcount); + } + + pspanpackage++; + } +} + +/* +================ +D_RasterizeAliasPolySmooth +================ +*/ +void D_RasterizeAliasPolySmooth8 (void) +{ + int initialleftheight, initialrightheight; + int *plefttop, *prighttop, *pleftbottom, *prightbottom; + int working_lstepx, originalcount; + + void (*DrawSpans) (spanpackage_t *pspanpackage); + if (r_pixbytes == 1) + DrawSpans = D_PolysetDrawSpans8; + else + DrawSpans = D_PolysetDrawSpans16; + + plefttop = pedgetable->pleftedgevert0; + prighttop = pedgetable->prightedgevert0; + + pleftbottom = pedgetable->pleftedgevert1; + prightbottom = pedgetable->prightedgevert1; + + initialleftheight = pleftbottom[1] - plefttop[1]; + initialrightheight = prightbottom[1] - prighttop[1]; + +// +// set the s, t, and light gradients, which are consistent across the triangle +// because being a triangle, things are affine +// + D_PolysetCalcGradients (r_affinetridesc.skinwidth); + +// +// rasterize the polygon +// + +// +// scan out the top (and possibly only) part of the left edge +// + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + d_pedgespanpackage = a_spans; + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + + d_ptex = (qbyte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; +#if id386 + d_sfrac = (plefttop[2] & 0xFFFF) << 16; + d_tfrac = (plefttop[3] & 0xFFFF) << 16; + d_pzbasestep = (d_zwidth + ubasestep) << 1; + d_pzextrastep = d_pzbasestep + 2; +#else + d_sfrac = plefttop[2] & 0xFFFF; + d_tfrac = plefttop[3] & 0xFFFF; + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; +#endif + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdestbasestep = (screenwidth + ubasestep)*r_pixbytes; + d_pdestextrastep = d_pdestbasestep + r_pixbytes; + d_pdest = (qbyte *)d_viewbuffer + + (ystart * screenwidth + plefttop[0])*r_pixbytes; + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + +// TODO: can reuse partial expressions here + +// for negative steps in x along left edge, bias toward overflow rather than +// underflow (sort of turning the floor () we did in the gradient calcs into +// ceil (), but plus a little bit) + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16; +#else + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; +#endif + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) << 16; + d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) << 16; +#else + d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF; +#endif + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdge (initialleftheight); + +// +// scan out the bottom part of the left edge, if it exists +// + if (pedgetable->numleftedges == 2) + { + int height; + + plefttop = pleftbottom; + pleftbottom = pedgetable->pleftedgevert2; + + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + height = pleftbottom[1] - plefttop[1]; + +// TODO: make this a function; modularize this function in general + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + d_ptex = (qbyte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; + d_sfrac = 0; + d_tfrac = 0; + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdestbasestep = (screenwidth + ubasestep)*r_pixbytes; + d_pdestextrastep = d_pdestbasestep + r_pixbytes; + d_pdest = (qbyte *)d_viewbuffer + (ystart * screenwidth + plefttop[0])*r_pixbytes; +#if id386 + d_pzbasestep = (d_zwidth + ubasestep) << 1; + d_pzextrastep = d_pzbasestep + 2; +#else + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; +#endif + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16; +#else + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; +#endif + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracextrastep = ((r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF)<<16; + d_tfracextrastep = ((r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF)<<16; +#else + d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF; +#endif + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdge (height); + } + +// scan out the top (and possibly only) part of the right edge, updating the +// count field + d_pedgespanpackage = a_spans; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + d_aspancount = 0; + d_countextrastep = ubasestep + 1; + originalcount = a_spans[initialrightheight].count; + a_spans[initialrightheight].count = -999999; // mark end of the spanpackages + DrawSpans (a_spans); + +// scan out the bottom part of the right edge, if it exists + if (pedgetable->numrightedges == 2) + { + int height; + spanpackage_t *pstart; + + pstart = a_spans + initialrightheight; + pstart->count = originalcount; + + d_aspancount = prightbottom[0] - prighttop[0]; + + prighttop = prightbottom; + prightbottom = pedgetable->prightedgevert2; + + height = prightbottom[1] - prighttop[1]; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + + d_countextrastep = ubasestep + 1; + a_spans[initialrightheight + height].count = -999999; + // mark end of the spanpackages + DrawSpans (pstart); + } +} + +void D_RasterizeAliasPolySmooth1 (void) +{ + int initialleftheight, initialrightheight; + int *plefttop, *prighttop, *pleftbottom, *prightbottom; + int working_lstepx, originalcount; + + plefttop = pedgetable->pleftedgevert0; + prighttop = pedgetable->prightedgevert0; + + pleftbottom = pedgetable->pleftedgevert1; + prightbottom = pedgetable->prightedgevert1; + + initialleftheight = pleftbottom[1] - plefttop[1]; + initialrightheight = prightbottom[1] - prighttop[1]; + +// +// set the s, t, and light gradients, which are consistent across the triangle +// because being a triangle, things are affine +// + D_PolysetCalcGradients (r_affinetridesc.skinwidth); + +// +// rasterize the polygon +// + +// +// scan out the top (and possibly only) part of the left edge +// + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + d_pedgespanpackage = a_spans; + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + + d_ptex = (qbyte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; +#if id386 + d_sfrac = (plefttop[2] & 0xFFFF) << 16; + d_tfrac = (plefttop[3] & 0xFFFF) << 16; + d_pzbasestep = (d_zwidth + ubasestep) << 1; + d_pzextrastep = d_pzbasestep + 2; +#else + d_sfrac = plefttop[2] & 0xFFFF; + d_tfrac = plefttop[3] & 0xFFFF; + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; +#endif + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdestbasestep = (screenwidth + ubasestep)*r_pixbytes; + d_pdestextrastep = d_pdestbasestep + r_pixbytes; + d_pdest = (qbyte *)d_viewbuffer + + (ystart * screenwidth + plefttop[0])*r_pixbytes; + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + +// TODO: can reuse partial expressions here + +// for negative steps in x along left edge, bias toward overflow rather than +// underflow (sort of turning the floor () we did in the gradient calcs into +// ceil (), but plus a little bit) + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16; +#else + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; +#endif + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) << 16; + d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) << 16; +#else + d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF; +#endif + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdge (initialleftheight); + +// +// scan out the bottom part of the left edge, if it exists +// + if (pedgetable->numleftedges == 2) + { + int height; + + plefttop = pleftbottom; + pleftbottom = pedgetable->pleftedgevert2; + + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + height = pleftbottom[1] - plefttop[1]; + +// TODO: make this a function; modularize this function in general + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + d_ptex = (qbyte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; + d_sfrac = 0; + d_tfrac = 0; + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdestbasestep = (screenwidth + ubasestep)*r_pixbytes; + d_pdestextrastep = d_pdestbasestep + r_pixbytes; + d_pdest = (qbyte *)d_viewbuffer + (ystart * screenwidth + plefttop[0])*r_pixbytes; +#if id386 + d_pzbasestep = (d_zwidth + ubasestep) << 1; + d_pzextrastep = d_pzbasestep + 2; +#else + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; +#endif + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16; +#else + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; +#endif + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; +#if id386 + d_sfracextrastep = ((r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF)<<16; + d_tfracextrastep = ((r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF)<<16; +#else + d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF; +#endif + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdge (height); + } + +// scan out the top (and possibly only) part of the right edge, updating the +// count field + d_pedgespanpackage = a_spans; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + d_aspancount = 0; + d_countextrastep = ubasestep + 1; + originalcount = a_spans[initialrightheight].count; + a_spans[initialrightheight].count = -999999; // mark end of the spanpackages + D_PolysetDrawSpans8 (a_spans); + +// scan out the bottom part of the right edge, if it exists + if (pedgetable->numrightedges == 2) + { + int height; + spanpackage_t *pstart; + + pstart = a_spans + initialrightheight; + pstart->count = originalcount; + + d_aspancount = prightbottom[0] - prighttop[0]; + + prighttop = prightbottom; + prightbottom = pedgetable->prightedgevert2; + + height = prightbottom[1] - prighttop[1]; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + + d_countextrastep = ubasestep + 1; + a_spans[initialrightheight + height].count = -999999; + // mark end of the spanpackages + D_PolysetDrawSpans8 (pstart); + } +} + + +/* +================ +D_PolysetSetEdgeTable +================ +*/ +void D_PolysetSetEdgeTable (void) +{ + int edgetableindex; + + edgetableindex = 0; // assume the vertices are already in + // top to bottom order + +// +// determine which edges are right & left, and the order in which +// to rasterize them +// + if (r_p0[1] >= r_p1[1]) + { + if (r_p0[1] == r_p1[1]) + { + if (r_p0[1] < r_p2[1]) + pedgetable = &edgetables[2]; + else + pedgetable = &edgetables[5]; + + return; + } + else + { + edgetableindex = 1; + } + } + + if (r_p0[1] == r_p2[1]) + { + if (edgetableindex) + pedgetable = &edgetables[8]; + else + pedgetable = &edgetables[9]; + + return; + } + else if (r_p1[1] == r_p2[1]) + { + if (edgetableindex) + pedgetable = &edgetables[10]; + else + pedgetable = &edgetables[11]; + + return; + } + + if (r_p0[1] > r_p2[1]) + edgetableindex += 2; + + if (r_p1[1] > r_p2[1]) + edgetableindex += 4; + + pedgetable = &edgetables[edgetableindex]; +} + + +#if 0 + +void D_PolysetRecursiveDrawLine (int *lp1, int *lp2) +{ + int d; + int new[6]; + int ofs; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + return; // line is completed + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[4] = (lp1[4] + lp2[4]) >> 1; + +// draw the point + ofs = d_scantable[new[1]] + new[0]; + if (new[5] > d_pzbuffer[ofs]) + { + int pix; + + d_pzbuffer[ofs] = new[5]; + pix = skintable[new[3]>>16][new[2]>>16]; +// pix = ((qbyte *)acolormap)[pix + (new[4] & 0xFF00)]; + d_viewbuffer[ofs] = pix; + } + +// recursively continue + D_PolysetRecursiveDrawLine (lp1, new); + D_PolysetRecursiveDrawLine (new, lp2); +} + +void D_PolysetRecursiveTriangle2 (int *lp1, int *lp2, int *lp3) +{ + int d; + int new[4]; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + return; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[4] = (lp1[4] + lp2[4]) >> 1; + + D_PolysetRecursiveDrawLine (new, lp3); + +// recursively continue + D_PolysetRecursiveTriangle (lp1, new, lp3); + D_PolysetRecursiveTriangle (new, lp2, lp3); +} + +#endif + diff --git a/engine/sw/d_scan.c b/engine/sw/d_scan.c new file mode 100644 index 000000000..4a21783ec --- /dev/null +++ b/engine/sw/d_scan.c @@ -0,0 +1,1728 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_scan.c +// +// Portable C scan-level rasterization code, all pixel depths. + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + +unsigned char *r_turb_pbase, *r_turb_pdest; +fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep; +int *r_turb_turb; +int r_turb_spancount; + +void D_DrawTurbulent8Span (void); + + +/* +============= +D_WarpScreen + +// this performs a slight compression of the screen at the same time as +// the sine warp, to keep the edges from wrapping +============= +*/ +void D_WarpScreen (void) +{ + int w, h; + int u,v; + qbyte *dest; + int *turb; + int *col; + qbyte **row; + qbyte *rowptr[MAXHEIGHT+AMP2*2]; + int column[MAXWIDTH+AMP2*2]; + float wratio, hratio; + + w = r_refdef.vrect.width; + h = r_refdef.vrect.height; + + wratio = w / (float)scr_vrect.width; + hratio = h / (float)scr_vrect.height; + + for (v=0 ; v>16)&(CYCLE-1)])>>16)&63; + tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63; + *r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb); + r_turb_s += r_turb_sstep; + r_turb_t += r_turb_tstep; + } while (--r_turb_spancount > 0); +} + +#endif // !id386 + +/* +============= +Turbulent8 +============= +*/ +void Turbulent8 (espan_t *pspan) +{ + int count; + fixed16_t snext, tnext; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz16stepu, tdivz16stepu, zi16stepu; + + r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); + + r_turb_sstep = 0; // keep compiler happy + r_turb_tstep = 0; // ditto + + r_turb_pbase = (unsigned char *)cacheblock; + + sdivz16stepu = d_sdivzstepu * 16; + tdivz16stepu = d_tdivzstepu * 16; + zi16stepu = d_zistepu * 16; + + do + { + r_turb_pdest = (unsigned char *)((qbyte *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + r_turb_s = (int)(sdivz * z) + sadjust; + if (r_turb_s > bbextents) + r_turb_s = bbextents; + else if (r_turb_s < 0) + r_turb_s = 0; + + r_turb_t = (int)(tdivz * z) + tadjust; + if (r_turb_t > bbextentt) + r_turb_t = bbextentt; + else if (r_turb_t < 0) + r_turb_t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 16) + r_turb_spancount = 16; + else + r_turb_spancount = count; + + count -= r_turb_spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz16stepu; + tdivz += tdivz16stepu; + zi += zi16stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 16) + snext = 16; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 16) + tnext = 16; // guard against round-off error on <0 steps + + r_turb_sstep = (snext - r_turb_s) >> 4; + r_turb_tstep = (tnext - r_turb_t) >> 4; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(r_turb_spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 16) + snext = 16; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 16) + tnext = 16; // guard against round-off error on <0 steps + + if (r_turb_spancount > 1) + { + r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1); + r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1); + } + } + + r_turb_s = r_turb_s & ((CYCLE<<16)-1); + r_turb_t = r_turb_t & ((CYCLE<<16)-1); + + D_DrawTurbulent8Span (); + + r_turb_s = snext; + r_turb_t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +void Turbulent16 (espan_t *pspan) +{ + unsigned short *r_turb_pdest; + int count; + fixed16_t snext, tnext; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz16stepu, tdivz16stepu, zi16stepu; + + r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); + + r_turb_sstep = 0; // keep compiler happy + r_turb_tstep = 0; // ditto + + r_turb_pbase = (unsigned char *)cacheblock; + + sdivz16stepu = d_sdivzstepu * 16; + tdivz16stepu = d_tdivzstepu * 16; + zi16stepu = d_zistepu * 16; + + do + { + r_turb_pdest = ((unsigned short *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + r_turb_s = (int)(sdivz * z) + sadjust; + if (r_turb_s > bbextents) + r_turb_s = bbextents; + else if (r_turb_s < 0) + r_turb_s = 0; + + r_turb_t = (int)(tdivz * z) + tadjust; + if (r_turb_t > bbextentt) + r_turb_t = bbextentt; + else if (r_turb_t < 0) + r_turb_t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 16) + r_turb_spancount = 16; + else + r_turb_spancount = count; + + count -= r_turb_spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz16stepu; + tdivz += tdivz16stepu; + zi += zi16stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 16) + snext = 16; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 16) + tnext = 16; // guard against round-off error on <0 steps + + r_turb_sstep = (snext - r_turb_s) >> 4; + r_turb_tstep = (tnext - r_turb_t) >> 4; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(r_turb_spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 16) + snext = 16; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 16) + tnext = 16; // guard against round-off error on <0 steps + + if (r_turb_spancount > 1) + { + r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1); + r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1); + } + } + + r_turb_s = r_turb_s & ((CYCLE<<16)-1); + r_turb_t = r_turb_t & ((CYCLE<<16)-1); + + { + int sturb, tturb; + + do + { + sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63; + *r_turb_pdest++ = d_8to16table[*(r_turb_pbase + (tturb<<6) + sturb)]; + r_turb_s += r_turb_sstep; + r_turb_t += r_turb_tstep; + } while (--r_turb_spancount > 0); + } + + r_turb_s = snext; + r_turb_t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +void Turbulent32 (espan_t *pspan) +{ + unsigned int *r_turb_pdest; + int count; + fixed16_t snext, tnext; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz16stepu, tdivz16stepu, zi16stepu; + + r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); + + r_turb_sstep = 0; // keep compiler happy + r_turb_tstep = 0; // ditto + + r_turb_pbase = (unsigned char *)cacheblock; + + sdivz16stepu = d_sdivzstepu * 16; + tdivz16stepu = d_tdivzstepu * 16; + zi16stepu = d_zistepu * 16; + + do + { + r_turb_pdest = ((unsigned int *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + r_turb_s = (int)(sdivz * z) + sadjust; + if (r_turb_s > bbextents) + r_turb_s = bbextents; + else if (r_turb_s < 0) + r_turb_s = 0; + + r_turb_t = (int)(tdivz * z) + tadjust; + if (r_turb_t > bbextentt) + r_turb_t = bbextentt; + else if (r_turb_t < 0) + r_turb_t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 16) + r_turb_spancount = 16; + else + r_turb_spancount = count; + + count -= r_turb_spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz16stepu; + tdivz += tdivz16stepu; + zi += zi16stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 16) + snext = 16; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 16) + tnext = 16; // guard against round-off error on <0 steps + + r_turb_sstep = (snext - r_turb_s) >> 4; + r_turb_tstep = (tnext - r_turb_t) >> 4; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(r_turb_spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 16) + snext = 16; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 16) + tnext = 16; // guard against round-off error on <0 steps + + if (r_turb_spancount > 1) + { + r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1); + r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1); + } + } + + r_turb_s = r_turb_s & ((CYCLE<<16)-1); + r_turb_t = r_turb_t & ((CYCLE<<16)-1); + + { + int sturb, tturb; + + do + { + sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63; + *r_turb_pdest++ = d_8to32table[*(r_turb_pbase + (tturb<<6) + sturb)]; + r_turb_s += r_turb_sstep; + r_turb_t += r_turb_tstep; + } while (--r_turb_spancount > 0); + } + + r_turb_s = snext; + r_turb_t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +void D_DrawSpans8_Smooth (espan_t *pspan) +{ + int count, spancount; + unsigned char *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned char *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + do + { + pdest = (unsigned char *)((qbyte *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >>3; + tstep = (tnext - t) >>3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + do + { +#if 1 +#define mins (s>>16) +#define mint (t>>16) +#define pix *(pbase + (mins) + (mint) * cachewidth) +#define pixs *(pbase + (mins>=cachewidth-1?mins:(mins+1)) + (mint) * cachewidth) +#define pixt *(pbase + (mins) + (mint>=cacheheight-1?mint:(mint+1)) * cachewidth) +#define pixst *(pbase + (mins>=cachewidth-1?mins:(mins+1)) + (mint>=cacheheight-1?mint:(mint+1)) * cachewidth) +#define T(factor, a, b) (t_lookup[(factor)/t_numtablesinv])[a][b] //FIXME: remove this divide + //find the right fractional blend (blend the top blend with the lower blend) + *pdest++ = T(t-(mint<<16), T(s-(mins<<16), pix, pixs), T(s-(mins<<16), pixt, pixst)); + +#else//basic code in comparison. + *pdest++ = *(pbase + (int)(s >> 16) + (int)(t >> 16) * cachewidth); +#endif + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + + +void D_DrawSpans32From8 (espan_t *pspan) //based on the d_drawspawns8 function +{ + int count, spancount; + unsigned char *pbase; + unsigned int *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned char *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + do + { + pdest = ((unsigned int *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + *pdest++ = d_8to32table[*(pbase + (s >> 16) + (t >> 16) * cachewidth)]; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +#if 1 +void D_DrawSpans32 (espan_t *pspan) //based on the d_drawspawns8 function +{ //combine depth and colour + int count, spancount; + unsigned int *pbase; + unsigned int *pdest; + unsigned short *pddest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + unsigned int izistep, izi, doublecount, ltemp; + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned int *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pddest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + // calculate the initial 1/z + du = (float)pspan->u; + dv = (float)pspan->v; + + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + if ((long)pddest & 0x02) + { + *pddest++ = (short)(izi >> 16); + izi += izistep; + count--; + } + + if ((doublecount = count >> 1) > 0) + { + do + { + ltemp = izi >> 16; + izi += izistep; + ltemp |= izi & 0xFFFF0000; + izi += izistep; + *(int *)pddest = ltemp; + pddest += 2; + } while (--doublecount > 0); + } + + if (count & 1) + *pddest = (short)(izi >> 16); +//end depth + + + pdest = ((unsigned int *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp +// du = (float)pspan->u; +// dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; +// zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} +#else +void D_DrawSpans32 (espan_t *pspan) //based on the d_drawspawns8 function +{ + int count, spancount; + unsigned int *pbase; + unsigned int *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned int *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + do + { + pdest = ((unsigned int *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} +#endif +void D_DrawSpans32_Smooth (espan_t *pspan) //based on the d_drawspawns8 function +{ + int count, spancount; + unsigned int *pbase; + unsigned char *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + int x=0; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned int *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + do + { + pdest = (qbyte *)((unsigned int *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { +#undef pix +#undef pixs +#undef pixt +#undef pixst +#undef T + +#define mins (s>>16) +#define mint (t>>16) +#define pix *((qbyte *)pbase + x + (((mins) + (mint) * cachewidth)*4)) +#define pixs *((qbyte *)pbase + x + (((mins>=cachewidth-1?mins:(mins+1)) + (mint) * cachewidth)*4)) +#define pixt *((qbyte *)pbase + x + (((mins) + (mint>=cacheheight-1?mint:(mint+1)) * cachewidth)<<2)) +#define pixst *((qbyte *)pbase + x + (((mins>=cachewidth-1?mins:(mins+1)) + (mint>=cacheheight-1?mint:(mint+1)) * cachewidth)<<2)) +#define T(factor, a, b) ((((a)*(1-(factor)/65536.0)) + ((b)*((factor)/65536.0)))) + //find the right fractional blend (blend the top blend with the lower blend) + x = 0; + *pdest++ = T(t-(mint<<16), T(s-(mins<<16), pix, pixs), T(s-(mins<<16), pixt, pixst)); + x = 1; + *pdest++ = T(t-(mint<<16), T(s-(mins<<16), pix, pixs), T(s-(mins<<16), pixt, pixst)); + x = 2; + *pdest++ = T(t-(mint<<16), T(s-(mins<<16), pix, pixs), T(s-(mins<<16), pixt, pixst)); + pdest++; + + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +#if !id386 + +/* +============= +D_DrawSpans8 +============= +*/ +void D_DrawSpans8 (espan_t *pspan) +{ +#define SUBDIV 8 + int count, spancount; + unsigned char *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned char *)cacheblock; + + sdivz8stepu = d_sdivzstepu * SUBDIV; + tdivz8stepu = d_tdivzstepu * SUBDIV; + zi8stepu = d_zistepu * SUBDIV; + + do + { + pdest = (unsigned char *)((qbyte *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= SUBDIV) + spancount = SUBDIV; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < spancount) + snext = spancount; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < spancount) + tnext = spancount; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } +#if 0 +//* spancount -= ((int)pdest & 3); + /*while ((int)pdest & 3) + { + *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + s += sstep; + t += tstep; + spancount--; + }*/ + + do + { + *((unsigned int *)pdest)++ = *((pbase + (s >> 16) + (t >> 16) * cachewidth))* 0x01010101; + s += sstep<<2; + t += tstep<<2; + } while((spancount-=4) > 3); + + /* while (spancount-- > 0) + { + *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + s += sstep; + t += tstep; + }*/ +#else + do + { + *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + s += sstep; + t += tstep; + } while (--spancount > 0); +#endif + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +#endif + +void D_DrawSpans16 (espan_t *pspan) +{ + int count, spancount; + unsigned short *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned short *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + do + { + pdest = (unsigned short *)((unsigned short *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +void D_DrawSpans16From8 (espan_t *pspan) +{ + int count, spancount; + unsigned char *pbase; + unsigned short *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + Con_Printf("spans16from8\n"); + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned char *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + do + { + pdest = (unsigned short *)((unsigned short *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + *pdest++ = vid.colormap16[*(pbase + (s >> 16) + (t >> 16) * cachewidth)]; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + + + +#if !id386 + +/* +============= +D_DrawZSpans +============= +*/ +void D_DrawZSpans (espan_t *pspan) +{ + int count, doublecount, izistep; + int izi; + short *pdest; + unsigned ltemp; + double zi; + float du, dv; + +// FIXME: check for clamping/range problems +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + // calculate the initial 1/z + du = (float)pspan->u; + dv = (float)pspan->v; + + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + if ((long)pdest & 0x02) + { + *pdest++ = (short)(izi >> 16); + izi += izistep; + count--; + } + + if ((doublecount = count >> 1) > 0) + { + do + { + ltemp = izi >> 16; + izi += izistep; + ltemp |= izi & 0xFFFF0000; + izi += izistep; + *(int *)pdest = ltemp; + pdest += 2; + } while (--doublecount > 0); + } + + if (count & 1) + *pdest = (short)(izi >> 16); + + } while ((pspan = pspan->pnext) != NULL); +} + +#endif diff --git a/engine/sw/d_scana.s b/engine/sw/d_scana.s new file mode 100644 index 000000000..bd4fd7447 --- /dev/null +++ b/engine/sw/d_scana.s @@ -0,0 +1,89 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// d_scana.s +// x86 assembly-language turbulent texture mapping code +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" +#include "d_ifacea.h" + +#if id386 + + .data + + .text + +//---------------------------------------------------------------------- +// turbulent texture mapping code +//---------------------------------------------------------------------- + + .align 4 +.globl C(D_DrawTurbulent8Span) +C(D_DrawTurbulent8Span): + pushl %ebp // preserve caller's stack frame pointer + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + + movl C(r_turb_s),%esi + movl C(r_turb_t),%ecx + movl C(r_turb_pdest),%edi + movl C(r_turb_spancount),%ebx + +Llp: + movl %ecx,%eax + movl %esi,%edx + sarl $16,%eax + movl C(r_turb_turb),%ebp + sarl $16,%edx + andl $(CYCLE-1),%eax + andl $(CYCLE-1),%edx + movl (%ebp,%eax,4),%eax + movl (%ebp,%edx,4),%edx + addl %esi,%eax + sarl $16,%eax + addl %ecx,%edx + sarl $16,%edx + andl $(TURB_TEX_SIZE-1),%eax + andl $(TURB_TEX_SIZE-1),%edx + shll $6,%edx + movl C(r_turb_pbase),%ebp + addl %eax,%edx + incl %edi + addl C(r_turb_sstep),%esi + addl C(r_turb_tstep),%ecx + movb (%ebp,%edx,1),%dl + decl %ebx + movb %dl,-1(%edi) + jnz Llp + + movl %edi,C(r_turb_pdest) + + popl %ebx // restore register variables + popl %edi + popl %esi + popl %ebp // restore caller's stack frame pointer + ret + +#endif // id386 + diff --git a/engine/sw/d_sky.c b/engine/sw/d_sky.c new file mode 100644 index 000000000..157534634 --- /dev/null +++ b/engine/sw/d_sky.c @@ -0,0 +1,301 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_sky.c + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + +#define SKY_SPAN_SHIFT 5 +#define SKY_SPAN_MAX (1 << SKY_SPAN_SHIFT) + + +/* +================= +D_Sky_uv_To_st +================= +*/ +void D_Sky_uv_To_st (int u, int v, fixed16_t *s, fixed16_t *t) +{ + float wu, wv, temp; + vec3_t end; + + if (r_refdef.vrect.width >= r_refdef.vrect.height) + temp = (float)r_refdef.vrect.width; + else + temp = (float)r_refdef.vrect.height; + + wu = 8192.0 * (float)(u-((int)vid.width>>1)) / temp; + wv = 8192.0 * (float)(((int)vid.height>>1)-v) / temp; + + end[0] = 4096*vpn[0] + wu*vright[0] + wv*vup[0]; + end[1] = 4096*vpn[1] + wu*vright[1] + wv*vup[1]; + end[2] = 4096*vpn[2] + wu*vright[2] + wv*vup[2]; + end[2] *= 3; + VectorNormalize (end); + + temp = skytime*skyspeed; // TODO: add D_SetupFrame & set this there + *s = (int)((temp + 6*(SKYSIZE/2-1)*end[0]) * 0x10000); + *t = (int)((temp + 6*(SKYSIZE/2-1)*end[1]) * 0x10000); +} + + +/* +================= +D_DrawSkyScans8 +================= +*/ +void D_DrawSkyScans8 (espan_t *pspan) +{ + int count, spancount, u, v; + unsigned char *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + int spancountminus1; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + do + { + pdest = (unsigned char *)((qbyte *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s & t + u = pspan->u; + v = pspan->v; + D_Sky_uv_To_st (u, v, &s, &t); + + do + { + if (count >= SKY_SPAN_MAX) + spancount = SKY_SPAN_MAX; + else + spancount = count; + + count -= spancount; + + if (count) + { + u += spancount; + + // calculate s and t at far end of span, + // calculate s and t steps across span by shifting + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) >> SKY_SPAN_SHIFT; + tstep = (tnext - t) >> SKY_SPAN_SHIFT; + } + else + { + // calculate s and t at last pixel in span, + // calculate s and t steps across span by division + spancountminus1 = (float)(spancount - 1); + + if (spancountminus1 > 0) + { + u += spancountminus1; + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) / spancountminus1; + tstep = (tnext - t) / spancountminus1; + } + else + { + snext = 0; + tnext = 0; + } + } + + do + { + *pdest++ = r_skysource[((t & R_SKY_TMASK) >> 8) + + ((s & R_SKY_SMASK) >> 16)]; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +void D_DrawSkyScans16 (espan_t *pspan) +{ + int count, spancount, u, v; + unsigned short *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + int spancountminus1; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + do + { + pdest = ((unsigned short *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s & t + u = pspan->u; + v = pspan->v; + D_Sky_uv_To_st (u, v, &s, &t); + + do + { + if (count >= SKY_SPAN_MAX) + spancount = SKY_SPAN_MAX; + else + spancount = count; + + count -= spancount; + + if (count) + { + u += spancount; + + // calculate s and t at far end of span, + // calculate s and t steps across span by shifting + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) >> SKY_SPAN_SHIFT; + tstep = (tnext - t) >> SKY_SPAN_SHIFT; + } + else + { + // calculate s and t at last pixel in span, + // calculate s and t steps across span by division + spancountminus1 = (float)(spancount - 1); + + if (spancountminus1 > 0) + { + u += spancountminus1; + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) / spancountminus1; + tstep = (tnext - t) / spancountminus1; + } + else + { + snext=0; + tnext=0; + } + } + + do + { + *pdest++ = d_8to16table[r_skysource[((t & R_SKY_TMASK) >> 8) + + ((s & R_SKY_SMASK) >> 16)]]; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + +void D_DrawSkyScans32 (espan_t *pspan) +{ + int count, spancount, u, v; + unsigned int *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + int spancountminus1; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + do + { + pdest = ((unsigned int *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s & t + u = pspan->u; + v = pspan->v; + D_Sky_uv_To_st (u, v, &s, &t); + + do + { + if (count >= SKY_SPAN_MAX) + spancount = SKY_SPAN_MAX; + else + spancount = count; + + count -= spancount; + + if (count) + { + u += spancount; + + // calculate s and t at far end of span, + // calculate s and t steps across span by shifting + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) >> SKY_SPAN_SHIFT; + tstep = (tnext - t) >> SKY_SPAN_SHIFT; + } + else + { + // calculate s and t at last pixel in span, + // calculate s and t steps across span by division + spancountminus1 = (float)(spancount - 1); + + if (spancountminus1 > 0) + { + u += spancountminus1; + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) / spancountminus1; + tstep = (tnext - t) / spancountminus1; + } + else + { + snext=0; + tnext=0; + } + } + + do + { + *pdest++ = d_8to32table[r_skysource[((t & R_SKY_TMASK) >> 8) + + ((s & R_SKY_SMASK) >> 16)]]; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} + diff --git a/engine/sw/d_spr8.s b/engine/sw/d_spr8.s new file mode 100644 index 000000000..37c81c5e6 --- /dev/null +++ b/engine/sw/d_spr8.s @@ -0,0 +1,899 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// d_spr8.s +// x86 assembly-language horizontal 8-bpp transparent span-drawing code. +// +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" + +#if id386 + +//---------------------------------------------------------------------- +// 8-bpp horizontal span drawing code for polygons, with transparency. +//---------------------------------------------------------------------- + + .text + +// out-of-line, rarely-needed clamping code + +LClampHigh0: + movl C(bbextents),%esi + jmp LClampReentry0 +LClampHighOrLow0: + jg LClampHigh0 + xorl %esi,%esi + jmp LClampReentry0 + +LClampHigh1: + movl C(bbextentt),%edx + jmp LClampReentry1 +LClampHighOrLow1: + jg LClampHigh1 + xorl %edx,%edx + jmp LClampReentry1 + +LClampLow2: + movl $2048,%ebp + jmp LClampReentry2 +LClampHigh2: + movl C(bbextents),%ebp + jmp LClampReentry2 + +LClampLow3: + movl $2048,%ecx + jmp LClampReentry3 +LClampHigh3: + movl C(bbextentt),%ecx + jmp LClampReentry3 + +LClampLow4: + movl $2048,%eax + jmp LClampReentry4 +LClampHigh4: + movl C(bbextents),%eax + jmp LClampReentry4 + +LClampLow5: + movl $2048,%ebx + jmp LClampReentry5 +LClampHigh5: + movl C(bbextentt),%ebx + jmp LClampReentry5 + + +#define pspans 4+16 + + .align 4 +.globl C(D_SpriteDrawSpans) +C(D_SpriteDrawSpans): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// +// set up scaled-by-8 steps, for 8-long segments; also set up cacheblock +// and span list pointers, and 1/z step in 0.32 fixed-point +// +// FIXME: any overlap from rearranging? + flds C(d_sdivzstepu) + fmuls fp_8 + movl C(cacheblock),%edx + flds C(d_tdivzstepu) + fmuls fp_8 + movl pspans(%esp),%ebx // point to the first span descriptor + flds C(d_zistepu) + fmuls fp_8 + movl %edx,pbase // pbase = cacheblock + flds C(d_zistepu) + fmuls fp_64kx64k + fxch %st(3) + fstps sdivz8stepu + fstps zi8stepu + fstps tdivz8stepu + fistpl izistep + movl izistep,%eax + rorl $16,%eax // put upper 16 bits in low word + movl sspan_t_count(%ebx),%ecx + movl %eax,izistep + + cmpl $0,%ecx + jle LNextSpan + +LSpanLoop: + +// +// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the +// initial s and t values +// +// FIXME: pipeline FILD? + fildl sspan_t_v(%ebx) + fildl sspan_t_u(%ebx) + + fld %st(1) // dv | du | dv + fmuls C(d_sdivzstepv) // dv*d_sdivzstepv | du | dv + fld %st(1) // du | dv*d_sdivzstepv | du | dv + fmuls C(d_sdivzstepu) // du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fld %st(2) // du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fmuls C(d_tdivzstepu) // du*d_tdivzstepu | du*d_sdivzstepu | + // dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu | du*d_tdivzstepu | + // dv*d_sdivzstepv | du | dv + faddp %st(0),%st(2) // du*d_tdivzstepu | + // du*d_sdivzstepu + dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fld %st(3) // dv | du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fmuls C(d_tdivzstepv) // dv*d_tdivzstepv | + // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // dv*d_tdivzstepv | du*d_tdivzstepu | du | dv + fadds C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv + + // du*d_sdivzstepu; stays in %st(2) at end + fxch %st(4) // dv | dv*d_tdivzstepv | du*d_tdivzstepu | du | + // s/z + fmuls C(d_zistepv) // dv*d_zistepv | dv*d_tdivzstepv | + // du*d_tdivzstepu | du | s/z + fxch %st(1) // dv*d_tdivzstepv | dv*d_zistepv | + // du*d_tdivzstepu | du | s/z + faddp %st(0),%st(2) // dv*d_zistepv | + // dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z + fxch %st(2) // du | dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fmuls C(d_zistepu) // du*d_zistepu | + // dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fxch %st(1) // dv*d_tdivzstepv + du*d_tdivzstepu | + // du*d_zistepu | dv*d_zistepv | s/z + fadds C(d_tdivzorigin) // tdivz = d_tdivzorigin + dv*d_tdivzstepv + + // du*d_tdivzstepu; stays in %st(1) at end + fxch %st(2) // dv*d_zistepv | du*d_zistepu | t/z | s/z + faddp %st(0),%st(1) // dv*d_zistepv + du*d_zistepu | t/z | s/z + + flds fp_64k // fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z + fxch %st(1) // dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z + fadds C(d_ziorigin) // zi = d_ziorigin + dv*d_zistepv + + // du*d_zistepu; stays in %st(0) at end + // 1/z | fp_64k | t/z | s/z + + fld %st(0) // FIXME: get rid of stall on FMUL? + fmuls fp_64kx64k + fxch %st(1) + +// +// calculate and clamp s & t +// + fdivr %st(0),%st(2) // 1/z | z*64k | t/z | s/z + fxch %st(1) + + fistpl izi // 0.32 fixed-point 1/z + movl izi,%ebp + +// +// set pz to point to the first z-buffer pixel in the span +// + rorl $16,%ebp // put upper 16 bits in low word + movl sspan_t_v(%ebx),%eax + movl %ebp,izi + movl sspan_t_u(%ebx),%ebp + imull C(d_zrowbytes) + shll $1,%ebp // a word per pixel + addl C(d_pzbuffer),%eax + addl %ebp,%eax + movl %eax,pz + +// +// point %edi to the first pixel in the span +// + movl C(d_viewbuffer),%ebp + movl sspan_t_v(%ebx),%eax + pushl %ebx // preserve spans pointer + movl C(tadjust),%edx + movl C(sadjust),%esi + movl C(d_scantable)(,%eax,4),%edi // v * screenwidth + addl %ebp,%edi + movl sspan_t_u(%ebx),%ebp + addl %ebp,%edi // pdest = &pdestspan[scans->u]; + +// +// now start the FDIV for the end of the span +// + cmpl $8,%ecx + ja LSetupNotLast1 + + decl %ecx + jz LCleanup1 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fildl spancountminus1 + + flds C(d_tdivzstepu) // _d_tdivzstepu | spancountminus1 + flds C(d_zistepu) // _d_zistepu | _d_tdivzstepu | spancountminus1 + fmul %st(2),%st(0) // _d_zistepu*scm1 | _d_tdivzstepu | scm1 + fxch %st(1) // _d_tdivzstepu | _d_zistepu*scm1 | scm1 + fmul %st(2),%st(0) // _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1 + fxch %st(2) // scm1 | _d_zistepu*scm1 | _d_tdivzstepu*scm1 + fmuls C(d_sdivzstepu) // _d_sdivzstepu*scm1 | _d_zistepu*scm1 | + // _d_tdivzstepu*scm1 + fxch %st(1) // _d_zistepu*scm1 | _d_sdivzstepu*scm1 | + // _d_tdivzstepu*scm1 + faddp %st(0),%st(3) // _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1 + fxch %st(1) // _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1 + faddp %st(0),%st(3) // _d_sdivzstepu*scm1 + faddp %st(0),%st(3) + + flds fp_64k + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight1 + +LCleanup1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + jmp LFDIVInFlight1 + + .align 4 +LSetupNotLast1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fadds zi8stepu + fxch %st(2) + fadds sdivz8stepu + fxch %st(2) + flds tdivz8stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight1: + + addl s,%esi + addl t,%edx + movl C(bbextents),%ebx + movl C(bbextentt),%ebp + cmpl %ebx,%esi + ja LClampHighOrLow0 +LClampReentry0: + movl %esi,s + movl pbase,%ebx + shll $16,%esi + cmpl %ebp,%edx + movl %esi,sfracf + ja LClampHighOrLow1 +LClampReentry1: + movl %edx,t + movl s,%esi // sfrac = scans->sfrac; + shll $16,%edx + movl t,%eax // tfrac = scans->tfrac; + sarl $16,%esi + movl %edx,tfracf + +// +// calculate the texture starting address +// + sarl $16,%eax + addl %ebx,%esi + imull C(cachewidth),%eax // (tfrac >> 16) * cachewidth + addl %eax,%esi // psource = pbase + (sfrac >> 16) + + // ((tfrac >> 16) * cachewidth); + +// +// determine whether last span or not +// + cmpl $8,%ecx + jna LLastSegment + +// +// not the last segment; do full 8-wide segment +// +LNotLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there +// + +// pick up after the FDIV that was left in flight previously + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + movl snext,%eax + movl tnext,%edx + + subl $8,%ecx // count off this segments' pixels + movl C(sadjust),%ebp + pushl %ecx // remember count of remaining pixels + movl C(tadjust),%ecx + + addl %eax,%ebp + addl %edx,%ecx + + movl C(bbextents),%eax + movl C(bbextentt),%edx + + cmpl $2048,%ebp + jl LClampLow2 + cmpl %eax,%ebp + ja LClampHigh2 +LClampReentry2: + + cmpl $2048,%ecx + jl LClampLow3 + cmpl %edx,%ecx + ja LClampHigh3 +LClampReentry3: + + movl %ebp,snext + movl %ecx,tnext + + subl s,%ebp + subl t,%ecx + +// +// set up advancetable +// + movl %ecx,%eax + movl %ebp,%edx + sarl $19,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + sarl $19,%eax // tstep >>= 16; + jz LIsZero + imull %ebx,%eax // (tstep >> 16) * cachewidth; +LIsZero: + addl %edx,%eax // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%edx + movl %eax,advancetable+4 // advance base in t + addl %ebx,%eax // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $13,%ebp // left-justify sstep fractional part + movl %ebp,sstep + movl sfracf,%ebx + shll $13,%ecx // left-justify tstep fractional part + movl %eax,advancetable // advance extra in t + movl %ecx,tstep + + movl pz,%ecx + movl izi,%ebp + + cmpw (%ecx),%bp + jl Lp1 + movb (%esi),%al // get first source texel + cmpb $(TRANSPARENT_COLOR),%al + jz Lp1 + movw %bp,(%ecx) + movb %al,(%edi) // store first dest pixel +Lp1: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx // advance tfrac fractional part by tstep frac + + sbbl %eax,%eax // turn tstep carry into -1 (0 if none) + addl sstep,%ebx // advance sfrac fractional part by sstep frac + adcl advancetable+4(,%eax,4),%esi // point to next source texel + + cmpw 2(%ecx),%bp + jl Lp2 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp2 + movw %bp,2(%ecx) + movb %al,1(%edi) +Lp2: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 4(%ecx),%bp + jl Lp3 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp3 + movw %bp,4(%ecx) + movb %al,2(%edi) +Lp3: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 6(%ecx),%bp + jl Lp4 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp4 + movw %bp,6(%ecx) + movb %al,3(%edi) +Lp4: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 8(%ecx),%bp + jl Lp5 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp5 + movw %bp,8(%ecx) + movb %al,4(%edi) +Lp5: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + +// +// start FDIV for end of next segment in flight, so it can overlap +// + popl %eax + cmpl $8,%eax // more than one segment after this? + ja LSetupNotLast2 // yes + + decl %eax + jz LFDIVInFlight2 // if only one pixel, no need to start an FDIV + movl %eax,spancountminus1 + fildl spancountminus1 + + flds C(d_zistepu) // _d_zistepu | spancountminus1 + fmul %st(1),%st(0) // _d_zistepu*scm1 | scm1 + flds C(d_tdivzstepu) // _d_tdivzstepu | _d_zistepu*scm1 | scm1 + fmul %st(2),%st(0) // _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1 + fxch %st(1) // _d_zistepu*scm1 | _d_tdivzstepu*scm1 | scm1 + faddp %st(0),%st(3) // _d_tdivzstepu*scm1 | scm1 + fxch %st(1) // scm1 | _d_tdivzstepu*scm1 + fmuls C(d_sdivzstepu) // _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1 + fxch %st(1) // _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1 + faddp %st(0),%st(3) // _d_sdivzstepu*scm1 + flds fp_64k // 64k | _d_sdivzstepu*scm1 + fxch %st(1) // _d_sdivzstepu*scm1 | 64k + faddp %st(0),%st(4) // 64k + + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight2 + + .align 4 +LSetupNotLast2: + fadds zi8stepu + fxch %st(2) + fadds sdivz8stepu + fxch %st(2) + flds tdivz8stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight2: + pushl %eax + + cmpw 10(%ecx),%bp + jl Lp6 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp6 + movw %bp,10(%ecx) + movb %al,5(%edi) +Lp6: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 12(%ecx),%bp + jl Lp7 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp7 + movw %bp,12(%ecx) + movb %al,6(%edi) +Lp7: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 14(%ecx),%bp + jl Lp8 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp8 + movw %bp,14(%ecx) + movb %al,7(%edi) +Lp8: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + addl $8,%edi + addl $16,%ecx + movl %edx,tfracf + movl snext,%edx + movl %ebx,sfracf + movl tnext,%ebx + movl %edx,s + movl %ebx,t + + movl %ecx,pz + movl %ebp,izi + + popl %ecx // retrieve count + +// +// determine whether last span or not +// + cmpl $8,%ecx // are there multiple segments remaining? + ja LNotLastSegment // yes + +// +// last segment of scan +// +LLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there. The number of pixels left is variable, and we want to land on the +// last pixel, not step one past it, so we can't run into arithmetic problems +// + testl %ecx,%ecx + jz LNoSteps // just draw the last pixel and we're done + +// pick up after the FDIV that was left in flight previously + + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + + movl C(tadjust),%ebx + movl C(sadjust),%eax + + addl snext,%eax + addl tnext,%ebx + + movl C(bbextents),%ebp + movl C(bbextentt),%edx + + cmpl $2048,%eax + jl LClampLow4 + cmpl %ebp,%eax + ja LClampHigh4 +LClampReentry4: + movl %eax,snext + + cmpl $2048,%ebx + jl LClampLow5 + cmpl %edx,%ebx + ja LClampHigh5 +LClampReentry5: + + cmpl $1,%ecx // don't bother + je LOnlyOneStep // if two pixels in segment, there's only one step, + // of the segment length + subl s,%eax + subl t,%ebx + + addl %eax,%eax // convert to 15.17 format so multiply by 1.31 + addl %ebx,%ebx // reciprocal yields 16.48 + imull reciprocal_table-8(,%ecx,4) // sstep = (snext - s) / (spancount-1) + movl %edx,%ebp + + movl %ebx,%eax + imull reciprocal_table-8(,%ecx,4) // tstep = (tnext - t) / (spancount-1) + +LSetEntryvec: +// +// set up advancetable +// + movl spr8entryvec_table(,%ecx,4),%ebx + movl %edx,%eax + pushl %ebx // entry point into code for RET later + movl %ebp,%ecx + sarl $16,%ecx // sstep >>= 16; + movl C(cachewidth),%ebx + sarl $16,%edx // tstep >>= 16; + jz LIsZeroLast + imull %ebx,%edx // (tstep >> 16) * cachewidth; +LIsZeroLast: + addl %ecx,%edx // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%ecx + movl %edx,advancetable+4 // advance base in t + addl %ebx,%edx // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $16,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $16,%eax // left-justify tstep fractional part + movl %edx,advancetable // advance extra in t + + movl %eax,tstep + movl %ebp,sstep + movl %ecx,%edx + + movl pz,%ecx + movl izi,%ebp + + ret // jump to the number-of-pixels handler + +//---------------------------------------- + +LNoSteps: + movl pz,%ecx + subl $7,%edi // adjust for hardwired offset + subl $14,%ecx + jmp LEndSpan + + +LOnlyOneStep: + subl s,%eax + subl t,%ebx + movl %eax,%ebp + movl %ebx,%edx + jmp LSetEntryvec + +//---------------------------------------- + +.globl Spr8Entry2_8 +Spr8Entry2_8: + subl $6,%edi // adjust for hardwired offsets + subl $12,%ecx + movb (%esi),%al + jmp LLEntry2_8 + +//---------------------------------------- + +.globl Spr8Entry3_8 +Spr8Entry3_8: + subl $5,%edi // adjust for hardwired offsets + subl $10,%ecx + jmp LLEntry3_8 + +//---------------------------------------- + +.globl Spr8Entry4_8 +Spr8Entry4_8: + subl $4,%edi // adjust for hardwired offsets + subl $8,%ecx + jmp LLEntry4_8 + +//---------------------------------------- + +.globl Spr8Entry5_8 +Spr8Entry5_8: + subl $3,%edi // adjust for hardwired offsets + subl $6,%ecx + jmp LLEntry5_8 + +//---------------------------------------- + +.globl Spr8Entry6_8 +Spr8Entry6_8: + subl $2,%edi // adjust for hardwired offsets + subl $4,%ecx + jmp LLEntry6_8 + +//---------------------------------------- + +.globl Spr8Entry7_8 +Spr8Entry7_8: + decl %edi // adjust for hardwired offsets + subl $2,%ecx + jmp LLEntry7_8 + +//---------------------------------------- + +.globl Spr8Entry8_8 +Spr8Entry8_8: + cmpw (%ecx),%bp + jl Lp9 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp9 + movw %bp,(%ecx) + movb %al,(%edi) +Lp9: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry7_8: + cmpw 2(%ecx),%bp + jl Lp10 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp10 + movw %bp,2(%ecx) + movb %al,1(%edi) +Lp10: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry6_8: + cmpw 4(%ecx),%bp + jl Lp11 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp11 + movw %bp,4(%ecx) + movb %al,2(%edi) +Lp11: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry5_8: + cmpw 6(%ecx),%bp + jl Lp12 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp12 + movw %bp,6(%ecx) + movb %al,3(%edi) +Lp12: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry4_8: + cmpw 8(%ecx),%bp + jl Lp13 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp13 + movw %bp,8(%ecx) + movb %al,4(%edi) +Lp13: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry3_8: + cmpw 10(%ecx),%bp + jl Lp14 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp14 + movw %bp,10(%ecx) + movb %al,5(%edi) +Lp14: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry2_8: + cmpw 12(%ecx),%bp + jl Lp15 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp15 + movw %bp,12(%ecx) + movb %al,6(%edi) +Lp15: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + +LEndSpan: + cmpw 14(%ecx),%bp + jl Lp16 + movb (%esi),%al // load first texel in segment + cmpb $(TRANSPARENT_COLOR),%al + jz Lp16 + movw %bp,14(%ecx) + movb %al,7(%edi) +Lp16: + +// +// clear s/z, t/z, 1/z from FP stack +// + fstp %st(0) + fstp %st(0) + fstp %st(0) + + popl %ebx // restore spans pointer +LNextSpan: + addl $(sspan_t_size),%ebx // point to next span + movl sspan_t_count(%ebx),%ecx + cmpl $0,%ecx // any more spans? + jg LSpanLoop // yes + jz LNextSpan // yes, but this one's empty + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +#endif // id386 diff --git a/engine/sw/d_sprite.c b/engine/sw/d_sprite.c new file mode 100644 index 000000000..24ca4fe3e --- /dev/null +++ b/engine/sw/d_sprite.c @@ -0,0 +1,926 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_sprite.c: software top-level rasterization driver module for drawing +// sprites + +#include "quakedef.h" +#include "d_local.h" + +static int sprite_height; +static int minindex, maxindex; +static sspan_t *sprite_spans; + +#if !id386 + +/* +===================== +D_SpriteDrawSpans +===================== +*/ +void D_SpriteDrawSpans (sspan_t *pspan) +{ + int count, spancount, izistep; + int izi; + qbyte *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + qbyte btemp; + short *pz; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = (qbyte *)d_viewbuffer + r_pixbytes*((screenwidth * pspan->v) + pspan->u); + pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + do + { + btemp = *(pbase + ((s >> 16) + (t >> 16) * cachewidth)); + if (btemp != 255) + { + if (*pz <= (izi >> 16)) + { + *pz = izi >> 16; + *pdest = btemp; + } + } + + izi += izistep; + pdest++; + pz++; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} +#endif + +void D_SpriteDrawSpans16 (sspan_t *pspan) +{ + int count, spancount, izistep; + int izi; + unsigned short *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + unsigned short btemp; + short *pz; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned short *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = (unsigned short *)d_viewbuffer + ((screenwidth * pspan->v) + pspan->u); + pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + do + { + btemp = *(pbase + ((s >> 16) + (t >> 16) * cachewidth)); + if (btemp != 0xffff) + { + if (*pz <= (izi >> 16)) + { + *pz = izi >> 16; + *pdest = btemp; + } + } + + izi += izistep; + pdest++; + pz++; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} + + +void D_SpriteDrawSpans32 (sspan_t *pspan) +{ + int count, spancount, izistep; + int izi; + unsigned int *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + unsigned int itemp; + qbyte *pbtemp, *pbdest, alpha; + short *pz; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned int*)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = (unsigned int *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u; + pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + do + { + itemp = *(pbase + ((s >> 16) + (t >> 16) * cachewidth)); + if ((alpha = itemp>>24)) + { + alpha = 128; + if (*pz <= (izi >> 16)) + { + *pz = izi >> 16; + + pbtemp = (qbyte *)&itemp; + pbdest = (qbyte *)pdest; + pbdest[0] = (pbdest[0]*(255-alpha) + pbtemp[0]*alpha)/255; + pbdest[1] = (pbdest[1]*(255-alpha) + pbtemp[1]*alpha)/255; + pbdest[2] = (pbdest[2]*(255-alpha) + pbtemp[2]*alpha)/255; + } + } + + izi += izistep; + pdest++; + pz++; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} + +#ifdef PEXT_TRANS +void D_SpriteDrawSpansTrans (sspan_t *pspan) +{ + int count, spancount, izistep; + int izi; + qbyte *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + qbyte btemp; + short *pz; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = (qbyte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u; + pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + if (btemp != 255) + { + if (*pz <= (izi >> 16)) + { + *pz = izi >> 16; + *pdest = Trans(*pdest, btemp); + } + } + + izi += izistep; + pdest++; + pz++; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} +#endif + +/* +===================== +D_SpriteScanLeftEdge +===================== +*/ +void D_SpriteScanLeftEdge (void) +{ + int i, v, itop, ibottom, lmaxindex; + emitpoint_t *pvert, *pnext; + sspan_t *pspan; + float du, dv, vtop, vbottom, slope; + fixed16_t u, u_step; + + pspan = sprite_spans; + i = minindex; + if (i == 0) + i = r_spritedesc.nump; + + lmaxindex = maxindex; + if (lmaxindex == 0) + lmaxindex = r_spritedesc.nump; + + vtop = ceil (r_spritedesc.pverts[i].v); + + do + { + pvert = &r_spritedesc.pverts[i]; + pnext = pvert - 1; + + vbottom = ceil (pnext->v); + + if (vtop < vbottom) + { + du = pnext->u - pvert->u; + dv = pnext->v - pvert->v; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vu = u >> 16; + pspan->v = v; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + + i--; + if (i == 0) + i = r_spritedesc.nump; + + } while (i != lmaxindex); +} + + +/* +===================== +D_SpriteScanRightEdge +===================== +*/ +void D_SpriteScanRightEdge (void) +{ + int i, v, itop, ibottom; + emitpoint_t *pvert, *pnext; + sspan_t *pspan; + float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext; + fixed16_t u, u_step; + + pspan = sprite_spans; + i = minindex; + + vvert = r_spritedesc.pverts[i].v; + if (vvert < r_refdef.fvrecty_adj) + vvert = r_refdef.fvrecty_adj; + if (vvert > r_refdef.fvrectbottom_adj) + vvert = r_refdef.fvrectbottom_adj; + + vtop = ceil (vvert); + + do + { + pvert = &r_spritedesc.pverts[i]; + pnext = pvert + 1; + + vnext = pnext->v; + if (vnext < r_refdef.fvrecty_adj) + vnext = r_refdef.fvrecty_adj; + if (vnext > r_refdef.fvrectbottom_adj) + vnext = r_refdef.fvrectbottom_adj; + + vbottom = ceil (vnext); + + if (vtop < vbottom) + { + uvert = pvert->u; + if (uvert < r_refdef.fvrectx_adj) + uvert = r_refdef.fvrectx_adj; + if (uvert > r_refdef.fvrectright_adj) + uvert = r_refdef.fvrectright_adj; + + unext = pnext->u; + if (unext < r_refdef.fvrectx_adj) + unext = r_refdef.fvrectx_adj; + if (unext > r_refdef.fvrectright_adj) + unext = r_refdef.fvrectright_adj; + + du = unext - uvert; + dv = vnext - vvert; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vcount = (u >> 16) - pspan->u; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + vvert = vnext; + + i++; + if (i == r_spritedesc.nump) + i = 0; + + } while (i != maxindex); + + pspan->count = DS_SPAN_LIST_END; // mark the end of the span list +} + + +/* +===================== +D_SpriteCalculateGradients +===================== +*/ +void D_SpriteCalculateGradients (void) +{ + vec3_t p_normal, p_saxis, p_taxis, p_temp1; + float distinv; + + TransformVector (r_spritedesc.vpn, p_normal); + TransformVector (r_spritedesc.vright, p_saxis); + TransformVector (r_spritedesc.vup, p_taxis); + VectorInverse (p_taxis); + + distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn)); + + d_sdivzstepu = p_saxis[0] * xscaleinv; + d_tdivzstepu = p_taxis[0] * xscaleinv; + + d_sdivzstepv = -p_saxis[1] * yscaleinv; + d_tdivzstepv = -p_taxis[1] * yscaleinv; + + d_zistepu = p_normal[0] * xscaleinv * distinv; + d_zistepv = -p_normal[1] * yscaleinv * distinv; + + d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - + ycenter * d_sdivzstepv; + d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - + ycenter * d_tdivzstepv; + d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - + ycenter * d_zistepv; + + TransformVector (modelorg, p_temp1); + + sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) - + (-(cachewidth >> 1) << 16); + tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) - + (-(sprite_height >> 1) << 16); + +// -1 (-epsilon) so we never wander off the edge of the texture + bbextents = (cachewidth << 16) - 1; + bbextentt = (sprite_height << 16) - 1; +} + + +/* +===================== +D_DrawSprite +===================== +*/ +void D_DrawSprite (void) +{ + int i, nump; + float ymin, ymax; + emitpoint_t *pverts; + sspan_t spans[MAXHEIGHT+1]; + + sprite_spans = spans; + +// find the top and bottom vertices, and make sure there's at least one scan to +// draw + ymin = 999999.9; + ymax = -999999.9; + pverts = r_spritedesc.pverts; + + for (i=0 ; iv < ymin) + { + ymin = pverts->v; + minindex = i; + } + + if (pverts->v > ymax) + { + ymax = pverts->v; + maxindex = i; + } + + pverts++; + } + + ymin = ceil (ymin); + ymax = ceil (ymax); + + if (ymin >= ymax) + return; // doesn't cross any scans at all + + cachewidth = r_spritedesc.pspriteframe->width; + sprite_height = r_spritedesc.pspriteframe->height; + cacheblock = (qbyte *)&r_spritedesc.pspriteframe->pixels[0]; + +// copy the first vertex to the last vertex, so we don't have to deal with +// wrapping + nump = r_spritedesc.nump; + pverts = r_spritedesc.pverts; + pverts[nump] = pverts[0]; + + D_SpriteCalculateGradients (); + D_SpriteScanLeftEdge (); + D_SpriteScanRightEdge (); +#ifndef PEXT_TRANS + D_SpriteDrawSpans (sprite_spans); +#else + if (r_pixbytes == 4) + D_SpriteDrawSpans32 (sprite_spans); + else if (r_pixbytes == 2) + D_SpriteDrawSpans16 (sprite_spans); + else //1 + { + if (currententity->alpha>=0.9) + D_SpriteDrawSpans (sprite_spans); + else + { + Set_TransLevelF(currententity->alpha); + D_SpriteDrawSpansTrans (sprite_spans); + } + } +#endif +} + diff --git a/engine/sw/d_surf.c b/engine/sw/d_surf.c new file mode 100644 index 000000000..f6f56118e --- /dev/null +++ b/engine/sw/d_surf.c @@ -0,0 +1,351 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_surf.c: rasterization driver surface heap manager + +#include "quakedef.h" +#include "d_local.h" +#include "r_local.h" + +float surfscale; +qboolean r_cache_thrash; // set if surface cache is thrashing + +int r_flushcache; + +int sc_size; +surfcache_t *sc_rover, *sc_base; + +#define GUARDSIZE 4 + + +int D_SurfaceCacheForRes (int width, int height, int bpp) +{ + int size, pix; + + if (COM_CheckParm ("-surfcachesize")) + { + size = Q_atoi(com_argv[COM_CheckParm("-surfcachesize")+1]) * 1024; + return size; + } + + size = 4096*1024;//SURFCACHE_SIZE_AT_320X200; + + pix = width*height; + if (pix > 64000) + size += (pix-64000)*4; + + if (bpp) + return size*bpp; + return size; +} + +void D_CheckCacheGuard (void) +{ + qbyte *s; + int i; + + s = (qbyte *)sc_base + sc_size; + for (i=0 ; inext = NULL; + sc_base->owner = NULL; + sc_base->size = sc_size; + + D_ClearCacheGuard (); +} + + +/* +================== +D_FlushCaches +================== +*/ +void D_FlushCaches (void) +{ + surfcache_t *c; + + if (!sc_base) + return; + + for (c = sc_base ; c ; c = c->next) + { + if (c->owner) + *c->owner = NULL; + } + + sc_rover = sc_base; + sc_base->next = NULL; + sc_base->owner = NULL; + sc_base->size = sc_size; +} + +/* +================= +D_SCAlloc +================= +*/ +surfcache_t *D_SCAlloc (int width, int bpp, int size) +{ + surfcache_t *new; + qboolean wrapped_this_time; + +// if ((width < 0) || (width > 256)) +// Sys_Error ("D_SCAlloc: bad cache width %d\n", width); + +// if ((size <= 0) || (size > 0x10000*bpp)) +// Sys_Error ("D_SCAlloc: bad cache size %d\n", size); + +#ifdef __alpha__ + size = (int)((long)&((surfcache_t *)0)->data[size]); +#else + size = (int)&((surfcache_t *)0)->data[size]; +#endif + size = (size + 3) & ~3; + if (size > sc_size) + Sys_Error ("D_SCAlloc: %i > cache size",size); + +// if there is not size bytes after the rover, reset to the start + wrapped_this_time = false; + + if ( !sc_rover || (qbyte *)sc_rover - (qbyte *)sc_base > sc_size - size) + { + if (sc_rover) + { + wrapped_this_time = true; + } + sc_rover = sc_base; + } + +// colect and free surfcache_t blocks until the rover block is large enough + new = sc_rover; + if (sc_rover->owner) + *sc_rover->owner = NULL; + + while (new->size < size) + { + // free another + sc_rover = sc_rover->next; + if (!sc_rover) + Sys_Error ("D_SCAlloc: hit the end of memory"); + if (sc_rover->owner) + *sc_rover->owner = NULL; + + new->size += sc_rover->size; + new->next = sc_rover->next; + } + +// create a fragment out of any leftovers + if (new->size - size > 256) + { + sc_rover = (surfcache_t *)( (qbyte *)new + size); + sc_rover->size = new->size - size; + sc_rover->next = new->next; + sc_rover->width = 0; + sc_rover->owner = NULL; + new->next = sc_rover; + new->size = size; + } + else + sc_rover = new->next; + + new->width = width; +// DEBUG + if (width > 0) + new->height = (size - sizeof(*new) + sizeof(new->data)) / (width*bpp); + + new->bytesperpix = bpp; + + new->owner = NULL; // should be set properly after return + + if (d_roverwrapped) + { + if (wrapped_this_time || (sc_rover >= d_initial_rover)) + r_cache_thrash = true; + } + else if (wrapped_this_time) + { + d_roverwrapped = true; + } + +D_CheckCacheGuard (); // DEBUG + return new; +} + + +/* +================= +D_SCDump +================= +*/ +void D_SCDump (void) +{ + surfcache_t *test; + + for (test = sc_base ; test ; test = test->next) + { + if (test == sc_rover) + Sys_Printf ("ROVER:\n"); + Sys_Printf ("%p : %i bytes %i width\n",test, test->size, test->width); + } +} + +//============================================================================= + +// if the num is not a power of 2, assume it will not repeat + +int MaskForNum (int num) +{ + if (num==128) + return 127; + if (num==64) + return 63; + if (num==32) + return 31; + if (num==16) + return 15; + return 255; +} + +int D_log2 (int num) +{ + int c; + + c = 0; + + while (num>>=1) + c++; + return c; +} + +//============================================================================= + +/* +================ +D_CacheSurface +================ +*/ +surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel) +{ + surfcache_t *cache; + int bpp; + +// +// if the surface is animating or flashing, flush the cache +// + r_drawsurf.texture = SWR_TextureAnimation (surface->texinfo->texture); + r_drawsurf.lightadj[0] = d_lightstylevalue[surface->styles[0]]; + r_drawsurf.lightadj[1] = d_lightstylevalue[surface->styles[1]]; + r_drawsurf.lightadj[2] = d_lightstylevalue[surface->styles[2]]; + r_drawsurf.lightadj[3] = d_lightstylevalue[surface->styles[3]]; + +// +// see if the cache holds apropriate data +// + cache = surface->cachespots[miplevel]; + + if (cache && !cache->dlight && surface->dlightframe != r_framecount + && cache->texture == r_drawsurf.texture && cache->fcache == r_flushcache //extra part added to flush caches over a group of frames on palette change... + && cache->lightadj[0] == r_drawsurf.lightadj[0] + && cache->lightadj[1] == r_drawsurf.lightadj[1] + && cache->lightadj[2] == r_drawsurf.lightadj[2] + && cache->lightadj[3] == r_drawsurf.lightadj[3] ) + return cache; + +// +// determine shape of surface +// + surfscale = 1.0 / (1<extents[0] >> miplevel; + r_drawsurf.rowbytes = r_drawsurf.surfwidth; + r_drawsurf.surfheight = surface->extents[1] >> miplevel; + + bpp = r_pixbytes; +// +// allocate memory if needed +// + if (!cache) // if a texture just animated, don't reallocate it + { + cache = D_SCAlloc (r_drawsurf.surfwidth, bpp, + r_drawsurf.surfwidth * r_drawsurf.surfheight * bpp); + surface->cachespots[miplevel] = cache; + cache->owner = &surface->cachespots[miplevel]; + cache->mipscale = surfscale; + } + + if (surface->dlightframe == r_framecount) + cache->dlight = 1; + else + cache->dlight = 0; + + cache->fcache = r_flushcache; + + r_drawsurf.surfdat = (pixel_t *)cache->data; + + cache->texture = r_drawsurf.texture; + cache->lightadj[0] = r_drawsurf.lightadj[0]; + cache->lightadj[1] = r_drawsurf.lightadj[1]; + cache->lightadj[2] = r_drawsurf.lightadj[2]; + cache->lightadj[3] = r_drawsurf.lightadj[3]; + +// +// draw and light the surface texture +// + r_drawsurf.surf = surface; + + c_surf++; + if (cache->bytesperpix==4 && r_usinglits) + R_DrawSurface32 (); + else + R_DrawSurface (); + + return surface->cachespots[miplevel]; +} + + diff --git a/engine/sw/d_trans.c b/engine/sw/d_trans.c new file mode 100644 index 000000000..c43afb11d --- /dev/null +++ b/engine/sw/d_trans.c @@ -0,0 +1,180 @@ +#include "quakedef.h" +#include "d_local.h" +#include "r_local.h" + +#ifdef PEXT_TRANS +int t_numtables; + +qbyte p1multitable[] = {1, 99, 49, 97, 48, 19, 47, 93, 23, 91, 9, 89, 22, 87, 43, 17, 21, 83, 41, 81, 4, 79, 39, 77, 19, 3, 37, 73, 18, 71, 7, 69, 17, 67, 33, 13, 16, 63, 31, 61, 3, 59, 29, 57, 14, 11, 27, 53, 13, 51, 1, 49, 12, 47, 23, 9, 11, 43, 21, 41, 2, 39, 19, 37, 9, 7, 17, 33, 8, 31, 3, 29, 7, 27, 13, 1, 6, 23, 11, 21, 1, 19, 9, 17, 4, 3, 7, 13, 3, 11, 1, 9, 2, 7, 3, 1, 1, 3, 1, 1, 0}; +qbyte p2multitable[] = {0, 1, 1, 3, 2, 1, 3, 7, 2, 9, 1, 11, 3, 13, 7, 3, 4, 17, 9, 19, 1, 21, 11, 23, 6, 1, 13, 27, 7, 29, 3, 31, 8, 33, 17, 7, 9, 37, 19, 39, 2, 41, 21, 43, 11, 9, 23, 47, 12, 49, 1, 51, 13, 53, 27, 11, 14, 57, 29, 59, 3, 61, 31, 63, 16, 13, 33, 67, 17, 69, 7, 71, 18, 73, 37, 3, 19, 77, 39, 79, 4, 81, 41, 83, 21, 17, 43, 87, 22, 89, 9, 91, 23, 93, 47, 19, 24, 97, 49, 99, 1}; +tlookup *t_lookup; +tlookupp *t_curlookupp; +int t_curtable; + +int t_numtables; +int t_numtablesinv;//numtables/65546 + +#define palette host_basepal +#define _abs(x) ((x)*(x)) + + +void R_CalcTransTable(int table, int level) +{ + FILE * f; + int p; + int p2; + int r, g, b, j; + int i; + unsigned char *pa; + int m; + int dif, curdif; + + qbyte p1multi; + qbyte p2multi; + qbyte pixdivide; + + p1multi = p1multitable[level]; + p2multi = p2multitable[level]; + + pixdivide = p1multi + p2multi; + + COM_FOpenFile (va("data/ttable%i.dat", (int) level) , &f); //we can ignore the filesize return value + if (f) + { + if (fread (t_lookup[table], 256, 256, f) == 256) + { + fclose(f); + return; + } + fclose(f); + } + + Con_Printf("Generating transtable %i%%\n", level); + + for (p = 0; p < 256; p++) + { + j = p*3; + for (p2 = 0; p2 < 256; p2++) + { + dif = 0x7fffffff; + m=0; + + i = p2*3; + r = (palette[j+0] * p1multi + palette[i+0] * p2multi) / pixdivide; + g = (palette[j+1] * p1multi + palette[i+1] * p2multi) / pixdivide; + b = (palette[j+2] * p1multi + palette[i+2] * p2multi) / pixdivide; + for (i = 0,pa=palette; i < 256-16; i++,pa+=3) + { + curdif = _abs(r - pa[0]) + _abs(g - pa[1]) + _abs(b - pa[2]); + if (curdif <= 0) //force 0 + { + m = i; + break; + } + if (curdif < dif) + { + dif = curdif; + m = i; + } + } + (t_lookup[table])[p][p2] = m; + } + } + + COM_CreatePath(va("%s/data/", com_gamedir)); +#if 1 + f = fopen (va("%s/data/ttable%i.dat", com_gamedir, (int) level), "wb"); + if (f) + { + if (fwrite (t_lookup[table], 256, 256, f) != 256) + { + Con_Printf("Couldn't write data to \"data/ttable%i.dat\"\n", (int) level); + fclose(f); + return; + } + fclose(f); + } + else + Con_Printf("Couldn't write data to \"data/ttable%i.dat\"\n", (int) level); +#else + COM_WriteFile(va("data/ttable%i.dat", (int)level, t_lookup[table], 256*256); +#endif +} + +void D_InitTrans(void) +{ + int i; + int table; + + if (t_lookup) + BZ_Free(t_lookup); +//no trans palette yet.. + Con_SafePrintf("Making/loading transparency lookup tables\nPlease wait...\n"); + +MakeVideoPalette(); + + if ((i = COM_CheckParm("-ttables")) != 0) + { + t_numtables = Q_atoi(com_argv[i+1]); + if (t_numtables < 1) + t_numtables = 1; + } + else + t_numtables = 5; + +t_numtablesinv = ((float)65536/t_numtables)+1;//65546/numtables + +t_curtable=0; +//t_lookup = Hunk_AllocName(sizeof(tlookup)*t_numtables, "Transtables"); +t_lookup = BZ_Malloc(sizeof(tlookup)*t_numtables); +t_curlookupp = t_lookup[t_curtable]; + + if (t_numtables == 1) + R_CalcTransTable(0, 50); + else if (t_numtables == 2) + { + R_CalcTransTable(0, 50); + R_CalcTransTable(1, 100); + } + else + { + for (table = 0; table < t_numtables; table++) + R_CalcTransTable(table, 100/((float)(t_numtables-1)/table)); + } + Con_Printf("Done\n"); +} + +#ifndef Trans +byte _fastcall Trans(byte p, byte p2) +{ + return t_curlookupp[p][p2]; + +} +#endif + +void Set_TransLevelI(int level) +{ + /* + 0 =0 + 12.5 =1 + 25 =2 + 37.5 =3 + 50 =4 + 62.5 =5 + 75 =6 + 87.5 =7 + 100 =8 + */ + t_curtable = level/(100.0f/(t_numtables-1)); + t_curlookupp = t_lookup[t_curtable]; +} +void Set_TransLevelF(float level) //MUST be between 0 and 1 +{ +// level+=1.0/(NUMTABLES-1); + if (level>1) + level = 1; + t_curtable = level*(t_numtables-1); + t_curlookupp = t_lookup[t_curtable]; +} + +#endif diff --git a/engine/sw/d_vars.c b/engine/sw/d_vars.c new file mode 100644 index 000000000..d9be56725 --- /dev/null +++ b/engine/sw/d_vars.c @@ -0,0 +1,51 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_vars.c: global refresh variables + +#if !id386 + +#include "quakedef.h" + +// all global and static refresh variables are collected in a contiguous block +// to avoid cache conflicts. + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: make into one big structure, like cl or sv +// FIXME: do separately for refresh engine and driver + +float d_sdivzstepu, d_tdivzstepu, d_zistepu; +float d_sdivzstepv, d_tdivzstepv, d_zistepv; +float d_sdivzorigin, d_tdivzorigin, d_ziorigin; + +fixed16_t sadjust, tadjust, bbextents, bbextentt; + +pixel_t *cacheblock; +int cachewidth; +int cacheheight; +pixel_t *d_viewbuffer; +short *d_pzbuffer; +unsigned int d_zrowbytes; +unsigned int d_zwidth; + +#endif // !id386 + diff --git a/engine/sw/d_varsa.s b/engine/sw/d_varsa.s new file mode 100644 index 000000000..537c6b42c --- /dev/null +++ b/engine/sw/d_varsa.s @@ -0,0 +1,213 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// d_varsa.s +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" +#include "d_ifacea.h" + +#if id386 + + .data + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: put all refresh variables into one contiguous block. Make into one +// big structure, like cl or sv? + + .align 4 +.globl C(d_sdivzstepu) +.globl C(d_tdivzstepu) +.globl C(d_zistepu) +.globl C(d_sdivzstepv) +.globl C(d_tdivzstepv) +.globl C(d_zistepv) +.globl C(d_sdivzorigin) +.globl C(d_tdivzorigin) +.globl C(d_ziorigin) +C(d_sdivzstepu): .single 0 +C(d_tdivzstepu): .single 0 +C(d_zistepu): .single 0 +C(d_sdivzstepv): .single 0 +C(d_tdivzstepv): .single 0 +C(d_zistepv): .single 0 +C(d_sdivzorigin): .single 0 +C(d_tdivzorigin): .single 0 +C(d_ziorigin): .single 0 + +.globl C(sadjust) +.globl C(tadjust) +.globl C(bbextents) +.globl C(bbextentt) +C(sadjust): .long 0 +C(tadjust): .long 0 +C(bbextents): .long 0 +C(bbextentt): .long 0 + +.globl C(cacheblock) +.globl C(d_viewbuffer) +.globl C(cachewidth) +.globl C(d_pzbuffer) +.globl C(d_zrowbytes) +.globl C(d_zwidth) +C(cacheblock): .long 0 +C(cachewidth): .long 0 +C(d_viewbuffer): .long 0 +C(d_pzbuffer): .long 0 +C(d_zrowbytes): .long 0 +C(d_zwidth): .long 0 + + +//------------------------------------------------------- +// ASM-only variables +//------------------------------------------------------- +.globl izi +izi: .long 0 + +.globl pbase, s, t, sfracf, tfracf, snext, tnext +.globl spancountminus1, zi16stepu, sdivz16stepu, tdivz16stepu +.globl zi8stepu, sdivz8stepu, tdivz8stepu, pz +s: .long 0 +t: .long 0 +snext: .long 0 +tnext: .long 0 +sfracf: .long 0 +tfracf: .long 0 +pbase: .long 0 +zi8stepu: .long 0 +sdivz8stepu: .long 0 +tdivz8stepu: .long 0 +zi16stepu: .long 0 +sdivz16stepu: .long 0 +tdivz16stepu: .long 0 +spancountminus1: .long 0 +pz: .long 0 + +.globl izistep +izistep: .long 0 + +//------------------------------------------------------- +// local variables for d_draw16.s +//------------------------------------------------------- + +.globl reciprocal_table_16, entryvec_table_16 +// 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, +// 1/14, and 1/15 in 0.32 form +reciprocal_table_16: .long 0x40000000, 0x2aaaaaaa, 0x20000000 + .long 0x19999999, 0x15555555, 0x12492492 + .long 0x10000000, 0xe38e38e, 0xccccccc, 0xba2e8ba + .long 0xaaaaaaa, 0x9d89d89, 0x9249249, 0x8888888 + +#ifndef NeXT + .extern Entry2_16 + .extern Entry3_16 + .extern Entry4_16 + .extern Entry5_16 + .extern Entry6_16 + .extern Entry7_16 + .extern Entry8_16 + .extern Entry9_16 + .extern Entry10_16 + .extern Entry11_16 + .extern Entry12_16 + .extern Entry13_16 + .extern Entry14_16 + .extern Entry15_16 + .extern Entry16_16 +#endif + +entryvec_table_16: .long 0, Entry2_16, Entry3_16, Entry4_16 + .long Entry5_16, Entry6_16, Entry7_16, Entry8_16 + .long Entry9_16, Entry10_16, Entry11_16, Entry12_16 + .long Entry13_16, Entry14_16, Entry15_16, Entry16_16 + +//------------------------------------------------------- +// local variables for d_parta.s +//------------------------------------------------------- +.globl DP_Count, DP_u, DP_v, DP_32768, DP_Color, DP_Pix, DP_EntryTable +DP_Count: .long 0 +DP_u: .long 0 +DP_v: .long 0 +DP_32768: .single 32768.0 +DP_Color: .long 0 +DP_Pix: .long 0 + + +#ifndef NeXT + .extern DP_1x1 + .extern DP_2x2 + .extern DP_3x3 + .extern DP_4x4 +#endif + +DP_EntryTable: .long DP_1x1, DP_2x2, DP_3x3, DP_4x4 + +// +// advancetable is 8 bytes, but points to the middle of that range so negative +// offsets will work +// +.globl advancetable, sstep, tstep, pspantemp, counttemp, jumptemp +advancetable: .long 0, 0 +sstep: .long 0 +tstep: .long 0 + +pspantemp: .long 0 +counttemp: .long 0 +jumptemp: .long 0 + +// 1/2, 1/3, 1/4, 1/5, 1/6, and 1/7 in 0.32 form +.globl reciprocal_table, entryvec_table +reciprocal_table: .long 0x40000000, 0x2aaaaaaa, 0x20000000 + .long 0x19999999, 0x15555555, 0x12492492 + +#ifndef NeXT + .extern Entry2_8 + .extern Entry3_8 + .extern Entry4_8 + .extern Entry5_8 + .extern Entry6_8 + .extern Entry7_8 + .extern Entry8_8 +#endif + +entryvec_table: .long 0, Entry2_8, Entry3_8, Entry4_8 + .long Entry5_8, Entry6_8, Entry7_8, Entry8_8 + +#ifndef NeXT + .extern Spr8Entry2_8 + .extern Spr8Entry3_8 + .extern Spr8Entry4_8 + .extern Spr8Entry5_8 + .extern Spr8Entry6_8 + .extern Spr8Entry7_8 + .extern Spr8Entry8_8 +#endif + +.globl spr8entryvec_table +spr8entryvec_table: .long 0, Spr8Entry2_8, Spr8Entry3_8, Spr8Entry4_8 + .long Spr8Entry5_8, Spr8Entry6_8, Spr8Entry7_8, Spr8Entry8_8 + +#endif // id386 + diff --git a/engine/sw/d_zpoint.c b/engine/sw/d_zpoint.c new file mode 100644 index 000000000..f7b8e5041 --- /dev/null +++ b/engine/sw/d_zpoint.c @@ -0,0 +1,53 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_zpoint.c: software driver module for drawing z-buffered points + +#include "quakedef.h" +#include "d_local.h" + + +/* +===================== +D_DrawZPoint +===================== +*/ +void D_DrawZPoint (void) +{ + qbyte *pdest; + short *pz; + int izi; + + pz = d_pzbuffer + (d_zwidth * r_zpointdesc.v) + r_zpointdesc.u; + pdest = d_viewbuffer + d_scantable[r_zpointdesc.v] + r_zpointdesc.u; + izi = (int)(r_zpointdesc.zi * 0x8000); + + if (*pz <= izi) + { + *pz = izi; + *pdest = r_zpointdesc.color; + } +} + + +void D_ClearDepth(void) +{ + memset(d_pzbuffer, 0, sizeof(*d_pzbuffer)*vid.width*vid.height); +} + diff --git a/engine/sw/nonintel.c b/engine/sw/nonintel.c new file mode 100644 index 000000000..9163ee525 --- /dev/null +++ b/engine/sw/nonintel.c @@ -0,0 +1,62 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// nonintel.c: code for non-Intel processors only +// + +#include "quakedef.h" + +#if !id386 + +/* +================ +R_Surf8Patch +================ +*/ +void R_Surf8Patch () +{ + // we only patch code on Intel +} + + +/* +================ +R_Surf16Patch +================ +*/ +void R_Surf16Patch () +{ + // we only patch code on Intel +} + + +/* +================ +R_SurfacePatch +================ +*/ +void R_SurfacePatch (void) +{ + // we only patch code on Intel +} + + +#endif // !id386 + diff --git a/engine/sw/r_aclip.c b/engine/sw/r_aclip.c new file mode 100644 index 000000000..1ecffbbe3 --- /dev/null +++ b/engine/sw/r_aclip.c @@ -0,0 +1,358 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_aclip.c: clip routines for drawing Alias models directly to the screen + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + +static finalvert_t fv[2][8]; +static mstvert_t fstv[2][8]; +static auxvert_t av[8]; + +void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av); +void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); +void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); +void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); +void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); + + +/* +================ +R_Alias_clip_z + +pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex +================ +*/ +void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + auxvert_t *pav0, *pav1, avout; + + pav0 = &av[pfv0 - &fv[0][0]]; + pav1 = &av[pfv1 - &fv[0][0]]; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) / + (pav1->fv[2] - pav0->fv[2]); + + avout.fv[0] = pav0->fv[0] + (pav1->fv[0] - pav0->fv[0]) * scale; + avout.fv[1] = pav0->fv[1] + (pav1->fv[1] - pav0->fv[1]) * scale; + avout.fv[2] = ALIAS_Z_CLIP_PLANE; + + out->v[2] = pfv0->v[2] + (pfv1->v[2] - pfv0->v[2]) * scale; + out->v[3] = pfv0->v[3] + (pfv1->v[3] - pfv0->v[3]) * scale; + out->v[4] = pfv0->v[4] + (pfv1->v[4] - pfv0->v[4]) * scale; + } + else + { + scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) / + (pav0->fv[2] - pav1->fv[2]); + + avout.fv[0] = pav1->fv[0] + (pav0->fv[0] - pav1->fv[0]) * scale; + avout.fv[1] = pav1->fv[1] + (pav0->fv[1] - pav1->fv[1]) * scale; + avout.fv[2] = ALIAS_Z_CLIP_PLANE; + + out->v[2] = pfv1->v[2] + (pfv0->v[2] - pfv1->v[2]) * scale; + out->v[3] = pfv1->v[3] + (pfv0->v[3] - pfv1->v[3]) * scale; + out->v[4] = pfv1->v[4] + (pfv0->v[4] - pfv1->v[4]) * scale; + } + + R_AliasProjectFinalVert (out, &avout); + + if (out->v[0] < r_refdef.aliasvrect.x) + out->flags |= ALIAS_LEFT_CLIP; + if (out->v[1] < r_refdef.aliasvrect.y) + out->flags |= ALIAS_TOP_CLIP; + if (out->v[0] > r_refdef.aliasvrectright) + out->flags |= ALIAS_RIGHT_CLIP; + if (out->v[1] > r_refdef.aliasvrectbottom) + out->flags |= ALIAS_BOTTOM_CLIP; +} + + +#if !id386 + +void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrect.x - pfv0->v[0]) / + (pfv1->v[0] - pfv0->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrect.x - pfv1->v[0]) / + (pfv0->v[0] - pfv1->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5; + } +} + + +void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrectright - pfv0->v[0]) / + (pfv1->v[0] - pfv0->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrectright - pfv1->v[0]) / + (pfv0->v[0] - pfv1->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5; + } +} + + +void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrect.y - pfv0->v[1]) / + (pfv1->v[1] - pfv0->v[1]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrect.y - pfv1->v[1]) / + (pfv0->v[1] - pfv1->v[1]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5; + } +} + + +void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrectbottom - pfv0->v[1]) / + (pfv1->v[1] - pfv0->v[1]); + + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrectbottom - pfv1->v[1]) / + (pfv0->v[1] - pfv1->v[1]); + + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5; + } +} + +#endif + + +int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count, + void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) ) +{ + int i,j,k; + int flags, oldflags; + + j = count-1; + k = 0; + for (i=0 ; i r_refdef.aliasvrectright) + out[k].flags |= ALIAS_RIGHT_CLIP; + if (out[k].v[1] > r_refdef.aliasvrectbottom) + out[k].flags |= ALIAS_BOTTOM_CLIP; + k++; + } + if (!flags) + { + out[k] = in[i]; + k++; + } + } + + return k; +} + + +/* +================ +R_AliasClipTriangle +================ +*/ +void R_AliasClipTriangle (mtriangle_t *ptri) +{ + int i, k, pingpong; + mtriangle_t mtri; + unsigned clipflags; + + mstvert_t *pst = r_affinetridesc.pstverts; + + +// copy vertexes and fix seam texture coordinates + fv[0][0] = pfinalverts[ptri->xyz_index[0]]; + fv[0][1] = pfinalverts[ptri->xyz_index[1]]; + fv[0][2] = pfinalverts[ptri->xyz_index[2]]; + + fv[0][0].v[2] = pst[ptri->st_index[0]].s; + fv[0][0].v[3] = pst[ptri->st_index[0]].t; + + fv[0][1].v[2] = pst[ptri->st_index[1]].s; + fv[0][1].v[3] = pst[ptri->st_index[1]].t; + + fv[0][2].v[2] = pst[ptri->st_index[2]].s; + fv[0][2].v[3] = pst[ptri->st_index[2]].t; + +// clip + clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags; + + if (clipflags & ALIAS_Z_CLIP) + { + for (i=0 ; i<3 ; i++) + av[i] = pauxverts[ptri->xyz_index[i]]; + + k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z); + if (k == 0) + return; + + pingpong = 1; + clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags; + } + else + { + pingpong = 0; + k = 3; + } + + if (clipflags & ALIAS_LEFT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_LEFT_CLIP, k, R_Alias_clip_left); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_RIGHT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_RIGHT_CLIP, k, R_Alias_clip_right); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_BOTTOM_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_TOP_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_TOP_CLIP, k, R_Alias_clip_top); + if (k == 0) + return; + + pingpong ^= 1; + } + + for (i=0 ; i r_refdef.aliasvrectright) + fv[pingpong][i].v[0] = r_refdef.aliasvrectright; + + if (fv[pingpong][i].v[1] < r_refdef.aliasvrect.y) + fv[pingpong][i].v[1] = r_refdef.aliasvrect.y; + else if (fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom) + fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom; + + fv[pingpong][i].flags = 0; + } + +// draw triangles + r_affinetridesc.ptriangles = &mtri; + r_affinetridesc.pfinalverts = fv[pingpong]; + r_affinetridesc.pstverts = fstv[pingpong]; + +// FIXME: do all at once as trifan? + mtri.xyz_index[0] = 0; + mtri.st_index[0] = 0; + + for (i=1 ; itrivial_accept = 0; + pmodel = currententity->model; + pahdr = SWMod_Extradata (pmodel); + pmdl = (mmdl_t *)((qbyte *)pahdr + pahdr->model); + + R_AliasSetUpTransform (0); + +// construct the base bounding box for this frame + nframe = currententity->frame; +// TODO: don't repeat this check when drawing? + if ((nframe >= pmdl->numframes) || (nframe < 0)) + { + Con_DPrintf ("No such frame %d %s\n", nframe, + pmodel->name); + nframe = 0; + } + +// construct the base bounding box for this frame + oframe = currententity->frame; +// TODO: don't repeat this check when drawing? + if ((oframe >= pmdl->numframes) || (oframe < 0)) + { + Con_DPrintf ("No such frame %d %s\n", oframe, + pmodel->name); + oframe = 0; + } + + pnewframedesc = &pahdr->frames[nframe]; + poldframedesc = &pahdr->frames[oframe]; + + for (i = 0; i < 3; i++) //choose the most outward of the two. + { + a = poldframedesc->scale_origin[i] + poldframedesc->bboxmin.v[i]*poldframedesc->scale[i]; + b = pnewframedesc->scale_origin[i] + pnewframedesc->bboxmin.v[i]*pnewframedesc->scale[i]; + min[i] = a>b?b:a; + + a = poldframedesc->scale_origin[i] + poldframedesc->bboxmax.v[i]*poldframedesc->scale[i]; + b = pnewframedesc->scale_origin[i] + pnewframedesc->bboxmax.v[i]*pnewframedesc->scale[i]; + max[i] = a>b?a:b; + } + + // x worldspace coordinates + basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] = min[0]; + basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] = max[0]; + + // y worldspace coordinates + basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] = min[1]; + basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] = max[1]; + + // z worldspace coordinates + basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] = min[2]; + basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] = max[2]; + + zclipped = false; + zfullyclipped = true; + + minz = 9999; + for (i=0; i<8 ; i++) + { + R_AliasTransformVector (&basepts[i][0], &viewaux[i].fv[0]); + + if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE) + { + // we must clip points that are closer than the near clip plane + viewpts[i].flags = ALIAS_Z_CLIP; + zclipped = true; + } + else + { + if (viewaux[i].fv[2] < minz) + minz = viewaux[i].fv[2]; + viewpts[i].flags = 0; + zfullyclipped = false; + } + } + + + if (zfullyclipped) + { + return false; // everything was near-z-clipped + } + + numv = 8; + + if (zclipped) + { + // organize points by edges, use edges to get new points (possible trivial + // reject) + for (i=0 ; i<12 ; i++) + { + // edge endpoints + pv0 = &viewpts[aedges[i].index0]; + pv1 = &viewpts[aedges[i].index1]; + pa0 = &viewaux[aedges[i].index0]; + pa1 = &viewaux[aedges[i].index1]; + + // if one end is clipped and the other isn't, make a new point + if (pv0->flags ^ pv1->flags) + { + frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) / + (pa1->fv[2] - pa0->fv[2]); + viewaux[numv].fv[0] = pa0->fv[0] + + (pa1->fv[0] - pa0->fv[0]) * frac; + viewaux[numv].fv[1] = pa0->fv[1] + + (pa1->fv[1] - pa0->fv[1]) * frac; + viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE; + viewpts[numv].flags = 0; + numv++; + } + } + } + +// project the vertices that remain after clipping + anyclip = 0; + allclip = ALIAS_XY_CLIP_MASK; + +// TODO: probably should do this loop in ASM, especially if we use floats + for (i=0 ; i r_refdef.fvrectright) + flags |= ALIAS_RIGHT_CLIP; + if (v1 > r_refdef.fvrectbottom) + flags |= ALIAS_BOTTOM_CLIP; + + anyclip |= flags; + allclip &= flags; + } + + if (allclip) + return false; // trivial reject off one side + +// currententity->trivial_accept = !anyclip & !zclipped; + + if (currententity->trivial_accept) + { + if (minz > (r_aliastransition + (pmdl->size * r_resfudge))) + { + // currententity->trivial_accept |= 2; + } + } + + return true; +} + +/* +================ +R_AliasTransformVector +================ +*/ +void R_AliasTransformVector (vec3_t in, vec3_t out) +{ + out[0] = DotProduct(in, aliastransform[0]) + aliastransform[0][3]; + out[1] = DotProduct(in, aliastransform[1]) + aliastransform[1][3]; + out[2] = DotProduct(in, aliastransform[2]) + aliastransform[2][3]; +} + + +/* +================ +R_AliasPreparePoints + +General clipped case +================ +*/ +void R_AliasPreparePoints (void) +{ + int i; + mstvert_t *pstverts; + finalvert_t *fv; + auxvert_t *av; + mtriangle_t *ptri; + finalvert_t *pfv[3]; + + r_anumverts = pmdl->numverts; + fv = pfinalverts; + av = pauxverts; + +#ifdef PEXT_TRANS + if (currententity->alpha != 1) + { + Set_TransLevelF(currententity->alpha); + } +#endif + + for (i=0 ; ifv[2] < ALIAS_Z_CLIP_PLANE) + fv->flags |= ALIAS_Z_CLIP; + else + { + R_AliasProjectFinalVert (fv, av); + + if (fv->v[0] < r_refdef.aliasvrect.x) + fv->flags |= ALIAS_LEFT_CLIP; + if (fv->v[1] < r_refdef.aliasvrect.y) + fv->flags |= ALIAS_TOP_CLIP; + if (fv->v[0] > r_refdef.aliasvrectright) + fv->flags |= ALIAS_RIGHT_CLIP; + if (fv->v[1] > r_refdef.aliasvrectbottom) + fv->flags |= ALIAS_BOTTOM_CLIP; + } + } + + pstverts = (mstvert_t *)((qbyte *)paliashdr + paliashdr->stverts); +// +// clip and draw all triangles +// + r_affinetridesc.numtriangles = 1; + + ptri = (mtriangle_t *)((qbyte *)paliashdr + paliashdr->triangles); + for (i=0 ; inumtris ; i++, ptri++) + { + pfv[0] = &pfinalverts[ptri->xyz_index[0]]; + pfv[1] = &pfinalverts[ptri->xyz_index[1]]; + pfv[2] = &pfinalverts[ptri->xyz_index[2]]; + + if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) + continue; // completely clipped + + pfv[0]->v[2] = pstverts[ptri->st_index[0]].s; + pfv[0]->v[3] = pstverts[ptri->st_index[0]].t; + + pfv[1]->v[2] = pstverts[ptri->st_index[1]].s; + pfv[1]->v[3] = pstverts[ptri->st_index[1]].t; + + pfv[2]->v[2] = pstverts[ptri->st_index[2]].s; + pfv[2]->v[3] = pstverts[ptri->st_index[2]].t; + + if ( ! ( (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) & + (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) ) + { // totally unclipped + r_affinetridesc.pfinalverts = pfinalverts; + r_affinetridesc.ptriangles = ptri; + if (r_pixbytes == 4) + D_PolysetDraw32 (); + else if (r_pixbytes == 2) + D_PolysetDraw16 (); + else + D_PolysetDraw (); + } + else + { // partially clipped + R_AliasClipTriangle (ptri); + } + } +} + + +/* +================ +R_AliasSetUpTransform +================ +*/ +void R_AliasSetUpTransform (int trivial_accept) +{ + int i; + float rotationmatrix[3][4], t2matrix[3][4]; + static float tmatrix[3][4]; + static float viewmatrix[3][4]; + vec3_t angles; + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity + + angles[ROLL] = currententity->angles[ROLL]; + angles[PITCH] = -currententity->angles[PITCH]; + angles[YAW] = currententity->angles[YAW]; + AngleVectors (angles, alias_forward, alias_right, alias_up); + + tmatrix[0][0] = currententity->scale; + tmatrix[1][1] = currententity->scale; + tmatrix[2][2] = currententity->scale; + + tmatrix[0][3] = 0; + tmatrix[1][3] = 0; + tmatrix[2][3] = 0; + +// TODO: can do this with simple matrix rearrangement + + for (i=0 ; i<3 ; i++) + { + t2matrix[i][0] = alias_forward[i]; + t2matrix[i][1] = -alias_right[i]; + t2matrix[i][2] = alias_up[i]; + } + + t2matrix[0][3] = -modelorg[0]; + t2matrix[1][3] = -modelorg[1]; + t2matrix[2][3] = -modelorg[2]; + +// FIXME: can do more efficiently than full concatenation + R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix); + +// TODO: should be global, set when vright, etc., set + VectorCopy (vright, viewmatrix[0]); + VectorCopy (vup, viewmatrix[1]); + VectorInverse (viewmatrix[1]); + VectorCopy (vpn, viewmatrix[2]); + +// viewmatrix[0][3] = 0; +// viewmatrix[1][3] = 0; +// viewmatrix[2][3] = 0; + + R_ConcatTransforms (viewmatrix, rotationmatrix, aliastransform); + +// do the scaling up of x and y to screen coordinates as part of the transform +// for the unclipped case (it would mess up clipping in the clipped case). +// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y +// correspondingly so the projected x and y come out right +// FIXME: make this work for clipped case too? + if (trivial_accept) + { + for (i=0 ; i<4 ; i++) + { + aliastransform[0][i] *= aliasxscale * + (1.0 / ((float)0x8000 * 0x10000)); + aliastransform[1][i] *= aliasyscale * + (1.0 / ((float)0x8000 * 0x10000)); + aliastransform[2][i] *= 1.0 / ((float)0x8000 * 0x10000); + + } + } +} + + +/* +================ +R_AliasTransformFinalVert +================ +*/ +void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av, + dtrivertx_t *pnewverts, dtrivertx_t *poldverts)//, mstvert_t *pstverts) +{ + int temp; + float lightcos, *plightnormal; + + vec3_t lerp_org; + + lerp_org[0] = r_amovelerp[0] + pnewverts->v[0]*r_afrntlerp[0] + poldverts->v[0]*r_abacklerp[0]; + lerp_org[1] = r_amovelerp[1] + pnewverts->v[1]*r_afrntlerp[1] + poldverts->v[1]*r_abacklerp[1]; + lerp_org[2] = r_amovelerp[2] + pnewverts->v[2]*r_afrntlerp[2] + poldverts->v[2]*r_abacklerp[2]; + + av->fv[0] = DotProduct(lerp_org, aliastransform[0]) + + aliastransform[0][3]; + av->fv[1] = DotProduct(lerp_org, aliastransform[1]) + + aliastransform[1][3]; + av->fv[2] = DotProduct(lerp_org, aliastransform[2]) + + aliastransform[2][3]; + + fv->v[2] = 0; + fv->v[3] = 0; + + fv->flags = 0; + +// lighting + plightnormal = r_avertexnormals[pnewverts->lightnormalindex]; + lightcos = DotProduct (plightnormal, r_plightvec); + temp = r_ambientlight; + + if (lightcos < 0) + { + temp += (int)(r_shadelight * lightcos); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->v[4] = temp; +} + + +#if 1 //!id386 since stvert_t was changed. + +/* +================ +R_AliasTransformAndProjectFinalVerts +================ +*/ +void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv)//, stvert_t *pstverts) +{ + int i, temp; + float lightcos, *plightnormal, zi; + dtrivertx_t *pnewverts, *poldverts; + + vec3_t lerp_org; + + pnewverts = r_apnewverts; + poldverts = r_apoldverts; + + for (i=0 ; iv[0]*r_afrntlerp[0] + poldverts->v[0]*r_abacklerp[0]; + lerp_org[1] = r_amovelerp[1] + pnewverts->v[1]*r_afrntlerp[1] + poldverts->v[1]*r_abacklerp[1]; + lerp_org[2] = r_amovelerp[2] + pnewverts->v[2]*r_afrntlerp[2] + poldverts->v[2]*r_abacklerp[2]; + + // transform and project + zi = 1.0 / (DotProduct(lerp_org, aliastransform[2]) + + aliastransform[2][3]); + + // x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is + // scaled up by 1/2**31, and the scaling cancels out for x and y in the + // projection + fv->v[5] = zi; + + fv->v[0] = ((DotProduct(lerp_org, aliastransform[0]) + + aliastransform[0][3]) * zi) + aliasxcenter; + fv->v[1] = ((DotProduct(lerp_org, aliastransform[1]) + + aliastransform[1][3]) * zi) + aliasycenter; + + fv->v[2] = 0;//pstverts->s; + fv->v[3] = 0;//pstverts->t; + fv->flags = 0; + + // lighting + plightnormal = r_avertexnormals[pnewverts->lightnormalindex]; //don't bother lerping light. + lightcos = DotProduct (plightnormal, r_plightvec); + temp = r_ambientlight; + + if (lightcos < 0) + { + temp += (int)(r_shadelight * lightcos); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->v[4] = temp; + } +} + +#endif + + +/* +================ +R_AliasProjectFinalVert +================ +*/ +void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av) +{ + float zi; + +// project points + zi = 1.0 / av->fv[2]; + + fv->v[5] = zi * ziscale; + + fv->v[0] = (av->fv[0] * aliasxscale * zi) + aliasxcenter; + fv->v[1] = (av->fv[1] * aliasyscale * zi) + aliasycenter; +} + + +/* +================ +R_AliasPrepareUnclippedPoints +================ +*/ +void R_AliasPrepareUnclippedPoints (void) +{ + finalvert_t *fv; + + r_anumverts = pmdl->numverts; +// FIXME: just use pfinalverts directly? + fv = pfinalverts; + + R_AliasTransformAndProjectFinalVerts (fv); + + if (r_affinetridesc.drawtype) + { + if (r_pixbytes == 4) + D_PolysetDrawFinalVerts32Trans (fv, r_anumverts); + else + D_PolysetDrawFinalVerts (fv, r_anumverts); + } + + r_affinetridesc.pfinalverts = pfinalverts; + r_affinetridesc.ptriangles = (mtriangle_t *) + ((qbyte *)paliashdr + paliashdr->triangles); + r_affinetridesc.numtriangles = pmdl->numtris; + + if (r_pixbytes == 4) + D_PolysetDraw32 (); + else + D_PolysetDraw (); +} + +/* +=============== +R_AliasSetupSkin +=============== +*/ +void R_AliasSetupSkin (void) +{ + int skinnum; + int i, numskins; + maliasskingroup_t *paliasskingroup; + float *pskinintervals, fullskininterval; + float skintargettime, skintime; + + skinnum = currententity->skinnum; + if ((skinnum >= pmdl->numskins) || (skinnum < 0)) + { + Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum); + skinnum = 0; + } + + pskindesc = ((maliasskindesc_t *) + ((qbyte *)paliashdr + paliashdr->skindesc)) + skinnum; + a_skinwidth = pmdl->skinwidth; + + if (pskindesc->type == ALIAS_SKIN_GROUP) + { + paliasskingroup = (maliasskingroup_t *)((qbyte *)paliashdr + + pskindesc->skin); + pskinintervals = (float *) + ((qbyte *)paliashdr + paliasskingroup->intervals); + numskins = paliasskingroup->numskins; + fullskininterval = pskinintervals[numskins-1]; + + skintime = cl.time + currententity->syncbase; + + // when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval + // values are positive, so we don't have to worry about division by 0 + skintargettime = skintime - + ((int)(skintime / fullskininterval)) * fullskininterval; + + for (i=0 ; i<(numskins-1) ; i++) + { + if (pskinintervals[i] > skintargettime) + break; + } + + pskindesc = &paliasskingroup->skindescs[i]; + } + + r_affinetridesc.pskindesc = pskindesc; + r_affinetridesc.pskin = (void *)((qbyte *)paliashdr + pskindesc->skin); + r_affinetridesc.skinwidth = a_skinwidth; + r_affinetridesc.skinheight = pmdl->skinheight; + + if (currententity->model != cl.model_precache[cl_playerindex]) + return; +//alternate player skins. + if (currententity->scoreboard && r_pixbytes == 1) + { + qbyte *base; + skin_t *skin; + + if (!currententity->scoreboard->skin) + Skin_Find (currententity->scoreboard); + base = Skin_Cache8 (currententity->scoreboard->skin); + skin = currententity->scoreboard->skin; + if (base && skin->cachedbpp == r_pixbytes*8) + { + r_affinetridesc.pskin = base; + r_affinetridesc.skinwidth = skin->width; + r_affinetridesc.skinheight = skin->height; + } + } + else if (currententity->scoreboard) + { + qbyte *base; + skin_t *skin; + + if (!currententity->scoreboard->skin) + Skin_Find (currententity->scoreboard); + base = Skin_Cache32 (currententity->scoreboard->skin); + skin = currententity->scoreboard->skin; + if (base && skin->cachedbpp == r_pixbytes*8) + { + r_affinetridesc.pskin = base; + r_affinetridesc.skinwidth = skin->width; + r_affinetridesc.skinheight = skin->height; + } + } +} + +/* +================ +R_AliasSetupLighting +================ +*/ +void R_AliasSetupLighting (alight_t *plighting) +{ + + if (r_pixbytes == 4) + { //fixes inverse lighting in sw 32. + //we fix it here so the lighting code doesn't have to have lots of extra minuses, as they are multiplied out + plighting->ambientlight=(128-plighting->ambientlight); + plighting->shadelight=(128-plighting->shadelight); + } + +// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have +// to clamp off the bottom + r_ambientlight = plighting->ambientlight; + + r_shadelight = plighting->shadelight; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + r_ambientlight = (255 - r_ambientlight) << VID_CBITS; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + if (r_shadelight < 0) + r_shadelight = 0; + + r_shadelight *= VID_GRADES; + +// rotate the lighting vector into the model's frame of reference + r_plightvec[0] = DotProduct (plighting->plightvec, alias_forward); + r_plightvec[1] = -DotProduct (plighting->plightvec, alias_right); + r_plightvec[2] = DotProduct (plighting->plightvec, alias_up); +} + +/* +================= +R_AliasSetupFrame + +set r_apverts +================= +*/ +void R_AliasSetupFrame (void) +{ + int frame, oframe; + int i, numframes; + maliasgroup_t *paliasgroup; + float *pintervals, fullinterval, targettime, time; + +// float *min1, *min2; +// vec3_t max1, max2; + float fl, bl; + + frame = currententity->frame; + if ((frame >= pmdl->numframes) || (frame < 0)) + { + Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); + frame = 0; + } + oframe = currententity->oldframe; + if ((oframe >= pmdl->numframes) || (oframe < 0)) + { +// Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", oframe); //pointless + oframe = 0; + } + + bl = currententity->lerptime; + fl = 1.0 - bl; + + for (i = 0; i < 3; i++) + { + r_abacklerp[i] = paliashdr->frames[oframe].scale[i]*bl; + r_afrntlerp[i] = paliashdr->frames[frame].scale[i]*fl; + r_amovelerp[i] = paliashdr->frames[frame].scale_origin[i]*fl + paliashdr->frames[oframe].scale_origin[i]*bl; + + } + + if (paliashdr->frames[frame].type == ALIAS_SINGLE) + { + r_apnewverts = (dtrivertx_t *) + ((qbyte *)paliashdr + paliashdr->frames[frame].frame); + } + else + { + paliasgroup = (maliasgroup_t *) + ((qbyte *)paliashdr + paliashdr->frames[frame].frame); + pintervals = (float *)((qbyte *)paliashdr + paliasgroup->intervals); + numframes = paliasgroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = cl.time + currententity->syncbase; + + // + // when loading in Mod_LoadAliasGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by 0 + // + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + r_apnewverts = (dtrivertx_t *) + ((qbyte *)paliashdr + paliasgroup->frames[i].frame); + } + + if (paliashdr->frames[oframe].type == ALIAS_SINGLE) //things could go haywire here... + { + r_apoldverts = (dtrivertx_t *) + ((qbyte *)paliashdr + paliashdr->frames[oframe].frame); + } + else + { + paliasgroup = (maliasgroup_t *) + ((qbyte *)paliashdr + paliashdr->frames[oframe].frame); + pintervals = (float *)((qbyte *)paliashdr + paliasgroup->intervals); + numframes = paliasgroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = cl.time + currententity->syncbase; + + // + // when loading in Mod_LoadAliasGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by 0 + // + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + r_apoldverts = (dtrivertx_t *) + ((qbyte *)paliashdr + paliasgroup->frames[i].frame); + } +} + + +/* +================ +R_AliasDrawModel +================ +*/ +void R_AliasDrawModel (alight_t *plighting) +{ + finalvert_t finalverts[MAXALIASVERTS + + ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1]; + auxvert_t auxverts[MAXALIASVERTS]; + + extern qbyte transfactor; + extern qbyte transbackfac; + + + r_amodels_drawn++; + +// cache align + pfinalverts = (finalvert_t *) + (((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + pauxverts = &auxverts[0]; + + paliashdr = (aliashdr_t *)SWMod_Extradata (currententity->model); + pmdl = (mmdl_t *)((qbyte *)paliashdr + paliashdr->model); + + R_AliasSetupSkin (); + R_AliasSetUpTransform (currententity->trivial_accept); + R_AliasSetupLighting (plighting); + R_AliasSetupFrame (); + + transfactor = currententity->alpha*255; + transbackfac = 255 - transfactor; + + if (!currententity->colormap) + currententity->colormap = vid.colormap; +// Sys_Error ("R_AliasDrawModel: !currententity->colormap"); + + r_affinetridesc.drawtype = (currententity->trivial_accept == 3) && + r_recursiveaffinetriangles; + + r_affinetridesc.pstverts = (mstvert_t *)((qbyte *)paliashdr + paliashdr->stverts); + + if (r_affinetridesc.drawtype) + { + D_PolysetUpdateTables (); // FIXME: precalc... + } + else + { +#if id386 + D_Aff8Patch (currententity->colormap); +#endif + } + + acolormap = currententity->colormap; + if (r_pixbytes == 2) + acolormap = vid.colormap16; + + if (currententity == &cl.viewent[r_refdef.currentplayernum] || currententity->flags & Q2RF_DEPTHHACK) + ziscale = (float)0x8000 * (float)0x10000 * 3.0; + else + ziscale = (float)0x8000 * (float)0x10000; + + if (currententity->trivial_accept) + R_AliasPrepareUnclippedPoints (); + else + R_AliasPreparePoints (); +} + diff --git a/engine/sw/r_aliasa.s b/engine/sw/r_aliasa.s new file mode 100644 index 000000000..34a2e1806 --- /dev/null +++ b/engine/sw/r_aliasa.s @@ -0,0 +1,247 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// r_aliasa.s +// x86 assembly-language Alias model transform and project code. +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" +#include "d_ifacea.h" + +//FIXME: rework the changes to stvert_t in. +#if 0//id386 + + .data + +Lfloat_1: .single 1.0 +Ltemp: .long 0 +Lcoords: .long 0, 0, 0 + + .text + +#define fv 12+4 +#if 0 +#define pstverts 12+8 +#endif + +.globl C(R_AliasTransformAndProjectFinalVerts) +C(R_AliasTransformAndProjectFinalVerts): +#if 0 + pushl %ebp // preserve caller's stack frame +#endif + pushl %edi + pushl %esi // preserve register variables + +// int i, temp; +// float lightcos, *plightnormal, zi; +// trivertx_t *pverts; + +// pverts = r_apverts; + movl C(r_apnewverts),%esi + +// for (i=0 ; iv, aliastransform[2]) + +// aliastransform[2][3]); + movb (%esi),%dl + movb %dl,Lcoords + fildl Lcoords // v[0] + movb 1(%esi),%dl + movb %dl,Lcoords+4 + fildl Lcoords+4 // v[1] | v[0] + movb 2(%esi),%dl + movb %dl,Lcoords+8 + fildl Lcoords+8 // v[2] | v[1] | v[0] + + fld %st(2) // v[0] | v[2] | v[1] | v[0] + fmuls C(aliastransform)+32 // accum | v[2] | v[1] | v[0] + fld %st(2) // v[1] | accum | v[2] | v[1] | v[0] + fmuls C(aliastransform)+36 // accum2 | accum | v[2] | v[1] | v[0] + fxch %st(1) // accum | accum2 | v[2] | v[1] | v[0] + fadds C(aliastransform)+44 // accum | accum2 | v[2] | v[1] | v[0] + fld %st(2) // v[2] | accum | accum2 | v[2] | v[1] | v[0] + fmuls C(aliastransform)+40 // accum3 | accum | accum2 | v[2] | v[1] | + // v[0] + fxch %st(1) // accum | accum3 | accum2 | v[2] | v[1] | v[0] + faddp %st(0),%st(2) // accum3 | accum | v[2] | v[1] | v[0] + movb tv_lightnormalindex(%esi),%dl + movl stv_s(%ebp),%eax + movl %eax,fv_v+8(%edi) + faddp %st(0),%st(1) // z | v[2] | v[1] | v[0] + + movl stv_t(%ebp),%eax + movl %eax,fv_v+12(%edi) + +// // lighting +// plightnormal = r_avertexnormals[pverts->lightnormalindex]; + + fdivrs Lfloat_1 // zi | v[2] | v[1] | v[0] + +#if 0 +// fv->v[2] = pstverts->s; +// fv->v[3] = pstverts->t; +// fv->flags = pstverts->onseam; + movl stv_onseam(%ebp),%eax + movl %eax,fv_flags(%edi) + + movl fv_size(%edi),%eax + movl stv_size(%ebp),%eax + movl 4(%esi),%eax + + leal (%edx,%edx,2),%eax // index*3 + + fxch %st(3) // v[0] | v[2] | v[1] | zi +#endif +// lightcos = DotProduct (plightnormal, r_plightvec); + flds C(r_avertexnormals)(,%eax,4) + fmuls C(r_plightvec) + flds C(r_avertexnormals)+4(,%eax,4) + fmuls C(r_plightvec)+4 + flds C(r_avertexnormals)+8(,%eax,4) + fmuls C(r_plightvec)+8 + fxch %st(1) + faddp %st(0),%st(2) + fld %st(2) // v[0] | laccum | laccum2 | v[0] | v[2] | + // v[1] | zi + fmuls C(aliastransform)+0 // xaccum | laccum | laccum2 | v[0] | v[2] | + // v[1] | zi + fxch %st(2) // laccum2 | laccum | xaccum | v[0] | v[2] | + // v[1] | zi + faddp %st(0),%st(1) // laccum | xaccum | v[0] | v[2] | v[1] | zi + +// temp = r_ambientlight; +// if (lightcos < 0) +// { + fsts Ltemp + movl C(r_ambientlight),%eax + movb Ltemp+3,%dl + testb $0x80,%dl + jz Lsavelight // no need to clamp if only ambient lit, because + // r_ambientlight is preclamped + +// temp += (int)(r_shadelight * lightcos); + fmuls C(r_shadelight) +// FIXME: fast float->int conversion? + fistpl Ltemp + addl Ltemp,%eax + +// // clamp; because we limited the minimum ambient and shading light, we +// // don't have to clamp low light, just bright +// if (temp < 0) +// temp = 0; + jns Lp1 + subl %eax,%eax + +// } + +Lp1: + +// fv->v[4] = temp; +// +// // x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is +// // scaled up by 1/2**31, and the scaling cancels out for x and y in the +// // projection +// fv->v[0] = ((DotProduct(pverts->v, aliastransform[0]) + +// aliastransform[0][3]) * zi) + aliasxcenter; +// fv->v[1] = ((DotProduct(pverts->v, aliastransform[1]) + +// aliastransform[1][3]) * zi) + aliasycenter; +// fv->v[5] = zi; + fxch %st(1) // v[0] | xaccum | v[2] | v[1] | zi + fmuls C(aliastransform)+16 // yaccum | xaccum | v[2] | v[1] | zi + fxch %st(3) // v[1] | xaccum | v[2] | yaccum | zi + fld %st(0) // v[1] | v[1] | xaccum | v[2] | yaccum | zi + fmuls C(aliastransform)+4 // xaccum2 | v[1] | xaccum | v[2] | yaccum |zi + fxch %st(1) // v[1] | xaccum2 | xaccum | v[2] | yaccum |zi + movl %eax,fv_v+16(%edi) + fmuls C(aliastransform)+20 // yaccum2 | xaccum2 | xaccum | v[2] | yaccum| + // zi + fxch %st(2) // xaccum | xaccum2 | yaccum2 | v[2] | yaccum| + // zi + fadds C(aliastransform)+12 // xaccum | xaccum2 | yaccum2 | v[2] | yaccum| + // zi + fxch %st(4) // yaccum | xaccum2 | yaccum2 | v[2] | xaccum| + // zi + fadds C(aliastransform)+28 // yaccum | xaccum2 | yaccum2 | v[2] | xaccum| + // zi + fxch %st(3) // v[2] | xaccum2 | yaccum2 | yaccum | xaccum| + // zi + fld %st(0) // v[2] | v[2] | xaccum2 | yaccum2 | yaccum | + // xaccum | zi + fmuls C(aliastransform)+8 // xaccum3 | v[2] | xaccum2 | yaccum2 |yaccum| + // xaccum | zi + fxch %st(1) // v[2] | xaccum3 | xaccum2 | yaccum2 |yaccum| + // xaccum | zi + fmuls C(aliastransform)+24 // yaccum3 | xaccum3 | xaccum2 | yaccum2 | + // yaccum | xaccum | zi + fxch %st(5) // xaccum | xaccum3 | xaccum2 | yaccum2 | + // yaccum | yaccum3 | zi + faddp %st(0),%st(2) // xaccum3 | xaccum | yaccum2 | yaccum | + // yaccum3 | zi + fxch %st(3) // yaccum | xaccum | yaccum2 | xaccum3 | + // yaccum3 | zi + faddp %st(0),%st(2) // xaccum | yaccum | xaccum3 | yaccum3 | zi + addl $(tv_size),%esi + faddp %st(0),%st(2) // yaccum | x | yaccum3 | zi + faddp %st(0),%st(2) // x | y | zi + addl $(stv_size),%ebp + fmul %st(2),%st(0) // x/z | y | zi + fxch %st(1) // y | x/z | zi + fmul %st(2),%st(0) // y/z | x/z | zi + fxch %st(1) // x/z | y/z | zi + fadds C(aliasxcenter) // u | y/z | zi + fxch %st(1) // y/z | u | zi + fadds C(aliasycenter) // v | u | zi + fxch %st(2) // zi | u | v +// FIXME: fast float->int conversion? + fistpl fv_v+20(%edi) // u | v + fistpl fv_v+0(%edi) // v + fistpl fv_v+4(%edi) + +// } + + addl $(fv_size),%edi + decl %ecx + jnz Lloop + + popl %esi // restore register variables + popl %edi +#if 0 +// popl %ebp // restore the caller's stack frame +#endif + ret + +Lsavelight: + fstp %st(0) + jmp Lp1 + +#endif // id386 + diff --git a/engine/sw/r_bsp.c b/engine/sw/r_bsp.c new file mode 100644 index 000000000..13c3e2082 --- /dev/null +++ b/engine/sw/r_bsp.c @@ -0,0 +1,907 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_bsp.c + +#include "quakedef.h" +#include "r_local.h" + +// +// current entity info +// +qboolean insubmodel; +entity_t *currententity; +vec3_t modelorg, base_modelorg; + // modelorg is the viewpoint reletive to + // the currently rendering entity +vec3_t r_entorigin; // the currently rendering entity in world + // coordinates + +float entity_rotation[3][3]; + +vec3_t r_worldmodelorg; + +int r_currentbkey; + +typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t; + +#define MAX_BMODEL_VERTS 500 // 6K +#define MAX_BMODEL_EDGES 1000 // 12K + +static mvertex_t *pbverts; +static bedge_t *pbedges; +static int numbverts, numbedges; + +static mvertex_t *pfrontenter, *pfrontexit; + +static qboolean makeclippededge; + + +//=========================================================================== + +/* +================ +R_EntityRotate +================ +*/ +void R_EntityRotate (vec3_t vec) +{ + vec3_t tvec; + + VectorCopy (vec, tvec); + vec[0] = DotProduct (entity_rotation[0], tvec); + vec[1] = DotProduct (entity_rotation[1], tvec); + vec[2] = DotProduct (entity_rotation[2], tvec); +} + + +/* +================ +R_RotateBmodel +================ +*/ +void R_RotateBmodel (void) +{ + float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3]; + +// TODO: should use a look-up table +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: could cache lazily, stored in the entity +// TODO: share work with R_SetUpAliasTransform + +// yaw + angle = currententity->angles[YAW]; + angle = angle * M_PI*2 / 360; + s = sin(angle); + c = cos(angle); + + temp1[0][0] = c; + temp1[0][1] = s; + temp1[0][2] = 0; + temp1[1][0] = -s; + temp1[1][1] = c; + temp1[1][2] = 0; + temp1[2][0] = 0; + temp1[2][1] = 0; + temp1[2][2] = 1; + + +// pitch + angle = currententity->angles[PITCH]; + angle = angle * M_PI*2 / 360; + s = sin(angle); + c = cos(angle); + + temp2[0][0] = c; + temp2[0][1] = 0; + temp2[0][2] = -s; + temp2[1][0] = 0; + temp2[1][1] = 1; + temp2[1][2] = 0; + temp2[2][0] = s; + temp2[2][1] = 0; + temp2[2][2] = c; + + R_ConcatRotations (temp2, temp1, temp3); + +// roll + angle = currententity->angles[ROLL]; + angle = angle * M_PI*2 / 360; + s = sin(angle); + c = cos(angle); + + temp1[0][0] = 1; + temp1[0][1] = 0; + temp1[0][2] = 0; + temp1[1][0] = 0; + temp1[1][1] = c; + temp1[1][2] = s; + temp1[2][0] = 0; + temp1[2][1] = -s; + temp1[2][2] = c; + + R_ConcatRotations (temp1, temp3, entity_rotation); + +// +// rotate modelorg and the transformation matrix +// + R_EntityRotate (modelorg); + R_EntityRotate (vpn); + R_EntityRotate (vright); + R_EntityRotate (vup); + + R_TransformFrustum (); +} + + +/* +================ +R_RecursiveClipBPoly +================ +*/ +void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) +{ + bedge_t *psideedges[2], *pnextedge, *ptedge; + int i, side, lastside; + float dist, frac, lastdist; + mplane_t *splitplane, tplane; + mvertex_t *pvert, *plastvert, *ptvert; + mnode_t *pn; + + psideedges[0] = psideedges[1] = NULL; + + makeclippededge = false; + +// transform the BSP plane into model space +// FIXME: cache these? + splitplane = pnode->plane; + if (!splitplane) + return; + tplane.dist = splitplane->dist - + DotProduct(r_entorigin, splitplane->normal); + tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal); + tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal); + tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal); + +// clip edges to BSP plane + for ( ; pedges ; pedges = pnextedge) + { + pnextedge = pedges->pnext; + + // set the status for the last point as the previous point + // FIXME: cache this stuff somehow? + plastvert = pedges->v[0]; + lastdist = DotProduct (plastvert->position, tplane.normal) - + tplane.dist; + + if (lastdist > 0) + lastside = 0; + else + lastside = 1; + + pvert = pedges->v[1]; + + dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; + + if (dist > 0) + side = 0; + else + side = 1; + + if (side != lastside) + { + // clipped + if (numbverts >= MAX_BMODEL_VERTS) + return; + + // generate the clipped vertex + frac = lastdist / (lastdist - dist); + ptvert = &pbverts[numbverts++]; + ptvert->position[0] = plastvert->position[0] + + frac * (pvert->position[0] - + plastvert->position[0]); + ptvert->position[1] = plastvert->position[1] + + frac * (pvert->position[1] - + plastvert->position[1]); + ptvert->position[2] = plastvert->position[2] + + frac * (pvert->position[2] - + plastvert->position[2]); + + // split into two edges, one on each side, and remember entering + // and exiting points + // FIXME: share the clip edge by having a winding direction flag? + if (numbedges >= (MAX_BMODEL_EDGES - 1)) + { + Con_Printf ("Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[lastside]; + psideedges[lastside] = ptedge; + ptedge->v[0] = plastvert; + ptedge->v[1] = ptvert; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[side]; + psideedges[side] = ptedge; + ptedge->v[0] = ptvert; + ptedge->v[1] = pvert; + + numbedges += 2; + + if (side == 0) + { + // entering for front, exiting for back + pfrontenter = ptvert; + makeclippededge = true; + } + else + { + pfrontexit = ptvert; + makeclippededge = true; + } + } + else + { + // add the edge to the appropriate side + pedges->pnext = psideedges[side]; + psideedges[side] = pedges; + } + } + +// if anything was clipped, reconstitute and add the edges along the clip +// plane to both sides (but in opposite directions) + if (makeclippededge) + { + if (numbedges >= (MAX_BMODEL_EDGES - 2)) + { + Con_Printf ("Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[0]; + psideedges[0] = ptedge; + ptedge->v[0] = pfrontexit; + ptedge->v[1] = pfrontenter; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[1]; + psideedges[1] = ptedge; + ptedge->v[0] = pfrontenter; + ptedge->v[1] = pfrontexit; + + numbedges += 2; + } + +// draw or recurse further + for (i=0 ; i<2 ; i++) + { + if (psideedges[i]) + { + // draw if we've reached a non-solid leaf, done if all that's left is a + // solid leaf, and continue down the tree if it's not a leaf + pn = pnode->children[i]; + + // we're done with this branch if the node or leaf isn't in the PVS + if (pn->visframe == r_visframecount) + { + if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) + { + if (pn->contents != -1) + { + if (pn->contents != Q2CONTENTS_SOLID) + { + r_currentbkey = ((mleaf_t *)pn)->key; + R_RenderBmodelFace (psideedges[i], psurf); + } + } + else + { + R_RecursiveClipBPoly (psideedges[i], pnode->children[i], + psurf); + } + } + else + { + if (pn->contents < 0) + { + if (pn->contents != Q1CONTENTS_SOLID) + { + r_currentbkey = ((mleaf_t *)pn)->key; + R_RenderBmodelFace (psideedges[i], psurf); + } + } + else + { + R_RecursiveClipBPoly (psideedges[i], pnode->children[i], + psurf); + } + } + } + } + } +} + + +/* +================ +R_DrawSolidClippedSubmodelPolygons +================ +*/ +void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) +{ + int i, j, lindex; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + mvertex_t bverts[MAX_BMODEL_VERTS]; + bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; + medge_t *pedge, *pedges; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + pedges = pmodel->edges; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + // FIXME: use bounding-box-based frustum clipping info? + + // copy the edges to bedges, flipping if necessary so always + // clockwise winding + // FIXME: if edges and vertices get caches, these assignments must move + // outside the loop, and overflow checking must be done here + pbverts = bverts; + pbedges = bedges; + numbverts = numbedges = 0; + + if (psurf->numedges > 0) + { + pbedge = &bedges[numbedges]; + numbedges += psurf->numedges; + + for (j=0 ; jnumedges ; j++) + { + lindex = pmodel->surfedges[psurf->firstedge+j]; + + if (lindex > 0) + { + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]]; + } + else + { + lindex = -lindex; + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]]; + } + + pbedge[j].pnext = &pbedge[j+1]; + } + + pbedge[j-1].pnext = NULL; // mark end of edges + + R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf); + } + else + { + Sys_Error ("no edges in bmodel"); + } + } + } +} + + +/* +================ +R_DrawSubmodelPolygons +================ +*/ +void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) +{ + int i; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // 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; + + // FIXME: use bounding-box-based frustum clipping info? + R_RenderFace (psurf, clipflags); + } + } +} + + +/* +================ +R_RecursiveWorldNode +================ +*/ +void SWR_RecursiveWorldNode (mnode_t *node, int clipflags) +{ + int i, c, side, *pindex; + vec3_t acceptpt, rejectpt; + mplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + double d, dot; + + if (node->contents == Q1CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + +// cull the clipping planes if not trivial accept +// FIXME: the compiler is doing a lousy job of optimizing here; it could be +// twice as fast in ASM + if (clipflags) + { + for (i=0 ; i<4 ; i++) + { + if (! (clipflags & (1<minmaxs[pindex[0]]; + rejectpt[1] = (float)node->minmaxs[pindex[1]]; + rejectpt[2] = (float)node->minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + return; + + acceptpt[0] = (float)node->minmaxs[pindex[3+0]]; + acceptpt[1] = (float)node->minmaxs[pindex[3+1]]; + acceptpt[2] = (float)node->minmaxs[pindex[3+2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d >= 0) + clipflags &= ~(1<contents < 0) + { + pleaf = (mleaf_t *)node; + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + + // deal with model fragments in this leaf + if (pleaf->efrags) + { + R_StoreEfrags (&pleaf->efrags); + } + + pleaf->key = r_currentkey; + r_currentkey++; // all bmodels in a leaf share the same key + } + else + { + // node is just a decision point, so go down the apropriate sides + + // find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + side = 0; + else + side = 1; + + // recurse down the children, front side first + SWR_RecursiveWorldNode (node->children[side], clipflags); + + // draw stuff + c = node->numsurfaces; + + if (c) + { + surf = cl.worldmodel->surfaces + node->firstsurface; + + if (dot < -BACKFACE_EPSILON) + { + do + { + if ((surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + { + if (r_drawpolys) + { + if (r_worldpolysbacktofront) + { + if (numbtofpolys < MAX_BTOFPOLYS) + { + pbtofpolys[numbtofpolys].clipflags = + clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } + else + { + R_RenderPoly (surf, clipflags); + } + } + else + { + R_RenderFace (surf, clipflags); + } + } + + surf++; + } while (--c); + } + else if (dot > BACKFACE_EPSILON) + { + do + { + if (!(surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + { + if (r_drawpolys) + { + if (r_worldpolysbacktofront) + { + if (numbtofpolys < MAX_BTOFPOLYS) + { + pbtofpolys[numbtofpolys].clipflags = + clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } + else + { + R_RenderPoly (surf, clipflags); + } + } + else + { + R_RenderFace (surf, clipflags); + } + } + + surf++; + } while (--c); + } + + // all surfaces on the same node share the same sequence number + r_currentkey++; + } + + // recurse down the back side + SWR_RecursiveWorldNode (node->children[!side], clipflags); + } +} + +qbyte areabits[MAX_Q2MAP_AREAS/8]; +void SWR_RecursiveQ2WorldNode (mnode_t *node, int clipflags) +{ + int i, c, side, *pindex; + vec3_t acceptpt, rejectpt; + mplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + double d, dot; + + if (node->contents == Q2CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + +// cull the clipping planes if not trivial accept +// FIXME: the compiler is doing a lousy job of optimizing here; it could be +// twice as fast in ASM + if (clipflags) + { + for (i=0 ; i<4 ; i++) + { + if (! (clipflags & (1<minmaxs[pindex[0]]; + rejectpt[1] = (float)node->minmaxs[pindex[1]]; + rejectpt[2] = (float)node->minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + return; + + acceptpt[0] = (float)node->minmaxs[pindex[3+0]]; + acceptpt[1] = (float)node->minmaxs[pindex[3+1]]; + acceptpt[2] = (float)node->minmaxs[pindex[3+2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d >= 0) + clipflags &= ~(1<contents != -1) + { + pleaf = (mleaf_t *)node; + + // check for door connected areas +// if (areabits) +// { + if (! (areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) + return; // not visible +// } + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + + pleaf->key = r_currentkey; + r_currentkey++; // all bmodels in a leaf share the same key + } + else + { + // node is just a decision point, so go down the apropriate sides + + // find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + side = 0; + else + side = 1; + + // recurse down the children, front side first + SWR_RecursiveQ2WorldNode (node->children[side], clipflags); + + // draw stuff + c = node->numsurfaces; + + if (c) + { + surf = cl.worldmodel->surfaces + node->firstsurface; + + if (dot < -BACKFACE_EPSILON) + { + do + { + if ((surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + { + if (r_drawpolys) + { + if (r_worldpolysbacktofront) + { + if (numbtofpolys < MAX_BTOFPOLYS) + { + pbtofpolys[numbtofpolys].clipflags = + clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } + else + { + R_RenderPoly (surf, clipflags); + } + } + else + { + R_RenderFace (surf, clipflags); + } + } + + surf++; + } while (--c); + } + else if (dot > BACKFACE_EPSILON) + { + do + { + if (!(surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + { + if (r_drawpolys) + { + if (r_worldpolysbacktofront) + { + if (numbtofpolys < MAX_BTOFPOLYS) + { + pbtofpolys[numbtofpolys].clipflags = + clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } + else + { + R_RenderPoly (surf, clipflags); + } + } + else + { + R_RenderFace (surf, clipflags); + } + } + + surf++; + } while (--c); + } + + // all surfaces on the same node share the same sequence number + r_currentkey++; + } + + // recurse down the back side + SWR_RecursiveQ2WorldNode (node->children[!side], clipflags); + } +} + + +/* +================ +R_RenderWorld +================ +*/ +void R_RenderWorld (void) +{ + int i; + model_t *clmodel; + btofpoly_t btofpolys[MAX_BTOFPOLYS]; + + pbtofpolys = btofpolys; + + currententity = &r_worldentity; + VectorCopy (r_origin, modelorg); + clmodel = currententity->model; + r_pcurrentvertbase = clmodel->vertexes; + + if (clmodel->fromgame == fg_quake2) + { + int leafnum; + int clientarea; + int CM_WriteAreaBits (qbyte *buffer, int area); + if (cls.q2server) + memcpy(areabits, cl.q2frame.areabits, sizeof(areabits)); + else + { + leafnum = CM_PointLeafnum (r_refdef.vieworg); + clientarea = CM_LeafArea (leafnum); + CM_WriteAreaBits(areabits, clientarea); + } + + SWR_RecursiveQ2WorldNode (clmodel->nodes, 15); + } + else + SWR_RecursiveWorldNode (clmodel->nodes, 15); + +// if the driver wants the polygons back to front, play the visible ones back +// in that order + + if (r_worldpolysbacktofront) + { + for (i=numbtofpolys-1 ; i>=0 ; i--) + { + R_RenderPoly (btofpolys[i].psurf, btofpolys[i].clipflags); + } + } +} + + diff --git a/engine/sw/r_draw.c b/engine/sw/r_draw.c new file mode 100644 index 000000000..a8d29fbee --- /dev/null +++ b/engine/sw/r_draw.c @@ -0,0 +1,2696 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// r_draw.c + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" // FIXME: shouldn't need to include this + +#define MAXLEFTCLIPEDGES 100 + +// !!! if these are changed, they must be changed in asm_draw.h too !!! +#define FULLY_CLIPPED_CACHED 0x80000000 +#define FRAMECOUNT_MASK 0x7FFFFFFF + +unsigned int cacheoffset; + +int c_faceclip; // number of faces clipped + +zpointdesc_t r_zpointdesc; + +polydesc_t r_polydesc; + + + +clipplane_t *entity_clipplanes; +clipplane_t view_clipplanes[4]; +clipplane_t world_clipplanes[16]; + +medge_t *r_pedge; + +qboolean r_leftclipped, r_rightclipped; +static qboolean makeleftedge, makerightedge; +qboolean r_nearzionly; + +int sintable[SINTABLESIZE]; +int intsintable[SINTABLESIZE]; + +mvertex_t r_leftenter, r_leftexit; +mvertex_t r_rightenter, r_rightexit; + +typedef struct +{ + float u,v; + int ceilv; +} evert_t; + +int r_emitted; +float r_nearzi; +float r_u1, r_v1, r_lzi1; +int r_ceilv1; + +qboolean r_lastvertvalid; + +msurface_t *r_alpha_surfaces; + + + + + + +int r_skyframe; + +msurface_t *r_skyfaces; +mplane_t r_skyplanes[6]; +mtexinfo_t r_skytexinfo[6]; +mvertex_t *r_skyverts; +medge_t *r_skyedges; +int *r_skysurfedges; + +// I just copied this code from q2... +int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128}; + +int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11, + 12,-3,-11,-8, -12,-10,-5,-4}; +int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4}; + +int box_faces[6] = {0,0,2,2,2,0}; + +vec3_t box_vecs[6][2] = { + { {0,-1,0}, {-1,0,0} }, + { {0,1,0}, {0,0,-1} }, + { {0,-1,0}, {1,0,0} }, + { {1,0,0}, {0,0,-1} }, + { {0,-1,0}, {0,0,-1} }, + { {-1,0,0}, {0,0,-1} } +}; + +float box_verts[8][3] = { + {-1,-1,-1}, + {-1,1,-1}, + {1,1,-1}, + {1,-1,-1}, + {-1,-1,1}, + {-1,1,1}, + {1,-1,1}, + {1,1,1} +}; + +// down, west, up, north, east, south +// {"rt", "bk", "lf", "ft", "up", "dn"}; +static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; +int r_skysideimage[6] = {5, 2, 4, 1, 0, 3}; +extern mtexinfo_t r_skytexinfo[6]; + +char skyname[128]; +void SWR_SetSky (char *name, float rotate, vec3_t axis) +{ + int i; + + Q_strncpyz (skyname, name, sizeof(skyname)); +// skyrotate = rotate; +// VectorCopy (axis, skyaxis); + + for (i=0 ; i<6 ; i++) + { + r_skytexinfo[i].texture = NULL; + } +} + +qboolean SWR_CheckSky (void) +{ + int i; + char pathname[MAX_QPATH]; + + if (!*skyname) + return true; + for (i=0 ; i<6 ; i++) + { + sprintf (pathname, "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]); + if (COM_FCheckExists(pathname)) + { + continue;// it exists, don't bother going for a tga version + } + + sprintf (pathname, "env/%s%s.tga", skyname, suf[r_skysideimage[i]]); + if (!CL_CheckOrDownloadFile(pathname, -1)) + return false; + } + return true; +} + +/* +================ +R_InitSkyBox + +================ +*/ +void *Mod_LoadWall(char *name); +void R_InitSkyBox (void) +{ + int i; + model_t *wm; + char pathname[MAX_QPATH]; + + wm = cl.worldmodel; + + r_skyfaces = wm->surfaces + wm->numsurfaces; + wm->numsurfaces += 6; + r_skyverts = wm->vertexes + wm->numvertexes; + wm->numvertexes += 8; + r_skyedges = wm->edges + wm->numedges; + wm->numedges += 12; + r_skysurfedges = wm->surfedges + wm->numsurfedges; + wm->numsurfedges += 24; + if (wm->numsurfaces > MAX_MAP_FACES + || wm->numvertexes > MAX_MAP_VERTS + || wm->numedges > MAX_MAP_EDGES) + Host_Error ("InitSkyBox: map overflow"); + + memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces)); + for (i=0 ; i<6 ; i++) + { + r_skyplanes[i].normal[skybox_planes[i*2]] = 1; + r_skyplanes[i].dist = skybox_planes[i*2+1]; + + VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]); + VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]); + + r_skyfaces[i].plane = &r_skyplanes[i]; + r_skyfaces[i].numedges = 4; + r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX; + r_skyfaces[i].firstedge = wm->numsurfedges-24+i*4; + r_skyfaces[i].texinfo = &r_skytexinfo[i]; + r_skyfaces[i].texturemins[0] = -128; + r_skyfaces[i].texturemins[1] = -128; + r_skyfaces[i].extents[0] = 256; + r_skyfaces[i].extents[1] = 256; + } + + for (i=0 ; i<24 ; i++) + if (box_surfedges[i] > 0) + r_skysurfedges[i] = wm->numedges-13 + box_surfedges[i]; + else + r_skysurfedges[i] = - (wm->numedges-13 + -box_surfedges[i]); + + for(i=0 ; i<12 ; i++) + { + r_skyedges[i].v[0] = wm->numvertexes-9+box_edges[i*2+0]; + r_skyedges[i].v[1] = wm->numvertexes-9+box_edges[i*2+1]; + r_skyedges[i].cachededgeoffset = 0; + } + + + for (i=0 ; i<6 ; i++) + { + sprintf (pathname, "env/%s%s.tga", skyname, suf[r_skysideimage[i]]); + r_skytexinfo[i].texture = Mod_LoadWall (pathname); //preferable + if (!r_skytexinfo[i].texture) + { + sprintf (pathname, "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]); + r_skytexinfo[i].texture = Mod_LoadWall (pathname); //q2 fall back + } + } +} + +/* +================ +R_EmitSkyBox +================ +*/ +qboolean R_EmitSkyBox (void) +{ + int i, j; + int oldkey; + + if (insubmodel) + return false; // submodels should never have skies + if (r_skyframe == r_framecount) + return true; // already set this frame + + if (!*skyname) //none set + return false; + + r_skyframe = r_framecount; + + // set the eight fake vertexes + for (i=0 ; i<8 ; i++) + for (j=0 ; j<3 ; j++) + r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128; + + // set the six fake planes + for (i=0 ; i<6 ; i++) + if (skybox_planes[i*2+1] > 0) + r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128; + else + r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128; + + // fix texture offseets + for (i=0 ; i<6 ; i++) + { + r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]); + r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]); + } + + // emit the six faces + oldkey = r_currentkey; + r_currentkey = 0x7ffffff0; + for (i=0 ; i<6 ; i++) + { + R_RenderFace (r_skyfaces + i, 15); + } + r_currentkey = oldkey; // bsp sorting order + + return true; +} + + + + +#if !id386 + +/* +================ +R_EmitEdge +================ +*/ +void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1) +{ + edge_t *edge, *pcheck; + int u_check; + float u, u_step; + vec3_t local, transformed; + float *world; + int v, v2, ceilv0; + float scale, lzi0, u0, v0; + int side; + + if (r_lastvertvalid) + { + u0 = r_u1; + v0 = r_v1; + lzi0 = r_lzi1; + ceilv0 = r_ceilv1; + } + else + { + world = &pv0->position[0]; + + // transform and project + VectorSubtract (world, modelorg, local); + TransformVector (local, transformed); + + if (transformed[2] < NEAR_CLIP) + transformed[2] = NEAR_CLIP; + + lzi0 = 1.0 / transformed[2]; + + // FIXME: build x/yscale into transform? + scale = xscale * lzi0; + u0 = (xcenter + scale*transformed[0]); + if (u0 < r_refdef.fvrectx_adj) + u0 = r_refdef.fvrectx_adj; + if (u0 > r_refdef.fvrectright_adj) + u0 = r_refdef.fvrectright_adj; + + scale = yscale * lzi0; + v0 = (ycenter - scale*transformed[1]); + if (v0 < r_refdef.fvrecty_adj) + v0 = r_refdef.fvrecty_adj; + if (v0 > r_refdef.fvrectbottom_adj) + v0 = r_refdef.fvrectbottom_adj; + + ceilv0 = (int) ceil(v0); + } + + world = &pv1->position[0]; + +// transform and project + VectorSubtract (world, modelorg, local); + TransformVector (local, transformed); + + if (transformed[2] < NEAR_CLIP) + transformed[2] = NEAR_CLIP; + + r_lzi1 = 1.0 / transformed[2]; + + scale = xscale * r_lzi1; + r_u1 = (xcenter + scale*transformed[0]); + if (r_u1 < r_refdef.fvrectx_adj) + r_u1 = r_refdef.fvrectx_adj; + if (r_u1 > r_refdef.fvrectright_adj) + r_u1 = r_refdef.fvrectright_adj; + + scale = yscale * r_lzi1; + r_v1 = (ycenter - scale*transformed[1]); + if (r_v1 < r_refdef.fvrecty_adj) + r_v1 = r_refdef.fvrecty_adj; + if (r_v1 > r_refdef.fvrectbottom_adj) + r_v1 = r_refdef.fvrectbottom_adj; + + if (r_lzi1 > lzi0) + lzi0 = r_lzi1; + + if (lzi0 > r_nearzi) // for mipmap finding + r_nearzi = lzi0; + +// for right edges, all we want is the effect on 1/z + if (r_nearzionly) + return; + + r_emitted = 1; + + r_ceilv1 = (int) ceil(r_v1); + + +// create the edge + if (ceilv0 == r_ceilv1) + { + // we cache unclipped horizontal edges as fully clipped + if (cacheoffset != 0x7FFFFFFF) + { + cacheoffset = FULLY_CLIPPED_CACHED | + (r_framecount & FRAMECOUNT_MASK); + } + + return; // horizontal edge + } + + side = ceilv0 > r_ceilv1; + + edge = edge_p++; + + edge->owner = r_pedge; + + edge->nearzi = lzi0; + + if (side == 0) + { + // trailing edge (go from p1 to p2) + v = ceilv0; + v2 = r_ceilv1 - 1; + + edge->surfs[0] = surface_p - surfaces; + edge->surfs[1] = 0; + + u_step = ((r_u1 - u0) / (r_v1 - v0)); + u = u0 + ((float)v - v0) * u_step; + } + else + { + // leading edge (go from p2 to p1) + v2 = ceilv0 - 1; + v = r_ceilv1; + + edge->surfs[0] = 0; + edge->surfs[1] = surface_p - surfaces; + + u_step = ((u0 - r_u1) / (v0 - r_v1)); + u = r_u1 + ((float)v - r_v1) * u_step; + } + + edge->u_step = u_step*0x100000; + edge->u = u*0x100000 + 0xFFFFF; + +// we need to do this to avoid stepping off the edges if a very nearly +// horizontal edge is less than epsilon above a scan, and numeric error causes +// it to incorrectly extend to the scan, and the extension of the line goes off +// the edge of the screen +// FIXME: is this actually needed? + if (edge->u < r_refdef.vrect_x_adj_shift20) + edge->u = r_refdef.vrect_x_adj_shift20; + if (edge->u > r_refdef.vrectright_adj_shift20) + edge->u = r_refdef.vrectright_adj_shift20; + +// +// sort the edge in normally +// + u_check = edge->u; + if (edge->surfs[0]) + u_check++; // sort trailers after leaders + + if (!newedges[v] || newedges[v]->u >= u_check) + { + edge->next = newedges[v]; + newedges[v] = edge; + } + else + { + pcheck = newedges[v]; + while (pcheck->next && pcheck->next->u < u_check) + pcheck = pcheck->next; + edge->next = pcheck->next; + pcheck->next = edge; + } + + edge->nextremove = removeedges[v2]; + removeedges[v2] = edge; +} + + +/* +================ +R_ClipEdge +================ +*/ +void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip) +{ + float d0, d1, f; + mvertex_t clipvert; + + if (clip) + { + do + { + d0 = DotProduct (pv0->position, clip->normal) - clip->dist; + d1 = DotProduct (pv1->position, clip->normal) - clip->dist; + + if (d0 >= 0) + { + // point 0 is unclipped + if (d1 >= 0) + { + // both points are unclipped + continue; + } + + // only point 1 is clipped + + // we don't cache clipped edges + cacheoffset = 0x7FFFFFFF; + + f = d0 / (d0 - d1); + clipvert.position[0] = pv0->position[0] + + f * (pv1->position[0] - pv0->position[0]); + clipvert.position[1] = pv0->position[1] + + f * (pv1->position[1] - pv0->position[1]); + clipvert.position[2] = pv0->position[2] + + f * (pv1->position[2] - pv0->position[2]); + + if (clip->leftedge) + { + r_leftclipped = true; + r_leftexit = clipvert; + } + else if (clip->rightedge) + { + r_rightclipped = true; + r_rightexit = clipvert; + } + + R_ClipEdge (pv0, &clipvert, clip->next); + return; + } + else + { + // point 0 is clipped + if (d1 < 0) + { + // both points are clipped + // we do cache fully clipped edges + if (!r_leftclipped) + cacheoffset = FULLY_CLIPPED_CACHED | + (r_framecount & FRAMECOUNT_MASK); + return; + } + + // only point 0 is clipped + r_lastvertvalid = false; + + // we don't cache partially clipped edges + cacheoffset = 0x7FFFFFFF; + + f = d0 / (d0 - d1); + clipvert.position[0] = pv0->position[0] + + f * (pv1->position[0] - pv0->position[0]); + clipvert.position[1] = pv0->position[1] + + f * (pv1->position[1] - pv0->position[1]); + clipvert.position[2] = pv0->position[2] + + f * (pv1->position[2] - pv0->position[2]); + + if (clip->leftedge) + { + r_leftclipped = true; + r_leftenter = clipvert; + } + else if (clip->rightedge) + { + r_rightclipped = true; + r_rightenter = clipvert; + } + + R_ClipEdge (&clipvert, pv1, clip->next); + return; + } + } while ((clip = clip->next) != NULL); + } + +// add the edge + R_EmitEdge (pv0, pv1); +} + +#endif // !id386 + + +/* +================ +R_EmitCachedEdge +================ +*/ +void R_EmitCachedEdge (void) +{ + edge_t *pedge_t; + + pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset); + + if (!pedge_t->surfs[0]) + pedge_t->surfs[0] = surface_p - surfaces; + else + pedge_t->surfs[1] = surface_p - surfaces; + + if (pedge_t->nearzi > r_nearzi) // for mipmap finding + r_nearzi = pedge_t->nearzi; + + r_emitted = 1; +} + + +/* +================ +R_RenderFace +================ +*/ +void R_RenderFace (msurface_t *fa, int clipflags) +{ + int i, lindex; + unsigned mask; + mplane_t *pplane; + float distinv; + vec3_t p_normal; + medge_t *pedges, tedge; + clipplane_t *pclip; + + if (fa->texinfo->texture && (*fa->texinfo->texture->name == '{' || fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))) + { + if (fa->nextalphasurface) + return; + + fa->nextalphasurface = r_alpha_surfaces; + r_alpha_surfaces = fa; + return; + } + + if ( fa->texinfo->flags & SURF_SKY) + { + if (R_EmitSkyBox ()) + return; + } + +// skip out if no more surfs + if ((surface_p) >= surf_max) + { + r_outofsurfaces++; + return; + } + +// ditto if not enough edges left, or switch to auxedges if possible + if ((edge_p + fa->numedges + 4) >= edge_max) + { + r_outofedges += fa->numedges; + return; + } + + c_faceclip++; + +// set up clip planes + pclip = NULL; + + for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) + { + if (clipflags & mask) + { + view_clipplanes[i].next = pclip; + pclip = &view_clipplanes[i]; + } + } + + +// push the edges through + r_emitted = 0; + r_nearzi = 0; + r_nearzionly = false; + makeleftedge = makerightedge = false; + pedges = currententity->model->edges; + r_lastvertvalid = false; + + for (i=0 ; inumedges ; i++) + { + lindex = currententity->model->surfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + + // if the edge is cached, we can just reuse the edge + if (!insubmodel) + { + if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) + { + if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == + r_framecount) + { + r_lastvertvalid = false; + continue; + } + } + else + { + if ((((unsigned long)edge_p - (unsigned long)r_edges) > + r_pedge->cachededgeoffset) && + (((edge_t *)((unsigned long)r_edges + + r_pedge->cachededgeoffset))->owner == r_pedge)) + { + R_EmitCachedEdge (); + r_lastvertvalid = false; + continue; + } + } + } + + // assume it's cacheable + cacheoffset = (qbyte *)edge_p - (qbyte *)r_edges; + r_leftclipped = r_rightclipped = false; + R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]], + &r_pcurrentvertbase[r_pedge->v[1]], + pclip); + r_pedge->cachededgeoffset = cacheoffset; + + if (r_leftclipped) + makeleftedge = true; + if (r_rightclipped) + makerightedge = true; + r_lastvertvalid = true; + } + else + { + lindex = -lindex; + r_pedge = &pedges[lindex]; + // if the edge is cached, we can just reuse the edge + if (!insubmodel) + { + if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) + { + if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == + r_framecount) + { + r_lastvertvalid = false; + continue; + } + } + else + { + // it's cached if the cached edge is valid and is owned + // by this medge_t + if ((((unsigned long)edge_p - (unsigned long)r_edges) > + r_pedge->cachededgeoffset) && + (((edge_t *)((unsigned long)r_edges + + r_pedge->cachededgeoffset))->owner == r_pedge)) + { + R_EmitCachedEdge (); + r_lastvertvalid = false; + continue; + } + } + } + + // assume it's cacheable + cacheoffset = (qbyte *)edge_p - (qbyte *)r_edges; + r_leftclipped = r_rightclipped = false; + R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]], + &r_pcurrentvertbase[r_pedge->v[0]], + pclip); + r_pedge->cachededgeoffset = cacheoffset; + + if (r_leftclipped) + makeleftedge = true; + if (r_rightclipped) + makerightedge = true; + r_lastvertvalid = true; + } + } + +// if there was a clip off the left edge, add that edge too +// FIXME: faster to do in screen space? +// FIXME: share clipped edges? + if (makeleftedge) + { + r_pedge = &tedge; + r_lastvertvalid = false; + R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next); + } + +// if there was a clip off the right edge, get the right r_nearzi + if (makerightedge) + { + r_pedge = &tedge; + r_lastvertvalid = false; + r_nearzionly = true; + R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); + } + +// if no edges made it out, return without posting the surface + if (!r_emitted) + return; + + r_polycount++; + + surface_p->data = (void *)fa; + surface_p->nearzi = r_nearzi; + surface_p->flags = fa->flags; + surface_p->insubmodel = insubmodel; + surface_p->spanstate = 0; + surface_p->entity = currententity; + surface_p->key = r_currentkey++; + surface_p->spans = NULL; + + pplane = fa->plane; +// FIXME: cache this? + TransformVector (pplane->normal, p_normal); +// FIXME: cache this? + distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal)); + + surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; + surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; + surface_p->d_ziorigin = p_normal[2] * distinv - + xcenter * surface_p->d_zistepu - + ycenter * surface_p->d_zistepv; + +//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg); + surface_p++; +} + + +/* +================ +R_RenderBmodelFace +================ +*/ +void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf) +{ + int i; + unsigned mask; + mplane_t *pplane; + float distinv; + vec3_t p_normal; + medge_t tedge; + clipplane_t *pclip; + +// skip out if no more surfs + if (surface_p >= surf_max) + { + r_outofsurfaces++; + return; + } + + if (*psurf->texinfo->texture->name == '{' || psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) + { + if (psurf->nextalphasurface) + return; + + psurf->nextalphasurface = r_alpha_surfaces; + r_alpha_surfaces = psurf; + return; + } + +// ditto if not enough edges left, or switch to auxedges if possible + if ((edge_p + psurf->numedges + 4) >= edge_max) + { + r_outofedges += psurf->numedges; + return; + } + + c_faceclip++; + +// this is a dummy to give the caching mechanism someplace to write to + r_pedge = &tedge; + +// set up clip planes + pclip = NULL; + + for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) + { + if (r_clipflags & mask) + { + view_clipplanes[i].next = pclip; + pclip = &view_clipplanes[i]; + } + } + +// push the edges through + r_emitted = 0; + r_nearzi = 0; + r_nearzionly = false; + makeleftedge = makerightedge = false; +// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching +// can be used? + r_lastvertvalid = false; + + for ( ; pedges ; pedges = pedges->pnext) + { + r_leftclipped = r_rightclipped = false; + R_ClipEdge (pedges->v[0], pedges->v[1], pclip); + + if (r_leftclipped) + makeleftedge = true; + if (r_rightclipped) + makerightedge = true; + } + +// if there was a clip off the left edge, add that edge too +// FIXME: faster to do in screen space? +// FIXME: share clipped edges? + if (makeleftedge) + { + r_pedge = &tedge; + R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next); + } + +// if there was a clip off the right edge, get the right r_nearzi + if (makerightedge) + { + r_pedge = &tedge; + r_nearzionly = true; + R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); + } + +// if no edges made it out, return without posting the surface + if (!r_emitted) + return; + + r_polycount++; + + surface_p->data = (void *)psurf; + surface_p->nearzi = r_nearzi; + surface_p->flags = psurf->flags; + surface_p->insubmodel = true; + surface_p->spanstate = 0; + surface_p->entity = currententity; + surface_p->key = r_currentbkey; + surface_p->spans = NULL; + + pplane = psurf->plane; +// FIXME: cache this? + TransformVector (pplane->normal, p_normal); +// FIXME: cache this? + distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal)); + + surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; + surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; + surface_p->d_ziorigin = p_normal[2] * distinv - + xcenter * surface_p->d_zistepu - + ycenter * surface_p->d_zistepv; + +//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg); + surface_p++; +} + + +/* +================ +R_RenderPoly +================ +*/ +void R_RenderPoly (msurface_t *fa, int clipflags) +{ + int i, lindex, lnumverts, s_axis, t_axis; + float dist, lastdist, lzi, scale, u, v, frac; + unsigned mask; + vec3_t local, transformed; + clipplane_t *pclip; + medge_t *pedges; + mplane_t *pplane; + mvertex_t verts[2][100]; //FIXME: do real number + polyvert_t pverts[100]; //FIXME: do real number, safely + int vertpage, newverts, newpage, lastvert; + qboolean visible; + +// FIXME: clean this up and make it faster +// FIXME: guard against running out of vertices + + s_axis = t_axis = 0; // keep compiler happy + +// set up clip planes + pclip = NULL; + + for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) + { + if (clipflags & mask) + { + view_clipplanes[i].next = pclip; + pclip = &view_clipplanes[i]; + } + } + +// reconstruct the polygon +// FIXME: these should be precalculated and loaded off disk + pedges = currententity->model->edges; + lnumverts = fa->numedges; + vertpage = 0; + + for (i=0 ; imodel->surfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]]; + } + else + { + r_pedge = &pedges[-lindex]; + verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]]; + } + } + +// clip the polygon, done if not visible + while (pclip) + { + lastvert = lnumverts - 1; + lastdist = DotProduct (verts[vertpage][lastvert].position, + pclip->normal) - pclip->dist; + + visible = false; + newverts = 0; + newpage = vertpage ^ 1; + + for (i=0 ; inormal) - + pclip->dist; + + if ((lastdist > 0) != (dist > 0)) + { + frac = dist / (dist - lastdist); + verts[newpage][newverts].position[0] = + verts[vertpage][i].position[0] + + ((verts[vertpage][lastvert].position[0] - + verts[vertpage][i].position[0]) * frac); + verts[newpage][newverts].position[1] = + verts[vertpage][i].position[1] + + ((verts[vertpage][lastvert].position[1] - + verts[vertpage][i].position[1]) * frac); + verts[newpage][newverts].position[2] = + verts[vertpage][i].position[2] + + ((verts[vertpage][lastvert].position[2] - + verts[vertpage][i].position[2]) * frac); + newverts++; + } + + if (dist >= 0) + { + verts[newpage][newverts] = verts[vertpage][i]; + newverts++; + visible = true; + } + + lastvert = i; + lastdist = dist; + } + + if (!visible || (newverts < 3)) + return; + + lnumverts = newverts; + vertpage ^= 1; + pclip = pclip->next; + } + +// transform and project, remembering the z values at the vertices and +// r_nearzi, and extract the s and t coordinates at the vertices + pplane = fa->plane; + switch (pplane->type) + { + case PLANE_X: + case PLANE_ANYX: + s_axis = 1; + t_axis = 2; + break; + case PLANE_Y: + case PLANE_ANYY: + s_axis = 0; + t_axis = 2; + break; + case PLANE_Z: + case PLANE_ANYZ: + s_axis = 0; + t_axis = 1; + break; + } + + r_nearzi = 0; + + for (i=0 ; i r_nearzi) // for mipmap finding + r_nearzi = lzi; + + // FIXME: build x/yscale into transform? + scale = xscale * lzi; + u = (xcenter + scale*transformed[0]); + if (u < r_refdef.fvrectx_adj) + u = r_refdef.fvrectx_adj; + if (u > r_refdef.fvrectright_adj) + u = r_refdef.fvrectright_adj; + + scale = yscale * lzi; + v = (ycenter - scale*transformed[1]); + if (v < r_refdef.fvrecty_adj) + v = r_refdef.fvrecty_adj; + if (v > r_refdef.fvrectbottom_adj) + v = r_refdef.fvrectbottom_adj; + + pverts[i].u = u; + pverts[i].v = v; + pverts[i].zi = lzi; + pverts[i].s = verts[vertpage][i].position[s_axis]; + pverts[i].t = verts[vertpage][i].position[t_axis]; + } + +// build the polygon descriptor, including fa, r_nearzi, and u, v, s, t, and z +// for each vertex + r_polydesc.numverts = lnumverts; + r_polydesc.nearzi = r_nearzi; + r_polydesc.pcurrentface = fa; + r_polydesc.pverts = pverts; + +// draw the polygon + D_DrawPoly (); +} + + +/* +================ +R_ZDrawSubmodelPolys +================ +*/ +void R_ZDrawSubmodelPolys (model_t *pmodel) +{ + int i, numsurfaces; + msurface_t *psurf; + float dot; + mplane_t *pplane; + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + // FIXME: use bounding-box-based frustum clipping info? + R_RenderPoly (psurf, 15); + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + +//this code from Quake2 + +typedef struct +{ + int nump; + emitpoint_t *pverts; + qbyte *pixels; // image + int pixel_width; // image width + int pixel_height; // image height + vec3_t vup, vright, vpn; // in worldspace, for plane eq + float dist; + float s_offset, t_offset; + float viewer_position[3]; + void (*drawspanlet)( void ); + int stipple_parity; + int alpha; +} q2polydesc_t; + +q2polydesc_t r_q2polydesc; +static espan_t *s_polygon_spans; +static int clip_current; +static int s_minindex, s_maxindex; +vec5_t r_clip_verts[2][MAXWORKINGVERTS+2]; + + + +model_t *currentmodel; + +#define AFFINE_SPANLET_SIZE 16 +#define AFFINE_SPANLET_SIZE_BITS 4 + +typedef struct +{ + qbyte *pbase, *pdest; + short *pz; + fixed16_t s, t; + fixed16_t sstep, tstep; + int izi, izistep, izistep_times_2; + int spancount; + unsigned u, v; +} spanletvars_t; + +spanletvars_t s_spanletvars; + +void R_DrawSpanletTurbulentStipple33( void ) +{ + extern int *r_turb_turb; + unsigned btemp; + int sturb, tturb; + qbyte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( s_spanletvars.v & 1 ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( s_spanletvars.u & 1 ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } +} + +/* +** R_DrawSpanletTurbulentStipple66 +*/ +void R_DrawSpanletTurbulentStipple66( void ) +{ + extern int *r_turb_turb; + unsigned btemp; + int sturb, tturb; + qbyte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( !( s_spanletvars.v & 1 ) ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( s_spanletvars.u & 1 ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } + else + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + + s_spanletvars.spancount--; + } + } +} + +/* +** R_DrawSpanletTurbulentBlended +*/ +/*void R_DrawSpanletTurbulentBlended66( void ) +{ + extern int *r_turb_turb; + unsigned btemp; + int sturb, tturb; + + do + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) ) + *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest]; + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + } while ( --s_spanletvars.spancount > 0 ); +} + +void R_DrawSpanletTurbulentBlended33( void ) +{ + unsigned btemp; + int sturb, tturb; + + do + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) ) + *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256]; + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + } while ( --s_spanletvars.spancount > 0 ); +} +*/ +/* +** R_DrawSpanlet33 +*/ +/*void R_DrawSpanlet33( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256]; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +void R_DrawSpanletConstant33( void ) +{ + do + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256]; + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + } while (--s_spanletvars.spancount > 0); +} +*/ +/* +** R_DrawSpanlet66 +*/ +/* +void R_DrawSpanlet66( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest]; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} +*/ + +void R_DrawSpanletConstant( void ) +{ + do + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = 15;//r_polyblendcolor; + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + } while (--s_spanletvars.spancount > 0); +} +/* +** R_DrawSpanlet33Stipple +*/ +void R_DrawSpanlet33Stipple( void ) +{ + unsigned btemp; + qbyte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } +} +void R_16DrawSpanlet33Stipple( void ) +{ + unsigned btemp; + unsigned short *pdest = (unsigned short *)s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } +} + +void R_8DrawSpanletAlphaTest( void ) //8 bit rendering only +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = btemp; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +void R_16DrawSpanletAlphaTest( void ) //16 bit rendering only +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = btemp; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +void R_8DrawSpanletBlended( void ) //8 bit FIXME +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + +// if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = t_lookup[1][btemp][*s_spanletvars.pdest]; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +void R_32DrawSpanletAlphaTest( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *((int *)s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp &0xff000000 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *(int*)s_spanletvars.pdest = btemp; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest+=4; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} +void R_32DrawSpanletBlended( void ) +{ + unsigned *btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = ((unsigned int *)s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( ((qbyte *)btemp)[3] ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + ((qbyte *)s_spanletvars.pdest)[0] = (((qbyte *)s_spanletvars.pdest)[0]*(255-r_q2polydesc.alpha) + ((qbyte *)btemp)[2]*r_q2polydesc.alpha)/255; + ((qbyte *)s_spanletvars.pdest)[1] = (((qbyte *)s_spanletvars.pdest)[1]*(255-r_q2polydesc.alpha) + ((qbyte *)btemp)[1]*r_q2polydesc.alpha)/255; + ((qbyte *)s_spanletvars.pdest)[2] = (((qbyte *)s_spanletvars.pdest)[2]*(255-r_q2polydesc.alpha) + ((qbyte *)btemp)[0]*r_q2polydesc.alpha)/255; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest+=4; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +void R_32DrawSpanletTurbulentBlended( void ) +{ + extern int *r_turb_turb; + unsigned *btemp; + int sturb, tturb; + do + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = ( (int *)s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) ) + { + ((qbyte *)s_spanletvars.pdest)[0] = (((qbyte *)s_spanletvars.pdest)[0]*(255-r_q2polydesc.alpha) + ((qbyte *)btemp)[2]*r_q2polydesc.alpha)/255; + ((qbyte *)s_spanletvars.pdest)[1] = (((qbyte *)s_spanletvars.pdest)[1]*(255-r_q2polydesc.alpha) + ((qbyte *)btemp)[1]*r_q2polydesc.alpha)/255; + ((qbyte *)s_spanletvars.pdest)[2] = (((qbyte *)s_spanletvars.pdest)[2]*(255-r_q2polydesc.alpha) + ((qbyte *)btemp)[0]*r_q2polydesc.alpha)/255; + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest+=4; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + } while ( --s_spanletvars.spancount > 0 ); +} + +/* +** R_DrawSpanlet66Stipple +*/ +void R_DrawSpanlet66Stipple( void ) +{ + unsigned btemp; + qbyte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } + else + { + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + + s_spanletvars.spancount--; + } + } +} + +void R_16DrawSpanlet66Stipple( void ) +{ + unsigned btemp; + unsigned short *pdest = (unsigned short *)s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + s_spanletvars.pdest += s_spanletvars.spancount<<1; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + if ( r_q2polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = vid.colormap16[*( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) )]; + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } + else + { + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = s+t;//vid.colormap16[*( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) )]; + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + + s_spanletvars.spancount--; + } + } +} + +/* +** R_PolygonDrawSpans +*/ +// PGM - iswater was qboolean. changed to allow passing more flags +void R_PolygonDrawSpans(espan_t *pspan, int iswater ) +{ + extern int *r_turb_turb; + int count; + fixed16_t snext, tnext; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivzspanletstepu, tdivzspanletstepu, zispanletstepu; + + s_spanletvars.pbase = cacheblock; + +//PGM +// if ( iswater & SURF_WARP) + r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); +// else if (iswater & SURF_FLOWING) +// r_turb_turb = blanktable; +//PGM + + sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE; + tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE; + zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE; + +// we count on FP exceptions being turned off to avoid range problems + s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000); + s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2; + + s_spanletvars.pz = 0; + + do + { + s_spanletvars.pdest = (qbyte *)d_viewbuffer + r_pixbytes*( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/ + pspan->u); + s_spanletvars.pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + s_spanletvars.u = pspan->u; + s_spanletvars.v = pspan->v; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000); + + s_spanletvars.s = (int)(sdivz * z) + sadjust; + s_spanletvars.t = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (s_spanletvars.s > bbextents) + s_spanletvars.s = bbextents; + else if (s_spanletvars.s < 0) + s_spanletvars.s = 0; + + if (s_spanletvars.t > bbextentt) + s_spanletvars.t = bbextentt; + else if (s_spanletvars.t < 0) + s_spanletvars.t = 0; + } + + do + { + // calculate s and t at the far end of the span + if (count >= AFFINE_SPANLET_SIZE ) + s_spanletvars.spancount = AFFINE_SPANLET_SIZE; + else + s_spanletvars.spancount = count; + + count -= s_spanletvars.spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivzspanletstepu; + tdivz += tdivzspanletstepu; + zi += zispanletstepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + tnext = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (snext > bbextents) + snext = bbextents; + else if (snext < AFFINE_SPANLET_SIZE) + snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < AFFINE_SPANLET_SIZE) + tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps + } + + s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS; + s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(s_spanletvars.spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + tnext = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (snext > bbextents) + snext = bbextents; + else if (snext < AFFINE_SPANLET_SIZE) + snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < AFFINE_SPANLET_SIZE) + tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps + } + + if (s_spanletvars.spancount > 1) + { + s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1); + s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1); + } + } + + if ( iswater ) + { + s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1); + s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1); + } + + r_q2polydesc.drawspanlet(); + + s_spanletvars.s = snext; + s_spanletvars.t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} + +/* +** +** R_PolygonScanLeftEdge +** +** Goes through the polygon and scans the left edge, filling in +** screen coordinate data for the spans +*/ +void R_PolygonScanLeftEdge (void) +{ + int i, v, itop, ibottom, lmaxindex; + emitpoint_t *pvert, *pnext; + espan_t *pspan; + float du, dv, vtop, vbottom, slope; + fixed16_t u, u_step; + + pspan = s_polygon_spans; + i = s_minindex; + if (i == 0) + i = r_q2polydesc.nump; + + lmaxindex = s_maxindex; + if (lmaxindex == 0) + lmaxindex = r_q2polydesc.nump; + + vtop = ceil (r_q2polydesc.pverts[i].v); + + do + { + pvert = &r_q2polydesc.pverts[i]; + pnext = pvert - 1; + + vbottom = ceil (pnext->v); + + if (vtop < vbottom) + { + du = pnext->u - pvert->u; + dv = pnext->v - pvert->v; + + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vu = u >> 16; + pspan->v = v; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + + i--; + if (i == 0) + i = r_q2polydesc.nump; + + } while (i != lmaxindex); +} + +/* +** R_PolygonScanRightEdge +** +** Goes through the polygon and scans the right edge, filling in +** count values. +*/ +void R_PolygonScanRightEdge (void) +{ + int i, v, itop, ibottom; + emitpoint_t *pvert, *pnext; + espan_t *pspan; + float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext; + fixed16_t u, u_step; + + pspan = s_polygon_spans; + i = s_minindex; + + vvert = r_q2polydesc.pverts[i].v; + if (vvert < r_refdef.fvrecty_adj) + vvert = r_refdef.fvrecty_adj; + if (vvert > r_refdef.fvrectbottom_adj) + vvert = r_refdef.fvrectbottom_adj; + + vtop = ceil (vvert); + + do + { + pvert = &r_q2polydesc.pverts[i]; + pnext = pvert + 1; + + vnext = pnext->v; + if (vnext < r_refdef.fvrecty_adj) + vnext = r_refdef.fvrecty_adj; + if (vnext > r_refdef.fvrectbottom_adj) + vnext = r_refdef.fvrectbottom_adj; + + vbottom = ceil (vnext); + + if (vtop < vbottom) + { + uvert = pvert->u; + if (uvert < r_refdef.fvrectx_adj) + uvert = r_refdef.fvrectx_adj; + if (uvert > r_refdef.fvrectright_adj) + uvert = r_refdef.fvrectright_adj; + + unext = pnext->u; + if (unext < r_refdef.fvrectx_adj) + unext = r_refdef.fvrectx_adj; + if (unext > r_refdef.fvrectright_adj) + unext = r_refdef.fvrectright_adj; + + du = unext - uvert; + dv = vnext - vvert; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vcount = (u >> 16) - pspan->u; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + vvert = vnext; + + i++; + if (i == r_q2polydesc.nump) + i = 0; + + } while (i != s_maxindex); + + pspan->count = DS_SPAN_LIST_END; // mark the end of the span list +} + +/* +** R_ClipPolyFace +** +** Clips the winding at clip_verts[clip_current] and changes clip_current +** Throws out the back side +*/ +int R_ClipPolyFace (int nump, clipplane_t *pclipplane) +{ + int i, outcount; + float dists[MAXWORKINGVERTS+3]; + float frac, clipdist, *pclipnormal; + float *in, *instep, *outstep, *vert2; + + clipdist = pclipplane->dist; + pclipnormal = pclipplane->normal; + +// calc dists + if (clip_current) + { + in = r_clip_verts[1][0]; + outstep = r_clip_verts[0][0]; + clip_current = 0; + } + else + { + in = r_clip_verts[0][0]; + outstep = r_clip_verts[1][0]; + clip_current = 1; + } + + instep = in; + for (i=0 ; i= 0) + { + memcpy (outstep, instep, sizeof (vec5_t)); + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + if (dists[i] == 0 || dists[i+1] == 0) + continue; + + if ( (dists[i] > 0) == (dists[i+1] > 0) ) + continue; + + // split it into a new vertex + frac = dists[i] / (dists[i] - dists[i+1]); + + vert2 = instep + sizeof (vec5_t) / sizeof (float); + + outstep[0] = instep[0] + frac*(vert2[0] - instep[0]); + outstep[1] = instep[1] + frac*(vert2[1] - instep[1]); + outstep[2] = instep[2] + frac*(vert2[2] - instep[2]); + outstep[3] = instep[3] + frac*(vert2[3] - instep[3]); + outstep[4] = instep[4] + frac*(vert2[4] - instep[4]); + + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + return outcount; +} + +void R_PolygonCalculateGradients (void) +{ + vec3_t p_normal, p_saxis, p_taxis; + float distinv; + + TransformVector (r_q2polydesc.vpn, p_normal); + TransformVector (r_q2polydesc.vright, p_saxis); + TransformVector (r_q2polydesc.vup, p_taxis); + + distinv = 1.0 / (-(DotProduct (r_q2polydesc.viewer_position, r_q2polydesc.vpn)) + r_q2polydesc.dist ); + + d_sdivzstepu = p_saxis[0] * xscaleinv; + d_sdivzstepv = -p_saxis[1] * yscaleinv; + d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv; + + d_tdivzstepu = p_taxis[0] * xscaleinv; + d_tdivzstepv = -p_taxis[1] * yscaleinv; + d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv; + + d_zistepu = p_normal[0] * xscaleinv * distinv; + d_zistepv = -p_normal[1] * yscaleinv * distinv; + d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv; + + sadjust = (fixed16_t) ( ( DotProduct( r_q2polydesc.viewer_position, r_q2polydesc.vright) + r_q2polydesc.s_offset ) * 0x10000 ); + tadjust = (fixed16_t) ( ( DotProduct( r_q2polydesc.viewer_position, r_q2polydesc.vup ) + r_q2polydesc.t_offset ) * 0x10000 ); + +// -1 (-epsilon) so we never wander off the edge of the texture + bbextents = (r_q2polydesc.pixel_width << 16) - 1; + bbextentt = (r_q2polydesc.pixel_height << 16) - 1; +} + +static void R_DrawPoly( int iswater ) +{ + int i, nump; + float ymin, ymax; + emitpoint_t *pverts; + espan_t spans[MAXHEIGHT+1]; + + s_polygon_spans = spans; + +// find the top and bottom vertices, and make sure there's at least one scan to +// draw + ymin = 999999.9; + ymax = -999999.9; + pverts = r_q2polydesc.pverts; + + for (i=0 ; iv < ymin) + { + ymin = pverts->v; + s_minindex = i; + } + + if (pverts->v > ymax) + { + ymax = pverts->v; + s_maxindex = i; + } + + pverts++; + } + + ymin = ceil (ymin); + ymax = ceil (ymax); + + if (ymin >= ymax) + return; // doesn't cross any scans at all + + cachewidth = r_q2polydesc.pixel_width; + cacheblock = r_q2polydesc.pixels; + +// copy the first vertex to the last vertex, so we don't have to deal with +// wrapping + nump = r_q2polydesc.nump; + pverts = r_q2polydesc.pverts; + pverts[nump] = pverts[0]; + + R_PolygonCalculateGradients (); + R_PolygonScanLeftEdge (); + R_PolygonScanRightEdge (); + + R_PolygonDrawSpans( s_polygon_spans, iswater ); +} + + +void R_ClipAndDrawPoly ( float alpha, int isturbulent, qboolean textured ) +{ + emitpoint_t outverts[MAXWORKINGVERTS+3], *pout; + float *pv; + int i, nump; + float scale; + vec3_t transformed, local; + + if (r_pixbytes == 4) + { + if (alpha == 1 && !isturbulent) + r_q2polydesc.drawspanlet = R_32DrawSpanletAlphaTest; + else + { + r_q2polydesc.alpha = alpha*255; + if (isturbulent) + r_q2polydesc.drawspanlet = R_32DrawSpanletTurbulentBlended; + else + r_q2polydesc.drawspanlet = R_32DrawSpanletBlended; + } + } + else if (r_pixbytes == 2) + { + if (alpha < 0.5) + r_q2polydesc.drawspanlet = R_16DrawSpanlet33Stipple; + else if (alpha < 0.9) + r_q2polydesc.drawspanlet = R_16DrawSpanlet66Stipple; + else + r_q2polydesc.drawspanlet = R_16DrawSpanletAlphaTest; + } + else + { + if (alpha < 0.5) + r_q2polydesc.drawspanlet = R_DrawSpanlet33Stipple; + else if (alpha < 0.9) + r_q2polydesc.drawspanlet = R_DrawSpanlet66Stipple; + else + r_q2polydesc.drawspanlet = R_8DrawSpanletAlphaTest; +/* + if ( !textured ) + { + r_q2polydesc.drawspanlet = R_DrawSpanletConstant;//R_DrawSpanletConstant33; + } + else + { + // + // choose the correct spanlet routine based on alpha + // + if ( alpha == 1 ) + { + // isturbulent is ignored because we know that turbulent surfaces + // can't be opaque + r_q2polydesc.drawspanlet = R_DrawSpanletConstant;//R_DrawSpanletOpaque; + } + else + { + if (1)// sw_stipplealpha->value ) + { + if ( isturbulent ) + { + if ( alpha > 0.33 ) + r_q2polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66; + else + r_q2polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33; + } + else if (1) + r_q2polydesc.drawspanlet = R_DrawSpanletAlphaTest; + else + { + if ( alpha > 0.33 ) + r_q2polydesc.drawspanlet = R_DrawSpanlet66Stipple; + else + r_q2polydesc.drawspanlet = R_DrawSpanlet33Stipple; + } + } + else + { + if ( isturbulent ) + { + if ( alpha > 0.33 ) + r_q2polydesc.drawspanlet = R_DrawSpanletConstant;//R_DrawSpanletTurbulentBlended66; + else + r_q2polydesc.drawspanlet = R_DrawSpanletConstant;//R_DrawSpanletTurbulentBlended33; + } + else + { + if ( alpha > 0.33 ) + r_q2polydesc.drawspanlet = R_DrawSpanletConstant;//R_DrawSpanlet66; + else + r_q2polydesc.drawspanlet = R_DrawSpanletConstant;//R_DrawSpanlet33; + } + } + } + } + */ + } + + // clip to the frustum in worldspace + nump = r_q2polydesc.nump; + clip_current = 0; + + for (i=0 ; i<4 ; i++) + { + nump = R_ClipPolyFace (nump, &view_clipplanes[i]); + if (nump < 3) + return; + if (nump > MAXWORKINGVERTS) + Host_Error("R_ClipAndDrawPoly: too many points: %d", nump ); + } + +// transform vertices into viewspace and project + pv = &r_clip_verts[clip_current][0][0]; + + for (i=0 ; izi = 1.0 / transformed[2]; + + pout->s = pv[3]; + pout->t = pv[4]; + + scale = xscale * pout->zi; + pout->u = (xcenter+0.5 + scale * transformed[0]); + + scale = yscale * pout->zi; + pout->v = (ycenter - scale * transformed[1]); + + pv += sizeof (vec5_t) / sizeof (pv); + } + +// draw it + r_q2polydesc.nump = nump; + r_q2polydesc.pverts = outverts; + + R_DrawPoly( isturbulent ); +} + + +void R_BuildPolygonFromSurface(msurface_t *fa) +{ + int i, lindex, lnumverts; + medge_t *pedges, *r_pedge; + int vertpage; + float *vec; + vec5_t *pverts; + float tmins[2] = { 0, 0 }; + + r_q2polydesc.nump = 0; + + // reconstruct the polygon + pedges = currentmodel->edges; + lnumverts = fa->numedges; + vertpage = 0; + + pverts = r_clip_verts[0]; + + for (i=0 ; isurfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + vec = currentmodel->vertexes[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = currentmodel->vertexes[r_pedge->v[1]].position; + } + + VectorCopy (vec, pverts[i] ); + } + + VectorCopy( fa->texinfo->vecs[0], r_q2polydesc.vright ); + VectorCopy( fa->texinfo->vecs[1], r_q2polydesc.vup ); + VectorCopy( fa->plane->normal, r_q2polydesc.vpn ); + VectorCopy( r_origin, r_q2polydesc.viewer_position ); + + if ( fa->flags & SURF_PLANEBACK ) + { + VectorSubtract( vec3_origin, r_q2polydesc.vpn, r_q2polydesc.vpn ); + } + +// PGM 09/16/98 + if ( fa->texinfo->flags & (SURF_WARP|SURF_FLOWING) ) + { + r_q2polydesc.pixels = (qbyte *)fa->texinfo->texture + fa->texinfo->texture->offsets[0]; + r_q2polydesc.pixel_width = fa->texinfo->texture->width; + r_q2polydesc.pixel_height = fa->texinfo->texture->height; + } +// PGM 09/16/98 + else + { + surfcache_t *scache; + + scache = D_CacheSurface( fa, 0 ); + + r_q2polydesc.pixels = scache->data; + r_q2polydesc.pixel_width = scache->width; + r_q2polydesc.pixel_height = scache->height; + + tmins[0] = fa->texturemins[0]; + tmins[1] = fa->texturemins[1]; + } + + r_q2polydesc.dist = DotProduct( r_q2polydesc.vpn, pverts[0] ); + + r_q2polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0]; + r_q2polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1]; + + // scrolling texture addition + if (fa->texinfo->flags & SURF_FLOWING) + { + r_q2polydesc.s_offset += -128 * ( (cl.time*0.25) - (int)(cl.time*0.25) ); + } + + r_q2polydesc.nump = lnumverts; +} + + + +void SWR_DrawAlphaSurfaces( void ) +{ + msurface_t *s = r_alpha_surfaces, *os; + + currentmodel = r_worldentity.model; + + modelorg[0] = -r_origin[0]; + modelorg[1] = -r_origin[1]; + modelorg[2] = -r_origin[2]; + + while ( s ) + { + R_BuildPolygonFromSurface( s ); + + if (s->texinfo->flags & SURF_TRANS66) + { + R_ClipAndDrawPoly( 0.66f, 0/*(s->texinfo->flags & (SURF_WARP|SURF_FLOWING))*/, true ); + } + else if (s->texinfo->flags & SURF_TRANS33) + { + R_ClipAndDrawPoly( 0.33f, 0/*(s->texinfo->flags & (SURF_WARP|SURF_FLOWING))*/, true ); + } + else + R_ClipAndDrawPoly( 1.f, 0/*(s->texinfo->flags & (SURF_WARP|SURF_FLOWING))*/, true ); + + os = s; + s = s->nextalphasurface; + os->nextalphasurface=NULL; + } + + r_alpha_surfaces = NULL; +} diff --git a/engine/sw/r_drawa.s b/engine/sw/r_drawa.s new file mode 100644 index 000000000..3cb22394e --- /dev/null +++ b/engine/sw/r_drawa.s @@ -0,0 +1,838 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// r_drawa.s +// x86 assembly-language edge clipping and emission code +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" +#include "d_ifacea.h" + +#if id386 + +// !!! if these are changed, they must be changed in r_draw.c too !!! +#define FULLY_CLIPPED_CACHED 0x80000000 +#define FRAMECOUNT_MASK 0x7FFFFFFF + + .data + +Ld0: .single 0.0 +Ld1: .single 0.0 +Lstack: .long 0 +Lfp_near_clip: .single NEAR_CLIP +Lceilv0: .long 0 +Lv: .long 0 +Lu0: .long 0 +Lv0: .long 0 +Lzi0: .long 0 + + .text + +//---------------------------------------------------------------------- +// edge clipping code +//---------------------------------------------------------------------- + +#define pv0 4+12 +#define pv1 8+12 +#define clip 12+12 + + .align 4 +.globl C(R_ClipEdge) +C(R_ClipEdge): + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + movl %esp,Lstack // for clearing the stack later + +// float d0, d1, f; +// mvertex_t clipvert; + + movl clip(%esp),%ebx + movl pv0(%esp),%esi + movl pv1(%esp),%edx + +// if (clip) +// { + testl %ebx,%ebx + jz Lemit + +// do +// { + +Lcliploop: + +// d0 = DotProduct (pv0->position, clip->normal) - clip->dist; +// d1 = DotProduct (pv1->position, clip->normal) - clip->dist; + flds mv_position+0(%esi) + fmuls cp_normal+0(%ebx) + flds mv_position+4(%esi) + fmuls cp_normal+4(%ebx) + flds mv_position+8(%esi) + fmuls cp_normal+8(%ebx) + fxch %st(1) + faddp %st(0),%st(2) // d0mul2 | d0add0 + + flds mv_position+0(%edx) + fmuls cp_normal+0(%ebx) + flds mv_position+4(%edx) + fmuls cp_normal+4(%ebx) + flds mv_position+8(%edx) + fmuls cp_normal+8(%ebx) + fxch %st(1) + faddp %st(0),%st(2) // d1mul2 | d1add0 | d0mul2 | d0add0 + fxch %st(3) // d0add0 | d1add0 | d0mul2 | d1mul2 + + faddp %st(0),%st(2) // d1add0 | dot0 | d1mul2 + faddp %st(0),%st(2) // dot0 | dot1 + + fsubs cp_dist(%ebx) // d0 | dot1 + fxch %st(1) // dot1 | d0 + fsubs cp_dist(%ebx) // d1 | d0 + fxch %st(1) + fstps Ld0 + fstps Ld1 + +// if (d0 >= 0) +// { + movl Ld0,%eax + movl Ld1,%ecx + orl %eax,%ecx + js Lp2 + +// both points are unclipped + +Lcontinue: + +// +// R_ClipEdge (&clipvert, pv1, clip->next); +// return; +// } +// } while ((clip = clip->next) != NULL); + movl cp_next(%ebx),%ebx + testl %ebx,%ebx + jnz Lcliploop + +// } + +//// add the edge +// R_EmitEdge (pv0, pv1); +Lemit: + +// +// set integer rounding to ceil mode, set to single precision +// +// FIXME: do away with by manually extracting integers from floats? +// FIXME: set less often + fldcw ceil_cw + +// edge_t *edge, *pcheck; +// int u_check; +// float u, u_step; +// vec3_t local, transformed; +// float *world; +// int v, v2, ceilv0; +// float scale, lzi0, u0, v0; +// int side; + +// if (r_lastvertvalid) +// { + cmpl $0,C(r_lastvertvalid) + jz LCalcFirst + +// u0 = r_u1; +// v0 = r_v1; +// lzi0 = r_lzi1; +// ceilv0 = r_ceilv1; + movl C(r_lzi1),%eax + movl C(r_u1),%ecx + movl %eax,Lzi0 + movl %ecx,Lu0 + movl C(r_v1),%ecx + movl C(r_ceilv1),%eax + movl %ecx,Lv0 + movl %eax,Lceilv0 + jmp LCalcSecond + +// } + +LCalcFirst: + +// else +// { +// world = &pv0->position[0]; + + call LTransformAndProject // v0 | lzi0 | u0 + + fsts Lv0 + fxch %st(2) // u0 | lzi0 | v0 + fstps Lu0 // lzi0 | v0 + fstps Lzi0 // v0 + +// ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0); + fistpl Lceilv0 + +// } + +LCalcSecond: + +// world = &pv1->position[0]; + movl %edx,%esi + + call LTransformAndProject // v1 | lzi1 | u1 + + flds Lu0 // u0 | v1 | lzi1 | u1 + fxch %st(3) // u1 | v1 | lzi1 | u0 + flds Lzi0 // lzi0 | u1 | v1 | lzi1 | u0 + fxch %st(3) // lzi1 | u1 | v1 | lzi0 | u0 + flds Lv0 // v0 | lzi1 | u1 | v1 | lzi0 | u0 + fxch %st(3) // v1 | lzi1 | u1 | v0 | lzi0 | u0 + +// r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1); + fistl C(r_ceilv1) + + fldcw single_cw // put back normal floating-point state + + fsts C(r_v1) + fxch %st(4) // lzi0 | lzi1 | u1 | v0 | v1 | u0 + +// if (r_lzi1 > lzi0) +// lzi0 = r_lzi1; + fcom %st(1) + fnstsw %ax + testb $1,%ah + jz LP0 + fstp %st(0) + fld %st(0) +LP0: + + fxch %st(1) // lzi1 | lzi0 | u1 | v0 | v1 | u0 + fstps C(r_lzi1) // lzi0 | u1 | v0 | v1 | u0 + fxch %st(1) + fsts C(r_u1) + fxch %st(1) + +// if (lzi0 > r_nearzi) // for mipmap finding +// r_nearzi = lzi0; + fcoms C(r_nearzi) + fnstsw %ax + testb $0x45,%ah + jnz LP1 + fsts C(r_nearzi) +LP1: + +// // for right edges, all we want is the effect on 1/z +// if (r_nearzionly) +// return; + movl C(r_nearzionly),%eax + testl %eax,%eax + jz LP2 +LPop5AndDone: + movl C(cacheoffset),%eax + movl C(r_framecount),%edx + cmpl $0x7FFFFFFF,%eax + jz LDoPop + andl $(FRAMECOUNT_MASK),%edx + orl $(FULLY_CLIPPED_CACHED),%edx + movl %edx,C(cacheoffset) + +LDoPop: + fstp %st(0) // u1 | v0 | v1 | u0 + fstp %st(0) // v0 | v1 | u0 + fstp %st(0) // v1 | u0 + fstp %st(0) // u0 + fstp %st(0) + jmp Ldone + +LP2: + +// // create the edge +// if (ceilv0 == r_ceilv1) +// return; // horizontal edge + movl Lceilv0,%ebx + movl C(edge_p),%edi + movl C(r_ceilv1),%ecx + movl %edi,%edx + movl C(r_pedge),%esi + addl $(et_size),%edx + cmpl %ecx,%ebx + jz LPop5AndDone + + movl C(r_pedge),%eax + movl %eax,et_owner(%edi) + +// side = ceilv0 > r_ceilv1; +// +// edge->nearzi = lzi0; + fstps et_nearzi(%edi) // u1 | v0 | v1 | u0 + +// if (side == 1) +// { + jc LSide0 + +LSide1: + +// // leading edge (go from p2 to p1) + +// u_step = ((u0 - r_u1) / (v0 - r_v1)); + fsubrp %st(0),%st(3) // v0 | v1 | u0-u1 + fsub %st(1),%st(0) // v0-v1 | v1 | u0-u1 + fdivrp %st(0),%st(2) // v1 | ustep + +// r_emitted = 1; + movl $1,C(r_emitted) + +// edge = edge_p++; + movl %edx,C(edge_p) + +// pretouch next edge + movl (%edx),%eax + +// v2 = ceilv0 - 1; +// v = r_ceilv1; + movl %ecx,%eax + leal -1(%ebx),%ecx + movl %eax,%ebx + +// edge->surfs[0] = 0; +// edge->surfs[1] = surface_p - surfaces; + movl C(surface_p),%eax + movl C(surfaces),%esi + subl %edx,%edx + subl %esi,%eax + shrl $(SURF_T_SHIFT),%eax + movl %edx,et_surfs(%edi) + movl %eax,et_surfs+2(%edi) + + subl %esi,%esi + +// u = r_u1 + ((float)v - r_v1) * u_step; + movl %ebx,Lv + fildl Lv // v | v1 | ustep + fsubp %st(0),%st(1) // v-v1 | ustep + fmul %st(1),%st(0) // (v-v1)*ustep | ustep + fadds C(r_u1) // u | ustep + + jmp LSideDone + +// } + +LSide0: + +// else +// { +// // trailing edge (go from p1 to p2) + +// u_step = ((r_u1 - u0) / (r_v1 - v0)); + fsub %st(3),%st(0) // u1-u0 | v0 | v1 | u0 + fxch %st(2) // v1 | v0 | u1-u0 | u0 + fsub %st(1),%st(0) // v1-v0 | v0 | u1-u0 | u0 + fdivrp %st(0),%st(2) // v0 | ustep | u0 + +// r_emitted = 1; + movl $1,C(r_emitted) + +// edge = edge_p++; + movl %edx,C(edge_p) + +// pretouch next edge + movl (%edx),%eax + +// v = ceilv0; +// v2 = r_ceilv1 - 1; + decl %ecx + +// edge->surfs[0] = surface_p - surfaces; +// edge->surfs[1] = 0; + movl C(surface_p),%eax + movl C(surfaces),%esi + subl %edx,%edx + subl %esi,%eax + shrl $(SURF_T_SHIFT),%eax + movl %edx,et_surfs+2(%edi) + movl %eax,et_surfs(%edi) + + movl $1,%esi + +// u = u0 + ((float)v - v0) * u_step; + movl %ebx,Lv + fildl Lv // v | v0 | ustep | u0 + fsubp %st(0),%st(1) // v-v0 | ustep | u0 + fmul %st(1),%st(0) // (v-v0)*ustep | ustep | u0 + faddp %st(0),%st(2) // ustep | u + fxch %st(1) // u | ustep + +// } + +LSideDone: + +// edge->u_step = u_step*0x100000; +// edge->u = u*0x100000 + 0xFFFFF; + + fmuls fp_1m // u*0x100000 | ustep + fxch %st(1) // ustep | u*0x100000 + fmuls fp_1m // ustep*0x100000 | u*0x100000 + fxch %st(1) // u*0x100000 | ustep*0x100000 + fadds fp_1m_minus_1 // u*0x100000 + 0xFFFFF | ustep*0x100000 + fxch %st(1) // ustep*0x100000 | u*0x100000 + 0xFFFFF + fistpl et_u_step(%edi) // u*0x100000 + 0xFFFFF + fistpl et_u(%edi) + +// // we need to do this to avoid stepping off the edges if a very nearly +// // horizontal edge is less than epsilon above a scan, and numeric error +// // causes it to incorrectly extend to the scan, and the extension of the +// // line goes off the edge of the screen +// // FIXME: is this actually needed? +// if (edge->u < r_refdef.vrect_x_adj_shift20) +// edge->u = r_refdef.vrect_x_adj_shift20; +// if (edge->u > r_refdef.vrectright_adj_shift20) +// edge->u = r_refdef.vrectright_adj_shift20; + movl et_u(%edi),%eax + movl C(r_refdef)+rd_vrect_x_adj_shift20,%edx + cmpl %edx,%eax + jl LP4 + movl C(r_refdef)+rd_vrectright_adj_shift20,%edx + cmpl %edx,%eax + jng LP5 +LP4: + movl %edx,et_u(%edi) + movl %edx,%eax +LP5: + +// // sort the edge in normally +// u_check = edge->u; +// +// if (edge->surfs[0]) +// u_check++; // sort trailers after leaders + addl %esi,%eax + +// if (!newedges[v] || newedges[v]->u >= u_check) +// { + movl C(newedges)(,%ebx,4),%esi + testl %esi,%esi + jz LDoFirst + cmpl %eax,et_u(%esi) + jl LNotFirst +LDoFirst: + +// edge->next = newedges[v]; +// newedges[v] = edge; + movl %esi,et_next(%edi) + movl %edi,C(newedges)(,%ebx,4) + + jmp LSetRemove + +// } + +LNotFirst: + +// else +// { +// pcheck = newedges[v]; +// +// while (pcheck->next && pcheck->next->u < u_check) +// pcheck = pcheck->next; +LFindInsertLoop: + movl %esi,%edx + movl et_next(%esi),%esi + testl %esi,%esi + jz LInsertFound + cmpl %eax,et_u(%esi) + jl LFindInsertLoop + +LInsertFound: + +// edge->next = pcheck->next; +// pcheck->next = edge; + movl %esi,et_next(%edi) + movl %edi,et_next(%edx) + +// } + +LSetRemove: + +// edge->nextremove = removeedges[v2]; +// removeedges[v2] = edge; + movl C(removeedges)(,%ecx,4),%eax + movl %edi,C(removeedges)(,%ecx,4) + movl %eax,et_nextremove(%edi) + +Ldone: + movl Lstack,%esp // clear temporary variables from stack + + popl %ebx // restore register variables + popl %edi + popl %esi + ret + +// at least one point is clipped + +Lp2: + testl %eax,%eax + jns Lp1 + +// else +// { +// // point 0 is clipped + +// if (d1 < 0) +// { + movl Ld1,%eax + testl %eax,%eax + jns Lp3 + +// // both points are clipped +// // we do cache fully clipped edges +// if (!leftclipped) + movl C(r_leftclipped),%eax + movl C(r_pedge),%ecx + testl %eax,%eax + jnz Ldone + +// r_pedge->framecount = r_framecount; + movl C(r_framecount),%eax + andl $(FRAMECOUNT_MASK),%eax + orl $(FULLY_CLIPPED_CACHED),%eax + movl %eax,C(cacheoffset) + +// return; + jmp Ldone + +// } + +Lp1: + +// // point 0 is unclipped +// if (d1 >= 0) +// { +// // both points are unclipped +// continue; + +// // only point 1 is clipped + +// f = d0 / (d0 - d1); + flds Ld0 + flds Ld1 + fsubr %st(1),%st(0) + +// // we don't cache partially clipped edges + movl $0x7FFFFFFF,C(cacheoffset) + + fdivrp %st(0),%st(1) + + subl $(mv_size),%esp // allocate space for clipvert + +// clipvert.position[0] = pv0->position[0] + +// f * (pv1->position[0] - pv0->position[0]); +// clipvert.position[1] = pv0->position[1] + +// f * (pv1->position[1] - pv0->position[1]); +// clipvert.position[2] = pv0->position[2] + +// f * (pv1->position[2] - pv0->position[2]); + flds mv_position+8(%edx) + fsubs mv_position+8(%esi) + flds mv_position+4(%edx) + fsubs mv_position+4(%esi) + flds mv_position+0(%edx) + fsubs mv_position+0(%esi) // 0 | 1 | 2 + +// replace pv1 with the clip point + movl %esp,%edx + movl cp_leftedge(%ebx),%eax + testb %al,%al + + fmul %st(3),%st(0) + fxch %st(1) // 1 | 0 | 2 + fmul %st(3),%st(0) + fxch %st(2) // 2 | 0 | 1 + fmulp %st(0),%st(3) // 0 | 1 | 2 + fadds mv_position+0(%esi) + fxch %st(1) // 1 | 0 | 2 + fadds mv_position+4(%esi) + fxch %st(2) // 2 | 0 | 1 + fadds mv_position+8(%esi) + fxch %st(1) // 0 | 2 | 1 + fstps mv_position+0(%esp) // 2 | 1 + fstps mv_position+8(%esp) // 1 + fstps mv_position+4(%esp) + +// if (clip->leftedge) +// { + jz Ltestright + +// r_leftclipped = true; +// r_leftexit = clipvert; + movl $1,C(r_leftclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_leftexit)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_leftexit)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_leftexit)+mv_position+8 + + jmp Lcontinue + +// } + +Ltestright: +// else if (clip->rightedge) +// { + testb %ah,%ah + jz Lcontinue + +// r_rightclipped = true; +// r_rightexit = clipvert; + movl $1,C(r_rightclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_rightexit)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_rightexit)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_rightexit)+mv_position+8 + +// } +// +// R_ClipEdge (pv0, &clipvert, clip->next); +// return; +// } + jmp Lcontinue + +// } + +Lp3: + +// // only point 0 is clipped +// r_lastvertvalid = false; + + movl $0,C(r_lastvertvalid) + +// f = d0 / (d0 - d1); + flds Ld0 + flds Ld1 + fsubr %st(1),%st(0) + +// // we don't cache partially clipped edges + movl $0x7FFFFFFF,C(cacheoffset) + + fdivrp %st(0),%st(1) + + subl $(mv_size),%esp // allocate space for clipvert + +// clipvert.position[0] = pv0->position[0] + +// f * (pv1->position[0] - pv0->position[0]); +// clipvert.position[1] = pv0->position[1] + +// f * (pv1->position[1] - pv0->position[1]); +// clipvert.position[2] = pv0->position[2] + +// f * (pv1->position[2] - pv0->position[2]); + flds mv_position+8(%edx) + fsubs mv_position+8(%esi) + flds mv_position+4(%edx) + fsubs mv_position+4(%esi) + flds mv_position+0(%edx) + fsubs mv_position+0(%esi) // 0 | 1 | 2 + + movl cp_leftedge(%ebx),%eax + testb %al,%al + + fmul %st(3),%st(0) + fxch %st(1) // 1 | 0 | 2 + fmul %st(3),%st(0) + fxch %st(2) // 2 | 0 | 1 + fmulp %st(0),%st(3) // 0 | 1 | 2 + fadds mv_position+0(%esi) + fxch %st(1) // 1 | 0 | 2 + fadds mv_position+4(%esi) + fxch %st(2) // 2 | 0 | 1 + fadds mv_position+8(%esi) + fxch %st(1) // 0 | 2 | 1 + fstps mv_position+0(%esp) // 2 | 1 + fstps mv_position+8(%esp) // 1 + fstps mv_position+4(%esp) + +// replace pv0 with the clip point + movl %esp,%esi + +// if (clip->leftedge) +// { + jz Ltestright2 + +// r_leftclipped = true; +// r_leftenter = clipvert; + movl $1,C(r_leftclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_leftenter)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_leftenter)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_leftenter)+mv_position+8 + + jmp Lcontinue + +// } + +Ltestright2: +// else if (clip->rightedge) +// { + testb %ah,%ah + jz Lcontinue + +// r_rightclipped = true; +// r_rightenter = clipvert; + movl $1,C(r_rightclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_rightenter)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_rightenter)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_rightenter)+mv_position+8 + +// } + jmp Lcontinue + +// %esi = vec3_t point to transform and project +// %edx preserved +LTransformAndProject: + +// // transform and project +// VectorSubtract (world, modelorg, local); + flds mv_position+0(%esi) + fsubs C(modelorg)+0 + flds mv_position+4(%esi) + fsubs C(modelorg)+4 + flds mv_position+8(%esi) + fsubs C(modelorg)+8 + fxch %st(2) // local[0] | local[1] | local[2] + +// TransformVector (local, transformed); +// +// if (transformed[2] < NEAR_CLIP) +// transformed[2] = NEAR_CLIP; +// +// lzi0 = 1.0 / transformed[2]; + fld %st(0) // local[0] | local[0] | local[1] | local[2] + fmuls C(vpn)+0 // zm0 | local[0] | local[1] | local[2] + fld %st(1) // local[0] | zm0 | local[0] | local[1] | + // local[2] + fmuls C(vright)+0 // xm0 | zm0 | local[0] | local[1] | local[2] + fxch %st(2) // local[0] | zm0 | xm0 | local[1] | local[2] + fmuls C(vup)+0 // ym0 | zm0 | xm0 | local[1] | local[2] + fld %st(3) // local[1] | ym0 | zm0 | xm0 | local[1] | + // local[2] + fmuls C(vpn)+4 // zm1 | ym0 | zm0 | xm0 | local[1] | + // local[2] + fld %st(4) // local[1] | zm1 | ym0 | zm0 | xm0 | + // local[1] | local[2] + fmuls C(vright)+4 // xm1 | zm1 | ym0 | zm0 | xm0 | + // local[1] | local[2] + fxch %st(5) // local[1] | zm1 | ym0 | zm0 | xm0 | + // xm1 | local[2] + fmuls C(vup)+4 // ym1 | zm1 | ym0 | zm0 | xm0 | + // xm1 | local[2] + fxch %st(1) // zm1 | ym1 | ym0 | zm0 | xm0 | + // xm1 | local[2] + faddp %st(0),%st(3) // ym1 | ym0 | zm2 | xm0 | xm1 | local[2] + fxch %st(3) // xm0 | ym0 | zm2 | ym1 | xm1 | local[2] + faddp %st(0),%st(4) // ym0 | zm2 | ym1 | xm2 | local[2] + faddp %st(0),%st(2) // zm2 | ym2 | xm2 | local[2] + fld %st(3) // local[2] | zm2 | ym2 | xm2 | local[2] + fmuls C(vpn)+8 // zm3 | zm2 | ym2 | xm2 | local[2] + fld %st(4) // local[2] | zm3 | zm2 | ym2 | xm2 | local[2] + fmuls C(vright)+8 // xm3 | zm3 | zm2 | ym2 | xm2 | local[2] + fxch %st(5) // local[2] | zm3 | zm2 | ym2 | xm2 | xm3 + fmuls C(vup)+8 // ym3 | zm3 | zm2 | ym2 | xm2 | xm3 + fxch %st(1) // zm3 | ym3 | zm2 | ym2 | xm2 | xm3 + faddp %st(0),%st(2) // ym3 | zm4 | ym2 | xm2 | xm3 + fxch %st(4) // xm3 | zm4 | ym2 | xm2 | ym3 + faddp %st(0),%st(3) // zm4 | ym2 | xm4 | ym3 + fxch %st(1) // ym2 | zm4 | xm4 | ym3 + faddp %st(0),%st(3) // zm4 | xm4 | ym4 + + fcoms Lfp_near_clip + fnstsw %ax + testb $1,%ah + jz LNoClip + fstp %st(0) + flds Lfp_near_clip + +LNoClip: + + fdivrs float_1 // lzi0 | x | y + fxch %st(1) // x | lzi0 | y + +// // FIXME: build x/yscale into transform? +// scale = xscale * lzi0; +// u0 = (xcenter + scale*transformed[0]); + flds C(xscale) // xscale | x | lzi0 | y + fmul %st(2),%st(0) // scale | x | lzi0 | y + fmulp %st(0),%st(1) // scale*x | lzi0 | y + fadds C(xcenter) // u0 | lzi0 | y + +// if (u0 < r_refdef.fvrectx_adj) +// u0 = r_refdef.fvrectx_adj; +// if (u0 > r_refdef.fvrectright_adj) +// u0 = r_refdef.fvrectright_adj; +// FIXME: use integer compares of floats? + fcoms C(r_refdef)+rd_fvrectx_adj + fnstsw %ax + testb $1,%ah + jz LClampP0 + fstp %st(0) + flds C(r_refdef)+rd_fvrectx_adj +LClampP0: + fcoms C(r_refdef)+rd_fvrectright_adj + fnstsw %ax + testb $0x45,%ah + jnz LClampP1 + fstp %st(0) + flds C(r_refdef)+rd_fvrectright_adj +LClampP1: + + fld %st(1) // lzi0 | u0 | lzi0 | y + +// scale = yscale * lzi0; +// v0 = (ycenter - scale*transformed[1]); + fmuls C(yscale) // scale | u0 | lzi0 | y + fmulp %st(0),%st(3) // u0 | lzi0 | scale*y + fxch %st(2) // scale*y | lzi0 | u0 + fsubrs C(ycenter) // v0 | lzi0 | u0 + +// if (v0 < r_refdef.fvrecty_adj) +// v0 = r_refdef.fvrecty_adj; +// if (v0 > r_refdef.fvrectbottom_adj) +// v0 = r_refdef.fvrectbottom_adj; +// FIXME: use integer compares of floats? + fcoms C(r_refdef)+rd_fvrecty_adj + fnstsw %ax + testb $1,%ah + jz LClampP2 + fstp %st(0) + flds C(r_refdef)+rd_fvrecty_adj +LClampP2: + fcoms C(r_refdef)+rd_fvrectbottom_adj + fnstsw %ax + testb $0x45,%ah + jnz LClampP3 + fstp %st(0) + flds C(r_refdef)+rd_fvrectbottom_adj +LClampP3: + ret + +#endif // id386 + diff --git a/engine/sw/r_edge.c b/engine/sw/r_edge.c new file mode 100644 index 000000000..6eeef491b --- /dev/null +++ b/engine/sw/r_edge.c @@ -0,0 +1,931 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_edge.c + +#include "quakedef.h" +#include "r_local.h" + +#if 0 +// FIXME +the complex cases add new polys on most lines, so dont optimize for keeping them the same +have multiple free span lists to try to get better coherence? +low depth complexity -- 1 to 3 or so + +this breaks spans at every edge, even hidden ones (bad) + +have a sentinal at both ends? +#endif + + +edge_t *auxedges; +edge_t *r_edges, *edge_p, *edge_max; + +surf_t *surfaces, *surface_p, *surf_max; + +// surfaces are generated in back to front order by the bsp, so if a surf +// pointer is greater than another one, it should be drawn in front +// surfaces[1] is the background, and is used as the active surface stack + +edge_t *newedges[MAXHEIGHT]; +edge_t *removeedges[MAXHEIGHT]; + +espan_t *span_p, *max_span_p; + +int r_currentkey; + +extern int screenwidth; + +int current_iv; + +int edge_head_u_shift20, edge_tail_u_shift20; + +static void (*pdrawfunc)(void); + +edge_t edge_head; +edge_t edge_tail; +edge_t edge_aftertail; +edge_t edge_sentinel; + +float fv; + +void R_GenerateSpans (void); +void R_GenerateSpansTrans (void); +void R_GenerateSpansBackward (void); + +void R_LeadingEdge (edge_t *edge); +void R_LeadingEdgeBackwards (edge_t *edge); +void R_TrailingEdge (surf_t *surf, edge_t *edge); + + +//============================================================================= + + +/* +============== +R_DrawCulledPolys +============== +*/ +void R_DrawCulledPolys (void) +{ + surf_t *s; + msurface_t *pface; + + currententity = &r_worldentity; + + if (r_worldpolysbacktofront) + { + for (s=surface_p-1 ; s>&surfaces[1] ; s--) + { + if (!s->spans) + continue; + + if (!(s->flags & SURF_DRAWBACKGROUND)) + { + pface = (msurface_t *)s->data; + R_RenderPoly (pface, 15); + } + } + } + else + { + for (s = &surfaces[1] ; sspans) + continue; + + if (!(s->flags & SURF_DRAWBACKGROUND)) + { + pface = (msurface_t *)s->data; + R_RenderPoly (pface, 15); + } + } + } +} + + +/* +============== +R_BeginEdgeFrame +============== +*/ +void R_BeginEdgeFrame (void) +{ + int v; + + edge_p = r_edges; + edge_max = &r_edges[r_numallocatededges]; + + surface_p = &surfaces[2]; // background is surface 1, + // surface 0 is a dummy + surfaces[1].spans = NULL; // no background spans yet + surfaces[1].flags = SURF_DRAWBACKGROUND; + +// put the background behind everything in the world + if (r_draworder.value) + { + pdrawfunc = R_GenerateSpansBackward; + surfaces[1].key = 0; + r_currentkey = 1; + } + else if (cl.worldmodel->fromgame == fg_halflife) + { + pdrawfunc = R_GenerateSpansTrans; + surfaces[1].key = 0x7FFFFFFF; + r_currentkey = 0; + } + else + { + pdrawfunc = R_GenerateSpans; + surfaces[1].key = 0x7FFFFFFF; + r_currentkey = 0; + } + +// FIXME: set with memset + for (v=r_refdef.vrect.y ; vnext; +edgesearch: + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + goto edgesearch; + + // insert edgestoadd before edgelist +addedge: + edgestoadd->next = edgelist; + edgestoadd->prev = edgelist->prev; + edgelist->prev->next = edgestoadd; + edgelist->prev = edgestoadd; + } while ((edgestoadd = next_edge) != NULL); +} + +#endif // !id386 + + +#if !id386 + +/* +============== +R_RemoveEdges +============== +*/ +void R_RemoveEdges (edge_t *pedge) +{ + + do + { + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + } while ((pedge = pedge->nextremove) != NULL); +} + +#endif // !id386 + + +#if !id386 + +/* +============== +R_StepActiveU +============== +*/ +void R_StepActiveU (edge_t *pedge) +{ + edge_t *pnext_edge, *pwedge; + + while (1) + { +nextedge: + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + goto nextedge; + +pushback: + if (pedge == &edge_aftertail) + return; + + // push it back to keep it sorted + pnext_edge = pedge->next; + + // pull the edge out of the edge list + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + + // find out where the edge goes in the edge list + pwedge = pedge->prev->prev; + + while (pwedge->u > pedge->u) + { + pwedge = pwedge->prev; + } + + // put the edge back into the edge list + pedge->next = pwedge->next; + pedge->prev = pwedge; + pedge->next->prev = pedge; + pwedge->next = pedge; + + pedge = pnext_edge; + if (pedge == &edge_tail) + return; + } +} + +#endif // !id386 + + +/* +============== +R_CleanupSpan +============== +*/ +void R_CleanupSpan (void) +{ + surf_t *surf; + int iu; + espan_t *span; + +// now that we've reached the right edge of the screen, we're done with any +// unfinished surfaces, so emit a span for whatever's on top + surf = surfaces[1].next; + iu = edge_tail_u_shift20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + +// reset spanstate for all surfaces in the surface stack + do + { + surf->spanstate = 0; + surf = surf->next; + } while (surf != &surfaces[1]); +} + + +/* +============== +R_LeadingEdgeBackwards +============== +*/ +void R_LeadingEdgeBackwards (edge_t *edge) +{ + espan_t *span; + surf_t *surf, *surf2; + int iu; + +// it's adding a new surface in, so find the correct place + surf = &surfaces[edge->surfs[1]]; + +// don't start a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we've already seen the +// end edge) + if (++surf->spanstate == 1) + { + surf2 = surfaces[1].next; + + if (surf->key > surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; don't care, because they'll + // never be farthest anyway + goto newtop; + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key < surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; don't care which is really + // in front, because they'll never be farthest anyway + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } +} + + +/* +============== +R_TrailingEdge +============== +*/ +void R_TrailingEdge (surf_t *surf, edge_t *edge) +{ + espan_t *span; + int iu; + +// don't generate a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we haven't seen the +// start edge yet) + if (--surf->spanstate == 0) + { + if (surf->insubmodel) + r_bmodelactive--; + + if (surf == surfaces[1].next) + { + // emit a span (current top going away) + iu = edge->u >> 20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + + // set last_u on the surface below + surf->next->last_u = iu; + } + + surf->prev->next = surf->next; + surf->next->prev = surf->prev; + } +} + + +#if !id386 + +/* +============== +R_LeadingEdge +============== +*/ +void R_LeadingEdge (edge_t *edge) +{ + espan_t *span; + surf_t *surf, *surf2; + int iu; + double fu, newzi, testzi, newzitop, newzibottom; + + if (edge->surfs[1]) + { + // it's adding a new surface in, so find the correct place + surf = &surfaces[edge->surfs[1]]; + + // don't start a span if this is an inverted span, with the end + // edge preceding the start edge (that is, we've already seen the + // end edge) + if (++surf->spanstate == 1) + { + if (surf->insubmodel) + r_bmodelactive++; + + surf2 = surfaces[1].next; + + if (surf->key < surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto newtop; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto newtop; + } + } + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key > surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto gotposition; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto gotposition; + } + } + + goto continue_search; + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } + } +} + + +/* +============== +R_GenerateSpans +============== +*/ +void R_GenerateSpans (void) +{ + edge_t *edge; + surf_t *surf; + + r_bmodelactive = 0; + +// clear active surfaces to just the background surface + surfaces[1].next = surfaces[1].prev = &surfaces[1]; + surfaces[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next) + { + if (edge->surfs[0]) + { + // it has a left surface, so a surface is going away for this span + surf = &surfaces[edge->surfs[0]]; + + R_TrailingEdge (surf, edge); + + if (!edge->surfs[1]) + continue; + } + + R_LeadingEdge (edge); + } + + R_CleanupSpan (); +} + +#endif // !id386 + +void R_LeadingTransEdge (edge_t *edge) +{ + espan_t *span; + surf_t *surf, *surf2; + int iu; + double fu, newzi, testzi, newzitop, newzibottom; + + if (edge->surfs[1]) + { + // it's adding a new surface in, so find the correct place + surf = &surfaces[edge->surfs[1]]; + + // don't start a span if this is an inverted span, with the end + // edge preceding the start edge (that is, we've already seen the + // end edge) + if (++surf->spanstate == 1) + { + if (surf->insubmodel) + r_bmodelactive++; + + surf2 = surfaces[1].next; + + if (surf->key < surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto newtop; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto newtop; + } + } + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key > surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto gotposition; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto gotposition; + } + } + + goto continue_search; + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } + } +} + + +void R_GenerateSpansTrans (void) +{ + edge_t *edge; + surf_t *surf; + + r_bmodelactive = 0; + +// clear active surfaces to just the background surface + surfaces[1].next = surfaces[1].prev = &surfaces[1]; + surfaces[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next) + { + if (edge->surfs[0]) + { + // it has a left surface, so a surface is going away for this span + surf = &surfaces[edge->surfs[0]]; + + R_TrailingEdge (surf, edge); + + if (!edge->surfs[1]) + continue; + } + + R_LeadingTransEdge (edge); + } + + R_CleanupSpan (); +} + + +/* +============== +R_GenerateSpansBackward +============== +*/ +void R_GenerateSpansBackward (void) +{ + edge_t *edge; + + r_bmodelactive = 0; + +// clear active surfaces to just the background surface + surfaces[1].next = surfaces[1].prev = &surfaces[1]; + surfaces[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next) + { + if (edge->surfs[0]) + R_TrailingEdge (&surfaces[edge->surfs[0]], edge); + + if (edge->surfs[1]) + R_LeadingEdgeBackwards (edge); + } + + R_CleanupSpan (); +} + + +/* +============== +R_ScanEdges + +Input: +newedges[] array + this has links to edges, which have links to surfaces + +Output: +Each surface has a linked list of its visible spans +============== +*/ +void R_ScanEdges (void) +{ + int iv, bottom; + qbyte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE]; + espan_t *basespan_p; + surf_t *s; + + basespan_p = (espan_t *) + ((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width]; + + span_p = basespan_p; + +// clear active edges to just the background edges around the whole screen +// FIXME: most of this only needs to be set up once + edge_head.u = r_refdef.vrect.x << 20; + edge_head_u_shift20 = edge_head.u >> 20; + edge_head.u_step = 0; + edge_head.prev = NULL; + edge_head.next = &edge_tail; + edge_head.surfs[0] = 0; + edge_head.surfs[1] = 1; + + edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF; + edge_tail_u_shift20 = edge_tail.u >> 20; + edge_tail.u_step = 0; + edge_tail.prev = &edge_head; + edge_tail.next = &edge_aftertail; + edge_tail.surfs[0] = 1; + edge_tail.surfs[1] = 0; + + edge_aftertail.u = -1; // force a move + edge_aftertail.u_step = 0; + edge_aftertail.next = &edge_sentinel; + edge_aftertail.prev = &edge_tail; + +// FIXME: do we need this now that we clamp x in r_draw.c? + edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this + edge_sentinel.prev = &edge_aftertail; + +// +// process all scan lines +// + bottom = r_refdef.vrectbottom - 1; + + for (iv=r_refdef.vrect.y ; iv max_span_p) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + + if (r_drawculledpolys) + R_DrawCulledPolys (); + else + D_DrawSurfaces (); + + // clear the surface span pointers + for (s = &surfaces[1] ; sspans = NULL; + + span_p = basespan_p; + } + + if (removeedges[iv]) + R_RemoveEdges (removeedges[iv]); + + if (edge_head.next != &edge_tail) + R_StepActiveU (edge_head.next); + } + +// do the last scan (no need to step or sort or remove on the last scan) + + current_iv = iv; + fv = (float)iv; + +// mark that the head (background start) span is pre-included + surfaces[1].spanstate = 1; + + if (newedges[iv]) + R_InsertNewEdges (newedges[iv], edge_head.next); + + (*pdrawfunc) (); + +// draw whatever's left in the span list + if (r_drawculledpolys) + R_DrawCulledPolys (); + else + D_DrawSurfaces (); +} + + diff --git a/engine/sw/r_edgea.s b/engine/sw/r_edgea.s new file mode 100644 index 000000000..f67130f11 --- /dev/null +++ b/engine/sw/r_edgea.s @@ -0,0 +1,750 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// r_edgea.s +// x86 assembly-language edge-processing code. +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" + +#if id386 + + .data +Ltemp: .long 0 +float_1_div_0100000h: .long 0x35800000 // 1.0/(float)0x100000 +float_point_999: .single 0.999 +float_1_point_001: .single 1.001 + + .text + +//-------------------------------------------------------------------- + +#define edgestoadd 4+8 // note odd stack offsets because of interleaving +#define edgelist 8+12 // with pushes + +.globl C(R_EdgeCodeStart) +C(R_EdgeCodeStart): + +.globl C(R_InsertNewEdges) +C(R_InsertNewEdges): + pushl %edi + pushl %esi // preserve register variables + movl edgestoadd(%esp),%edx + pushl %ebx + movl edgelist(%esp),%ecx + +LDoNextEdge: + movl et_u(%edx),%eax + movl %edx,%edi + +LContinueSearch: + movl et_u(%ecx),%ebx + movl et_next(%ecx),%esi + cmpl %ebx,%eax + jle LAddedge + movl et_u(%esi),%ebx + movl et_next(%esi),%ecx + cmpl %ebx,%eax + jle LAddedge2 + movl et_u(%ecx),%ebx + movl et_next(%ecx),%esi + cmpl %ebx,%eax + jle LAddedge + movl et_u(%esi),%ebx + movl et_next(%esi),%ecx + cmpl %ebx,%eax + jg LContinueSearch + +LAddedge2: + movl et_next(%edx),%edx + movl et_prev(%esi),%ebx + movl %esi,et_next(%edi) + movl %ebx,et_prev(%edi) + movl %edi,et_next(%ebx) + movl %edi,et_prev(%esi) + movl %esi,%ecx + + cmpl $0,%edx + jnz LDoNextEdge + jmp LDone + + .align 4 +LAddedge: + movl et_next(%edx),%edx + movl et_prev(%ecx),%ebx + movl %ecx,et_next(%edi) + movl %ebx,et_prev(%edi) + movl %edi,et_next(%ebx) + movl %edi,et_prev(%ecx) + + cmpl $0,%edx + jnz LDoNextEdge + +LDone: + popl %ebx // restore register variables + popl %esi + popl %edi + + ret + +//-------------------------------------------------------------------- + +#define predge 4+4 + +.globl C(R_RemoveEdges) +C(R_RemoveEdges): + pushl %ebx + movl predge(%esp),%eax + +Lre_loop: + movl et_next(%eax),%ecx + movl et_nextremove(%eax),%ebx + movl et_prev(%eax),%edx + testl %ebx,%ebx + movl %edx,et_prev(%ecx) + jz Lre_done + movl %ecx,et_next(%edx) + + movl et_next(%ebx),%ecx + movl et_prev(%ebx),%edx + movl et_nextremove(%ebx),%eax + movl %edx,et_prev(%ecx) + testl %eax,%eax + movl %ecx,et_next(%edx) + jnz Lre_loop + + popl %ebx + ret + +Lre_done: + movl %ecx,et_next(%edx) + popl %ebx + + ret + +//-------------------------------------------------------------------- + +#define pedgelist 4+4 // note odd stack offset because of interleaving + // with pushes + +.globl C(R_StepActiveU) +C(R_StepActiveU): + pushl %edi + movl pedgelist(%esp),%edx + pushl %esi // preserve register variables + pushl %ebx + + movl et_prev(%edx),%esi + +LNewEdge: + movl et_u(%esi),%edi + +LNextEdge: + movl et_u(%edx),%eax + movl et_u_step(%edx),%ebx + addl %ebx,%eax + movl et_next(%edx),%esi + movl %eax,et_u(%edx) + cmpl %edi,%eax + jl LPushBack + + movl et_u(%esi),%edi + movl et_u_step(%esi),%ebx + addl %ebx,%edi + movl et_next(%esi),%edx + movl %edi,et_u(%esi) + cmpl %eax,%edi + jl LPushBack2 + + movl et_u(%edx),%eax + movl et_u_step(%edx),%ebx + addl %ebx,%eax + movl et_next(%edx),%esi + movl %eax,et_u(%edx) + cmpl %edi,%eax + jl LPushBack + + movl et_u(%esi),%edi + movl et_u_step(%esi),%ebx + addl %ebx,%edi + movl et_next(%esi),%edx + movl %edi,et_u(%esi) + cmpl %eax,%edi + jnl LNextEdge + +LPushBack2: + movl %edx,%ebx + movl %edi,%eax + movl %esi,%edx + movl %ebx,%esi + +LPushBack: +// push it back to keep it sorted + movl et_prev(%edx),%ecx + movl et_next(%edx),%ebx + +// done if the -1 in edge_aftertail triggered this + cmpl $(C(edge_aftertail)),%edx + jz LUDone + +// pull the edge out of the edge list + movl et_prev(%ecx),%edi + movl %ecx,et_prev(%esi) + movl %ebx,et_next(%ecx) + +// find out where the edge goes in the edge list +LPushBackLoop: + movl et_prev(%edi),%ecx + movl et_u(%edi),%ebx + cmpl %ebx,%eax + jnl LPushBackFound + + movl et_prev(%ecx),%edi + movl et_u(%ecx),%ebx + cmpl %ebx,%eax + jl LPushBackLoop + + movl %ecx,%edi + +// put the edge back into the edge list +LPushBackFound: + movl et_next(%edi),%ebx + movl %edi,et_prev(%edx) + movl %ebx,et_next(%edx) + movl %edx,et_next(%edi) + movl %edx,et_prev(%ebx) + + movl %esi,%edx + movl et_prev(%esi),%esi + + cmpl $(C(edge_tail)),%edx + jnz LNewEdge + +LUDone: + popl %ebx // restore register variables + popl %esi + popl %edi + + ret + +//-------------------------------------------------------------------- + +#define surf 4 // note this is loaded before any pushes + + .align 4 +TrailingEdge: + movl st_spanstate(%esi),%eax // check for edge inversion + decl %eax + jnz LInverted + + movl %eax,st_spanstate(%esi) + movl st_insubmodel(%esi),%ecx + movl 0x12345678,%edx // surfaces[1].st_next +LPatch0: + movl C(r_bmodelactive),%eax + subl %ecx,%eax + cmpl %esi,%edx + movl %eax,C(r_bmodelactive) + jnz LNoEmit // surface isn't on top, just remove + +// emit a span (current top going away) + movl et_u(%ebx),%eax + shrl $20,%eax // iu = integral pixel u + movl st_last_u(%esi),%edx + movl st_next(%esi),%ecx + cmpl %edx,%eax + jle LNoEmit2 // iu <= surf->last_u, so nothing to emit + + movl %eax,st_last_u(%ecx) // surf->next->last_u = iu; + subl %edx,%eax + movl %edx,espan_t_u(%ebp) // span->u = surf->last_u; + + movl %eax,espan_t_count(%ebp) // span->count = iu - span->u; + movl C(current_iv),%eax + movl %eax,espan_t_v(%ebp) // span->v = current_iv; + movl st_spans(%esi),%eax + movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans; + movl %ebp,st_spans(%esi) // surf->spans = span; + addl $(espan_t_size),%ebp + + movl st_next(%esi),%edx // remove the surface from the surface + movl st_prev(%esi),%esi // stack + + movl %edx,st_next(%esi) + movl %esi,st_prev(%edx) + ret + +LNoEmit2: + movl %eax,st_last_u(%ecx) // surf->next->last_u = iu; + movl st_next(%esi),%edx // remove the surface from the surface + movl st_prev(%esi),%esi // stack + + movl %edx,st_next(%esi) + movl %esi,st_prev(%edx) + ret + +LNoEmit: + movl st_next(%esi),%edx // remove the surface from the surface + movl st_prev(%esi),%esi // stack + + movl %edx,st_next(%esi) + movl %esi,st_prev(%edx) + ret + +LInverted: + movl %eax,st_spanstate(%esi) + ret + +//-------------------------------------------------------------------- + +// trailing edge only +Lgs_trailing: + pushl $Lgs_nextedge + jmp TrailingEdge + + +.globl C(R_GenerateSpans) +C(R_GenerateSpans): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// clear active surfaces to just the background surface + movl C(surfaces),%eax + movl C(edge_head_u_shift20),%edx + addl $(st_size),%eax +// %ebp = span_p throughout + movl C(span_p),%ebp + + movl $0,C(r_bmodelactive) + + movl %eax,st_next(%eax) + movl %eax,st_prev(%eax) + movl %edx,st_last_u(%eax) + movl C(edge_head)+et_next,%ebx // edge=edge_head.next + +// generate spans + cmpl $(C(edge_tail)),%ebx // done if empty list + jz Lgs_lastspan + +Lgs_edgeloop: + + movl et_surfs(%ebx),%edi + movl C(surfaces),%eax + movl %edi,%esi + andl $0xFFFF0000,%edi + andl $0xFFFF,%esi + jz Lgs_leading // not a trailing edge + +// it has a left surface, so a surface is going away for this span + shll $(SURF_T_SHIFT),%esi + addl %eax,%esi + testl %edi,%edi + jz Lgs_trailing + +// both leading and trailing + call TrailingEdge + movl C(surfaces),%eax + +// --------------------------------------------------------------- +// handle a leading edge +// --------------------------------------------------------------- + +Lgs_leading: + shrl $16-SURF_T_SHIFT,%edi + movl C(surfaces),%eax + addl %eax,%edi + movl 0x12345678,%esi // surf2 = surfaces[1].next; +LPatch2: + movl st_spanstate(%edi),%edx + movl st_insubmodel(%edi),%eax + testl %eax,%eax + jnz Lbmodel_leading + +// handle a leading non-bmodel edge + +// don't start a span if this is an inverted span, with the end edge preceding +// the start edge (that is, we've already seen the end edge) + testl %edx,%edx + jnz Lxl_done + + +// if (surf->key < surf2->key) +// goto newtop; + incl %edx + movl st_key(%edi),%eax + movl %edx,st_spanstate(%edi) + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jl Lnewtop + +// main sorting loop to search through surface stack until insertion point +// found. Always terminates because background surface is sentinel +// do +// { +// surf2 = surf2->next; +// } while (surf->key >= surf2->key); +Lsortloopnb: + movl st_next(%esi),%esi + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jge Lsortloopnb + + jmp LInsertAndExit + + +// handle a leading bmodel edge + .align 4 +Lbmodel_leading: + +// don't start a span if this is an inverted span, with the end edge preceding +// the start edge (that is, we've already seen the end edge) + testl %edx,%edx + jnz Lxl_done + + movl C(r_bmodelactive),%ecx + incl %edx + incl %ecx + movl %edx,st_spanstate(%edi) + movl %ecx,C(r_bmodelactive) + +// if (surf->key < surf2->key) +// goto newtop; + movl st_key(%edi),%eax + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jl Lnewtop + +// if ((surf->key == surf2->key) && surf->insubmodel) +// { + jz Lzcheck_for_newtop + +// main sorting loop to search through surface stack until insertion point +// found. Always terminates because background surface is sentinel +// do +// { +// surf2 = surf2->next; +// } while (surf->key > surf2->key); +Lsortloop: + movl st_next(%esi),%esi + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jg Lsortloop + + jne LInsertAndExit + +// Do 1/z sorting to see if we've arrived in the right position + movl et_u(%ebx),%eax + subl $0xFFFFF,%eax + movl %eax,Ltemp + fildl Ltemp + + fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) * + // (1.0 / 0x100000); + + fld %st(0) // fu | fu + fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu + flds C(fv) // fv | fu*surf->d_zistepu | fu + fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu + fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu + fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + + flds st_d_zistepu(%esi) // surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fmul %st(3),%st(0) // fu*surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin | + // fu*surf2->d_zistepu | + // fv*surf->d_zistepv | fu + faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu + + flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu + fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fld %st(2) // newzi | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + + fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv | + // newzibottom | newzi | fu + fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin | + // fv*surf2->d_zistepv | newzibottom | newzi | + // fu + faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu + fxch %st(1) // newzibottom | testzi | newzi | fu + +// if (newzibottom >= testzi) +// goto Lgotposition; + + fcomp %st(1) // testzi | newzi | fu + + fxch %st(1) // newzi | testzi | fu + fmuls float_1_point_001 // newzitop | testzi | fu + fxch %st(1) // testzi | newzitop | fu + + fnstsw %ax + testb $0x01,%ah + jz Lgotposition_fpop3 + +// if (newzitop >= testzi) +// { + + fcomp %st(1) // newzitop | fu + fnstsw %ax + testb $0x45,%ah + jz Lsortloop_fpop2 + +// if (surf->d_zistepu >= surf2->d_zistepu) +// goto newtop; + + flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop| fu + fcomps st_d_zistepu(%esi) // newzitop | fu + fnstsw %ax + testb $0x01,%ah + jz Lgotposition_fpop2 + + fstp %st(0) // clear the FPstack + fstp %st(0) + movl st_key(%edi),%eax + jmp Lsortloop + + +Lgotposition_fpop3: + fstp %st(0) +Lgotposition_fpop2: + fstp %st(0) + fstp %st(0) + jmp LInsertAndExit + + +// emit a span (obscures current top) + +Lnewtop_fpop3: + fstp %st(0) +Lnewtop_fpop2: + fstp %st(0) + fstp %st(0) + movl st_key(%edi),%eax // reload the sorting key + +Lnewtop: + movl et_u(%ebx),%eax + movl st_last_u(%esi),%edx + shrl $20,%eax // iu = integral pixel u + movl %eax,st_last_u(%edi) // surf->last_u = iu; + cmpl %edx,%eax + jle LInsertAndExit // iu <= surf->last_u, so nothing to emit + + subl %edx,%eax + movl %edx,espan_t_u(%ebp) // span->u = surf->last_u; + + movl %eax,espan_t_count(%ebp) // span->count = iu - span->u; + movl C(current_iv),%eax + movl %eax,espan_t_v(%ebp) // span->v = current_iv; + movl st_spans(%esi),%eax + movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans; + movl %ebp,st_spans(%esi) // surf->spans = span; + addl $(espan_t_size),%ebp + +LInsertAndExit: +// insert before surf2 + movl %esi,st_next(%edi) // surf->next = surf2; + movl st_prev(%esi),%eax + movl %eax,st_prev(%edi) // surf->prev = surf2->prev; + movl %edi,st_prev(%esi) // surf2->prev = surf; + movl %edi,st_next(%eax) // surf2->prev->next = surf; + +// --------------------------------------------------------------- +// leading edge done +// --------------------------------------------------------------- + +// --------------------------------------------------------------- +// see if there are any more edges +// --------------------------------------------------------------- + +Lgs_nextedge: + movl et_next(%ebx),%ebx + cmpl $(C(edge_tail)),%ebx + jnz Lgs_edgeloop + +// clean up at the right edge +Lgs_lastspan: + +// now that we've reached the right edge of the screen, we're done with any +// unfinished surfaces, so emit a span for whatever's on top + movl 0x12345678,%esi // surfaces[1].st_next +LPatch3: + movl C(edge_tail_u_shift20),%eax + xorl %ecx,%ecx + movl st_last_u(%esi),%edx + subl %edx,%eax + jle Lgs_resetspanstate + + movl %edx,espan_t_u(%ebp) + movl %eax,espan_t_count(%ebp) + movl C(current_iv),%eax + movl %eax,espan_t_v(%ebp) + movl st_spans(%esi),%eax + movl %eax,espan_t_pnext(%ebp) + movl %ebp,st_spans(%esi) + addl $(espan_t_size),%ebp + +// reset spanstate for all surfaces in the surface stack +Lgs_resetspanstate: + movl %ecx,st_spanstate(%esi) + movl st_next(%esi),%esi + cmpl $0x12345678,%esi // &surfaces[1] +LPatch4: + jnz Lgs_resetspanstate + +// store the final span_p + movl %ebp,C(span_p) + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +// --------------------------------------------------------------- +// 1/z sorting for bmodels in the same leaf +// --------------------------------------------------------------- + .align 4 +Lxl_done: + incl %edx + movl %edx,st_spanstate(%edi) + + jmp Lgs_nextedge + + + .align 4 +Lzcheck_for_newtop: + movl et_u(%ebx),%eax + subl $0xFFFFF,%eax + movl %eax,Ltemp + fildl Ltemp + + fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) * + // (1.0 / 0x100000); + + fld %st(0) // fu | fu + fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu + flds C(fv) // fv | fu*surf->d_zistepu | fu + fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu + fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu + fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + + flds st_d_zistepu(%esi) // surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fmul %st(3),%st(0) // fu*surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin | + // fu*surf2->d_zistepu | + // fv*surf->d_zistepv | fu + faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu + + flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu + fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fld %st(2) // newzi | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + + fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv | + // newzibottom | newzi | fu + fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin | + // fv*surf2->d_zistepv | newzibottom | newzi | + // fu + faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu + fxch %st(1) // newzibottom | testzi | newzi | fu + +// if (newzibottom >= testzi) +// goto newtop; + + fcomp %st(1) // testzi | newzi | fu + + fxch %st(1) // newzi | testzi | fu + fmuls float_1_point_001 // newzitop | testzi | fu + fxch %st(1) // testzi | newzitop | fu + + fnstsw %ax + testb $0x01,%ah + jz Lnewtop_fpop3 + +// if (newzitop >= testzi) +// { + + fcomp %st(1) // newzitop | fu + fnstsw %ax + testb $0x45,%ah + jz Lsortloop_fpop2 + +// if (surf->d_zistepu >= surf2->d_zistepu) +// goto newtop; + + flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop | fu + fcomps st_d_zistepu(%esi) // newzitop | fu + fnstsw %ax + testb $0x01,%ah + jz Lnewtop_fpop2 + +Lsortloop_fpop2: + fstp %st(0) // clear the FP stack + fstp %st(0) + movl st_key(%edi),%eax + jmp Lsortloop + + +.globl C(R_EdgeCodeEnd) +C(R_EdgeCodeEnd): + + +//---------------------------------------------------------------------- +// Surface array address code patching routine +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_SurfacePatch) +C(R_SurfacePatch): + + movl C(surfaces),%eax + addl $(st_size),%eax + movl %eax,LPatch4-4 + + addl $(st_next),%eax + movl %eax,LPatch0-4 + movl %eax,LPatch2-4 + movl %eax,LPatch3-4 + + ret + +#endif // id386 + diff --git a/engine/sw/r_light.c b/engine/sw/r_light.c new file mode 100644 index 000000000..7d4294527 --- /dev/null +++ b/engine/sw/r_light.c @@ -0,0 +1,462 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_light.c + +#include "quakedef.h" +#include "r_local.h" + +int r_dlightframecount; + + +/* +================== +R_AnimateLight +================== +*/ +void SWR_AnimateLight (void) +{ + int i,j,k; + +// +// light animations +// 'm' is normal light, 'a' is no light, 'z' is double bright + i = (int)(cl.time*10); + for (j=0 ; jcontents < 0) + return; + + splitplane = node->plane; + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + + if (dist > light->radius) + { + SWR_MarkLights (light, bit, node->children[0]); + return; + } + if (dist < -light->radius) + { + SWR_MarkLights (light, bit, node->children[1]); + return; + } + +// mark the polygons + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } + + SWR_MarkLights (light, bit, node->children[0]); + SWR_MarkLights (light, bit, node->children[1]); +} + +void SWR_Q2MarkLights (dlight_t *light, int bit, mnode_t *node) +{ + mplane_t *splitplane; + float dist; + msurface_t *surf; + int i; + + if (node->contents != -1) + return; + + splitplane = node->plane; + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + + if (dist > light->radius) + { + SWR_Q2MarkLights (light, bit, node->children[0]); + return; + } + if (dist < -light->radius) + { + SWR_Q2MarkLights (light, bit, node->children[1]); + return; + } + +// mark the polygons + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } + + SWR_Q2MarkLights (light, bit, node->children[0]); + SWR_Q2MarkLights (light, bit, node->children[1]); +} + +/* +============= +R_PushDlights +============= +*/ +void SWR_PushDlights (void) +{ + int i; + dlight_t *l; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + + if (!r_dynamic.value) + return; + + l = cl_dlights; + + if (cl.worldmodel->fromgame == fg_quake2) + { + for (i=0 ; idie < cl.time || !l->radius) + continue; + SWR_Q2MarkLights ( l, 1<nodes ); + } + + } + else + { + for (i=0 ; idie < cl.time || !l->radius) + continue; + SWR_MarkLights ( l, 1<nodes ); + } + } +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +int SWRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) +{ + int r; + float front, back, frac; + int side; + mplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + qbyte *lightmap; + unsigned scale; + int maps; + + if (cl.worldmodel->fromgame == fg_quake2) + { + if (node->contents != -1) + return -1; // solid + } + else if (node->contents < 0) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return SWRecursiveLightPoint (node->children[side], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + +// go down front side + r = SWRecursiveLightPoint (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags & SURF_DRAWTILED) + continue; // no lightmaps + + tex = surf->texinfo; + + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + r = 0; + if (lightmap) + { + + lightmap += (dt * ((surf->extents[0]>>4)+1) + ds); + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + r += *lightmap * scale; + lightmap += ((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + + r >>= 8; + } + + return r; + } + +// go down back side + return SWRecursiveLightPoint (node->children[!side], mid, end); +} +int SWRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) +{ + int r; + float front, back, frac; + int side; + mplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + qbyte *lightmap; + unsigned scale; + int maps; + + + if (cl.worldmodel->fromgame == fg_quake2) + { + if (node->contents != -1) + return -1; // solid + } + else if (node->contents < 0) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return SWRecursiveLightPoint3C (node->children[side], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + +// go down front side + r = SWRecursiveLightPoint (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags & SURF_DRAWTILED) + continue; // no lightmaps + + tex = surf->texinfo; + + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + r = 0; + if (lightmap) + { + + lightmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + r += (lightmap[0]+lightmap[1]+lightmap[2])/3 * scale; + lightmap += ((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1)*3; + } + + r >>= 8; + } + + return r; + } + +// go down back side + return SWRecursiveLightPoint3C (node->children[!side], mid, end); +} +int SWR_LightPoint (vec3_t p) +{ + vec3_t end; + int r; + extern qboolean r_usinglits; + + if (r_refdef.flags & 1 || !cl.worldmodel || !cl.worldmodel->lightdata) + return 255; + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + if (r_usinglits) + r = SWRecursiveLightPoint3C (cl.worldmodel->nodes, p, end); + else + r = SWRecursiveLightPoint (cl.worldmodel->nodes, p, end); + + if (r == -1) + r = 0; + + if (r < r_refdef.ambientlight) + r = r_refdef.ambientlight; + + return r; +} + +void SWQ1BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +{ + vec3_t end; + float r; + + res_dir[0] = 0; //software doesn't load luxes + res_dir[1] = 1; + res_dir[2] = 1; + + end[0] = point[0]; + end[1] = point[1]; + end[2] = point[2] - 2048; + + r = SWRecursiveLightPoint3C(cl.worldmodel->nodes, point, end); + if (r < 0) + { + res_diffuse[0] = 0; + res_diffuse[1] = 0; + res_diffuse[2] = 0; + + res_ambient[0] = 0; + res_ambient[1] = 0; + res_ambient[2] = 0; + } + else + { + res_diffuse[0] = r; + res_diffuse[1] = r; + res_diffuse[2] = r; + + res_ambient[0] = r; + res_ambient[1] = r; + res_ambient[2] = r; + } +} + diff --git a/engine/sw/r_local.h b/engine/sw/r_local.h new file mode 100644 index 000000000..6d848f75f --- /dev/null +++ b/engine/sw/r_local.h @@ -0,0 +1,323 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_local.h -- private refresh defs + +#ifdef SWQUAKE + +#include "r_shared.h" + +#define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0) + // normalizing factor so player model works out to about + // 1 pixel per triangle + +#define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox () + // if bbox is trivially rejected + +//=========================================================================== +// viewmodel lighting + +typedef struct { + int ambientlight; + int shadelight; + float *plightvec; +} alight_t; + +//=========================================================================== +// clipped bmodel edges + +typedef struct bedge_s +{ + mvertex_t *v[2]; + struct bedge_s *pnext; +} bedge_t; + +typedef struct { + float fv[3]; // viewspace x, y +} auxvert_t; + +//=========================================================================== + +extern cvar_t r_draworder; +extern cvar_t r_speeds; +extern cvar_t r_timegraph; +extern cvar_t r_graphheight; +extern cvar_t r_clearcolor; +extern cvar_t r_waterwarp; +extern cvar_t r_fullbright; +extern cvar_t r_drawentities; +extern cvar_t r_aliasstats; +extern cvar_t r_dspeeds; +extern cvar_t r_drawflat; +extern cvar_t r_ambient; +extern cvar_t r_reportsurfout; +extern cvar_t r_maxsurfs; +extern cvar_t r_numsurfs; +extern cvar_t r_reportedgeout; +extern cvar_t r_maxedges; +extern cvar_t r_numedges; + +#define XCENTERING (1.0 / 2.0) +#define YCENTERING (1.0 / 2.0) + +#define CLIP_EPSILON 0.001 + +#define BACKFACE_EPSILON 0.01 + +//=========================================================================== + +#define DIST_NOT_SET 98765 + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct clipplane_s +{ + vec3_t normal; + float dist; + struct clipplane_s *next; + qbyte leftedge; + qbyte rightedge; + qbyte reserved[2]; +} clipplane_t; + +extern clipplane_t view_clipplanes[4]; + +//============================================================================= + +void R_RenderWorld (void); + +//============================================================================= + +extern mplane_t screenedge[4]; + +extern vec3_t r_origin; + +extern vec3_t r_entorigin; + +extern float screenAspect; +extern float verticalFieldOfView; +extern float xOrigin, yOrigin; + +extern int r_visframecount; + +//============================================================================= + +extern int vstartscan; + + +void R_ClearPolyList (void); +void R_DrawPolyList (void); + +// +// current entity info +// +extern qboolean insubmodel; +extern vec3_t r_worldmodelorg; + + +void R_DrawSprite (void); +void R_RenderFace (msurface_t *fa, int clipflags); +void R_RenderPoly (msurface_t *fa, int clipflags); +void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf); +void R_TransformPlane (mplane_t *p, float *normal, float *dist); +void R_TransformFrustum (void); +void R_SetSkyFrame (void); +void R_DrawSurfaceBlock16From8 (void); +void R_DrawSurfaceBlock8 (void); +texture_t *SWR_TextureAnimation (texture_t *base); + +#if id386 + +void R_DrawSurfaceBlock8_mip0 (void); +void R_DrawSurfaceBlock8_mip1 (void); +void R_DrawSurfaceBlock8_mip2 (void); +void R_DrawSurfaceBlock8_mip3 (void); + +#endif + +void R_GenSkyTile (void *pdest); +void R_GenSkyTile16 (void *pdest); +void R_Surf8Patch (void); +void R_Surf16Patch (void); +void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags); +void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel); + +void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel); +surf_t *R_GetSurf (void); +void R_AliasDrawModel (alight_t *plighting); +void R_BeginEdgeFrame (void); +void R_ScanEdges (void); +void D_DrawSurfaces (void); +void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist); +void R_StepActiveU (edge_t *pedge); +void R_RemoveEdges (edge_t *pedge); + +extern void R_Surf8Start (void); +extern void R_Surf8End (void); +extern void R_Surf16Start (void); +extern void R_Surf16End (void); +extern void R_EdgeCodeStart (void); +extern void R_EdgeCodeEnd (void); + +extern void R_RotateBmodel (void); + +extern int c_faceclip; +extern int r_polycount; +extern int r_wholepolycount; + +extern model_t *cl_worldmodel; + +extern int *pfrustum_indexes[4]; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +#define NEAR_CLIP 0.01 + +extern int ubasestep, errorterm, erroradjustup, erroradjustdown; +extern int vstartscan; + +extern fixed16_t sadjust, tadjust; +extern fixed16_t bbextents, bbextentt; + +#define MAXBVERTINDEXES 1000 // new clipped vertices when clipping bmodels + // to the world BSP +extern mvertex_t *r_ptverts, *r_ptvertsmax; + +extern vec3_t sbaseaxis[3], tbaseaxis[3]; +extern float entity_rotation[3][3]; + +extern int reinit_surfcache; + +extern int r_currentkey; +extern int r_currentbkey; + +typedef struct btofpoly_s { + int clipflags; + msurface_t *psurf; +} btofpoly_t; + +#define MAX_BTOFPOLYS 5000 // FIXME: tune this + +extern int numbtofpolys; +extern btofpoly_t *pbtofpolys; + +void R_InitTurb (void); +void R_ZDrawSubmodelPolys (model_t *clmodel); + +//========================================================= +// Alias models +//========================================================= + +extern int numverts; +extern int a_skinwidth; +extern mtriangle_t *ptriangles; +extern int numtriangles; +extern aliashdr_t *paliashdr; +extern mmdl_t *pmdl; +extern float leftclip, topclip, rightclip, bottomclip; +extern int r_acliptype; +extern finalvert_t *pfinalverts; +extern auxvert_t *pauxverts; + +qboolean R_AliasCheckBBox (void); + +//========================================================= +// turbulence stuff + +#define AMP 8*0x10000 +#define AMP2 3 +#define SPEED 20 + +//========================================================= +// particle stuff + +void R_DrawParticles (void); +void R_InitParticles (void); +void R_EmitSkyEffectTris(model_t *mod, msurface_t *fa); +void R_ClearParticles (void); +void R_ReadPointFile_f (void); +void R_SurfacePatch (void); + +extern int r_amodels_drawn; +extern edge_t *auxedges; +extern int r_numallocatededges; +extern edge_t *r_edges, *edge_p, *edge_max; + +extern edge_t *newedges[MAXHEIGHT]; +extern edge_t *removeedges[MAXHEIGHT]; + +extern int screenwidth; + +extern qboolean r_usinglits; + +// FIXME: make stack vars when debugging done +extern edge_t edge_head; +extern edge_t edge_tail; +extern edge_t edge_aftertail; +extern int r_bmodelactive; + +extern float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; +extern float r_aliastransition, r_resfudge; + +extern int r_outofsurfaces; +extern int r_outofedges; + +extern mvertex_t *r_pcurrentvertbase; +extern int r_maxvalidedgeoffset; + +void R_AliasClipTriangle (mtriangle_t *ptri); + +extern float r_time1; +extern float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; +extern float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2; +extern int r_frustum_indexes[4*6]; +extern int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; +extern qboolean r_surfsonstack; +extern cshift_t cshift_water; +extern qboolean r_dowarpold, r_viewchanged; + +extern mleaf_t *r_viewleaf, *r_oldviewleaf; + +extern vec3_t r_emins, r_emaxs; +extern mnode_t *r_pefragtopnode; +extern int r_clipflags; +extern int r_dlightframecount; +extern qboolean r_fov_greater_than_90; + +void R_StoreEfrags (efrag_t **ppefrag); +void SWR_TimeRefresh_f (void); +void R_TimeGraph (void); +void R_PrintAliasStats (void); +void R_PrintTimes (void); +void R_PrintDSpeeds (void); +void SWR_AnimateLight (void); +int SWR_LightPoint (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_Q1BSP_SplitEntityOnNode2 (mnode_t *node); +void SWR_MarkLights (dlight_t *light, int bit, mnode_t *node); + +void SWR_DrawAlphaSurfaces( void ); +void SWR_SetupFrame (void); +void R_InitSkyBox (void); +void R_InitSkyBox (void); +void SWR_BuildLightmaps(void); +void SWR_NetGraph (void); + +#endif //def SWQUAKE diff --git a/engine/sw/r_main.c b/engine/sw/r_main.c new file mode 100644 index 000000000..8612288c5 --- /dev/null +++ b/engine/sw/r_main.c @@ -0,0 +1,1816 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_main.c + +#define SWSTAINS + +#include "quakedef.h" +#include "r_local.h" + +int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; + +extern cvar_t r_drawviewmodel; +extern cvar_t r_netgraph; +extern cvar_t r_sirds; + +//define PASSAGES + +void *colormap; +vec3_t viewlightvec; +alight_t r_viewlighting = {128, 192, viewlightvec}; +float r_time1; +int r_numallocatededges; +qboolean r_drawpolys; +qboolean r_drawculledpolys; +qboolean r_worldpolysbacktofront; +qboolean r_recursiveaffinetriangles = true; +int r_pixbytes = 1; +float r_aliasuvscale = 1.0; +int r_outofsurfaces; +int r_outofedges; + +qboolean r_dowarp, r_dowarpold, r_viewchanged; + +int numbtofpolys; +btofpoly_t *pbtofpolys; +mvertex_t *r_pcurrentvertbase; + +int c_surf; +int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; +qboolean r_surfsonstack; +int r_clipflags; + +qbyte *r_warpbuffer; + +qbyte *r_stack_start; + +qboolean r_fov_greater_than_90; + +entity_t r_worldentity; + +// +// view origin +// +vec3_t vup, base_vup; +vec3_t vpn, base_vpn; +vec3_t vright, base_vright; +vec3_t r_origin; + +// +// screen size info +// +refdef_t r_refdef; +float xcenter, ycenter; +float xscale, yscale; +float xscaleinv, yscaleinv; +float xscaleshrink, yscaleshrink; +float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; + +int screenwidth; + +float pixelAspect; +float screenAspect; +float verticalFieldOfView; +float xOrigin, yOrigin; + +mplane_t screenedge[4]; + +//colour bits (for 16 bit rendering) +int redbits, redshift; +int greenbits, greenshift; +int bluebits, blueshift; + + +// +// refresh flags +// +int r_framecount = 1; // so frame counts initialized to 0 don't match +int r_visframecount; +int d_spanpixcount; +int r_polycount; +int r_drawnpolycount; +int r_wholepolycount; + +int *pfrustum_indexes[4]; +int r_frustum_indexes[4*6]; + +int reinit_surfcache = 1; // if 1, surface cache is currently empty and + // must be reinitialized for current cache size + +mleaf_t *r_viewleaf, *r_oldviewleaf; + +texture_t *r_notexture_mip; + +float r_aliastransition, r_resfudge; + +int d_lightstylevalue[256]; // 8.8 fraction of base light value + +float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; +float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2; + +void R_MarkLeaves (void); +extern cvar_t r_zgraph; +extern cvar_t r_aliastransbase; +extern cvar_t r_aliastransadj; +extern cvar_t r_fixmodelsbyclip; +/* +cvar_t r_draworder = {"r_draworder","0"}; +cvar_t r_speeds = {"r_speeds","0"}; +cvar_t r_timegraph = {"r_timegraph","0"}; +cvar_t r_netgraph = {"r_netgraph","0"}; +cvar_t r_graphheight = {"r_graphheight","15"}; +cvar_t r_clearcolor = {"r_clearcolor","218"}; +cvar_t r_waterwarp = {"r_waterwarp","1"}; +cvar_t r_fullbright = {"r_fullbright","0"}; +cvar_t r_drawentities = {"r_drawentities","1"}; +cvar_t r_drawviewmodel = {"r_drawviewmodel","1"}; +cvar_t r_aliasstats = {"r_polymodelstats","0"}; +cvar_t r_dspeeds = {"r_dspeeds","0"}; +cvar_t r_drawflat = {"r_drawflat", "0"}; +cvar_t r_ambient = {"r_ambient", "0"}; +cvar_t r_reportsurfout = {"r_reportsurfout", "0"}; +cvar_t r_maxsurfs = {"r_maxsurfs", "0"}; +cvar_t r_numsurfs = {"r_numsurfs", "0"}; +cvar_t r_reportedgeout = {"r_reportedgeout", "0"}; +cvar_t r_maxedges = {"r_maxedges", "0"}; +cvar_t r_numedges = {"r_numedges", "0"}; +*/ +extern cvar_t r_loadlits; + +extern cvar_t r_stains; +extern cvar_t r_stainfadetime; +extern cvar_t r_stainfadeammount; + +qboolean r_usinglits; + +#ifdef FISH +extern cvar_t ffov; +#endif +extern cvar_t scr_fov; + +void CreatePassages (void); +void SetVisibilityByPassages (void); + +void R_NetGraph (void); +void R_ZGraph (void); + +/* +================== +R_InitTextures +================== +* +void SWR_InitTextures (void) +{ + int x,y, m; + byte *dest; + +// create a simple checkerboard texture for the default + r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture"); + + r_notexture_mip->width = r_notexture_mip->height = 16; + r_notexture_mip->offsets[0] = sizeof(texture_t); + r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16; + r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8; + r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4; + + for (m=0 ; m<4 ; m++) + { + dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m]; + for (y=0 ; y< (16>>m) ; y++) + for (x=0 ; x< (16>>m) ; x++) + { + if ( (y< (8>>m) ) ^ (x< (8>>m) ) ) + *dest++ = 0; + else + *dest++ = 0xff; + } + } +}*/ + +void SWR_DeInit (void) +{ + Cmd_RemoveCommand ("timerefresh"); + Cmd_RemoveCommand ("pointfile"); + + SWDraw_Shutdown(); +} + +/* +=============== +R_Init +=============== +*/ +void SWR_Init (void) +{ + int dummy; + +// get stack position so we can guess if we are going to overflow + r_stack_start = (qbyte *)&dummy; + + R_InitTurb (); + + Cmd_AddRemCommand ("timerefresh", SWR_TimeRefresh_f); + Cmd_AddRemCommand ("pointfile", R_ReadPointFile_f); + + Cvar_SetValue (&r_maxedges, (float)NUMSTACKEDGES); + Cvar_SetValue (&r_maxsurfs, (float)NUMSTACKSURFACES); + + view_clipplanes[0].leftedge = true; + view_clipplanes[1].rightedge = true; + view_clipplanes[1].leftedge = view_clipplanes[2].leftedge = + view_clipplanes[3].leftedge = false; + view_clipplanes[0].rightedge = view_clipplanes[2].rightedge = + view_clipplanes[3].rightedge = false; + + r_refdef.xOrigin = XCENTERING; + r_refdef.yOrigin = YCENTERING; + +// TODO: collect 386-specific code in one place +#if id386 + Sys_MakeCodeWriteable ((long)R_EdgeCodeStart, + (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart); +#endif // id386 + + D_Init (); +} + + +/* +=============== +R_NewMap +=============== +*/ +void SWR_NewMap (void) +{ + int i; + + memset (&r_worldentity, 0, sizeof(r_worldentity)); + r_worldentity.model = cl.worldmodel; + +// clear out efrags in case the level hasn't been reloaded +// FIXME: is this one short? + for (i=0 ; inumleafs ; i++) + cl.worldmodel->leafs[i].efrags = NULL; + + r_viewleaf = NULL; + R_ClearParticles (); + + r_cnumsurfs = r_maxsurfs.value; + + if (r_cnumsurfs <= MINSURFACES) + r_cnumsurfs = MINSURFACES; + + if (r_cnumsurfs > NUMSTACKSURFACES) + { + surfaces = Hunk_AllocName (r_cnumsurfs * sizeof(surf_t), "surfaces"); + surface_p = surfaces; + surf_max = &surfaces[r_cnumsurfs]; + r_surfsonstack = false; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + else + { + r_surfsonstack = true; + } + + r_maxedgesseen = 0; + r_maxsurfsseen = 0; + + r_numallocatededges = r_maxedges.value; + + if (r_numallocatededges < MINEDGES) + r_numallocatededges = MINEDGES; + + if (r_numallocatededges <= NUMSTACKEDGES) + { + auxedges = NULL; + } + else + { + auxedges = Hunk_AllocName (r_numallocatededges * sizeof(edge_t), + "edges"); + } + + r_dowarpold = false; + r_viewchanged = false; +#ifdef SWSTAINS + SWR_BuildLightmaps(); +#endif + + R_InitSkyBox(); + + UI_Reset(); +} + + +/* +=============== +R_SetVrect +=============== +*/ +void R_SetVrect (vrect_t *pvrectin, vrect_t *pvrect, int lineadj) +{ + int h; + float size; + qboolean full = false; + +#ifdef SIDEVIEWS + if (r_secondaryview==1) + return; + + if (!r_dowarp && !r_dowarpold) + return; +#endif + + if (scr_viewsize.value >= 100.0) { + size = 100.0; + full = true; + } else + size = scr_viewsize.value; + + if (cl.intermission) + { + full = true; + size = 100.0; + lineadj = 0; + } + size /= 100.0; + + if (!cl_sbar.value && full) + h = pvrectin->height; + else + h = pvrectin->height - lineadj; + +// h = (!cl_sbar.value && size==1.0) ? pvrectin->height : (pvrectin->height - lineadj); +// h = pvrectin->height - lineadj; + if (full) + pvrect->width = pvrectin->width; + else + pvrect->width = pvrectin->width * size; + if (pvrect->width < 96) + { + size = 96.0 / pvrectin->width; + pvrect->width = 96; // min for icons + } + pvrect->width &= ~7; + pvrect->height = pvrectin->height * size; + if (cl_sbar.value || !full) { + if (pvrect->height > pvrectin->height - lineadj) + pvrect->height = pvrectin->height - lineadj; + } else + if (pvrect->height > pvrectin->height) + pvrect->height = pvrectin->height; + + pvrect->height &= ~1; + + pvrect->x = (pvrectin->width - pvrect->width)/2; + if (full) + pvrect->y = 0; + else + pvrect->y = (h - pvrect->height)/2; +} + + +/* +=============== +R_ViewChanged + +Called every time the vid structure or r_refdef changes. +Guaranteed to be called before the first refresh +=============== +*/ +void SWR_ViewChanged (vrect_t *pvrect, int lineadj, float aspect) +{ + int i; + float res_scale; + + r_viewchanged = true; + + R_SetVrect (pvrect, &r_refdef.vrect, lineadj); + + r_refdef.horizontalFieldOfView = 2.0 * tan (r_refdef.fov_x/360*M_PI); + r_refdef.fvrectx = (float)r_refdef.vrect.x; + r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5; + r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1; + r_refdef.fvrecty = (float)r_refdef.vrect.y; + r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5; + r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; + r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1; + r_refdef.fvrectright = (float)r_refdef.vrectright; + r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5; + r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99; + r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; + r_refdef.fvrectbottom = (float)r_refdef.vrectbottom; + r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5; + + r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale); + r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale); + r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale); + r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale); + r_refdef.aliasvrectright = r_refdef.aliasvrect.x + + r_refdef.aliasvrect.width; + r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + + r_refdef.aliasvrect.height; + + +#ifdef FISH + if (ffov.value && cls.allow_fish) + pixelAspect = (float)r_refdef.vrect.height/(float)r_refdef.vrect.width; + else +#endif + pixelAspect = aspect; + xOrigin = r_refdef.xOrigin; + yOrigin = r_refdef.yOrigin; +#ifdef FISH + if (ffov.value && cls.allow_fish) + screenAspect = 1; + else +#endif + screenAspect = r_refdef.vrect.width*pixelAspect / + r_refdef.vrect.height; +// 320*200 1.0 pixelAspect = 1.6 screenAspect +// 320*240 1.0 pixelAspect = 1.3333 screenAspect +// proper 320*200 pixelAspect = 0.8333333 + + verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect; + +// values for perspective projection +// if math were exact, the values would range from 0.5 to to range+0.5 +// hopefully they wll be in the 0.000001 to range+.999999 and truncate +// the polygon rasterization will never render in the first row or column +// but will definately render in the [range] row and column, so adjust the +// buffer origin to get an exact edge to edge fill + xcenter = ((float)r_refdef.vrect.width * XCENTERING) + + r_refdef.vrect.x - 0.5; + aliasxcenter = xcenter * r_aliasuvscale; + ycenter = ((float)r_refdef.vrect.height * YCENTERING) + + r_refdef.vrect.y - 0.5; + aliasycenter = ycenter * r_aliasuvscale; + + xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; + aliasxscale = xscale * r_aliasuvscale; + xscaleinv = 1.0 / xscale; + yscale = xscale * pixelAspect; + aliasyscale = yscale * r_aliasuvscale; + yscaleinv = 1.0 / yscale; + xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView; + yscaleshrink = xscaleshrink*pixelAspect; + +// left side clip + screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView); + screenedge[0].normal[1] = 0; + screenedge[0].normal[2] = 1; + screenedge[0].type = PLANE_ANYZ; + +// right side clip + screenedge[1].normal[0] = + 1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView); + screenedge[1].normal[1] = 0; + screenedge[1].normal[2] = 1; + screenedge[1].type = PLANE_ANYZ; + +// top side clip + screenedge[2].normal[0] = 0; + screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView); + screenedge[2].normal[2] = 1; + screenedge[2].type = PLANE_ANYZ; + +// bottom side clip + screenedge[3].normal[0] = 0; + screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView); + screenedge[3].normal[2] = 1; + screenedge[3].type = PLANE_ANYZ; + + for (i=0 ; i<4 ; i++) + VectorNormalize (screenedge[i].normal); + + res_scale = sqrt ((double)(r_refdef.vrect.width * r_refdef.vrect.height) / + (320.0 * 152.0)) * + (2.0 / r_refdef.horizontalFieldOfView); + r_aliastransition = r_aliastransbase.value * res_scale; + r_resfudge = r_aliastransadj.value * res_scale; + + if (scr_fov.value <= 90.0) + r_fov_greater_than_90 = false; + else + r_fov_greater_than_90 = true; + +// TODO: collect 386-specific code in one place +#if id386 + if (r_pixbytes == 1) + { + Sys_MakeCodeWriteable ((long)R_Surf8Start, + (long)R_Surf8End - (long)R_Surf8Start); + colormap = vid.colormap; + R_Surf8Patch (); + } + else + { + Sys_MakeCodeWriteable ((long)R_Surf16Start, + (long)R_Surf16End - (long)R_Surf16Start); + colormap = vid.colormap16; + R_Surf16Patch (); + } +#endif // id386 + + D_ViewChanged (); //make sure gamma changes and the like take affect. +} + + +/* +=============== +R_MarkLeaves +=============== +*/ +void SWR_MarkLeaves (void) +{ + qbyte *vis; + mnode_t *node; + int i; + + + if (cl.worldmodel->fromgame == fg_quake2) + { + qbyte fatvis[MAX_MAP_LEAFS/8]; + int c; + mleaf_t *leaf; + int cluster; + +// if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2) +// return; + + r_visframecount++; + + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + + if (/*r_novis.value || */r_viewcluster == -1 || !cl.worldmodel->vis) + { + // mark everything + for (i=0 ; inumleafs ; i++) + cl.worldmodel->leafs[i].visframe = r_visframecount; + for (i=0 ; inumnodes ; i++) + cl.worldmodel->nodes[i].visframe = r_visframecount; + return; + } + + vis = CM_ClusterPVS (r_viewcluster, NULL);//, cl.worldmodel); + // may have to combine two clusters because of solid water boundaries + if (r_viewcluster2 != r_viewcluster) + { + memcpy (fatvis, vis, (cl.worldmodel->numleafs+7)/8); + vis = CM_ClusterPVS (r_viewcluster2, NULL);//, cl.worldmodel); + c = (cl.worldmodel->numleafs+31)/32; + for (i=0 ; ileafs ; inumleafs ; i++, leaf++) + { + cluster = leaf->cluster; + if (cluster == -1) + continue; + if (vis[cluster>>3] & (1<<(cluster&7))) + { + node = (mnode_t *)leaf; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } + return; + } + + if (r_oldviewleaf == r_viewleaf) + return; + + r_visframecount++; + r_oldviewleaf = r_viewleaf; + + vis = SWMod_LeafPVS (r_viewleaf, cl.worldmodel, NULL); + + for (i=0 ; inumleafs ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + node = (mnode_t *)&cl.worldmodel->leafs[i+1]; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +} + + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void SWR_DrawEntitiesOnList (void) +{ + extern cvar_t gl_part_flame, gl_part_torch; + int i, j; + int lnum; + alight_t lighting; +// FIXME: remove and do real lighting + float lightvec[3] = {-1, 0, 0}; + vec3_t dist; + float add; + + if (!r_drawentities.value) + return; + + for (i=0 ; ikeynum == cl.viewentity[r_refdef.currentplayernum]) + continue; + if (currententity->flags & 2) + continue; + + if (!currententity->model) + continue; + + if (cls.allow_anyparticles || currententity->visframe) //allowed or static + { + if (currententity->model->particleeffect>=0) + { + if (currententity->model->particleengulphs) + { + if (gl_part_flame.value) + { + R_TorchEffect(currententity->origin, currententity->model->particleeffect); + continue; + } + } + else + { + if (gl_part_torch.value) + { + R_TorchEffect(currententity->origin, currententity->model->particleeffect); + } + } + } + } + + switch (currententity->model->type) + { + case mod_sprite: + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + R_DrawSprite (); + break; + + case mod_alias: + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + if (R_AliasCheckBBox ()) + { + j = SWR_LightPoint (currententity->origin); + + lighting.ambientlight = j; + lighting.shadelight = j; + + lighting.plightvec = lightvec; + + for (lnum=0 ; lnum= cl.time) + { + VectorSubtract (currententity->origin, + cl_dlights[lnum].origin, + dist); + add = cl_dlights[lnum].radius - Length(dist); + + if (add > 0) + lighting.ambientlight += add; + } + } + + // clamp lighting so it doesn't overbright as much + if (lighting.ambientlight > 128) + lighting.ambientlight = 128; + if (lighting.ambientlight + lighting.shadelight > 192) + lighting.shadelight = 192 - lighting.ambientlight; + + R_AliasDrawModel (&lighting); + } + + break; + + default: + break; + } + } +} + +/* +============= +R_DrawViewModel +============= +*/ +void SWR_DrawViewModel (void) +{ +// FIXME: remove and do real lighting + float lightvec[3] = {-1, 0, 0}; + int j; + int lnum; + vec3_t dist; + float add; + dlight_t *dl; + + int pnum = r_refdef.currentplayernum; + static struct model_s *oldmodel[MAX_SPLITS]; + static float lerptime[MAX_SPLITS]; + static int prevframe[MAX_SPLITS]; + +#ifdef SIDEVIEWS + if (r_secondaryview==1) + return; +#endif + + if (cls.q2server) + return; + + if (!r_drawviewmodel.value || r_fov_greater_than_90 || !Cam_DrawViewModel(pnum)) + return; + + if (cl.stats[pnum][STAT_ITEMS] & IT_INVISIBILITY) + return; + + if (cl.stats[pnum][STAT_HEALTH] <= 0) + return; + + + currententity = &cl.viewent[pnum]; + if (!currententity->model) + return; + + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + VectorCopy (vup, viewlightvec); + VectorInverse (viewlightvec); + + j = SWR_LightPoint (currententity->origin); + + if (j < 24) + j = 24; // allways give some light on gun + r_viewlighting.ambientlight = j; + r_viewlighting.shadelight = j; + +// add dynamic lights + for (lnum=0 ; lnumradius) + continue; + if (dl->die < cl.time) + continue; + + VectorSubtract (currententity->origin, dl->origin, dist); + add = dl->radius - Length(dist); + if (add > 0) + r_viewlighting.ambientlight += add; + } + +// clamp lighting so it doesn't overbright as much + if (r_viewlighting.ambientlight > 128) + r_viewlighting.ambientlight = 128; + if (r_viewlighting.ambientlight + r_viewlighting.shadelight > 192) + r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight; + + r_viewlighting.plightvec = lightvec; + + currententity->scale = 1; + if (r_drawviewmodel.value > 0 && r_drawviewmodel.value < 1) + currententity->alpha = r_drawviewmodel.value; + else + currententity->alpha = 1; + + if (currententity->frame != prevframe[pnum]) + { + currententity->oldframe = prevframe[pnum]; + lerptime[pnum] = realtime; + } + prevframe[pnum] = currententity->frame; + + if (currententity->model != oldmodel[pnum]) + { + oldmodel[pnum] = currententity->model; + currententity->oldframe = currententity->frame; + lerptime[pnum] = realtime; + } + currententity->lerptime = 1-(realtime-lerptime[pnum])*10; + if (currententity->lerptime<0)currententity->lerptime=0; + + switch(currententity->model->type) + { + default: + Sys_Error("Invalid model type in R_DrawViewModel"); + break; + case mod_alias: + R_AliasDrawModel (&r_viewlighting); + break; + case mod_dummy: + break; + } +} + + +/* +============= +R_BmodelCheckBBox +============= +*/ +int R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) +{ + int i, *pindex, clipflags; + vec3_t acceptpt, rejectpt; + double d; + + clipflags = 0; + + if (currententity->angles[0] || currententity->angles[1] + || currententity->angles[2]) + { + for (i=0 ; i<4 ; i++) + { + d = DotProduct (currententity->origin, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= -clmodel->radius) + return BMODEL_FULLY_CLIPPED; + + if (d <= clmodel->radius) + clipflags |= (1<nodes; + + while (1) + { + if (node->visframe != r_visframecount) + return NULL; // not visible at all + + if (node->contents != -1) + { + if (node->contents != Q2CONTENTS_SOLID) + return node; // we've reached a non-solid leaf, so it's + // visible and not BSP clipped + return NULL; // in solid, so not visible + } + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE(mins, maxs, splitplane); + + if (sides == 3) + return node; // this is the splitter + + // not split yet; recurse down the contacted side + if (sides & 1) + node = node->children[0]; + else + node = node->children[1]; + } +} +void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs) +{ + vec3_t tmp, v; + int i, j; + vec3_t forward, right, up; + + if (!angles[0] && !angles[1] && !angles[2]) + { + VectorCopy (mins, tmins); + VectorCopy (maxs, tmaxs); + return; + } + + for (i=0 ; i<3 ; i++) + { + tmins[i] = 99999; + tmaxs[i] = -99999; + } + + AngleVectors (angles, forward, right, up); + + for ( i = 0; i < 8; i++ ) + { + if ( i & 1 ) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ( i & 2 ) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ( i & 4 ) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + + + VectorScale (forward, tmp[0], v); + VectorMA (v, -tmp[1], right, v); + VectorMA (v, tmp[2], up, v); + + for (j=0 ; j<3 ; j++) + { + if (v[j] < tmins[j]) + tmins[j] = v[j]; + if (v[j] > tmaxs[j]) + tmaxs[j] = v[j]; + } + } +} + + +/* +============= +R_DrawBEntitiesOnList +============= +*/ +void R_DrawBEntitiesOnList (void) +{ + int i, j, k, clipflags; + vec3_t oldorigin; + model_t *clmodel; + float minmaxs[6]; + vec3_t mins, maxs; + mnode_t *topnode; + + model_t *currentmodel; + + if (!r_drawentities.value) + return; + + VectorCopy (modelorg, oldorigin); + insubmodel = true; + r_dlightframecount = r_framecount; + + for (i=0 ; imodel) + continue; + + switch (currententity->model->type) + { + case mod_brush: + if (cl.worldmodel->fromgame == fg_quake2) + { + currentmodel = currententity->model; + if (!currentmodel) + continue; + if (currentmodel->nummodelsurfaces == 0) + continue; // clip brush only + // if ( currententity->flags & RF_BEAM ) + // continue; + // if (currentmodel->type != mod_brush) + // continue; + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + RotatedBBox (currentmodel->mins, currentmodel->maxs, + currententity->angles, mins, maxs); + VectorAdd (mins, currententity->origin, minmaxs); + VectorAdd (maxs, currententity->origin, (minmaxs+3)); + + clipflags = R_BmodelCheckBBox (currentmodel, minmaxs); + if (clipflags == BMODEL_FULLY_CLIPPED) + continue; // off the edge of the screen + + topnode = R_FindTopnode (minmaxs, minmaxs+3); + if (!topnode) + continue; // no part in a visible leaf + + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + r_pcurrentvertbase = currentmodel->vertexes; + + // FIXME: stop transforming twice + R_RotateBmodel (); + + // calculate dynamic lighting for bmodel +// R_PushDlights (currentmodel); + + currententity->topnode = r_pefragtopnode = topnode; + if (topnode->contents == -1) + { + // not a leaf; has to be clipped to the world BSP + r_clipflags = clipflags; + R_DrawSolidClippedSubmodelPolygons (currentmodel); + } + else + { + // falls entirely in one leaf, so we just put all the + // edges in the edge list and let 1/z sorting handle + // drawing order + R_DrawSubmodelPolygons (currentmodel, clipflags);//, topnode); + } + r_pefragtopnode = NULL; + + // put back world rotation and frustum clipping + // FIXME: R_RotateBmodel should just work off base_vxx + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (oldorigin, modelorg); + R_TransformFrustum (); + } + else //q1/hl levels + { + clmodel = currententity->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]; + } + + clipflags = R_BmodelCheckBBox (clmodel, minmaxs); + + if (clipflags != BMODEL_FULLY_CLIPPED) + { + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + // FIXME: is this needed? + VectorCopy (modelorg, r_worldmodelorg); + + r_pcurrentvertbase = clmodel->vertexes; + + // FIXME: stop transforming twice + R_RotateBmodel (); + + // calculate dynamic lighting for bmodel if it's not an + // instanced model + if (clmodel->firstmodelsurface != 0) + { + for (k=0 ; knodes + clmodel->hulls[0].firstclipnode); + } + } + + // if the driver wants polygons, deliver those. Z-buffering is on + // at this point, so no clipping to the world tree is needed, just + // frustum clipping + if (r_drawpolys | r_drawculledpolys) + { + R_ZDrawSubmodelPolys (clmodel); + } + else + { + if (cl.worldmodel->fromgame == fg_quake2) + { + r_pefragtopnode = R_FindTopnode (minmaxs, minmaxs+3); + if (r_pefragtopnode) + { + currententity->topnode = r_pefragtopnode; + + if (r_pefragtopnode->contents == -1) + { + // not a leaf; has to be clipped to the world BSP + r_clipflags = clipflags; + R_DrawSolidClippedSubmodelPolygons (clmodel); + } + else + { + // falls entirely in one leaf, so we just put all the + // edges in the edge list and let 1/z sorting handle + // drawing order + R_DrawSubmodelPolygons (clmodel, clipflags); + } + + currententity->topnode = NULL; + } + } + else + { + r_pefragtopnode = NULL; + + for (j=0 ; j<3 ; j++) + { + r_emins[j] = minmaxs[j]; + r_emaxs[j] = minmaxs[3+j]; + } + + R_Q1BSP_SplitEntityOnNode2 (cl.worldmodel->nodes); + + if (r_pefragtopnode) + { + currententity->topnode = r_pefragtopnode; + + if (r_pefragtopnode->contents >= 0) + { + // not a leaf; has to be clipped to the world BSP + r_clipflags = clipflags; + R_DrawSolidClippedSubmodelPolygons (clmodel); + } + else + { + // falls entirely in one leaf, so we just put all the + // edges in the edge list and let 1/z sorting handle + // drawing order + R_DrawSubmodelPolygons (clmodel, clipflags); + } + + currententity->topnode = NULL; + } + } + } + + // put back world rotation and frustum clipping + // FIXME: R_RotateBmodel should just work off base_vxx + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + VectorCopy (oldorigin, modelorg); + R_TransformFrustum (); + } + } + break; + + default: + break; + } + } + + insubmodel = false; +} + + +/* +================ +R_EdgeDrawing +================ +*/ +void R_EdgeDrawing (void) +{ + edge_t ledges[NUMSTACKEDGES + + ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1]; + surf_t lsurfs[NUMSTACKSURFACES + + ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1]; + + if (auxedges) + { + r_edges = auxedges; + } + else + { + r_edges = (edge_t *) + (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + } + + if (r_surfsonstack) + { + surfaces = (surf_t *) + (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + surf_max = &surfaces[r_cnumsurfs]; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + + R_BeginEdgeFrame (); + + if (r_dspeeds.value) + { + rw_time1 = Sys_DoubleTime (); + } + + R_RenderWorld (); + + if (r_drawculledpolys) + R_ScanEdges (); + +// only the world can be drawn back to front with no z reads or compares, just +// z writes, so have the driver turn z compares on now + D_TurnZOn (); + + if (r_dspeeds.value) + { + rw_time2 = Sys_DoubleTime (); + db_time1 = rw_time2; + } + + R_DrawBEntitiesOnList (); + + if (r_dspeeds.value) + { + db_time2 = Sys_DoubleTime (); + se_time1 = db_time2; + } + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + if (!(r_drawpolys | r_drawculledpolys)) + R_ScanEdges (); + + SWR_DrawAlphaSurfaces(); +} + + +void R_ApplySIRDAlgorithum(void); +qboolean r_dosirds = true; +/* +================ +R_RenderView + +r_refdef must be set before the first call +================ +*/ +void SWR_RenderView_ (void) +{ + qbyte warpbuffer[WARP_WIDTH * WARP_HEIGHT]; + + r_warpbuffer = warpbuffer; + r_dosirds = r_sirds.value; + + if (ffov.value && cls.allow_fish) //THAT's HORRIBLE! + r_dosirds = false; + + if (r_timegraph.value || r_speeds.value || r_dspeeds.value) + r_time1 = Sys_DoubleTime (); + + SWR_SetupFrame (); + + if (r_refdef.flags & 1) + { + D_ClearDepth(); + SWR_DrawEntitiesOnList (); + SWR_DrawViewModel (); + return; + } + +#ifdef PASSAGES +SetVisibilityByPassages (); +#else + SWR_MarkLeaves (); // done here so we know if we're in water +#endif + +// make FDIV fast. This reduces timing precision after we've been running for a +// while, so we don't do it globally. This also sets chop mode, and we do it +// here so that setup stuff like the refresh area calculations match what's +// done in screen.c + Sys_LowFPPrecision (); + + if (!r_worldentity.model || !cl.worldmodel) + Sys_Error ("R_RenderView: NULL worldmodel"); + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + R_EdgeDrawing (); + + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + if (r_dspeeds.value) + { + se_time2 = Sys_DoubleTime (); + de_time1 = se_time2; + } + + SWR_DrawEntitiesOnList (); + + if (r_dspeeds.value) + { + de_time2 = Sys_DoubleTime (); + dv_time1 = de_time2; + } + + SWR_DrawViewModel (); + + if (r_dspeeds.value) + { + dv_time2 = Sys_DoubleTime (); + dp_time1 = Sys_DoubleTime (); + } + + R_DrawParticles (); + + if (r_dspeeds.value) + dp_time2 = Sys_DoubleTime (); + + if (r_dosirds) + { + R_ApplySIRDAlgorithum(); + } + else if (r_dowarp) + D_WarpScreen (); + + V_SetContentsColor (r_viewleaf->contents); + + if (r_timegraph.value) + R_TimeGraph (); + + if (r_netgraph.value) + SWR_NetGraph (); + + if (r_zgraph.value) + R_ZGraph (); + + if (r_aliasstats.value) + R_PrintAliasStats (); + + if (r_speeds.value) + R_PrintTimes (); + + if (r_dspeeds.value) + R_PrintDSpeeds (); + + if (r_reportsurfout.value && r_outofsurfaces) + Con_Printf ("Short %d surfaces\n", r_outofsurfaces); + + if (r_reportedgeout.value && r_outofedges) + Con_Printf ("Short roughly %d edges\n", r_outofedges * 2 / 3); + +// back to high floating-point precision + Sys_HighFPPrecision (); +} + +void SWR_RenderView (void) +{ + int dummy; + int delta; + + delta = (qbyte *)&dummy - r_stack_start; + if (delta < -10000 || delta > 10000) + Sys_Error ("R_RenderView: called without enough stack"); + + if ( Hunk_LowMark() & 3 ) + Sys_Error ("Hunk is missaligned"); + + if ( (long)(&dummy) & 3 ) + Sys_Error ("Stack is missaligned"); + + if ( (long)(&r_warpbuffer) & 3 ) + Sys_Error ("Globals are missaligned"); + + SWR_RenderView_ (); +} + +/* +================ +R_InitTurb +================ +*/ +void R_InitTurb (void) +{ + int i; + + for (i=0 ; i>= 1; + mask &= (mask << b); + } + else + { + mask &= (mask << (b >> 1)); + mask >>= b; + b >>= 1; + } + } + return p; +} +#endif + +static int R_SIRDZFunc(int sub) +{ + int e; + + //special case the sky. + if (sub == R_SIRD_ZofSky) + return 0; + +#if id386 && defined(_MSC_VER) + e = sub; + //calculate the log (base 2) of the number. In other + //words the index of the highest set bit. bsr is undefined + //if it's input is 0, so special case that. + if (e!=0) + { + __asm + { + mov ebx, e + bsr eax, ebx + mov e, eax + } + } +#else + e = UShortLog(sub); +#endif + + //clip the exponent + if (e < R_SIRDIgnoreExponents) + return 0; + + // based on the power, shift the z so that + // it's as high as it can get while still staying + // under 0x100 + if (e > 8) + { + sub >>= (e-8); + } + else + { + if (e < 8) + { + sub <<= (8-e); + } + } + + // Lower the power of the number, this helps scaling and removes + // small z values. + e -= R_SIRDIgnoreExponents; + + // contruct the height value. The power is used as the primary calculator, + // and then the extra bits are used to offset. In this way you + // get more detail than just the log of the z value, and it works + // as a pretty good approximation of it. + e *= R_SIRDstepsPerExponent; + e += ((sub * R_SIRDstepsPerExponent) >> 8); + + //make sure we stay under maximum height. + return ((e<=R_SIRDmaxDiff)? e : R_SIRDmaxDiff ); +} + +void R_ApplySIRDAlgorithum(void) +{ + unsigned short* curz, *oldz; + unsigned short cz, lastz; + qbyte* curp; + qbyte* curbp, j; + int x, y, i, zinc, k; + + //note of interest: I've made this static so that + //if you like you could make it not static and see + //what would happen if you didn't change the background + static int ji = 0; + + InitSIRD(); + + if (cl.paused) + ji = 0; + + //create the background image to tile + //basically done by shifting the values around + //each time and xoring them with a randomly + //selected pixel + j = 0; + for (i=0; i=0; y--) + { + curz = (d_pzbuffer + (vid.width * y)); + oldz = (d_pzbuffer + (vid.width * ((y*WARP_HEIGHT)/vid.height) )); + k = (zinc * (vid.width-1)); + + for (x=vid.width-1; x>=0; x--) + { + curz[x] = oldz[k >> 16]; + k -= zinc; + } + } + } + + + //SIRDify each line + for (y=0; ys) + h = s; + + for (i=0 ; i>1); + y = vid.height - sb_lines - 24 - (int)r_graphheight.value*2 - 2; + + M_DrawTextBox (x, y, (w+7)/8, ((int)r_graphheight.value*2+7)/8 + 1); + y2 = y + 8; + y = vid.height - sb_lines - 8 - 2; + + x = 8; + lost = CL_CalcNet(); + for (a=NET_TIMINGS-w ; anormal); + *dist = p->dist - d; +// TODO: when we have rotating entities, this will need to use the view matrix + TransformVector (p->normal, normal); +} + + +/* +=============== +R_SetUpFrustumIndexes +=============== +*/ +void R_SetUpFrustumIndexes (void) +{ + int i, j, *pindex; + + pindex = r_frustum_indexes; + + for (i=0 ; i<4 ; i++) + { + for (j=0 ; j<3 ; j++) + { + if (view_clipplanes[i].normal[j] < 0) + { + pindex[j] = j; + pindex[j+3] = j+3; + } + else + { + pindex[j] = j+3; + pindex[j+3] = j; + } + } + + // FIXME: do just once at start + pfrustum_indexes[i] = pindex; + pindex += 6; + } +} + + +/* +=============== +R_SetupFrame +=============== +*/ +void SWR_SetupFrame (void) +{ + static mleaf_t fakeleaf; + extern int r_dosirds; + + extern int scr_chatmode; + + int edgecount; + vrect_t vrect; + float w, h; + +// don't allow cheats in multiplayer + + if (r_numsurfs.value) + { + if ((surface_p - surfaces) > r_maxsurfsseen) + r_maxsurfsseen = surface_p - surfaces; + + Con_Printf ("Used %d of %d surfs; %d max\n", surface_p - surfaces, + surf_max - surfaces, r_maxsurfsseen); + } + + if (r_numedges.value) + { + edgecount = edge_p - r_edges; + + if (edgecount > r_maxedgesseen) + r_maxedgesseen = edgecount; + + Con_Printf ("Used %d of %d edges; %d max\n", edgecount, + r_numallocatededges, r_maxedgesseen); + } + + r_refdef.ambientlight = r_ambient.value; + + if (r_refdef.ambientlight < 0) + r_refdef.ambientlight = 0; + +// if (!sv.active) + r_draworder.value = 0; // don't let cheaters look behind walls + + R_CheckVariables (); + + SWR_AnimateLight (); + + r_framecount++; + + numbtofpolys = 0; + +// debugging +#if 0 +r_refdef.vieworg[0]= 80; +r_refdef.vieworg[1]= 64; +r_refdef.vieworg[2]= 40; +r_refdef.viewangles[0]= 0; +r_refdef.viewangles[1]= 46.763641357; +r_refdef.viewangles[2]= 0; +#endif + +// build the transformation matrix for the given view angles + VectorCopy (r_refdef.vieworg, modelorg); + VectorCopy (r_refdef.vieworg, r_origin); + + AngleVectors (r_refdef.viewangles, vpn, vright, vup); + + if (r_refdef.flags & 1) + { + r_oldviewleaf = r_viewleaf = &fakeleaf; //so we can use quake1 rendering routines for q2 bsps. + r_viewleaf->contents = Q1CONTENTS_EMPTY; + } + else if (cl.worldmodel->fromgame == fg_quake2) + { + mleaf_t *leaf; + + r_viewleaf = &fakeleaf; //so we can use quake1 rendering routines for q2 bsps. + r_viewleaf->contents = Q1CONTENTS_EMPTY; + + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + leaf = SWMod_PointInLeaf (r_origin, cl.worldmodel); + r_viewcluster = r_viewcluster2 = leaf->cluster; + + // check above and below so crossing solid water doesn't draw wrong + if (!leaf->contents) + { // look down a bit + vec3_t temp; + + VectorCopy (r_origin, temp); + temp[2] -= 16; + leaf = SWMod_PointInLeaf (temp, cl.worldmodel); + if ( !(leaf->contents & Q2CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2) ) + r_viewcluster2 = leaf->cluster; + } + else + { // look up a bit + vec3_t temp; + + VectorCopy (r_origin, temp); + temp[2] += 16; + leaf = SWMod_PointInLeaf (temp, cl.worldmodel); + if ( !(leaf->contents & Q2CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2) ) + r_viewcluster2 = leaf->cluster; + } + } + else + { +// current viewleaf + r_oldviewleaf = r_viewleaf; + r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); + } + + r_dowarpold = r_dowarp; +#ifdef SIDEVIEWS + r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= Q1CONTENTS_WATER) && !r_secondaryview; +#else + r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= Q1CONTENTS_WATER); +#endif + if (vid.width > MAXWIDTH || r_pixbytes == 4 || scr_chatmode) + r_dowarp = 0; + if (r_dosirds) + r_dowarp = 0; + + if ((r_dowarp != r_dowarpold) || r_viewchanged) + { + if (r_dowarp) + { + if ((vid.width <= vid.maxwarpwidth) && + (vid.height <= vid.maxwarpheight)) + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + + SWR_ViewChanged (&vrect, sb_lines, vid.aspect); + } + else + { + w = vid.width; + h = vid.height; + + if (w > vid.maxwarpwidth) + { + h *= (float)vid.maxwarpwidth / w; + w = vid.maxwarpwidth; + } + + if (h > vid.maxwarpheight) + { + h = vid.maxwarpheight; + w *= (float)vid.maxwarpheight / h; + } + + vrect.x = 0; + vrect.y = 0; + vrect.width = (int)w; + vrect.height = (int)h; + + SWR_ViewChanged (&vrect, + (int)((float)sb_lines * (h/(float)vid.height)), + vid.aspect * (h / w) * + ((float)vid.width / (float)vid.height)); + } + } + else + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + + SWR_ViewChanged (&vrect, sb_lines, vid.aspect); + } + + r_viewchanged = false; + } + +// start off with just the four screen edge clip planes + R_TransformFrustum (); + +// save base values + VectorCopy (vpn, base_vpn); + VectorCopy (vright, base_vright); + VectorCopy (vup, base_vup); + VectorCopy (modelorg, base_modelorg); + + R_SetSkyFrame (); + + R_SetUpFrustumIndexes (); + + r_cache_thrash = false; + +// clear frame counts + c_faceclip = 0; + d_spanpixcount = 0; + r_polycount = 0; + r_drawnpolycount = 0; + r_wholepolycount = 0; + r_amodels_drawn = 0; + r_outofsurfaces = 0; + r_outofedges = 0; + + D_SetupFrame (); +} + diff --git a/engine/sw/r_shared.h b/engine/sw/r_shared.h new file mode 100644 index 000000000..5f1504c99 --- /dev/null +++ b/engine/sw/r_shared.h @@ -0,0 +1,155 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifdef SWQUAKE +// r_shared.h: general refresh-related stuff shared between the refresh and the +// driver + +// FIXME: clean up and move into d_iface.h + +#ifndef _R_SHARED_H_ +#define _R_SHARED_H_ + +#define MAXVERTS 16 // max points in a surface polygon +#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate + // polygon (while processing) +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define MAXHEIGHT 1024 +#define MAXWIDTH 1280 + +#define INFINITE_DISTANCE 0x10000 // distance that's always guaranteed to + // be farther away than anything in + // the scene + +//=================================================================== + +extern void R_DrawLine (polyvert_t *polyvert0, polyvert_t *polyvert1); + +extern int cachewidth; +extern int cacheheight; +extern pixel_t *cacheblock; +extern int screenwidth; + +extern float pixelAspect; + +extern int r_drawnpolycount; + +extern cvar_t r_clearcolor; +#define SINTABLESIZE (MAXWIDTH+CYCLE) +extern int sintable[SINTABLESIZE]; +extern int intsintable[SINTABLESIZE]; + +extern vec3_t vup, base_vup; +extern vec3_t vpn, base_vpn; +extern vec3_t vright, base_vright; +extern entity_t *currententity; + +#define NUMSTACKEDGES 2000 +#define MINEDGES NUMSTACKEDGES +#define NUMSTACKSURFACES 1000 +#define MINSURFACES NUMSTACKSURFACES +#define MAXSPANS 3000 + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct espan_s +{ + int u, v, count; + struct espan_s *pnext; +} espan_t; + +// FIXME: compress, make a union if that will help +// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte +typedef struct surf_s +{ + struct surf_s *next; // active surface stack in r_edge.c + struct surf_s *prev; // used in r_edge.c for active surf stack + struct espan_s *spans; // pointer to linked list of spans to draw + int key; // sorting key (BSP order) + int last_u; // set during tracing + int spanstate; // 0 = not in span + // 1 = in span + // -1 = in inverted span (end before + // start) + int flags; // currentface flags + void *data; // associated data like msurface_t + entity_t *entity; + float nearzi; // nearest 1/z on surface, for mipmapping + qboolean insubmodel; + float d_ziorigin, d_zistepu, d_zistepv; + + int pad[2]; // to 64 bytes +} surf_t; + +extern surf_t *surfaces, *surface_p, *surf_max; + +// surfaces are generated in back to front order by the bsp, so if a surf +// pointer is greater than another one, it should be drawn in front +// surfaces[1] is the background, and is used as the active surface stack. +// surfaces[0] is a dummy, because index 0 is used to indicate no surface +// attached to an edge_t + +//=================================================================== + +extern vec3_t sxformaxis[4]; // s axis transformed into viewspace +extern vec3_t txformaxis[4]; // t axis transformed into viewspac + +extern vec3_t modelorg, base_modelorg; + +extern float xcenter, ycenter; +extern float xscale, yscale; +extern float xscaleinv, yscaleinv; +extern float xscaleshrink, yscaleshrink; + +extern int d_lightstylevalue[256]; // 8.8 frac of base light value + +extern void TransformVector (vec3_t in, vec3_t out); +extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, + fixed8_t endvertu, fixed8_t endvertv); + +extern int r_skymade; +extern void R_MakeSky (void); + +extern int ubasestep, errorterm, erroradjustup, erroradjustdown; + +// flags in finalvert_t.flags +#define ALIAS_LEFT_CLIP 0x0001 +#define ALIAS_TOP_CLIP 0x0002 +#define ALIAS_RIGHT_CLIP 0x0004 +#define ALIAS_BOTTOM_CLIP 0x0008 +#define ALIAS_Z_CLIP 0x0010 +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define ALIAS_ONSEAM 0x0020 // also defined in modelgen.h; + // must be kept in sync +#define ALIAS_XY_CLIP_MASK 0x000F + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct edge_s +{ + fixed16_t u; + fixed16_t u_step; + struct edge_s *prev, *next; + unsigned short surfs[2]; + struct edge_s *nextremove; + float nearzi; + medge_t *owner; +} edge_t; + +#endif // _R_SHARED_H_ + +#endif // SWQUAKE diff --git a/engine/sw/r_sky.c b/engine/sw/r_sky.c new file mode 100644 index 000000000..ce8c038d0 --- /dev/null +++ b/engine/sw/r_sky.c @@ -0,0 +1,280 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_sky.c + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + + +int iskyspeed = 8; +int iskyspeed2 = 2; +float skyspeed, skyspeed2; + +float skytime; + +qbyte *r_skysource; + +int r_skymade; +int r_skydirect; // not used? + + +// TODO: clean up these routines + +qbyte bottomsky[128*131]; +qbyte bottommask[128*131]; +qbyte newsky[128*256]; // newsky and topsky both pack in here, 128 bytes + // of newsky on the left of each scan, 128 bytes + // of topsky on the right, because the low-level + // drawers need 256-qbyte scan widths + + +/* +============= +R_InitSky + +A sky texture is 256*128, with the right side being a masked overlay +============== +*/ +void SWR_InitSky (texture_t *mt) +{ + int i, j; + qbyte *src; + + src = (qbyte *)mt + mt->offsets[0]; + + for (i=0 ; i<128 ; i++) + { + for (j=0 ; j<128 ; j++) + { + newsky[(i*256) + j + 128] = src[i*256 + j + 128]; + } + } + + for (i=0 ; i<128 ; i++) + { + for (j=0 ; j<131 ; j++) + { + if (src[i*256 + (j & 0x7F)]) + { + bottomsky[(i*131) + j] = src[i*256 + (j & 0x7F)]; + bottommask[(i*131) + j] = 0; + } + else + { + bottomsky[(i*131) + j] = 0; + bottommask[(i*131) + j] = 0xff; + } + } + } + + r_skysource = newsky; +} + + +/* +================= +R_MakeSky +================= +*/ +void R_MakeSky (void) +{ + int x, y; + int ofs, baseofs; + int xshift, yshift; + unsigned *pnewsky; + static int xlast = -1, ylast = -1; + + xshift = skytime*skyspeed; + yshift = skytime*skyspeed; + + if ((xshift == xlast) && (yshift == ylast)) + return; + + xlast = xshift; + ylast = yshift; + + pnewsky = (unsigned *)&newsky[0]; + + for (y=0 ; ydist; + pclipnormal = pclipplane->normal; + +// calc dists + if (clip_current) + { + in = clip_verts[1][0]; + outstep = clip_verts[0][0]; + clip_current = 0; + } + else + { + in = clip_verts[0][0]; + outstep = clip_verts[1][0]; + clip_current = 1; + } + + instep = in; + for (i=0 ; i= 0) + { + Q_memcpy (outstep, instep, sizeof (vec5_t)); + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + if (dists[i] == 0 || dists[i+1] == 0) + continue; + + if ( (dists[i] > 0) == (dists[i+1] > 0) ) + continue; + + // split it into a new vertex + frac = dists[i] / (dists[i] - dists[i+1]); + + vert2 = instep + sizeof (vec5_t) / sizeof (float); + + outstep[0] = instep[0] + frac*(vert2[0] - instep[0]); + outstep[1] = instep[1] + frac*(vert2[1] - instep[1]); + outstep[2] = instep[2] + frac*(vert2[2] - instep[2]); + outstep[3] = instep[3] + frac*(vert2[3] - instep[3]); + outstep[4] = instep[4] + frac*(vert2[4] - instep[4]); + + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + return outcount; +} + + +/* +================ +R_SetupAndDrawSprite +================ +*/ +void R_SetupAndDrawSprite () +{ + int i, nump; + float dot, scale, *pv; + vec5_t *pverts; + vec3_t left, up, right, down, transformed, local; + emitpoint_t outverts[MAXWORKINGVERTS+1], *pout; + + dot = DotProduct (r_spritedesc.vpn, modelorg); + +// backface cull + if (dot >= 0) + return; + +// build the sprite poster in worldspace + VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right); + VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up); + VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left); + VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down); + + pverts = clip_verts[0]; + + pverts[0][0] = r_entorigin[0] + up[0] + left[0]; + pverts[0][1] = r_entorigin[1] + up[1] + left[1]; + pverts[0][2] = r_entorigin[2] + up[2] + left[2]; + pverts[0][3] = 0; + pverts[0][4] = 0; + + pverts[1][0] = r_entorigin[0] + up[0] + right[0]; + pverts[1][1] = r_entorigin[1] + up[1] + right[1]; + pverts[1][2] = r_entorigin[2] + up[2] + right[2]; + pverts[1][3] = sprite_width; + pverts[1][4] = 0; + + pverts[2][0] = r_entorigin[0] + down[0] + right[0]; + pverts[2][1] = r_entorigin[1] + down[1] + right[1]; + pverts[2][2] = r_entorigin[2] + down[2] + right[2]; + pverts[2][3] = sprite_width; + pverts[2][4] = sprite_height; + + pverts[3][0] = r_entorigin[0] + down[0] + left[0]; + pverts[3][1] = r_entorigin[1] + down[1] + left[1]; + pverts[3][2] = r_entorigin[2] + down[2] + left[2]; + pverts[3][3] = 0; + pverts[3][4] = sprite_height; + +// clip to the frustum in worldspace + nump = 4; + clip_current = 0; + + for (i=0 ; i<4 ; i++) + { + nump = R_ClipSpriteFace (nump, &view_clipplanes[i]); + if (nump < 3) + return; + if (nump >= MAXWORKINGVERTS) + Sys_Error("R_SetupAndDrawSprite: too many points"); + } + +// transform vertices into viewspace and project + pv = &clip_verts[clip_current][0][0]; + r_spritedesc.nearzi = -999999; + + for (i=0 ; izi = 1.0 / transformed[2]; + if (pout->zi > r_spritedesc.nearzi) + r_spritedesc.nearzi = pout->zi; + + pout->s = pv[3]; + pout->t = pv[4]; + + scale = xscale * pout->zi; + pout->u = (xcenter + scale * transformed[0]); + + scale = yscale * pout->zi; + pout->v = (ycenter - scale * transformed[1]); + + pv += sizeof (vec5_t) / sizeof (pv); + } + +// draw it + r_spritedesc.nump = nump; + r_spritedesc.pverts = outverts; + D_DrawSprite (); +} + + +/* +================ +R_GetSpriteframe +================ +*/ +mspriteframe_t *R_GetSpriteframe (msprite_t *psprite) +{ + mspritegroup_t *pspritegroup; + mspriteframe_t *pspriteframe; + int i, numframes, frame; + float *pintervals, fullinterval, targettime, time; + + frame = currententity->frame; + + if ((frame >= psprite->numframes) || (frame < 0)) + { + Con_Printf ("R_DrawSprite: no such frame %d\n", frame); + frame = 0; + } + + if (psprite->frames[frame].type == SPR_SINGLE) + { + pspriteframe = psprite->frames[frame].frameptr; + } + else + { + pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; + pintervals = pspritegroup->intervals; + numframes = pspritegroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = cl.time + currententity->syncbase; + + // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by 0 + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + pspriteframe = pspritegroup->frames[i]; + } + + return pspriteframe; +} + + +/* +================ +R_DrawSprite +================ +*/ +void R_DrawSprite (void) +{ + int i; + msprite_t *psprite; + vec3_t tvec; + float dot, angle, sr, cr; + + psprite = currententity->model->cache.data; + + r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); + + sprite_width = r_spritedesc.pspriteframe->width; + sprite_height = r_spritedesc.pspriteframe->height; + +// TODO: make this caller-selectable + if (psprite->type == SPR_FACING_UPRIGHT) + { + // generate the sprite's axes, with vup straight up in worldspace, and + // r_spritedesc.vright perpendicular to modelorg. + // This will not work if the view direction is very close to straight up or + // down, because the cross product will be between two nearly parallel + // vectors and starts to approach an undefined state, so we don't draw if + // the two vectors are less than 1 degree apart + tvec[0] = -modelorg[0]; + tvec[1] = -modelorg[1]; + tvec[2] = -modelorg[2]; + VectorNormalize (tvec); + dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because + // r_spritedesc.vup is 0, 0, 1 + if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 + return; + r_spritedesc.vup[0] = 0; + r_spritedesc.vup[1] = 0; + r_spritedesc.vup[2] = 1; + r_spritedesc.vright[0] = tvec[1]; + // CrossProduct(r_spritedesc.vup, -modelorg, + r_spritedesc.vright[1] = -tvec[0]; + // r_spritedesc.vright) + r_spritedesc.vright[2] = 0; + VectorNormalize (r_spritedesc.vright); + r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; + r_spritedesc.vpn[1] = r_spritedesc.vright[0]; + r_spritedesc.vpn[2] = 0; + // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, + // r_spritedesc.vpn) + } + else if (psprite->type == SPR_VP_PARALLEL) + { + // generate the sprite's axes, completely parallel to the viewplane. There + // are no problem situations, because the sprite is always in the same + // position relative to the viewer + for (i=0 ; i<3 ; i++) + { + r_spritedesc.vup[i] = vup[i]; + r_spritedesc.vright[i] = vright[i]; + r_spritedesc.vpn[i] = vpn[i]; + } + } + else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) + { + // generate the sprite's axes, with vup straight up in worldspace, and + // r_spritedesc.vright parallel to the viewplane. + // This will not work if the view direction is very close to straight up or + // down, because the cross product will be between two nearly parallel + // vectors and starts to approach an undefined state, so we don't draw if + // the two vectors are less than 1 degree apart + dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because + // r_spritedesc.vup is 0, 0, 1 + if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 + return; + r_spritedesc.vup[0] = 0; + r_spritedesc.vup[1] = 0; + r_spritedesc.vup[2] = 1; + r_spritedesc.vright[0] = vpn[1]; + // CrossProduct (r_spritedesc.vup, vpn, + r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright) + r_spritedesc.vright[2] = 0; + VectorNormalize (r_spritedesc.vright); + r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; + r_spritedesc.vpn[1] = r_spritedesc.vright[0]; + r_spritedesc.vpn[2] = 0; + // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, + // r_spritedesc.vpn) + } + else if (psprite->type == SPR_ORIENTED) + { + // generate the sprite's axes, according to the sprite's world orientation + AngleVectors (currententity->angles, r_spritedesc.vpn, + r_spritedesc.vright, 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); + + for (i=0 ; i<3 ; i++) + { + r_spritedesc.vpn[i] = vpn[i]; + r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr; + r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr; + } + } + else + { + Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type); + } + + R_RotateSprite (psprite->beamlength); + + R_SetupAndDrawSprite (); +} + diff --git a/engine/sw/r_surf.c b/engine/sw/r_surf.c new file mode 100644 index 000000000..452c0a65c --- /dev/null +++ b/engine/sw/r_surf.c @@ -0,0 +1,1604 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_surf.c: surface-related refresh code + +#define SWSTAINS + +#include "quakedef.h" +#include "r_local.h" +#ifdef SWSTAINS +#include "d_local.h" +#endif + +drawsurf_t r_drawsurf; + +int lightleft, sourcesstep, blocksize, sourcetstep; +int lightdelta, lightdeltastep; +int lightright, lightleftstep, lightrightstep, blockdivshift; +unsigned blockdivmask; +void *prowdestbase; +unsigned char *pbasesource; +int surfrowbytes; // used by ASM files +unsigned *r_lightptr; +int r_stepback; +int r_lightwidth; +int r_numhblocks, r_numvblocks; +unsigned char *r_source, *r_sourcemax; + +void R_DrawSurfaceBlock8_mip0 (void); +void R_DrawSurfaceBlock8_mip1 (void); +void R_DrawSurfaceBlock8_mip2 (void); +void R_DrawSurfaceBlock8_mip3 (void); +void R_DrawSurfaceBlock16From8 (void); +void R_DrawSurfaceBlock32From8 (void); +void R_DrawSurfaceBlock32From8Lit (void); +void R_DrawSurfaceBlock32From32Lit (void); + +static void (*surfmiptable[4])(void) = { + R_DrawSurfaceBlock8_mip0, + R_DrawSurfaceBlock8_mip1, + R_DrawSurfaceBlock8_mip2, + R_DrawSurfaceBlock8_mip3 +}; + + + +unsigned blocklights[18*18*3]; + + + + + + + +#ifdef SWSTAINS + +extern cvar_t r_stains; +extern cvar_t r_stainfadetime; +extern cvar_t r_stainfadeammount; + +#define BLOCK_WIDTH 128 +#define BLOCK_HEIGHT 128 + +#define MAX_LIGHTMAPS 64 + +int stainmaps[MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT]; //added to lightmap for added (hopefully) speed. +int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH]; + +//radius, x y z, a +void SWR_StainSurf (msurface_t *surf, float *parms) +{ + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + float amm; + mtexinfo_t *tex; + + int *stainbase; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + stainbase = stainmaps + surf->lightmaptexturenum*BLOCK_WIDTH*BLOCK_HEIGHT; + stainbase += (surf->light_t * BLOCK_WIDTH + surf->light_s); + + + + rad = *parms; + dist = DotProduct ((parms+1), surf->plane->normal) - surf->plane->dist; + rad -= fabs(dist); + minlight = 0; + if (rad < minlight) //not hit + return; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = (parms+1)[i] - surf->plane->normal[i]*dist; + } + + 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 td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + { + amm = (rad - dist); + if (stainbase[(s)]>0) + amm *= (255-stainbase[(s)])/255.0; + else + amm *= (255+stainbase[(s)])/255.0; + stainbase[(s)] += amm*parms[4]; + + surf->stained = true; + } + } + stainbase += BLOCK_WIDTH; + } + + if (surf->stained) + { + for (i = 0; i < 4; i++) + if (surf->cachespots[i]) + surf->cachespots[i]->dlight = -1; + } +} + +//combination of R_AddDynamicLights and R_MarkLights +void SWR_Q1BSP_StainNode (mnode_t *node, float *parms) +{ + mplane_t *splitplane; + float dist; + msurface_t *surf; + int i; + + if (node->contents < 0) + return; + + splitplane = node->plane; + dist = DotProduct ((parms+1), splitplane->normal) - splitplane->dist; + + if (dist > (*parms)) + { + SWR_Q1BSP_StainNode (node->children[0], parms); + return; + } + if (dist < (-*parms)) + { + SWR_Q1BSP_StainNode (node->children[1], parms); + return; + } + +// mark the polygons + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags&~(SURF_DRAWTURB|SURF_PLANEBACK)) + continue; + SWR_StainSurf(surf, parms); + } + + SWR_Q1BSP_StainNode (node->children[0], parms); + SWR_Q1BSP_StainNode (node->children[1], parms); +} + +void SWR_AddStain(vec3_t org, float red, float green, float blue, float radius) +{ + physent_t *pe; + int i; + float parms[5]; + if (red != green && red != blue) //sw only does luminance of stain maps + return; //a mix would look wrong. + if (!r_stains.value || !cl.worldmodel) + return; + parms[0] = radius; + parms[1] = org[0]; + parms[2] = org[1]; + parms[3] = org[2]; + parms[4] = (red + green + blue)/3; + + cl.worldmodel->funcs.StainNode(cl.worldmodel->nodes+cl.worldmodel->hulls[0].firstclipnode, parms); + + //now stain bsp models other than world. + + for (i=1 ; i< pmove.numphysent ; i++) //0 is world... + { + pe = &pmove.physents[i]; + if (pe->model && pe->model->surfaces == cl.worldmodel->surfaces) + { + parms[1] = org[0] - pe->origin[0]; + parms[2] = org[1] - pe->origin[1]; + parms[3] = org[2] - pe->origin[2]; + pe->model->funcs.StainNode(pe->model->nodes+pe->model->hulls[0].firstclipnode, parms); + } + } +} + +void SWR_WipeStains(void) +{ + memset(stainmaps, 0, sizeof(stainmaps)); +} + +void SWR_LessenStains(void) +{ + int i, j; + msurface_t *surf; + + int smax, tmax; + int s, t; + int *stain; + int stride; + int ammount; + + static float time; + + if (!r_stains.value || cl.paused) + { + time = 0; + return; + } + + time += host_frametime; + if (time < r_stainfadetime.value) + return; + time-=r_stainfadetime.value; + + ammount = r_stainfadeammount.value; + + surf = cl.worldmodel->surfaces; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->stained) + { + for (j = 0; j < 4; j++) + if (surf->cachespots[j]) + surf->cachespots[j]->dlight = -1; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + stain = stainmaps + surf->lightmaptexturenum*BLOCK_WIDTH*BLOCK_HEIGHT; + stain += (surf->light_t * BLOCK_WIDTH + surf->light_s); + + stride = (BLOCK_WIDTH-smax); + + surf->stained = false; + + for (t = 0 ; tstained=true; + } + else if (*stain > ammount) //positive values reduce to 0 + { + *stain -= ammount; + surf->stained=true; + } + else //close to 0 or 0 already. + *stain = 0; + + stain++; + } + } + } + } +/* + int i; + msurface_t *surf; + + if (rand()&31) + return; + surf = cl.worldmodel->surfaces; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->stained) + { + surf->stained=2; + } + } +*/ +} + + + +// returns a texture number and the position inside it +int SWAllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + int texnum; + + if (!w || !h) + Sys_Error ("AllocBlock: bad size"); + + for (texnum=0 ; texnum= best) + break; + if (allocated[texnum][i+j] > best2) + best2 = allocated[texnum][i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + continue; + + for (i=0 ; iflags & (SURF_DRAWSKY|SURF_DRAWTURB)) + return; + if (surf->texinfo->flags & (TEX_SPECIAL)) + return; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + surf->lightmaptexturenum = SWAllocBlock (smax, tmax, &surf->light_s, &surf->light_t); +} + +void SWR_BuildLightmaps(void) +{ + int i; + msurface_t *surf; + + memset(allocated, 0, sizeof(allocated)); + + SWR_WipeStains(); + + surf = cl.worldmodel->surfaces; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if ( cl.worldmodel->surfaces[i].flags & SURF_DRAWSKY ) + R_EmitSkyEffectTris(cl.worldmodel, &cl.worldmodel->surfaces[i]); + SWR_CreateSurfaceLightmap(surf); + } +} +#endif + +/* +=============== +R_AddDynamicLights +=============== +*/ +void SWR_AddDynamicLights (void) +{ + msurface_t *surf; + int lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + + float a; + + surf = r_drawsurf.surf; + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<plane->normal) - + surf->plane->dist; + rad -= fabs(dist); + minlight = cl_dlights[lnum].minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + a = 256*(cl_dlights[lnum].color[0]*1.5 + cl_dlights[lnum].color[1]*2.95 + cl_dlights[lnum].color[2]*0.55); + + for (i=0 ; i<3 ; i++) + { + impact[i] = cl_dlights[lnum].origin[i] - + surf->plane->normal[i]*dist; + } + + 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 td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + blocklights[t*smax + s] += (rad - dist)*a; + } + } + } +} + +void SWR_AddDynamicLightsRGB (void) +{ + msurface_t *surf; + int lnum; + int sd, td; + float dist, rad, minlight, r, g, b; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + + surf = r_drawsurf.surf; + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<plane->normal) - + surf->plane->dist; + rad -= fabs(dist); + minlight = cl_dlights[lnum].minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = cl_dlights[lnum].origin[i] - + surf->plane->normal[i]*dist; + } + + 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]; + + r = cl_dlights[lnum].color[0]*3*256; + g = cl_dlights[lnum].color[1]*3*256; + b = cl_dlights[lnum].color[2]*3*256; + + for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + { + blocklights[(t*smax + s)*3] += (rad - dist)*r; + blocklights[(t*smax + s)*3+1] += (rad - dist)*g; + blocklights[(t*smax + s)*3+2] += (rad - dist)*b; + } + } + } + } +} +/* +=============== +R_BuildLightMap + +Combine and scale multiple lightmaps into the 8.8 format in blocklights +=============== +*/ +void SWR_BuildLightMap (void) +{ + int smax, tmax; + int t; + int i, size; + qbyte *lightmap; + unsigned scale; + int maps; + msurface_t *surf; + + surf = r_drawsurf.surf; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + lightmap = surf->samples; + + if (/* r_fullbright.value || */ !cl.worldmodel->lightdata) + { + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + scale = r_drawsurf.lightadj[maps]; // 8.8 fraction + for (i=0 ; idlightframe == r_framecount) + SWR_AddDynamicLights (); +#ifdef SWSTAINS + if (surf->stained) + { + int *stain; + int sstride; + int x, y; + int quant; + + stain = stainmaps + surf->lightmaptexturenum*BLOCK_WIDTH*BLOCK_HEIGHT; + stain += (surf->light_t * BLOCK_WIDTH + surf->light_s); + + sstride = BLOCK_WIDTH - smax; + + i=0; + + for (x = 0; x < tmax; x++, stain+=sstride) + { + for (y = 0; y < smax; y++, i++, stain++) + { + quant = (int)blocklights[i]+*stain*128; + if (quant < 0) + quant = 0; + t = (255*256 - (quant)) >> (8 - VID_CBITS); + + if (t < (1 << 6)) + t = (1 << 6); + + blocklights[i] = t; + } + } + return; + } +#endif +// bound, invert, and shift + for (i=0 ; i> (8 - VID_CBITS); + + if (t < (1 << 6)) + t = (1 << 6); + + blocklights[i] = t; + } +} + +void SWR_BuildLightMapRGB (void) +{ + int smax, tmax; + int i, size; + qbyte *lightmap; + unsigned scale; + int maps; + msurface_t *surf; + int r,g,b, cr, cg, cb; + + surf = r_drawsurf.surf; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax*3; + lightmap = surf->samples; + + if (/* r_fullbright.value || */ !cl.worldmodel->lightdata) + { + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + scale = r_drawsurf.lightadj[maps]; // 8.8 fraction + for (i=0 ; idlightframe == r_framecount) + SWR_AddDynamicLightsRGB (); +#ifdef SWSTAINS + if (surf->stained) + { + int *stain; + int sstride; + int x, y; + + stain = stainmaps + surf->lightmaptexturenum*BLOCK_WIDTH*BLOCK_HEIGHT; + stain += (surf->light_t * BLOCK_WIDTH + surf->light_s); + + sstride = BLOCK_WIDTH - smax; + + i=0; + + for (x = 0; x < tmax; x++, stain+=sstride) + { + for (y = 0; y < smax; y++, i+=3, stain++) + { + r = (255*256-(int)blocklights[i]-*stain*128) >> (8 - VID_CBITS); + g = (255*256-(int)blocklights[i+1]-*stain*128) >> (8 - VID_CBITS); + b = (255*256-(int)blocklights[i+2]-*stain*128) >> (8 - VID_CBITS); +#define MINL (1<<6) +#define MAXL ((255*256) >> (8 - VID_CBITS)) + + cr = 0; + cg = 0; + cb = 0; + + if (r < MINL) + { + cg += (MINL-r); + cb += (MINL-r); + r = MINL; + } + if (g < MINL) + { + cr += (MINL-g); + cb += (MINL-g); + g = MINL; + } + if (b < MINL) + { + cg += (MINL-b); + cr += (MINL-b); + b = MINL; + } + + if (cr + r < MINL) + blocklights[i] = MINL; + else if (cr + r > MAXL) + blocklights[i] = MAXL; + else + blocklights[i] = cr+r; + if (cg + g < MINL) + blocklights[i+1] = MINL; + else if (cg + g > MAXL) + blocklights[i+1] = MAXL; + else + blocklights[i+1] = cg+g; + if (cb + b < MINL) + blocklights[i+2] = MINL; + else if (cb + b > MAXL) + blocklights[i+2] = MAXL; + else + blocklights[i+2] = cb+b; + } + } + return; + } +#endif + +// bound, invert, and shift + for (i=0 ; i> (8 - VID_CBITS); + g = (255*256-(int)blocklights[i+1]) >> (8 - VID_CBITS); + b = (255*256-(int)blocklights[i+2]) >> (8 - VID_CBITS); +#define MINL (1<<6) +#define MAXL ((255*256) >> (8 - VID_CBITS)) + + cr = 0; + cg = 0; + cb = 0; + + if (r < MINL) + { + cg += (MINL-r); + cb += (MINL-r); + r = MINL; + } + if (g < MINL) + { + cr += (MINL-g); + cb += (MINL-g); + g = MINL; + } + if (b < MINL) + { + cg += (MINL-b); + cr += (MINL-b); + b = MINL; + } + + if (cr + r < MINL) + blocklights[i] = MINL; + else if (cr + r > MAXL) + blocklights[i] = MAXL; + else + blocklights[i] = cr+r; + if (cg + g < MINL) + blocklights[i+1] = MINL; + else if (cg + g > MAXL) + blocklights[i+1] = MAXL; + else + blocklights[i+1] = cg+g; + if (cb + b < MINL) + blocklights[i+2] = MINL; + else if (cb + b > MAXL) + blocklights[i+2] = MAXL; + else + blocklights[i+2] = cb+b; + } +} + +/* +=============== +R_TextureAnimation + +Returns the proper texture for a given time and base texture +=============== +*/ +texture_t *SWR_TextureAnimation (texture_t *base) +{ + int reletive; + int count; + + if (currententity->frame) + { + if (base->alternate_anims) + base = base->alternate_anims; + } + + if (!base->anim_total) + return base; + + reletive = (int)(cl.time*10) % base->anim_total; + + count = 0; + while (base->anim_min > reletive || base->anim_max <= reletive) + { + base = base->anim_next; + if (!base) + Sys_Error ("R_TextureAnimation: broken cycle"); + if (++count > 100) + Sys_Error ("R_TextureAnimation: infinite cycle"); + } + + return base; +} + + +/* +=============== +R_DrawSurface +=============== +*/ +void R_DrawSurface (void) +{ + unsigned char *basetptr; + int smax, tmax, twidth; + int u; + int soffset, basetoffset, texwidth; + int horzblockstep; + unsigned char *pcolumndest; + void (*pblockdrawer)(void); + texture_t *mt; + +// calculate the lightings + SWR_BuildLightMap (); + + surfrowbytes = r_drawsurf.rowbytes; + + mt = r_drawsurf.texture; + + r_source = (qbyte *)mt + mt->offsets[r_drawsurf.surfmip]; + +// the fractional light values should range from 0 to (VID_GRADES - 1) << 16 +// from a source range of 0 - 255 + + texwidth = mt->width >> r_drawsurf.surfmip; + + blocksize = 16 >> r_drawsurf.surfmip; + blockdivshift = 4 - r_drawsurf.surfmip; + blockdivmask = (1 << blockdivshift) - 1; + + r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1; + + r_numhblocks = r_drawsurf.surfwidth >> blockdivshift; + r_numvblocks = r_drawsurf.surfheight >> blockdivshift; + +//============================== + + if (r_pixbytes == 1 || r_pixbytes == 4) //if we are using 4, textures are stored as 1 and expanded acording to palette + { + pblockdrawer = surfmiptable[r_drawsurf.surfmip]; + // TODO: only needs to be set when there is a display settings change + horzblockstep = blocksize; + } + else + { + pblockdrawer = R_DrawSurfaceBlock16From8; + // TODO: only needs to be set when there is a display settings change + horzblockstep = blocksize << 1; + } + + smax = mt->width >> r_drawsurf.surfmip; + twidth = texwidth; + tmax = mt->height >> r_drawsurf.surfmip; + sourcetstep = texwidth; + r_stepback = tmax * twidth; + + r_sourcemax = r_source + (tmax * smax); + + soffset = r_drawsurf.surf->texturemins[0]; + basetoffset = r_drawsurf.surf->texturemins[1]; + +// << 16 components are to guarantee positive values for % + soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax; + basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) + + (tmax << 16)) % tmax) * twidth)]; + + pcolumndest = r_drawsurf.surfdat; + + for (u=0 ; u= smax) + soffset = 0; + + pcolumndest += horzblockstep; + } +} + +void R_DrawSurface32 (void) +{ + unsigned char *basetptr; + int smax, tmax, twidth; + int u; + int soffset, basetoffset, texwidth; + int horzblockstep; + unsigned char *pcolumndest; + texture_t *mt; + +// calculate the lightings + SWR_BuildLightMapRGB (); + + surfrowbytes = r_drawsurf.rowbytes; + + mt = r_drawsurf.texture; + + r_source = (qbyte *)mt + mt->offsets[r_drawsurf.surfmip]; + +// the fractional light values should range from 0 to (VID_GRADES - 1) << 16 +// from a source range of 0 - 255 + + texwidth = (mt->width*mt->pixbytes) >> r_drawsurf.surfmip; + + blocksize = 16 >> r_drawsurf.surfmip; + blockdivshift = 4 - r_drawsurf.surfmip; + blockdivmask = (1 << blockdivshift) - 1; + + r_lightwidth = ((r_drawsurf.surf->extents[0]>>4)+1)*3; + + r_numhblocks = r_drawsurf.surfwidth >> blockdivshift; + r_numvblocks = r_drawsurf.surfheight >> blockdivshift; + +//============================== + + horzblockstep = blocksize*4; + + smax = (mt->width*mt->pixbytes) >> r_drawsurf.surfmip; + twidth = texwidth; + tmax = mt->height >> r_drawsurf.surfmip; + sourcetstep = texwidth; + r_stepback = tmax * twidth; + + r_sourcemax = r_source + (tmax * smax); + + soffset = r_drawsurf.surf->texturemins[0]*mt->pixbytes; + basetoffset = r_drawsurf.surf->texturemins[1]; + +// << 16 components are to guarantee positive values for % + basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) + + (tmax << 16)) % tmax) * twidth)]; + soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % (smax); + + pcolumndest = r_drawsurf.surfdat; + + if (mt->pixbytes == 4) + { + for (u=0 ; u= smax) + soffset = 0; + + pcolumndest += horzblockstep; + } + } + else + { + for (u=0 ; u= smax) + soffset = 0; + + pcolumndest += horzblockstep; + } + } +} + +//============================================================================= + +#if !id386 + +/* +================ +R_DrawSurfaceBlock8_mip0 +================ +*/ +void R_DrawSurfaceBlock8_mip0 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 4; + lightrightstep = (r_lightptr[1] - lightright) >> 4; + + for (i=0 ; i<16 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 4; + + light = lightright; + + for (b=15; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + +/* +================ +R_DrawSurfaceBlock8_mip1 +================ +*/ +void R_DrawSurfaceBlock8_mip1 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 3; + lightrightstep = (r_lightptr[1] - lightright) >> 3; + + for (i=0 ; i<8 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 3; + + light = lightright; + + for (b=7; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + +/* +================ +R_DrawSurfaceBlock8_mip2 +================ +*/ +void R_DrawSurfaceBlock8_mip2 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 2; + lightrightstep = (r_lightptr[1] - lightright) >> 2; + + for (i=0 ; i<4 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 2; + + light = lightright; + + for (b=3; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + +/* +================ +R_DrawSurfaceBlock8_mip3 +================ +*/ +void R_DrawSurfaceBlock8_mip3 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 1; + lightrightstep = (r_lightptr[1] - lightright) >> 1; + + for (i=0 ; i<2 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 1; + + light = lightright; + + for (b=1; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + +#endif + +//add lits? +void R_DrawSurfaceBlock16From8 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource; + unsigned short *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> blockdivshift; + lightrightstep = (r_lightptr[1] - lightright) >> blockdivshift; + + for (i=0 ; i> blockdivshift; + + light = lightright; + + for (b=blocksize-1; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = vid.colormap16[(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + + +//8 bit disk texture to 32 bit mem cache +void R_DrawSurfaceBlock32From8 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource; + unsigned int *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> blockdivshift; + lightrightstep = (r_lightptr[1] - lightright) >> blockdivshift; + + for (i=0 ; i> blockdivshift; + + light = lightright; + + for (b=blocksize-1; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = d_8to32table[((unsigned char *)vid.colormap)[(light & 0xFF00) + pix]]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + +//8 bit disk texture to 32 bit mem cache, with added rgb lighting +void R_DrawSurfaceBlock32From8Lit (void) +{ +//#define SMOOTHLIGHT + int v, i, b; + int lightstepr; + int lightleftr, lightrightr, lightleftstepr, lightrightstepr; + int lightstepg; + int lightleftg, lightrightg, lightleftstepg, lightrightstepg; + int lightstepb; + int lightleftb, lightrightb, lightleftstepb, lightrightstepb; + unsigned char pix, *psource; + unsigned int lightb, lightg, lightr; +#ifdef SMOOTHLIGHT + unsigned char *prowdest; +#else + unsigned int *prowdest; +#endif + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> blockdivshift; + lightrightstepr = (r_lightptr[3] - lightrightr) >> blockdivshift; + lightleftstepg = (r_lightptr[0+1] - lightleftg) >> blockdivshift; + lightrightstepg = (r_lightptr[3+1] - lightrightg) >> blockdivshift; + lightleftstepb = (r_lightptr[0+2] - lightleftb) >> blockdivshift; + lightrightstepb = (r_lightptr[3+2] - lightrightb) >> blockdivshift; + for (i=0 ; i> blockdivshift; + lightstepg = (lightleftg - lightrightg) >> blockdivshift; + lightstepb = (lightleftb - lightrightb) >> blockdivshift; + + lightr = lightrightr; + lightg = lightrightg; + lightb = lightrightb; + + for (b=blocksize-1; b>=0; b--) + { + pix = psource[b]; +#ifndef SMOOTHLIGHT +#if 1 + prowdest[b] = (d_8to32table[((unsigned char *)vid.colormap)[(lightb & 0xFF00) + pix]]&0xff) | + (d_8to32table[((unsigned char *)vid.colormap)[(lightg & 0xFF00) + pix]]&0xff00) | + (d_8to32table[((unsigned char *)vid.colormap)[(lightr & 0xFF00) + pix]]&0xff0000); +#else + prowdest[b] = (d_8to32table[((unsigned char *)vid.colormap)[(lightb & 0xFF00) + 15]]&0xff) | + (d_8to32table[((unsigned char *)vid.colormap)[(lightg & 0xFF00) + 15]]&0xff00) | + (d_8to32table[((unsigned char *)vid.colormap)[(lightr & 0xFF00) + 15]]&0xff0000); +#endif +#else +#if 1 + prowdest[b*4] = (((d_8to32table[pix]&0x0000ff) ) * (0x3f00-(lightb& 0x3fff)))>>13; + prowdest[b*4+1] = (((d_8to32table[pix]&0x00ff00)>>8 ) * (0x3f00-(lightg& 0x3fff)))>>13; + prowdest[b*4+2] = (((d_8to32table[pix]&0xff0000)>>16) * (0x3f00-(lightr& 0x3fff)))>>13; +#else + prowdest[b*4] = (((d_8to32table[pix]&0x0000ff) ) * (0x4000-(lightb& 0x4000)))>>15; + prowdest[b*4+1] = ((255) * (0xFFFF-(lightg& 0xFF00)))>>14; + prowdest[b*4+2] = ((255) * (0xFFFF-(lightr& 0xFF00)))>>14; +#endif +#endif + lightr += lightstepr; + lightg += lightstepg; + lightb += lightstepb; + } + + psource += sourcetstep; + lightrightr += lightrightstepr; + lightleftr += lightleftstepr; + lightrightg += lightrightstepg; + lightleftg += lightleftstepg; + lightrightb += lightrightstepb; + lightleftb += lightleftstepb; +#ifdef SMOOTHLIGHT + prowdest += surfrowbytes*4; +#else + prowdest += surfrowbytes; +#endif + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + +extern qbyte gammatable[]; +//32 bit disk texture to 32 bit mem cache, with added rgb lighting +void R_DrawSurfaceBlock32From32Lit (void) +{ + int v, i, b; + int lightstepr, lightr; + int lightleftr, lightrightr, lightleftstepr, lightrightstepr; + int lightstepg, lightg; + int lightleftg, lightrightg, lightleftstepg, lightrightstepg; + int lightstepb, lightb; + int lightleftb, lightrightb, lightleftstepb, lightrightstepb; + qbyte pix, *psource; + qbyte *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> blockdivshift; + lightrightstepr = (r_lightptr[3] - lightrightr) >> blockdivshift; + lightleftstepg = (r_lightptr[0+1] - lightleftg) >> blockdivshift; + lightrightstepg = (r_lightptr[3+1] - lightrightg) >> blockdivshift; + lightleftstepb = (r_lightptr[0+2] - lightleftb) >> blockdivshift; + lightrightstepb = (r_lightptr[3+2] - lightrightb) >> blockdivshift; + for (i=0 ; i> blockdivshift; + lightstepg = (lightleftg - lightrightg) >> blockdivshift; + lightstepb = (lightleftb - lightrightb) >> blockdivshift; + + lightr = lightrightr; + lightg = lightrightg; + lightb = lightrightb; + + for (b=(blocksize-1)<<2; b>=0; b-=4) + { + pix = psource[b+2]; + prowdest[b+0] = pix; + + pix = psource[b+1]; + prowdest[b+1] = pix; + + pix = psource[b+0]; + prowdest[b+2] = pix; + + prowdest[b+0] = gammatable[((int)psource[b+2]*(256-((lightb&0xff00)>>6))) / 256]; + prowdest[b+1] = gammatable[((int)psource[b+1]*(256-((lightg&0xff00)>>6))) / 256]; + prowdest[b+2] = gammatable[((int)psource[b+0]*(256-((lightr&0xff00)>>6))) / 256]; + prowdest[b+3] = psource[b+3]; + + lightr += lightstepr; + lightg += lightstepg; + lightb += lightstepb; + } + + psource += sourcetstep; + lightrightr += lightrightstepr; + lightleftr += lightleftstepr; + lightrightg += lightrightstepg; + lightleftg += lightleftstepg; + lightrightb += lightrightstepb; + lightleftb += lightleftstepb; + prowdest += surfrowbytes<<2; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + +//============================================================================ + +/* +================ +R_GenTurbTile +================ +*/ +void R_GenTurbTile (pixel_t *pbasetex, void *pdest) +{ + int *turb; + int i, j, s, t; + qbyte *pd; + + turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); + pd = (qbyte *)pdest; + + for (i=0 ; i> 16) & 63; + t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63; + *pd++ = *(pbasetex + (t<<6) + s); + } + } +} + + +/* +================ +R_GenTurbTile16 +================ +*/ +void R_GenTurbTile16 (pixel_t *pbasetex, void *pdest) +{ + int *turb; + int i, j, s, t; + unsigned short *pd; + + turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); + pd = (unsigned short *)pdest; + + for (i=0 ; i> 16) & 63; + t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63; + *pd++ = d_8to16table[*(pbasetex + (t<<6) + s)]; + } + } +} + + +/* +================ +R_GenTile +================ +*/ +void R_GenTile (msurface_t *psurf, void *pdest) +{ + if (psurf->flags & SURF_DRAWTURB) + { + if (r_pixbytes == 1) + { + R_GenTurbTile ((pixel_t *) + ((qbyte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest); + } + else + { + R_GenTurbTile16 ((pixel_t *) + ((qbyte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest); + } + } + else if (psurf->flags & SURF_DRAWSKY) + { + if (r_pixbytes == 1) + { + R_GenSkyTile (pdest); + } + else + { + R_GenSkyTile16 (pdest); + } + } + else + { + Sys_Error ("Unknown tile type"); + } +} + diff --git a/engine/sw/r_vars.c b/engine/sw/r_vars.c new file mode 100644 index 000000000..eb41290e9 --- /dev/null +++ b/engine/sw/r_vars.c @@ -0,0 +1,39 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_vars.c: global refresh variables + +#include "quakedef.h" + +#if !id386 + +// all global and static refresh variables are collected in a contiguous block +// to avoid cache conflicts. + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: make into one big structure, like cl or sv +// FIXME: do separately for refresh engine and driver + +int r_bmodelactive; + +#endif // !id386 + diff --git a/engine/sw/r_varsa.s b/engine/sw/r_varsa.s new file mode 100644 index 000000000..2c3f9e541 --- /dev/null +++ b/engine/sw/r_varsa.s @@ -0,0 +1,64 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// r_varsa.s +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" +#include "d_ifacea.h" + +#if id386 + + .data + +//------------------------------------------------------- +// ASM-only variables +//------------------------------------------------------- +.globl float_1, float_particle_z_clip, float_point5 +.globl float_minus_1, float_0 +float_0: .single 0.0 +float_1: .single 1.0 +float_minus_1: .single -1.0 +float_particle_z_clip: .single PARTICLE_Z_CLIP +float_point5: .single 0.5 + +.globl fp_16, fp_64k, fp_1m, fp_64kx64k +.globl fp_1m_minus_1 +.globl fp_8 +fp_1m: .single 1048576.0 +fp_1m_minus_1: .single 1048575.0 +fp_64k: .single 65536.0 +fp_8: .single 8.0 +fp_16: .single 16.0 +fp_64kx64k: .long 0x4f000000 // (float)0x8000*0x10000 + + +.globl FloatZero, Float2ToThe31nd, FloatMinus2ToThe31nd +FloatZero: .long 0 +Float2ToThe31nd: .long 0x4f000000 +FloatMinus2ToThe31nd: .long 0xcf000000 + +.globl C(r_bmodelactive) +C(r_bmodelactive): .long 0 + +#endif // id386 + diff --git a/engine/sw/surf16.s b/engine/sw/surf16.s new file mode 100644 index 000000000..c0812a3b3 --- /dev/null +++ b/engine/sw/surf16.s @@ -0,0 +1,172 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// surf16.s +// x86 assembly-language 16 bpp surface block drawing code. +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" + +#if id386 + +//---------------------------------------------------------------------- +// Surface block drawer +//---------------------------------------------------------------------- + + .data + +k: .long 0 +loopentry: .long 0 + + .align 4 +blockjumptable16: + .long LEnter2_16 + .long LEnter4_16 + .long 0, LEnter8_16 + .long 0, 0, 0, LEnter16_16 + + + .text + + .align 4 +.globl C(R_Surf16Start) +C(R_Surf16Start): + + .align 4 +.globl C(R_DrawSurfaceBlock16) +C(R_DrawSurfaceBlock16): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + + movl C(blocksize),%eax + movl C(prowdestbase),%edi + movl C(pbasesource),%esi + movl C(sourcesstep),%ebx + movl blockjumptable16-4(,%eax,2),%ecx + movl %eax,k + movl %ecx,loopentry + movl C(lightleft),%edx + movl C(lightright),%ebp + +Lblockloop16: + + subl %edx,%ebp + movb C(blockdivshift),%cl + sarl %cl,%ebp + jns Lp1_16 + testl C(blockdivmask),%ebp + jz Lp1_16 + incl %ebp +Lp1_16: + + subl %eax,%eax + subl %ecx,%ecx // high words must be 0 in loop for addressing + + jmp *loopentry + + .align 4 + +#include "block16.h" + + movl C(pbasesource),%esi + movl C(lightleft),%edx + movl C(lightright),%ebp + movl C(sourcetstep),%eax + movl C(lightrightstep),%ecx + movl C(prowdestbase),%edi + + addl %eax,%esi + addl %ecx,%ebp + + movl C(lightleftstep),%eax + movl C(surfrowbytes),%ecx + + addl %eax,%edx + addl %ecx,%edi + + movl %esi,C(pbasesource) + movl %ebp,C(lightright) + movl k,%eax + movl %edx,C(lightleft) + decl %eax + movl %edi,C(prowdestbase) + movl %eax,k + jnz Lblockloop16 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +.globl C(R_Surf16End) +C(R_Surf16End): + +//---------------------------------------------------------------------- +// Code patching routines +//---------------------------------------------------------------------- + .data + + .align 4 +LPatchTable16: + .long LBPatch0-4 + .long LBPatch1-4 + .long LBPatch2-4 + .long LBPatch3-4 + .long LBPatch4-4 + .long LBPatch5-4 + .long LBPatch6-4 + .long LBPatch7-4 + .long LBPatch8-4 + .long LBPatch9-4 + .long LBPatch10-4 + .long LBPatch11-4 + .long LBPatch12-4 + .long LBPatch13-4 + .long LBPatch14-4 + .long LBPatch15-4 + + .text + + .align 4 +.globl C(R_Surf16Patch) +C(R_Surf16Patch): + pushl %ebx + + movl C(colormap),%eax + movl $LPatchTable16,%ebx + movl $16,%ecx +LPatchLoop16: + movl (%ebx),%edx + addl $4,%ebx + movl %eax,(%edx) + decl %ecx + jnz LPatchLoop16 + + popl %ebx + + ret + + +#endif // id386 diff --git a/engine/sw/surf8.s b/engine/sw/surf8.s new file mode 100644 index 000000000..a079f1d00 --- /dev/null +++ b/engine/sw/surf8.s @@ -0,0 +1,783 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// surf8.s +// x86 assembly-language 8 bpp surface block drawing code. +// + +#include "asm_i386.h" +#include "quakeasm.h" +#include "asm_draw.h" + +#if id386 + + .data + +sb_v: .long 0 + + .text + + .align 4 +.globl C(R_Surf8Start) +C(R_Surf8Start): + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 0 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip0) +C(R_DrawSurfaceBlock8_mip0): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $4,%ecx + orl $0xF0000000,%ebp + + sarl $4,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + andl $0xFFFFF,%ebx + + orl $0xF0000000,%ebx + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + +Lblockloop8_mip0: + movl %ebp,C(lightdelta) + movb 14(%esi),%cl + + sarl $4,%ebp + movb %dh,%bh + + movb 15(%esi),%bl + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch0: + movb 13(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch1: + movb 12(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch2: + + movb 11(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch3: + + movb 10(%esi),%cl + movl %eax,12(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch4: + movb 9(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch5: + movb 8(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch6: + + movb 7(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch7: + + movb 6(%esi),%cl + movl %eax,8(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch8: + movb 5(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch9: + movb 4(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch10: + + movb 3(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch11: + + movb 2(%esi),%cl + movl %eax,4(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch12: + movb 1(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch13: + movb (%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + movb 0x12345678(%ebx),%ah +LBPatch14: + movl C(lightright),%edx + + movb 0x12345678(%ecx),%al +LBPatch15: + movl C(lightdelta),%ebp + + movl %eax,(%edi) + + addl C(sourcetstep),%esi + addl C(surfrowbytes),%edi + + addl C(lightrightstep),%edx + addl C(lightdeltastep),%ebp + + movl %edx,C(lightright) + jc Lblockloop8_mip0 + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip0 + subl C(r_stepback),%esi +LSkip_mip0: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip0 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 1 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip1) +C(R_DrawSurfaceBlock8_mip1): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $3,%ecx + orl $0x70000000,%ebp + + sarl $3,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + andl $0xFFFFF,%ebx + + orl $0xF0000000,%ebx + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + +Lblockloop8_mip1: + movl %ebp,C(lightdelta) + movb 6(%esi),%cl + + sarl $3,%ebp + movb %dh,%bh + + movb 7(%esi),%bl + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch22: + movb 5(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch23: + movb 4(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch24: + + movb 3(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch25: + + movb 2(%esi),%cl + movl %eax,4(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch26: + movb 1(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch27: + movb (%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + movb 0x12345678(%ebx),%ah +LBPatch28: + movl C(lightright),%edx + + movb 0x12345678(%ecx),%al +LBPatch29: + movl C(lightdelta),%ebp + + movl %eax,(%edi) + movl C(sourcetstep),%eax + + addl %eax,%esi + movl C(surfrowbytes),%eax + + addl %eax,%edi + movl C(lightrightstep),%eax + + addl %eax,%edx + movl C(lightdeltastep),%eax + + addl %eax,%ebp + movl %edx,C(lightright) + + jc Lblockloop8_mip1 + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip1 + subl C(r_stepback),%esi +LSkip_mip1: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip1 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 2 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip2) +C(R_DrawSurfaceBlock8_mip2): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $2,%ecx + orl $0x30000000,%ebp + + sarl $2,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + + andl $0xFFFFF,%ebx + + orl $0xF0000000,%ebx + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + +Lblockloop8_mip2: + movl %ebp,C(lightdelta) + movb 2(%esi),%cl + + sarl $2,%ebp + movb %dh,%bh + + movb 3(%esi),%bl + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch18: + movb 1(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch19: + movb (%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + movb 0x12345678(%ebx),%ah +LBPatch20: + movl C(lightright),%edx + + movb 0x12345678(%ecx),%al +LBPatch21: + movl C(lightdelta),%ebp + + movl %eax,(%edi) + movl C(sourcetstep),%eax + + addl %eax,%esi + movl C(surfrowbytes),%eax + + addl %eax,%edi + movl C(lightrightstep),%eax + + addl %eax,%edx + movl C(lightdeltastep),%eax + + addl %eax,%ebp + movl %edx,C(lightright) + + jc Lblockloop8_mip2 + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip2 + subl C(r_stepback),%esi +LSkip_mip2: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip2 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 3 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip3) +C(R_DrawSurfaceBlock8_mip3): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $1,%ecx + + sarl $1,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + andl $0xFFFFF,%ebx + + sarl $1,%ebp + orl $0xF0000000,%ebx + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + + movb 1(%esi),%bl + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movb %dh,%bh + movb (%esi),%cl + + addl %ebp,%edx + movb %dh,%ch + + movb 0x12345678(%ebx),%al +LBPatch16: + movl C(lightright),%edx + + movb %al,1(%edi) + movb 0x12345678(%ecx),%al +LBPatch17: + + movb %al,(%edi) + movl C(sourcetstep),%eax + + addl %eax,%esi + movl C(surfrowbytes),%eax + + addl %eax,%edi + movl C(lightdeltastep),%eax + + movl C(lightdelta),%ebp + movb (%esi),%cl + + addl %eax,%ebp + movl C(lightrightstep),%eax + + sarl $1,%ebp + addl %eax,%edx + + movb %dh,%bh + movb 1(%esi),%bl + + addl %ebp,%edx + movb %dh,%ch + + movb 0x12345678(%ebx),%al +LBPatch30: + movl C(sourcetstep),%edx + + movb %al,1(%edi) + movb 0x12345678(%ecx),%al +LBPatch31: + + movb %al,(%edi) + movl C(surfrowbytes),%ebp + + addl %edx,%esi + addl %ebp,%edi + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip3 + subl C(r_stepback),%esi +LSkip_mip3: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip3 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +.globl C(R_Surf8End) +C(R_Surf8End): + +//---------------------------------------------------------------------- +// Code patching routines +//---------------------------------------------------------------------- + .data + + .align 4 +LPatchTable8: + .long LBPatch0-4 + .long LBPatch1-4 + .long LBPatch2-4 + .long LBPatch3-4 + .long LBPatch4-4 + .long LBPatch5-4 + .long LBPatch6-4 + .long LBPatch7-4 + .long LBPatch8-4 + .long LBPatch9-4 + .long LBPatch10-4 + .long LBPatch11-4 + .long LBPatch12-4 + .long LBPatch13-4 + .long LBPatch14-4 + .long LBPatch15-4 + .long LBPatch16-4 + .long LBPatch17-4 + .long LBPatch18-4 + .long LBPatch19-4 + .long LBPatch20-4 + .long LBPatch21-4 + .long LBPatch22-4 + .long LBPatch23-4 + .long LBPatch24-4 + .long LBPatch25-4 + .long LBPatch26-4 + .long LBPatch27-4 + .long LBPatch28-4 + .long LBPatch29-4 + .long LBPatch30-4 + .long LBPatch31-4 + + .text + + .align 4 +.globl C(R_Surf8Patch) +C(R_Surf8Patch): + pushl %ebx + + movl C(colormap),%eax + movl $LPatchTable8,%ebx + movl $32,%ecx +LPatchLoop8: + movl (%ebx),%edx + addl $4,%ebx + movl %eax,(%edx) + decl %ecx + jnz LPatchLoop8 + + popl %ebx + + ret + +#endif // id386 diff --git a/engine/sw/sw_draw.c b/engine/sw/sw_draw.c new file mode 100644 index 000000000..2c1705c76 --- /dev/null +++ b/engine/sw/sw_draw.c @@ -0,0 +1,2301 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// draw.c -- this is the only file outside the refresh that touches the +// vid buffer + +#include "quakedef.h" +#include "glquake.h" //with sw refresh??? +#include "d_local.h" //trans stuff + +extern unsigned int *d_8to32table; + +typedef struct { + vrect_t rect; + int width; + int height; + qbyte *ptexbytes; + int rowbytes; +} rectdesc_t; + +static rectdesc_t r_rectdesc; + +qbyte *draw_chars; // 8*8 graphic characters +qpic_t *draw_disc; +qpic_t *draw_backtile; + +//============================================================================= +/* Support Routines */ + +typedef struct cachepic_s +{ + char name[MAX_QPATH]; + cache_user_t cache; +} swcachepic_t; + +#define MAX_CACHED_PICS 1024 +swcachepic_t swmenu_cachepics[MAX_CACHED_PICS]; +int swmenu_numcachepics; + +/* +================ +Draw_CachePic +================ +*/ +qpic_t *SWDraw_SafeCachePic (char *extpath) +{ + swcachepic_t *pic; + int i; + qpic_t *dat; + char alternatename[MAX_QPATH]; + char path[MAX_QPATH]; + Q_strncpyz(path, extpath, sizeof(path)); + COM_StripExtension(path, path); + + for (pic=swmenu_cachepics, i=0 ; iname)) + break; + + if (i == swmenu_numcachepics) + { + if (swmenu_numcachepics == MAX_CACHED_PICS) + Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); + swmenu_numcachepics++; + strcpy (pic->name, path); + } + + dat = Cache_Check (&pic->cache); + + if (dat) + return dat; + + { + qbyte *file, *image; + int width; + int height; + _snprintf(alternatename, MAX_QPATH-1,"%s.pcx", path); + + file = COM_LoadMallocFile(alternatename); + if (file) + { + image = ReadPCXFile(file, com_filesize, &width, &height); + BZ_Free(file); + if (image) + { + dat = Cache_Alloc(&pic->cache, sizeof(qpic_t) + width*height, path); + dat->width = width; + dat->height = height; + for (i = 0; i < width*height; i++) + { + if (image[i*4+3] < 64) // 25% threshhold + dat->data[i] = 255; + else + dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]); + } + + BZ_Free(image); + + return dat; + } + } + } +#ifdef AVAIL_JPEGLIB + { + qbyte *file, *image; + int width; + int height; + _snprintf(alternatename, MAX_QPATH-1,"%s.jpg", path); + + file = COM_LoadMallocFile(alternatename); + if (file) + { + image = ReadJPEGFile(file, com_filesize, &width, &height); + BZ_Free(file); + if (image) + { + dat = Cache_Alloc(&pic->cache, sizeof(qpic_t) + width*height, path); + dat->width = width; + dat->height = height; + for (i = 0; i < width*height; i++) + { + if (image[i*4+3] < 64) // 25% threshhold + dat->data[i] = 255; + else + dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]); + } + + BZ_Free(image); + + return dat; + } + } + } +#endif + { + qbyte *file, *image; + int width; + int height; + _snprintf(alternatename, MAX_QPATH-1,"%s.tga", path); + + file = COM_LoadMallocFile(alternatename); + if (file) + { + image = ReadTargaFile (file, com_filesize, &width, &height, 0); + BZ_Free(file); + if (image) + { + dat = Cache_Alloc(&pic->cache, sizeof(qpic_t) + width*height, path); + dat->width = width; + dat->height = height; + for (i = 0; i < width*height; i++) + { + if (image[i*4+3] < 64) // 25% threshhold + dat->data[i] = 255; + else + dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]); + } + + BZ_Free(image); + + return dat; + } + } + } + +// +// load the pic from disk +// + _snprintf(alternatename, MAX_QPATH-1,"%s.lmp", path); + COM_LoadCacheFile (alternatename, &pic->cache); + + dat = (qpic_t *)pic->cache.data; + if (!dat) + { + char alternatename[MAX_QPATH]; + sprintf(alternatename, "gfx/%s.lmp", path); + dat = (qpic_t *)COM_LoadTempFile (alternatename); + if (!dat) + return NULL; +// Sys_Error ("Draw_CachePic: failed to load %s", path); + } + + SwapPic (dat); + + return dat; +} +qpic_t *SWDraw_CachePic (char *path) +{ + qpic_t *pic; + pic = SWDraw_SafeCachePic(path); + if (!pic) + Sys_Error ("Draw_CachePic: failed to load %s", path); + + return pic; +} + +qpic_t *SWDraw_ConcharsMalloc (char *name) +{ + // stupid hack for conchars... + qpic_t *dat; + swcachepic_t *pic; + int i, j; + + for (pic=swmenu_cachepics, i=0 ; iname)) + break; + + if (i == swmenu_numcachepics) + { + if (swmenu_numcachepics == MAX_CACHED_PICS) + Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); + swmenu_numcachepics++; + pic->cache.fake = true; + pic->cache.data = BZ_Malloc(sizeof(qpic_t) + 128*128); + dat = pic->cache.data; + // change 0 to 255 through conchars + for (j = 0; j < 128*128; j++) + dat->data[j] = (draw_chars[j] == 255 || !draw_chars[j]) ? draw_chars[j] ^ 255 : draw_chars[j]; +// memcpy (dat->data, draw_chars, 128*128); + dat->width = dat->height = 128; + strcpy (pic->name, name); + } + + return pic->cache.data; +} + +qpic_t *SWDraw_MallocPic (char *path) +{ + int i; + qpic_t *dat; + swcachepic_t *pic; + + for (pic=swmenu_cachepics, i=0 ; iname)) + break; + + if (i == swmenu_numcachepics) + { + if (swmenu_numcachepics == MAX_CACHED_PICS) + Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); + swmenu_numcachepics++; + pic->cache.fake = false; + pic->cache.data = NULL; + strcpy (pic->name, path); + } + + dat = Cache_Check (&pic->cache); + + if (dat) + return dat; + + + + { + qbyte *file, *image; + int width; + int height; + + file = COM_LoadMallocFile(path); + if (file) + { + image = ReadPCXFile(file, com_filesize, &width, &height); + BZ_Free(file); + if (image) + { + dat = BZ_Malloc(sizeof(qpic_t) + width*height); + if (dat) + { + pic->cache.data = dat; + pic->cache.fake = true; + dat->width = width; + dat->height = height; + for (i = 0; i < width*height; i++) + dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]); + + BZ_Free(image); + + return dat; + } + BZ_Free(image); + } + } + } + +// +// load the pic from disk +// + dat = (qpic_t *)COM_LoadHunkFile (path); + pic->cache.data = dat; + pic->cache.fake = true; + + if (!dat) + { + return NULL; +// Sys_Error ("Draw_CachePic: failed to load %s", path); + } + + SwapPic (dat); + + return dat; +} +qpic_t *SWDraw_PicFromWad (char *name) +{ + char q2name[MAX_QPATH]; + qpic_t *qpic; + + if (!strcmp(name, "conchars")) // conchars hack + return SWDraw_ConcharsMalloc("conchars"); + + sprintf(q2name, "pics/%s.pcx", name); + qpic = SWDraw_MallocPic(q2name); + if (qpic) + return qpic; + + return W_SafeGetLumpName (name); +} + + + +/* +=============== +Draw_Init +=============== +*/ +//FIXME: mallocs in place of wad references will not be freed +//we have a memory leak +void SWDraw_Init (void) +{ + draw_chars = W_SafeGetLumpName ("conchars"); //q1 + if (!draw_chars) + { + qpic_t *pic; //try q2 + int i; + int s; + pic = SWDraw_MallocPic("pics/conchars.pcx"); //safe from host_hunkmarks... + if (pic) + { + draw_chars = pic->data; + + s = pic->width*pic->height; + for (i = 0; i < s; i++) //convert 255s to 0, q1's transparent colour + if (draw_chars[i] == 162 || draw_chars[i] == 255) + draw_chars[i] = 0; + } + } + if (!draw_chars) + { //now go for hexen2 + int i, x; + char *tempchars = COM_LoadMallocFile("gfx/menu/conchars.lmp"); + char *in, *out; + if (!tempchars) + Sys_Error("No charset found\n"); + + draw_chars = BZ_Malloc(8*8*256*8); + + out = draw_chars; + for (i = 0; i < 8*8; i+=1) + { + if ((i/8)&1) + { + in = tempchars + ((i)/8)*16*8*8+(i&7)*32*8 - 256*4+128; + for (x = 0; x < 16*8; x++) + *out++ = *in++; + } + else + { + in = tempchars + (i/8)*16*8*8+(i&7)*32*8; + for (x = 0; x < 16*8; x++) + *out++ = *in++; + } + } + for (i = 0; i < 8*8; i+=1) + { + if ((i/8)&1) + { + in = tempchars+128*128 + ((i)/8)*16*8*8+(i&7)*32*8 - 256*4+128; + for (x = 0; x < 16*8; x++) + *out++ = *in++; + } + else + { + in = tempchars+128*128 + (i/8)*16*8*8+(i&7)*32*8; + for (x = 0; x < 16*8; x++) + *out++ = *in++; + } + } + Z_Free(tempchars); + } + if (!draw_chars) + Sys_Error("Failed to find suitable console charactures\n"); + draw_disc = W_SafeGetLumpName ("disc"); + draw_backtile = W_SafeGetLumpName ("backtile"); + if (!draw_backtile) + draw_backtile = (qpic_t *)COM_LoadMallocFile("gfx/menu/backtile.lmp"); + + if (draw_backtile) + { + r_rectdesc.width = draw_backtile->width; + r_rectdesc.height = draw_backtile->height; + r_rectdesc.ptexbytes = draw_backtile->data; + r_rectdesc.rowbytes = draw_backtile->width; + } +} + +void SWDraw_Shutdown(void) +{ + int i; + swcachepic_t *pic; + for (pic=swmenu_cachepics, i=0 ; icache.fake) + { + if (pic->cache.data) + BZ_Free(pic->cache.data); + pic->cache.fake = false; + pic->cache.data = NULL; + } + } + swmenu_numcachepics=0; + + draw_disc = NULL; +} + + +/* +================ +Draw_Character + +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. +================ +*/ +void SWDraw_Character (int x, int y, unsigned int num) +{ + qbyte *dest; + qbyte *source; + int drawline; + int row, col; + + num &= 255; + + if (y <= -8) + return; // totally off screen + + if (y > vid.height - 8 || x < 0 || x > vid.width - 8) + return; + + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + if (y < 0) + { // clipped + drawline = 8 + y; + source -= 128*y; + y = 0; + } + else + drawline = 8; + + + if (r_pixbytes == 1) + { + dest = vid.conbuffer + y*vid.conrowbytes + x; + + while (drawline--) + { + if (source[0]) + dest[0] = source[0]; + if (source[1]) + dest[1] = source[1]; + if (source[2]) + dest[2] = source[2]; + if (source[3]) + dest[3] = source[3]; + if (source[4]) + dest[4] = source[4]; + if (source[5]) + dest[5] = source[5]; + if (source[6]) + dest[6] = source[6]; + if (source[7]) + dest[7] = source[7]; + source += 128; + dest += vid.conrowbytes; + } + } + else if (r_pixbytes == 2) + { + unsigned short *dest16; + dest16 = (unsigned short*)vid.conbuffer + y*vid.conrowbytes + x; + + while (drawline--) + { + if (source[0]) + dest16[0] = d_8to16table[source[0]]; + if (source[1]) + dest16[1] = d_8to16table[source[1]]; + if (source[2]) + dest16[2] = d_8to16table[source[2]]; + if (source[3]) + dest16[3] = d_8to16table[source[3]]; + if (source[4]) + dest16[4] = d_8to16table[source[4]]; + if (source[5]) + dest16[5] = d_8to16table[source[5]]; + if (source[6]) + dest16[6] = d_8to16table[source[6]]; + if (source[7]) + dest16[7] = d_8to16table[source[7]]; + source += 128; + dest16 += vid.conrowbytes; + } + } + else if (r_pixbytes == 4) + { + unsigned int *p32dest; + p32dest = (unsigned int *)vid.conbuffer + y*vid.conrowbytes + x; + + while (drawline--) + { + if (source[0]) + p32dest[0] = d_8to32table[source[0]]; + if (source[1]) + p32dest[1] = d_8to32table[source[1]]; + if (source[2]) + p32dest[2] = d_8to32table[source[2]]; + if (source[3]) + p32dest[3] = d_8to32table[source[3]]; + if (source[4]) + p32dest[4] = d_8to32table[source[4]]; + if (source[5]) + p32dest[5] = d_8to32table[source[5]]; + if (source[6]) + p32dest[6] = d_8to32table[source[6]]; + if (source[7]) + p32dest[7] = d_8to32table[source[7]]; + source += 128; + p32dest += vid.conrowbytes; + } + } +} + +#define FindPallete(r,g,b) pal777to8[r>>1][g>>1][b>>1] +#define colourmask(p,r,g,b) FindPallete(host_basepal[p*3]*r, host_basepal[p*3+1]*g, host_basepal[p*3+2]*b) +#define draw(p) colourmask(p, (int)consolecolours[colour].r, (int)consolecolours[colour].g, (int)consolecolours[colour].b) +void SWDraw_ColouredCharacter (int x, int y, unsigned int num) +{ + qbyte *source; + int drawline; + int row, col; + +int colour; + + if (y <= -8) + return; // totally off screen + + if (y > vid.height - 8 || x < 0 || x > vid.width - 8) + return; + + colour = (num&CON_COLOURMASK)/256; + + if (num & CON_BLINKTEXT) + { + if ((int)(cl.time*2) & 1) + return; + } + + if (colour == 0) //0 is white anyway (speedup) + { + Draw_Character(x, y, num); + return; + } + + num &= 255; + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + if (y < 0) + { // clipped + drawline = 8 + y; + source -= 128*y; + y = 0; + } + else + drawline = 8; + + + if (r_pixbytes == 1) + { + qbyte *dest; + dest = vid.conbuffer + y*vid.conrowbytes + x; + + while (drawline--) + { + if (source[0]) + dest[0] = draw(source[0]); + if (source[1]) + dest[1] = draw(source[1]); + if (source[2]) + dest[2] = draw(source[2]); + if (source[3]) + dest[3] = draw(source[3]); + if (source[4]) + dest[4] = draw(source[4]); + if (source[5]) + dest[5] = draw(source[5]); + if (source[6]) + dest[6] = draw(source[6]); + if (source[7]) + dest[7] = draw(source[7]); + source += 128; + dest += vid.conrowbytes; + } + } + else if (r_pixbytes == 2) + { + unsigned short *dest16; + unsigned char *pal = (unsigned char *)d_8to32table; + int i; + int rm, gm, bm; + + dest16 = (unsigned short *)vid.conbuffer + y*vid.conrowbytes + x; + + rm = consolecolours[colour].r*32; + gm = consolecolours[colour].g*32; + bm = consolecolours[colour].b*32; + + while (drawline--) + { + for (i = 0; i < 8; i++) + { + if (source[i]) + dest16[i] = ((pal[source[i]*4+0]*bm/256)<<10)+ + ((pal[source[i]*4+1]*gm/256)<<5)+ + pal[source[i]*4+2]*rm/256; + } + /* + if (source[0]) + dest16[0] = pal[draw(source[0])]; + if (source[1]) + dest16[1] = pal[draw(source[1])]; + if (source[2]) + dest16[2] = pal[draw(source[2])]; + if (source[3]) + dest16[3] = pal[draw(source[3])]; + if (source[4]) + dest16[4] = pal[draw(source[4])]; + if (source[5]) + dest16[5] = pal[draw(source[5])]; + if (source[6]) + dest16[6] = pal[draw(source[6])]; + if (source[7]) + dest16[7] = pal[draw(source[7])]; + */ + source += 128; + dest16 += vid.conrowbytes; + } + } + else if (r_pixbytes == 4) + { + qbyte *dest; + int i; + unsigned char *pal = (unsigned char *)d_8to32table; + dest = vid.conbuffer + (y*vid.conrowbytes + x)*r_pixbytes; + + while (drawline--) + { + for (i = 0; i < 8; i++) + { + if (source[i]) + { + dest[0+i*4] = pal[source[i]*4+0]*consolecolours[colour].b; + dest[1+i*4] = pal[source[i]*4+1]*consolecolours[colour].g; + dest[2+i*4] = pal[source[i]*4+2]*consolecolours[colour].r; + } + } + source += 128; + dest += vid.conrowbytes*r_pixbytes; + } + } +} +#undef draw + +/* +================ +Draw_String +================ +*/ +void SWDraw_String (int x, int y, const qbyte *str) +{ + while (*str) + { + Draw_Character (x, y, *str); + str++; + x += 8; + } +} + +/* +================ +Draw_Alt_String +================ +*/ +void SWDraw_Alt_String (int x, int y, const qbyte *str) +{ + while (*str) + { + Draw_Character (x, y, (*str) | 0x80); + str++; + x += 8; + } +} + +void SWDraw_Pixel(int x, int y, qbyte color) +{ + qbyte *dest; + + if (r_pixbytes == 1) + { + dest = vid.conbuffer + y*vid.conrowbytes + x; + *dest = color; + } + else if (r_pixbytes == 4) + { + unsigned int *p32dest; + // FIXME: pre-expand to native format? + p32dest = ((unsigned int *)vid.conbuffer + y*vid.conrowbytes + x); + *p32dest = d_8to32table[color]; + } +} + +#include "crosshairs.dat" +qbyte *COM_LoadFile (char *path, int usehunk); +void SWDraw_Crosshair(void) +{ + int x, y; + extern cvar_t crosshair, cl_crossx, cl_crossy, crosshaircolor; + extern vrect_t scr_vrect; + qbyte c = (qbyte)crosshaircolor.value; + qbyte c2 = (qbyte)crosshaircolor.value; + + x = scr_vrect.x + scr_vrect.width/2 + cl_crossx.value; + y = scr_vrect.y + scr_vrect.height/2 + cl_crossy.value; + +#define Pix(xp,yp,c) SWDraw_Pixel(x+xp, y+yp, c) + + switch((int)crosshair.value) + { + case 0: + if (*crosshair.string>='a' && *crosshair.string<='z') + { + static qbyte *crosshairfile; + static int crosshairfilesize; + static char cachedcrosshairfile[64]; + int fx, fy; + qbyte *f; + + if (!strncmp(cachedcrosshairfile, crosshair.string, sizeof(cachedcrosshairfile))) + { + if (crosshairfile) + Z_Free(crosshairfile); + crosshairfile = COM_LoadFile(va("%s.csh", crosshair.string), 0); + crosshairfilesize = com_filesize; + Q_strncpyz(cachedcrosshairfile, crosshair.string, sizeof(cachedcrosshairfile)); + } + + f = crosshairfile; + if (!f) + return; + for (fy = 0; fy < 8; fy++) + { + for (fx = 0; fx < 8; ) + { + if (f - crosshairfile > crosshairfilesize) + { + Con_Printf("Crosshair file has overrun"); + fy=10; + break; + } + if (*f == 'x') + { + Pix(fx-3, fy-3, c); + fx++; + } + else if (*f == 'X') + { + Pix(fx-3, fy-3, c2); + fx++; + } + else if (*f == '0' || *f == 'o' || *f == 'O') + fx++; + + f++; + } + } + } + break; + default: + case 1: + Draw_Character ( + scr_vrect.x + scr_vrect.width/2-4 + cl_crossx.value, + scr_vrect.y + scr_vrect.height/2-4 + cl_crossy.value, + '+'); + break; +#include "crosshairs.dat" + } +} + +/* +================ +Draw_DebugChar + +Draws a single character directly to the upper right corner of the screen. +This is for debugging lockups by drawing different chars in different parts +of the code. +================ +*/ +void SWDraw_DebugChar (qbyte num) +{ + qbyte *dest; + qbyte *source; + int drawline; + extern qbyte *draw_chars; + int row, col; + + if (!vid.direct) + return; // don't have direct FB access, so no debugchars... + + drawline = 8; + + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + dest = vid.direct + 312; + + while (drawline--) + { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + dest[4] = source[4]; + dest[5] = source[5]; + dest[6] = source[6]; + dest[7] = source[7]; + source += 128; + dest += 320; + } +} + +/* +============= +Draw_Pic +============= +*/ +void SWDraw_Pic (int x, int y, qpic_t *pic) +{ + qbyte *dest, *source; + int v, u; + + if (!pic) + return; + + if ((x < 0) || + (x + pic->width > vid.width) || + (y < 0) || + (y + pic->height > vid.height)) + { + return;//Sys_Error ("Draw_Pic: bad coordinates"); + } + + source = pic->data; + + if (r_pixbytes == 1) + { + dest = vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vheight ; v++) + { + Q_memcpy (dest, source, pic->width); + dest += vid.rowbytes; + source += pic->width; + } + } + else if (r_pixbytes == 4) + { + unsigned int *p32dest; + p32dest = (unsigned int *)vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + p32dest[u] = d_8to32table[source[u]]; + p32dest += vid.rowbytes; + source += pic->width; + } + } + else if (r_pixbytes == 2) + { + unsigned short *p16dest; + + p16dest = (unsigned short *)vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + p16dest[u] = d_8to16table[source[u]]; + p16dest += vid.rowbytes; + source += pic->width; + } + } +} + + +/* +============= +Draw_SubPic +============= +*/ +void SWDraw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height) +{ + qbyte *dest, *source; + int v, u; + + if ((x < 0) || + (x + width > vid.width) || + (y < 0) || + (y + height > vid.height)) + { + Sys_Error ("Draw_Pic: bad coordinates"); + } + + source = pic->data + srcy * pic->width + srcx; + + if (r_pixbytes == 1) + { + dest = vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vwidth; + } + } + else if (r_pixbytes == 2) + { + unsigned short *p16dest; + p16dest = (unsigned short *)vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vwidth; + } + } + else if (r_pixbytes == 4) + { + unsigned int *p32dest; + p32dest = (unsigned int *)vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vwidth; + } + } +} + + +/* +============= +Draw_TransPic +============= +*/ +void SWDraw_TransPic (int x, int y, qpic_t *pic) +{ + qbyte *source, tbyte; + int v, u; + + if (!pic) + return; + if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || + (unsigned)(y + pic->height) > vid.height) + { + return; + Sys_Error ("Draw_TransPic: bad coordinates"); + } + + source = pic->data; + + if (r_pixbytes == 1) + { + qbyte *dest; + dest = vid.buffer + y * vid.rowbytes + x; + + if (pic->width & 7) + { // general + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = tbyte; + + dest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = tbyte; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + dest[u+1] = tbyte; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + dest[u+2] = tbyte; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + dest[u+3] = tbyte; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + dest[u+4] = tbyte; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + dest[u+5] = tbyte; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + dest[u+6] = tbyte; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + dest[u+7] = tbyte; + } + dest += vid.rowbytes; + source += pic->width; + } + } + } + else if (r_pixbytes == 2) + { + unsigned short *dest; + dest = (unsigned short *)vid.buffer + y * vid.rowbytes + x; + + if (pic->width & 7) + { // general + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = tbyte; + + dest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = d_8to16table[tbyte]; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + dest[u+1] = d_8to16table[tbyte]; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + dest[u+2] = d_8to16table[tbyte]; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + dest[u+3] = d_8to16table[tbyte]; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + dest[u+4] = d_8to16table[tbyte]; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + dest[u+5] = d_8to16table[tbyte]; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + dest[u+6] = d_8to16table[tbyte]; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + dest[u+7] = d_8to16table[tbyte]; + } + dest += vid.rowbytes; + source += pic->width; + } + } + } + else if (r_pixbytes == 4) + { + unsigned int *p32dest = (unsigned int *)vid.buffer + y * vid.rowbytes + x; + + if (pic->width & 7) + { // general + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + p32dest[u] = d_8to32table[tbyte]; + + p32dest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + p32dest[u] = d_8to32table[tbyte]; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + p32dest[u+1] = d_8to32table[tbyte]; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + p32dest[u+2] = d_8to32table[tbyte]; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + p32dest[u+3] = d_8to32table[tbyte]; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + p32dest[u+4] = d_8to32table[tbyte]; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + p32dest[u+5] = d_8to32table[tbyte]; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + p32dest[u+6] = d_8to32table[tbyte]; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + p32dest[u+7] = d_8to32table[tbyte]; + } + p32dest += vid.rowbytes; + source += pic->width; + } + } + } +} + + +/* +============= +Draw_TransPicTranslate +============= +*/ +void SWDraw_TransPicTranslate (int x, int y, qpic_t *pic, qbyte *translation) +{ + qbyte *source, tbyte; + int v, u; + + if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || + (unsigned)(y + pic->height) > vid.height) + { + Sys_Error ("Draw_TransPic: bad coordinates"); + } + + source = pic->data; + + if (r_pixbytes == 1) + { + qbyte *dest; + dest = vid.buffer + y * vid.rowbytes + x; + + if (pic->width & 7) + { // general + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = translation[tbyte]; + + dest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = translation[tbyte]; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + dest[u+1] = translation[tbyte]; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + dest[u+2] = translation[tbyte]; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + dest[u+3] = translation[tbyte]; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + dest[u+4] = translation[tbyte]; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + dest[u+5] = translation[tbyte]; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + dest[u+6] = translation[tbyte]; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + dest[u+7] = translation[tbyte]; + } + dest += vid.rowbytes; + source += pic->width; + } + } + } + else if (r_pixbytes == 4) + { + unsigned int *puidest; + + puidest = (unsigned int *)(vid.buffer + ((y * vid.rowbytes + x) << 2)); + + if (pic->width & 7) + { // general + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + puidest[u] = d_8to32table[translation[tbyte]]; + + puidest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + puidest[u] = d_8to32table[translation[tbyte]]; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + puidest[u+1] = d_8to32table[translation[tbyte]]; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + puidest[u+2] = d_8to32table[translation[tbyte]]; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + puidest[u+3] = d_8to32table[translation[tbyte]]; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + puidest[u+4] = d_8to32table[translation[tbyte]]; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + puidest[u+5] = d_8to32table[translation[tbyte]]; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + puidest[u+6] = d_8to32table[translation[tbyte]]; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + puidest[u+7] = d_8to32table[translation[tbyte]]; + } + puidest += vid.rowbytes; + source += pic->width; + } + } + } + else + Sys_Error("draw_transpictranslate: r_pixbytes\n"); +} + + +void SWDraw_CharToConback (int num, qbyte *dest) +{ + int row, col; + qbyte *source; + int drawline; + int x; + + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + drawline = 8; + + while (drawline--) + { + for (x=0 ; x<8 ; x++) + if (source[x]) + dest[x] = 0x60 + source[x]; + source += 128; + dest += 320; + } + +} + + +void SWDraw_SubImage32( + int scx, int scy, int scwidth, int scheight, //screen + int six, int siy, int siwidth, int siheight, //sub image + int iwidth, int iheight, qbyte *in) +{ + unsigned int *gamma = d_8to32table; + unsigned int *dest; + qbyte *src; + int v; + int f, fstep; + int x, y; + int outstride = vid.rowbytes; + + dest = (unsigned int *)vid.buffer + scx + scy*outstride; + + fstep = (siwidth<<16)/scwidth; + + for (y=0 ; y>16)] != 255) + { + dest[x] = gamma[src[(f>>16)]]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[1+x] = gamma[src[(f>>16)]]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[2+x] = gamma[src[(f>>16)]]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[3+x] = gamma[src[(f>>16)]]; + } + f += fstep; + } + for (; x>16)] != 255) + { + dest[x] = gamma[src[(f>>16)]]; + } + f += fstep; + } + } + } +} + +//blend in colour and alpha (still 8 bit source though) +void SWDraw_SubImageBlend32( + int scx, int scy, int scwidth, int scheight, //screen + int six, int siy, int siwidth, int siheight, //sub image + int iwidth, int iheight, qbyte *in, int red, int green, int blue, int alpha) +{ + unsigned char *pal = (unsigned char *)d_8to32table; + unsigned char *dest; + qbyte *src; + int v; + int f, fstep; + int x, y; + int outstride = vid.rowbytes; + + dest = (unsigned char *)vid.buffer + 4*(scx + scy*outstride); + + fstep = (siwidth<<16)/scwidth; + + for (y=0 ; y>16)] != 255) + { + dest[x + 0] = ((255-alpha)*dest[x + 0] + (blue*alpha*pal[(src[f>>16]<<2) + 0])/255)/255; + dest[x + 1] = ((255-alpha)*dest[x + 1] + (green*alpha*pal[(src[f>>16]<<2) + 1])/255)/255; + dest[x + 2] = ((255-alpha)*dest[x + 2] + (red*alpha*pal[(src[f>>16]<<2) + 2])/255)/255; + } + f += fstep; + } + } + } +} + +void SWDraw_SubImage16( + int scx, int scy, int scwidth, int scheight, //screen + int six, int siy, int siwidth, int siheight, //sub image + int iwidth, int iheight, qbyte *in) +{ + unsigned short *dest; + qbyte *src; + int v; + int f, fstep; + int x, y; + int outstride = vid.rowbytes; + + dest = (unsigned short *)vid.buffer + scx + scy*outstride; + + fstep = (siwidth<<16)/scwidth; + + for (y=0 ; y>16)] != 255) + { + dest[x] = d_8to16table[src[(f>>16)]]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[1+x] = d_8to16table[src[(f>>16)]]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[2+x] = d_8to16table[src[(f>>16)]]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[3+x] = d_8to16table[src[(f>>16)]]; + } + f += fstep; + } + for (; x>16)] != 255) + { + dest[x] = d_8to16table[src[(f>>16)]]; + } + f += fstep; + } + } + } +} + +void SWDraw_SubImage8( + int scx, int scy, int scwidth, int scheight, //screen + int six, int siy, int siwidth, int siheight, //sub image + int iwidth, int iheight, qbyte *in) +{ + unsigned char *dest; + qbyte *src; + int v; + int f, fstep; + int x, y; + int outstride = vid.rowbytes; + + dest = (unsigned char *)vid.buffer + scx + scy*outstride; + + fstep = (siwidth<<16)/scwidth; + + for (y=0 ; y>16)] != 255) + { + dest[x] = src[(f>>16)]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[1+x] = src[(f>>16)]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[2+x] = src[(f>>16)]; + } + f += fstep; + + if (src[(f>>16)] != 255) + { + dest[3+x] = src[(f>>16)]; + } + f += fstep; + } + for (; x>16)] != 255) + { + dest[x] = src[(f>>16)]; + } + f += fstep; + } + } + } +} + +static qboolean SWDraw_Image_Blend; +static int SWDraw_Image_Red=1, SWDraw_Image_Green=1, SWDraw_Image_Blue=1, SWDraw_Image_Alpha=1; +void SWDraw_ImageColours (float r, float g, float b, float a) //like glcolour4f +{ + SWDraw_Image_Red=r*255; + SWDraw_Image_Green=g*255; + SWDraw_Image_Blue=b*255; + SWDraw_Image_Alpha=a*255; + + SWDraw_Image_Blend = r<1 || b<1 || g<1 || a<1; +} + +void SWDraw_Image (float xp, float yp, float wp, float hp, float s1, float t1, float s2, float t2, qpic_t *pic) +{ + float xend, yend, xratio, yratio; + + if (!pic) + return; + + xratio = pic->width / wp; + yratio = pic->height / hp; + + // redefine borders + s2 = (s2-s1)*pic->width; + t2 = (t2-t1)*pic->height; + s1 = s1*pic->width; + t1 = t1*pic->height; + + // clip left/top edge + if (xp < 0) + { + s1 -= xp * xratio; + s2 += xp * xratio; + wp += xp; + xp = 0; + } + + if (yp < 0) + { + t1 -= yp * yratio; + t2 += yp * yratio; + hp += yp; + yp = 0; + } + + // clip right/bottom edge + xend = xp+wp; + yend = yp+hp; + + if (xend > vid.width) + { + xend -= vid.width; + s2 -= xend * xratio; + wp -= xend; + } + + if (yend > vid.height) + { + yend -= vid.height; + t2 -= yend * yratio; + hp -= yend; + } + + // bounds check... + if (s2 < 1) + s2 = 1; + if (t2 < 1) + t2 = 1; + + if (wp < 1 || hp < 1 || s1 >= pic->width || t1 >= pic->height) + return; + +// draw the pic + if (r_pixbytes == 1) + { + SWDraw_SubImage8(xp, yp, wp, hp, s1, t1, s2, t2, pic->width, pic->height, pic->data); + } + else if (r_pixbytes == 2) + { + SWDraw_SubImage16(xp, yp, wp, hp, s1, t1, s2, t2, pic->width, pic->height, pic->data); + } + else + { + if (SWDraw_Image_Blend) //blend it on + { + SWDraw_SubImageBlend32(xp, yp, wp, hp, s1, t1, s2, t2, + pic->width, pic->height, pic->data, + SWDraw_Image_Red, SWDraw_Image_Green, SWDraw_Image_Blue, SWDraw_Image_Alpha); + + } + else //block colour (fast) + { + SWDraw_SubImage32(xp, yp, wp, hp, s1, t1, s2, t2, pic->width, pic->height, pic->data); + } + } +} + + +/* +================ +Draw_ConsoleBackground + +================ +*/ +void SWDraw_ConsoleBackground (int lines) +{ + int x, y, v; + qbyte *src; + qbyte *dest; + int f, fstep; + qpic_t *conback; + char ver[100]; + static char saveback[320*8]; + + conback = SWDraw_SafeCachePic ("gfx/conback.lmp"); + if (!conback) + conback = SWDraw_SafeCachePic("pics/conback.pcx"); + if (!conback) + conback = SWDraw_SafeCachePic ("gfx/menu/conback.lmp"); + if (!conback) + Sys_Error("gfx/conback.lmp not found\n"); + + if (lines > vid.conheight) + lines = vid.conheight; + +// hack the version number directly into the pic + + //sprintf (ver, "start commands with a \\ character %4.2f", VERSION); + + if (cls.downloadmethod) //don't cover the downloading bit. + { + sprintf (ver, "%4.2f", VERSION); + dest = conback->data + 320 + 320*186 - 11 - 8*strlen(ver); + } + else + { + if (r_pixbytes == 4) +#ifdef DISTRIBUTION +#if defined(__linux__) + sprintf (ver, "rgb Linux (%4.2f) QuakeWorld %s %4.2f", LINUX_VERSION, DISTRIBUTION, VERSION); +#else + sprintf (ver, "rgb QuakeWorld %s %4.2f", DISTRIBUTION, VERSION); +#endif +#else +#if defined(__linux__) + sprintf (ver, "rgb Linux (%4.2f) QuakeWorld %4.2f", LINUX_VERSION, VERSION); +#else + sprintf (ver, "rgb QuakeWorld %4.2f", VERSION); +#endif +#endif + else +#ifdef DISTRIBUTION +#if defined(__linux__) + sprintf (ver, "Linux (%4.2f) QuakeWorld %s %4.2f", LINUX_VERSION, DISTRIBUTION, VERSION); +#else + sprintf (ver, "QuakeWorld %s %4.2f", DISTRIBUTION, VERSION); +#endif +#else +#if defined(__linux__) + sprintf (ver, "Linux (%4.2f) QuakeWorld %4.2f", LINUX_VERSION, VERSION); +#else + sprintf (ver, "QuakeWorld %4.2f", VERSION); +#endif +#endif + dest = conback->data + 320 - (strlen(ver)*8 + 11) + 320*186; + } + + memcpy(saveback, conback->data + 320*186, 320*8); + for (x=0 ; xdata + v*320; + if (vid.conwidth == 320) + memcpy (dest, src, vid.conwidth); + else + { + f = 0; + fstep = 320*0x10000/vid.conwidth; + for (x=0 ; x>16]; + f += fstep; + dest[x+1] = src[f>>16]; + f += fstep; + dest[x+2] = src[f>>16]; + f += fstep; + dest[x+3] = src[f>>16]; + f += fstep; + } + } + } + } + else if (r_pixbytes == 2) + { + unsigned short *dest16 = (unsigned short *)vid.conbuffer; + unsigned short *pal = d_8to16table; + + for (y=0 ; ydata + v*320; +// if (vid.conwidth == 320) +// memcpy (dest16, src, vid.conwidth); +// else + { + f = 0; + fstep = 320*0x10000/vid.conwidth; + for (x=0 ; x>16]]; + f += fstep; + dest16[x+1] = pal[src[f>>16]]; + f += fstep; + dest16[x+2] = pal[src[f>>16]]; + f += fstep; + dest16[x+3] = pal[src[f>>16]]; + f += fstep; + } + } + } + } + else + { + extern cvar_t d_smooth; + unsigned int *p24dest; + unsigned char *pal = (qbyte *)d_8to32table; + int alpha = ((float)(lines)/((vid.height * 3) >> 2))*255; + if (alpha > 255) alpha = 255; + p24dest = (unsigned int *)vid.conbuffer; + dest = (unsigned char *)vid.conbuffer; + + if (d_smooth.value) //smoothed + { + qbyte *src2; + int f1, f2; + int vf, hf; + for (y=0 ; ydata + v*320; + v = (vid.conheight - lines + y)*199/vid.conheight+1; + src2 = conback->data + v*320; + + v = (vid.conheight - lines + y)*199/vid.conheight; + vf = (((vid.conheight - lines + y)*199.0/vid.conheight) - v) * 255; + + f = 0; + fstep = 319*0x10000/vid.conwidth; + for (x=0 ; x>16)*65536) / 256; + f1 = ((255-hf) * pal[(src [f>>16]<<2) + 0] + hf * pal[(src [(f>>16)+1]<<2) + 0])/255; + f2 = ((255-hf) * pal[(src2[f>>16]<<2) + 0] + hf * pal[(src2[(f>>16)+1]<<2) + 0])/255; + f1 = ((255-vf)*f1+vf*f2)/255; + dest[(x<<2) + 0] = ((255-alpha)*dest[(x<<2) + 0] + alpha*f1)/255; + + + f1 = ((255-hf) * pal[(src [f>>16]<<2) + 1] + hf * pal[(src [(f>>16)+1]<<2) + 1])/255; + f2 = ((255-hf) * pal[(src2[f>>16]<<2) + 1] + hf * pal[(src2[(f>>16)+1]<<2) + 1])/255; + f1 = ((255-vf)*f1+vf*f2)/255; + dest[(x<<2) + 1] = ((255-alpha)*dest[(x<<2) + 1] + alpha*f1)/255; + + + f1 = ((255-hf) * pal[(src [f>>16]<<2) + 2] + hf * pal[(src [(f>>16)+1]<<2) + 2])/255; + f2 = ((255-hf) * pal[(src2[f>>16]<<2) + 2] + hf * pal[(src2[(f>>16)+1]<<2) + 2])/255; + f1 = ((255-vf)*f1+vf*f2)/255; + dest[(x<<2) + 2] = ((255-alpha)*dest[(x<<2) + 2] + alpha*f1)/255; + + + f += fstep; + } + } + + } + else + + if (alpha != 255) //blend it on + { + for (y=0 ; ydata + v*320; + + f = 0; + fstep = 320*0x10000/vid.conwidth; + for (x=0 ; x>16]<<2) + 0])/255; + dest[(x<<2) + 1] = ((255-alpha)*dest[(x<<2) + 1] + alpha*pal[(src[f>>16]<<2) + 1])/255; + dest[(x<<2) + 2] = ((255-alpha)*dest[(x<<2) + 2] + alpha*pal[(src[f>>16]<<2) + 2])/255; + f += fstep; + } + } + + } + else //block colour (fast) + { + for (y=0 ; ydata + v*320; + + f = 0; + fstep = 320*0x10000/vid.conwidth; + for (x=0 ; x>16]]; + f += fstep; + p24dest[x+1] = d_8to32table[src[f>>16]]; + f += fstep; + p24dest[x+2] = d_8to32table[src[f>>16]]; + f += fstep; + p24dest[x+3] = d_8to32table[src[f>>16]]; + f += fstep; + } + } + } + } + // put it back + memcpy(conback->data + 320*186, saveback, 320*8); +} + +#ifdef TEXTEDITOR +void SWDraw_EditorBackground (int lines) +{ + SWDraw_ConsoleBackground (lines); +} +#endif + + +/* +============== +R_DrawRect8 +============== +*/ +void R_DrawRect8 (vrect_t *prect, int rowbytes, qbyte *psrc, + int transparent) +{ + qbyte t; + int i, j, srcdelta, destdelta; + qbyte *pdest; + + pdest = vid.buffer + (prect->y * vid.rowbytes) + prect->x; + + srcdelta = rowbytes - prect->width; + destdelta = vid.rowbytes - prect->width; + + if (transparent) + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + t = *psrc; + if (t != TRANSPARENT_COLOR) + { + *pdest = t; + } + + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } + else + { + for (i=0 ; iheight ; i++) + { + memcpy (pdest, psrc, prect->width); + psrc += rowbytes; + pdest += vid.rowbytes; + } + } +} + + +/* +============== +R_DrawRect16 +============== +*/ +void R_DrawRect16 (vrect_t *prect, int rowbytes, qbyte *psrc, + int transparent) +{ + qbyte t; + int i, j, srcdelta, destdelta; + unsigned short *pdest; + +// FIXME: would it be better to pre-expand native-format versions? + + pdest = (unsigned short *)vid.buffer + + (prect->y * (vid.rowbytes)) + prect->x; + + srcdelta = rowbytes - prect->width; + destdelta = (vid.rowbytes) - prect->width; + + if (transparent) + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + t = *psrc; + if (t != TRANSPARENT_COLOR) + { + *pdest = d_8to16table[t]; + } + + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } + else + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + *pdest = d_8to16table[*psrc]; + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } +} + +void R_DrawRect32 (vrect_t *prect, int rowbytes, qbyte *psrc, + int transparent) +{ + qbyte t; + int i, j, srcdelta, destdelta; + unsigned int *pdest; + +// FIXME: would it be better to pre-expand native-format versions? + + pdest = (unsigned int *)vid.buffer + + (prect->y * vid.rowbytes) + prect->x; + + srcdelta = rowbytes - prect->width; + destdelta = vid.rowbytes - prect->width; + + if (transparent) + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + t = *psrc; + if (t != TRANSPARENT_COLOR) + { + *pdest = d_8to32table[t]; + } + + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } + else + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + + *pdest = d_8to32table[*psrc]; + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } +} + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void SWDraw_TileClear (int x, int y, int w, int h) +{ + int width, height, tileoffsetx, tileoffsety; + qbyte *psrc; + vrect_t vr; + + if (!r_rectdesc.height || !r_rectdesc.width) + return; + + r_rectdesc.rect.x = x; + r_rectdesc.rect.y = y; + r_rectdesc.rect.width = w; + r_rectdesc.rect.height = h; + + vr.y = r_rectdesc.rect.y; + height = r_rectdesc.rect.height; + + tileoffsety = vr.y % r_rectdesc.height; + + while (height > 0) + { + vr.x = r_rectdesc.rect.x; + width = r_rectdesc.rect.width; + + if (tileoffsety != 0) + vr.height = r_rectdesc.height - tileoffsety; + else + vr.height = r_rectdesc.height; + + if (vr.height > height) + vr.height = height; + + tileoffsetx = vr.x % r_rectdesc.width; + + while (width > 0) + { + if (tileoffsetx != 0) + vr.width = r_rectdesc.width - tileoffsetx; + else + vr.width = r_rectdesc.width; + + if (vr.width > width) + vr.width = width; + + psrc = r_rectdesc.ptexbytes + + (tileoffsety * r_rectdesc.rowbytes) + tileoffsetx; + + if (r_pixbytes == 1) + { + R_DrawRect8 (&vr, r_rectdesc.rowbytes, psrc, 0); + } + else if (r_pixbytes == 4) + { + R_DrawRect32 (&vr, r_rectdesc.rowbytes, psrc, 0); + } + else + { + R_DrawRect16 (&vr, r_rectdesc.rowbytes, psrc, 0); + } + + vr.x += vr.width; + width -= vr.width; + tileoffsetx = 0; // only the left tile can be left-clipped + } + + vr.y += vr.height; + height -= vr.height; + tileoffsety = 0; // only the top tile can be top-clipped + } +} + + +/* +============= +Draw_Fill + +Fills a box of pixels with a single color +============= +*/ +void SWDraw_Fill (int x, int y, int w, int h, int c) +{ + int u, v; + + if (x < 0 || x + w > vid.width || + y < 0 || y + h > vid.height) { + Con_Printf("Bad Draw_Fill(%d, %d, %d, %d, %c)\n", + x, y, w, h, c); + return; + } + + if (r_pixbytes == 1) + { + qbyte *dest; + dest = vid.buffer + y*vid.rowbytes + x; + for (v=0 ; v vid.width || + y < 0 || y + h > vid.height) { + Con_Printf("Bad SWDraw_Box(%d, %d, %d, %d, %i)\n", + x, y, w, h, paletteindex); + return; + } + + if (r_pixbytes == 1) + { + dest = vid.buffer + y*vid.rowbytes + x; + for (v=0 ; vdata, 24, 24); +} + + +/* +================ +Draw_EndDisc + +Erases the disc icon. +Call after completing any disc IO +================ +*/ +void SWDraw_EndDisc (void) +{ + if (draw_disc) + D_EndDirectRect (vid.width - 24, 0, 24, 24); +} + diff --git a/engine/sw/sw_draw.h b/engine/sw/sw_draw.h new file mode 100644 index 000000000..8f3a609aa --- /dev/null +++ b/engine/sw/sw_draw.h @@ -0,0 +1,48 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// draw.h -- these are the only functions outside the refresh allowed +// to touch the vid buffer + +void SWDraw_Init (void); +void SWDraw_ReInit (void); +void SWDraw_Shutdown(void); +void SWDraw_Character (int x, int y, unsigned int num); +void SWDraw_ColouredCharacter (int x, int y, unsigned int num); +void SWDraw_DebugChar (qbyte num); +void SWDraw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); +void SWDraw_Pic (int x, int y, qpic_t *pic); +void SWDraw_TransPic (int x, int y, qpic_t *pic); +void SWDraw_TransPicTranslate (int x, int y, qpic_t *pic, qbyte *translation); +void SWDraw_ConsoleBackground (int lines); +void SWDraw_EditorBackground (int lines); +void SWDraw_BeginDisc (void); +void SWDraw_EndDisc (void); +void SWDraw_TileClear (int x, int y, int w, int h); +void SWDraw_Fill (int x, int y, int w, int h, int c); +void SWDraw_FadeScreen (void); +void SWDraw_String (int x, int y, const qbyte *str); +void SWDraw_Alt_String (int x, int y, const qbyte *str); +qpic_t *SWDraw_SafePicFromWad (char *name); +qpic_t *SWDraw_PicFromWad (char *name); +qpic_t *SWDraw_SafeCachePic (char *path); +qpic_t *SWDraw_CachePic (char *path); +void SWDraw_Crosshair(void); + diff --git a/engine/sw/sw_model.c b/engine/sw/sw_model.c new file mode 100644 index 000000000..9aa8fea90 --- /dev/null +++ b/engine/sw/sw_model.c @@ -0,0 +1,3610 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// models.c -- model loading and caching + +// models are the only shared resource between a client and server running +// on the same machine. + +#include "quakedef.h" +#include "r_local.h" + +model_t *loadmodel; +char loadname[32]; // for hunk tags + +void SWMod_LoadSpriteModel (model_t *mod, void *buffer); +void SWMod_LoadSprite2Model (model_t *mod, void *buffer); +void SWMod_LoadBrushModel (model_t *mod, void *buffer); +void Mod_LoadQ2BrushModel (model_t *mod, void *buffer); +void SWMod_LoadAliasModel (model_t *mod, void *buffer); +void SWMod_LoadAlias2Model (model_t *mod, void *buffer); +void SWMod_LoadAlias3Model (model_t *mod, void *buffer); +model_t *SWMod_LoadModel (model_t *mod, qboolean crash); + +int Mod_ReadFlagsFromMD1(char *name, int md3version); + +qbyte mod_novis[MAX_MAP_LEAFS/8]; + +#define MAX_MOD_KNOWN 1024 +model_t mod_known[MAX_MOD_KNOWN]; +int mod_numknown; + +#ifdef SERVERONLY +#define SWMod_FindName Mod_FindName +#define SWMod_ForName Mod_ForName +#define SWMod_LeafPVS Mod_LeafPVS +#define SWMod_PointInLeaf Mod_PointInLeaf +#define SWMod_ClearAll Mod_ClearAll +#define SWMod_Init Mod_Init +#endif + +/* +=============== +Mod_Init +=============== +*/ +void SWMod_Init (void) +{ + mod_numknown = 0; + memset (mod_novis, 0xff, sizeof(mod_novis)); + + Cmd_RemoveCommand("mod_texturelist"); +} + +void SWMod_Think(void) +{ +} + +/* +=============== +Mod_Init + +Caches the data if needed +=============== +*/ +void *SWMod_Extradata (model_t *mod) +{ + void *r; + + r = Cache_Check (&mod->cache); + if (r) + return r; + + SWMod_LoadModel (mod, true); + + if (!mod->cache.data) + Sys_Error ("Mod_Extradata: caching failed"); + return mod->cache.data; +} + +/* +=============== +Mod_PointInLeaf +=============== +*/ +int SWMod_LeafForPoint (vec3_t p, model_t *model) +{ + mnode_t *node; + float d; + mplane_t *plane; + + if (model->fromgame == fg_quake2 || model->fromgame == fg_quake3) + { + return CM_PointLeafnum(p); + } + + if (!model || !model->nodes) + Sys_Error ("Mod_PointInLeaf: bad model"); + + node = model->nodes; + while (1) + { + if (node->contents < 0) + return (mleaf_t *)node - model->leafs; + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return 0; // never reached +} + +mleaf_t *SWMod_PointInLeaf (vec3_t p, model_t *model) +{ + return model->leafs + SWMod_LeafForPoint(p, model); +} + + +/* +=================== +Mod_DecompressVis +=================== +*/ +qbyte *SWMod_DecompressVis (qbyte *in, model_t *model, qbyte *decompressed) +{ + int c; + qbyte *out; + int row; + + row = (model->numleafs+7)>>3; + out = decompressed; + +#if 0 + memcpy (out, in, row); +#else + if (!in) + { // no vis info, so make all visible + while (row) + { + *out++ = 0xff; + row--; + } + return decompressed; + } + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); +#endif + + return decompressed; +} + +qbyte *SWMod_LeafPVS (mleaf_t *leaf, model_t *model, qbyte *buffer) +{ + static qbyte decompressed[MAX_MAP_LEAFS/8]; + + if (leaf == model->leafs) + return mod_novis; + + if (!buffer) + buffer = decompressed; + return SWMod_DecompressVis (leaf->compressed_vis, model, buffer); +} + +qbyte *SWMod_LeafnumPVS (int ln, model_t *model, qbyte *buffer) +{ + return SWMod_LeafPVS(model->leafs + ln, model, buffer); +} + +/* +=================== +Mod_ClearAll +=================== +*/ +void SWMod_ClearAll (void) +{ + int i; + model_t *mod; + + for (i=0 , mod=mod_known ; itype != mod_alias) + mod->needload = true; +} + +/* +================== +Mod_FindName + +================== +*/ +model_t *SWMod_FindName (char *name) +{ + int i; + model_t *mod; + + if (!name[0]) + Sys_Error ("Mod_ForName: NULL name"); + +// +// search the currently loaded models +// + for (i=0 , mod=mod_known ; iname, name) ) + break; + + if (i == mod_numknown) + { + if (mod_numknown == MAX_MOD_KNOWN) + Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); + memset(mod, 0, sizeof(model_t)); //clear the old model as the renderers use the same globals + strcpy (mod->name, name); + mod->needload = true; + mod_numknown++; + mod->particleeffect = -1; + mod->nodefaulttrail = false; + } + + return mod; +} + +/* +================== +Mod_TouchModel + +================== +*/ +void SWMod_TouchModel (char *name) +{ + model_t *mod; + + mod = SWMod_FindName (name); + + if (!mod->needload) + { + if (mod->type == mod_alias) + Cache_Check (&mod->cache); + } +} + +/* +================== +Mod_LoadModel + +Loads a model into the cache +================== +*/ +model_t *SWMod_LoadModel (model_t *mod, qboolean crash) +{ + void *d; + unsigned *buf = NULL; + qbyte stackbuf[1024]; // avoid dirtying the cache heap + char *ext; + + if (!mod->needload) + { + if (mod->type == mod_alias) + { + d = Cache_Check (&mod->cache); + if (d) + return mod; + } + else + return mod; // not cached at all + } + +// +// because the world is so huge, load it one piece at a time +// + + //look for a replacement + ext = COM_FileExtension(mod->name); +#ifndef SERVERONLY + if (!isDedicated && (!Q_strcasecmp(ext, "mdl") || !Q_strcasecmp(ext, "bsp"))) + { + char mdlbase[MAX_QPATH]; + COM_StripExtension(mod->name, mdlbase); + + if (!buf) + buf = (unsigned *)COM_LoadStackFile (va("%s.md3", mdlbase), stackbuf, sizeof(stackbuf)); + if (!buf) + buf = (unsigned *)COM_LoadStackFile (va("%s.md2", mdlbase), stackbuf, sizeof(stackbuf)); + } +#endif + if (!buf) + { +// +// load the file +// + buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); + if (!buf) + { + if (crash) + Sys_Error ("Mod_NumForName: %s not found", mod->name); + + mod->type = mod_dummy; + mod->mins[0] = -16; + mod->mins[1] = -16; + mod->mins[2] = -16; + mod->maxs[0] = 16; + mod->maxs[1] = 16; + mod->maxs[2] = 16; + mod->needload = true; + return mod; + return NULL; + } + } + +// +// allocate a new model +// + COM_FileBase (mod->name, loadname); + + loadmodel = mod; +#ifndef SERVERONLY + if (cl.model_precache[1]) //not the world. + Validation_IncludeFile(mod->name, (char *)buf, com_filesize); +#endif +// +// fill it in +// + +// call the apropriate loader + mod->needload = false; + + switch (LittleLong(*(unsigned *)buf)) + { +#ifndef SERVERONLY + case IDPOLYHEADER: + SWMod_LoadAliasModel (mod, buf); + break; + + case MD2IDALIASHEADER: + SWMod_LoadAlias2Model (mod, buf); + break; + + case MD3_IDENT: + SWMod_LoadAlias3Model (mod, buf); + break; + + case IDSPRITEHEADER: + SWMod_LoadSpriteModel (mod, buf); + break; + + case IDSPRITE2HEADER: + SWMod_LoadSprite2Model (mod, buf); + break; +#endif + case IDBSPHEADER: //looks like id switched to have proper ids + Mod_LoadQ2BrushModel (mod, buf); + break; + + case BSPVERSIONHL: + case BSPVERSION: //hmm. + SWMod_LoadBrushModel (mod, buf); + break; + + default: //some telejano mods can do this + if (crash) + Sys_Error ("Mod_NumForName: %s not found", mod->name); + + mod->type = mod_dummy; + mod->mins[0] = -16; + mod->mins[1] = -16; + mod->mins[2] = -16; + mod->maxs[0] = 16; + mod->maxs[1] = 16; + mod->maxs[2] = 16; + mod->needload = true; + return mod; + } + + R_DefaultTrail(mod); + + return mod; +} + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +model_t *SWMod_ForName (char *name, qboolean crash) +{ + model_t *mod; + + mod = SWMod_FindName (name); + + return SWMod_LoadModel (mod, crash); +} + + +/* +=============================================================================== + + BRUSHMODEL LOADING + +=============================================================================== +*/ + +qbyte *mod_base; + + +/* +================= +Mod_LoadTextures +================= +*/ +#ifndef SERVERONLY +void SWMod_LoadTextures (lump_t *l) +{ + int i, j, pixels, num, max, altmax; + miptex_t *mt; + texture_t *tx, *tx2; + texture_t *anims[10]; + texture_t *altanims[10]; + dmiptexlump_t *m; + + if (!l->filelen) + { + loadmodel->textures = NULL; + return; + } + m = (dmiptexlump_t *)(mod_base + l->fileofs); + + m->nummiptex = LittleLong (m->nummiptex); + + loadmodel->numtextures = m->nummiptex; + loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname); + + for (i=0 ; inummiptex ; i++) + { + m->dataofs[i] = LittleLong(m->dataofs[i]); + if (m->dataofs[i] == -1) + continue; + mt = (miptex_t *)((qbyte *)m + m->dataofs[i]); + mt->width = LittleLong (mt->width); + mt->height = LittleLong (mt->height); + for (j=0 ; joffsets[j] = LittleLong (mt->offsets[j]); + + if ( (mt->width & 15) || (mt->height & 15) ) + Sys_Error ("Texture %s is not 16 aligned", mt->name); + + if (!mt->offsets[0]) //external hl texture. + { + int pb; + if (r_usinglits) //allocate enough mem + pb = 4; + else + pb = 1; + + pixels = mt->width*pb*mt->height/64*85; + + tx = Hunk_AllocName (sizeof(texture_t) +pixels, mt->name ); //allocate enough to cover it. + tx->pixbytes = pb; + loadmodel->textures[i] = tx; + + memcpy (tx->name, mt->name, sizeof(tx->name)); + tx->width = mt->width; + tx->height = mt->height; + for (j=0 ; joffsets[j] = 0;//mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); + // the pixels immediately follow the structures + memset ( tx+1, 7, pixels); //set it all to 7 for no particular reason. + + + R_AddBulleten(tx); + continue; + } + else if (loadmodel->fromgame == fg_halflife) //internal hl texture + { + qboolean alphaed; + int pb; + if (r_usinglits) //allocate enough mem + pb = 4; + else + pb = 1; + + pixels = (mt->width*pb*mt->height)*85/64; + + tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); + tx->pixbytes = pb; + loadmodel->textures[i] = tx; + + memcpy (tx->name, mt->name, sizeof(tx->name)); + tx->width = mt->width; + tx->height = mt->height; + for (j=0 ; joffsets[j] = (mt->offsets[j]-sizeof(miptex_t))*4 + sizeof(texture_t); + // the pixels immediately follow the structures + if (pb == 4) + { + memcpy ( tx+1, W_ConvertWAD3Texture(mt, &mt->width, &mt->height, &alphaed), pixels); + } + else + { //need to convert it down + int k; + qbyte *in; + qbyte *out; + out = (qbyte *)(tx+1); + in = W_ConvertWAD3Texture(mt, &mt->width, &mt->height, &alphaed); + tx->offsets[0] = (char *)out - (char *)tx; + for (j = 0; j < mt->width*mt->height; j++, in+=4) + { + if (in[3] == 0) + *out++ = 255; + else + *out++ = GetPalette(in[0], in[1], in[2]); + } + + in = out-mt->width*mt->height; //shrink mips. + + tx->offsets[1] = (char *)out - (char *)tx; + for (j = 0; j < tx->height; j+=2) //we could convert mip[1], but shrinking is probably faster. + for (k = 0; k < tx->width; k+=2) + *out++ = in[k + tx->width*j]; + + tx->offsets[2] = (char *)out - (char *)tx; + for (j = 0; j < tx->height; j+=4) + for (k = 0; k < tx->width; k+=4) + *out++ = in[k + tx->width*j]; + + tx->offsets[3] = (char *)out - (char *)tx; + for (j = 0; j < tx->height; j+=8) + for (k = 0; k < tx->width; k+=8) + *out++ = in[k + tx->width*j]; + } + + +// if (!Q_strncmp(mt->name,"sky",3)) +// R_InitSky (tx); +#ifdef PEXT_BULLETENS +// else + R_AddBulleten(tx); +#endif + continue; + } +//internal 8bit texture + pixels = mt->width*mt->height/64*85; + + tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); + tx->pixbytes = 1; + loadmodel->textures[i] = tx; + + memcpy (tx->name, mt->name, sizeof(tx->name)); + tx->width = mt->width; + tx->height = mt->height; + for (j=0 ; joffsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); + // the pixels immediately follow the structures + memcpy ( tx+1, mt+1, pixels); + + if (!Q_strncmp(mt->name,"sky",3)) + R_InitSky (tx); +#ifdef PEXT_BULLETENS + else R_AddBulleten(tx); +#endif + } + +// +// sequence the animations +// + for (i=0 ; inummiptex ; i++) + { + tx = loadmodel->textures[i]; + if (!tx || tx->name[0] != '+') + continue; + if (tx->anim_next) + continue; // allready sequenced + + // find the number of frames in the animation + memset (anims, 0, sizeof(anims)); + memset (altanims, 0, sizeof(altanims)); + + max = tx->name[1]; + altmax = 0; + if (max >= 'a' && max <= 'z') + max -= 'a' - 'A'; + if (max >= '0' && max <= '9') + { + max -= '0'; + altmax = 0; + anims[max] = tx; + max++; + } + else if (max >= 'A' && max <= 'J') + { + altmax = max - 'A'; + max = 0; + altanims[altmax] = tx; + altmax++; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + + for (j=i+1 ; jnummiptex ; j++) + { + tx2 = loadmodel->textures[j]; + if (!tx2 || tx2->name[0] != '+') + continue; + if (strcmp (tx2->name+2, tx->name+2)) + continue; + + num = tx2->name[1]; + if (num >= 'a' && num <= 'z') + num -= 'a' - 'A'; + if (num >= '0' && num <= '9') + { + num -= '0'; + anims[num] = tx2; + if (num+1 > max) + max = num + 1; + } + else if (num >= 'A' && num <= 'J') + { + num = num - 'A'; + altanims[num] = tx2; + if (num+1 > altmax) + altmax = num+1; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + } + +#define ANIM_CYCLE 2 + // link them all together + for (j=0 ; jname); + tx2->anim_total = max * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = anims[ (j+1)%max ]; + if (altmax) + tx2->alternate_anims = altanims[0]; + } + for (j=0 ; jname); + tx2->anim_total = altmax * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = altanims[ (j+1)%altmax ]; + if (max) + tx2->alternate_anims = anims[0]; + } + } +} + +void SWMod_NowLoadExternal(void) +{ + int i, j, m, x, y; + texture_t *tx; + qbyte *in; + qbyte *out; + qboolean alphaed; + unsigned int *out32; + int width; + int height; + int t; + for (t=0 ; tnumtextures ; t++) + { + tx = loadmodel->textures[t]; + if (tx && !tx->offsets[0]) + { + in = W_GetTexture(tx->name, &width, &height, &alphaed); + i=0; + tx->offsets[0] = sizeof(texture_t); + tx->offsets[1] = tx->offsets[0] + tx->width*tx->pixbytes*tx->height; + tx->offsets[2] = tx->offsets[1] + (tx->width*tx->pixbytes*tx->height)/4; + tx->offsets[3] = tx->offsets[2] + (tx->width*tx->pixbytes*tx->height)/16; + + if (!in) + { + if (tx->pixbytes == 4) + { +// out32 = (unsigned int *)((qbyte *)tx+tx->offsets[0]); +// memset(out32, 255, tx->width*tx->pixbytes*tx->height*85/64); + for (m=0 ; m<4 ; m++) + { + out32 = (int *)((qbyte *)tx + tx->offsets[m]); + for (y=0 ; y< (tx->height>>m) ; y++) + for (x=0 ; x< (tx->width>>m) ; x++) + { + if ((y/2+x/2)&1) + *out32++ = 0; + else if (y/2&1&&x/2&1) + *out32++ = 0x00007700; + else + *out32++ = 0x00000077; + } + } + } + else + { +// out = (qbyte *)tx+tx->offsets[0]; +// memset(out32, 15, tx->width*tx->height*85/64); //usually white, anyway... + for (m=0 ; m<4 ; m++) + { + out = (qbyte *)tx + tx->offsets[m]; + for (y=0 ; y< (tx->height>>m) ; y++) + for (x=0 ; x< (tx->width>>m) ; x++) + { + if ((y+x)&1) + *out++ = 0; + else + *out++ = 0xff; + } + } + } + continue; //bother. + } + + if (tx->pixbytes == 4) + { + out32 = (unsigned int *)((qbyte *)tx+tx->offsets[0]); + memcpy(out32, in, tx->width*tx->pixbytes*tx->height*85/64); + } + else + { + out = (qbyte *)tx+tx->offsets[0]; + for (i=0; i < tx->width*tx->height; i++) //downgrade colour + { + if (in[3] == 0) + *out++ = 255; + else + *out++ = GetPalette(in[0], in[1], in[2]); + in += 4; + } + in = (qbyte *)tx+tx->offsets[0]; //shrink mips. + + for (j = 0; j < tx->height; j+=2) //we could convert mip[1], but shrinking is probably faster. + for (i = 0; i < tx->width; i+=2) + *out++ = in[i + tx->width*j]; + + for (j = 0; j < tx->height; j+=4) + for (i = 0; i < tx->width; i+=4) + *out++ = in[i + tx->width*j]; + + for (j = 0; j < tx->height; j+=8) + for (i = 0; i < tx->width; i+=8) + *out++ = in[i + tx->width*j]; + } + } + + } +} + +void SWMod_ReloadTextures (void) +{ +} + +/* +================= +Mod_LoadLighting +================= +*/ +void SWMod_LoadLighting (lump_t *l) +{ + extern cvar_t r_loadlits; + if (!l->filelen) + { + loadmodel->lightdata = NULL; + return; + } + if (r_pixbytes == 4) //using 24 bit lighting + { + r_usinglits = true; + if (r_loadlits.value && r_usinglits) + { + char litname[MAX_QPATH]; + qbyte *litdata = NULL; + if (!litdata) + { + strcpy(litname, loadmodel->name); + COM_StripExtension(loadmodel->name, litname); + COM_DefaultExtension(litname, ".lit"); + litdata = COM_LoadHunkFile(litname); + } + if (!litdata) + { + strcpy(litname, "lits/"); + COM_StripExtension(COM_SkipPath(loadmodel->name), litname+5); + strcat(litname, ".lit"); + + litdata = COM_LoadHunkFile(litname); + } + if (litdata) + { + if (l->filelen != (com_filesize-8)/3) + Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname); + else if (litdata[0] == 'Q' && litdata[1] == 'L' && litdata[2] == 'I' && litdata[3] == 'T') + { + if (LittleLong(*(int *)&litdata[4]) == 1) + { + float prop; + int i; + qbyte *normal; + // qbyte max; + loadmodel->lightdata = litdata+8; + + //now some cheat protection. + normal = mod_base + l->fileofs; + litdata = loadmodel->lightdata; + + for (i = 0; i < l->filelen; i++) //force it to the same intensity. (or less, depending on how you see it...) + { + #define m(a, b, c) (a>(b>c?b:c)?a:(b>c?b:c)) + prop = *normal / (float)m(litdata[0], litdata[1], litdata[2]); + litdata[0] *= prop; + litdata[1] *= prop; + litdata[2] *= prop; + + normal++; + litdata+=3; + } + //end anti-cheat + return; + } + else + Con_Printf("\"%s\" isn't a standard version 1 lit\n", litname); + } + else + Con_Printf("lit \"%s\" isn't a lit\n", litname); + } + } + if (loadmodel->fromgame == fg_halflife || loadmodel->fromgame == fg_quake2 || loadmodel->fromgame == fg_quake3) //half-life levels use 24 bit anyway. + { + loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + } + else if (!r_usinglits) + { + loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + } + else + { //expand to 24 bit + int i; + qbyte *dest, *src = mod_base + l->fileofs; + loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, loadname); + dest = loadmodel->lightdata; + for (i = 0; ifilelen; i++) + { + dest[0] = *src; + dest[1] = *src; + dest[2] = *src; + + src++; + dest+=3; + } + } + } + else + { + r_usinglits = false; + if (loadmodel->fromgame == fg_halflife || loadmodel->fromgame == fg_quake2 || loadmodel->fromgame == fg_quake3) + { + int i; + qbyte *out; + qbyte *in; + out = loadmodel->lightdata = Hunk_AllocName ( l->filelen/3, loadname); + in = mod_base + l->fileofs; //24 bit to luminance. + for (i = 0; i < l->filelen; i+=3) + *out++ = ((int)in[i] + (int)in[i] + (int)in[i])/3; + + } + else + {//standard Quake + loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + } + } +} +#endif + +/* +================= +Mod_LoadVisibility +================= +*/ +void SWMod_LoadVisibility (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->visdata = NULL; + return; + } + loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen); +} + + +/* +================= +Mod_LoadEntities +================= +*/ +void SWMod_LoadEntities (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->entities = NULL; + return; + } + loadmodel->entities = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen); +} + + +/* +================= +Mod_LoadVertexes +================= +*/ +void SWMod_LoadVertexes (lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count+8)*sizeof(*out), loadname); //spare for skybox + + loadmodel->vertexes = out; + loadmodel->numvertexes = count; + + for ( i=0 ; iposition[0] = LittleFloat (in->point[0]); + out->position[1] = LittleFloat (in->point[1]); + out->position[2] = LittleFloat (in->point[2]); + } +} + +static qboolean hexen2map; +/* +================= +Mod_LoadSubmodels +================= +*/ +void SWMod_LoadSubmodels (lump_t *l) +{ + dq1model_t *inq; + dh2model_t *inh; + mmodel_t *out; + int i, j, count; + + //this is crazy! + + inq = (void *)(mod_base + l->fileofs); + inh = (void *)(mod_base + l->fileofs); + if (!inq->numfaces) + { + hexen2map = true; + if (l->filelen % sizeof(*inh)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*inh); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (inh->mins[j]) - 1; + out->maxs[j] = LittleFloat (inh->maxs[j]) + 1; + out->origin[j] = LittleFloat (inh->origin[j]); + } + for (j=0 ; jheadnode[j] = LittleLong (inh->headnode[j]); + } + for ( ; jheadnode[j] = 0; + for (j=0 ; jhullavailable[j] = true; + for ( ; jhullavailable[j] = false; + out->visleafs = LittleLong (inh->visleafs); + out->firstface = LittleLong (inh->firstface); + out->numfaces = LittleLong (inh->numfaces); + } + + } + else + { + hexen2map = false; + if (l->filelen % sizeof(*inq)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*inq); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (inq->mins[j]) - 1; + out->maxs[j] = LittleFloat (inq->maxs[j]) + 1; + out->origin[j] = LittleFloat (inq->origin[j]); + } + for (j=0 ; jheadnode[j] = LittleLong (inq->headnode[j]); + } + for ( ; jheadnode[j] = 0; + for (j=0 ; j<3 ; j++) + out->hullavailable[j] = true; + for ( ; jhullavailable[j] = false; + out->visleafs = LittleLong (inq->visleafs); + out->firstface = LittleLong (inq->firstface); + out->numfaces = LittleLong (inq->numfaces); + } + } +} + +/* +================= +Mod_LoadEdges +================= +*/ +void SWMod_LoadEdges (lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count + 1 + 12) * sizeof(*out), loadname); //spare for skybox + + loadmodel->edges = out; + loadmodel->numedges = count; + + for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} + +/* +================= +Mod_LoadTexinfo +================= +*/ +#ifndef SERVERONLY +void SWMod_LoadTexinfo (lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out; + int i, j, count; + int miptex; + float len1, len2; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); + len1 = Length (out->vecs[0]); + len2 = Length (out->vecs[1]); + len1 = (len1 + len2)/2; + if (len1 < 0.32) + out->mipadjust = 4; + else if (len1 < 0.49) + out->mipadjust = 3; + else if (len1 < 0.99) + out->mipadjust = 2; + else + out->mipadjust = 1; +#if 0 + if (len1 + len2 < 0.001) + out->mipadjust = 1; // don't crash + else + out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 ); +#endif + + miptex = LittleLong (in->miptex); + out->flags = LittleLong (in->flags); + + if (!loadmodel->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 (!out->texture) + { + out->texture = r_notexture_mip; // texture not found + out->flags = 0; + } + else if (!strncmp(out->texture->name, "sky", 3)) + { + out->flags |= SURF_SKY; + } + else if (!strncmp(out->texture->name, "glass", 5)) //halflife levels + { + out->flags |= SURF_TRANS66; + } + else if (*out->texture->name == '{') //halflife levels + { +// out->flags |= SURF_TRANS66; + } + else if (*out->texture->name == '!') //halflife levels + { + out->flags |= SURF_WARP | SURF_TRANS33; + } + } + } +} +#endif +/* +================ +CalcSurfaceExtents + +Fills in s->texturemins[] and s->extents[] +================ +*/ + +void CalcSurfaceExtents (msurface_t *s); +/* +{ + float mins[2], maxs[2], val; + int i,j, e; + mvertex_t *v; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = s->texinfo; + + for (i=0 ; inumedges ; i++) + { + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + for (j=0 ; j<2 ; j++) + { + val = v->position[0] * tex->vecs[j][0] + + v->position[1] * tex->vecs[j][1] + + v->position[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + bmins[i] = floor(mins[i]/16); + bmaxs[i] = ceil(maxs[i]/16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + if (s->extents[i] < 16) + s->extents[i] = 16; // take at least one cache block + +// if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512) +// Sys_Error ("Bad surface extents"); + } +} +*/ + +/* +================= +Mod_LoadFaces +================= +*/ +#ifndef SERVERONLY +void SWMod_LoadFaces (lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count+6)*sizeof(*out), loadname); //spare for skybox + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->flags = 0; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo); + + if (!out->texinfo->texture) + out->texinfo->texture = r_notexture_mip; + + CalcSurfaceExtents (out); + + // lighting info + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else if (r_usinglits) + { + if (loadmodel->fromgame == fg_halflife) + out->samples = loadmodel->lightdata + i; + else + out->samples = loadmodel->lightdata + i*3; + } + else + { + if (loadmodel->fromgame == fg_halflife) + out->samples = loadmodel->lightdata + i/3; + else + out->samples = loadmodel->lightdata + i; + } + + // set the drawing flags flag + + if (!Q_strncmp(out->texinfo->texture->name,"sky",3)) // sky + { + if (loadmodel->fromgame == fg_halflife) + out->flags |= SURF_DRAWBACKGROUND; + else + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); + continue; + } + + if (!Q_strncmp(out->texinfo->texture->name,"*",1)) // turbulent + { + out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + continue; + } + } +} +#endif + +/* +================= +Mod_SetParent +================= +*/ +void SWMod_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents < 0) + return; + SWMod_SetParent (node->children[0], node); + SWMod_SetParent (node->children[1], node); +} + +/* +================= +Mod_LoadNodes +================= +*/ +void SWMod_LoadNodes (lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_t *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->nodes = out; + loadmodel->numnodes = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodel->planes + p; + + out->firstsurface = LittleShort (in->firstface); + out->numsurfaces = LittleShort (in->numfaces); + + for (j=0 ; j<2 ; j++) + { + p = LittleShort (in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + SWMod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs +} + +/* +================= +Mod_LoadLeafs +================= +*/ +void SWMod_LoadLeafs (lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count, p; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->contents); + out->contents = p; + + out->firstmarksurface = loadmodel->marksurfaces + + LittleShort(in->firstmarksurface); + out->nummarksurfaces = LittleShort(in->nummarksurfaces); + + p = LittleLong(in->visofs); + if (p == -1) + out->compressed_vis = NULL; + else + out->compressed_vis = loadmodel->visdata + p; + out->efrags = NULL; + + for (j=0 ; j<4 ; j++) + out->ambient_sound_level[j] = in->ambient_level[j]; + } +} + +//these are used to boost other info sizes +int numsuplementryplanes; +int numsuplementryclipnodes; +void *suplementryclipnodes; +void *suplementryplanes; +void *crouchhullfile; + +qbyte *COM_LoadMallocFile (char *path); +void SWMod_LoadCrouchHull(void) +{ + int i; + int numsm; + char crouchhullname[MAX_QPATH]; + int *data; + +// dclipnode_t *cn; + + numsuplementryplanes = numsuplementryclipnodes = 0; + + //find a name for a ccn and try to load it. + strcpy(crouchhullname, loadmodel->name); + COM_StripExtension(loadmodel->name, crouchhullname); + COM_DefaultExtension(crouchhullname, ".crh"); //crouch hull + + crouchhullfile = COM_LoadMallocFile(crouchhullname); //or otherwise temporary storage. load on hunk if you want, but that would be a waste. + if (!crouchhullfile) + return; + + if (LittleLong(((int *)crouchhullfile)[0]) != ('Q') + ('C'<<8) + ('C'<<16) + ('N'<<24)) //make sure it's the right version + return; + + if (LittleLong(((int *)crouchhullfile)[1]) != 0) //make sure it's the right version + return; + + numsm = LittleLong(((int *)crouchhullfile)[2]); + if (numsm != loadmodel->numsubmodels) //not compatable + return; + + numsuplementryplanes = LittleLong(((int *)crouchhullfile)[3]); + numsuplementryclipnodes = LittleLong(((int *)crouchhullfile)[4]); + + data = &((int *)crouchhullfile)[5]; + + for (i = 0; i < numsm; i++) //load headnode references + { + loadmodel->submodels[i].headnode[3] = LittleLong(*data)+1; + data++; + } + + suplementryplanes = data; + suplementryclipnodes = (qbyte*)data + sizeof(dplane_t)*numsuplementryplanes; +} + +/* +================= +Mod_LoadClipnodes +================= +*/ +void SWMod_LoadClipnodes (lump_t *l) +{ + dclipnode_t *in, *out; + int i, count; + hull_t *hull; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count+numsuplementryclipnodes)*sizeof(*out), loadname);//space for both + + loadmodel->clipnodes = out; + loadmodel->numclipnodes = count+numsuplementryclipnodes; + + if (hexen2map) + { //hexen2. + hexen2map=false; + hull = &loadmodel->hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 32; + hull->available = true; + + hull = &loadmodel->hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -24; + hull->clip_mins[1] = -24; + hull->clip_mins[2] = -20; + hull->clip_maxs[0] = 24; + hull->clip_maxs[1] = 24; + hull->clip_maxs[2] = 20; + hull->available = true; + + hull = &loadmodel->hulls[3]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -12; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 16; + hull->available = true; + + hull = &loadmodel->hulls[4]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -40; + hull->clip_mins[1] = -40; + hull->clip_mins[2] = -42; + hull->clip_maxs[0] = 40; + hull->clip_maxs[1] = 40; + hull->clip_maxs[2] = 42; + hull->available = true; + + hull = &loadmodel->hulls[5]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -48; + hull->clip_mins[1] = -48; + hull->clip_mins[2] = -50; + hull->clip_maxs[0] = 48; + hull->clip_maxs[1] = 48; + hull->clip_maxs[2] = 50; + hull->available = true; + } + else if (loadmodel->fromgame == fg_halflife) + { + hull = &loadmodel->hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -36; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 36; + hull->available = true; + + hull = &loadmodel->hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -32; + hull->clip_mins[1] = -32; + hull->clip_mins[2] = -32; + hull->clip_maxs[0] = 32; + hull->clip_maxs[1] = 32; + hull->clip_maxs[2] = 32; + hull->available = true; + + hull = &loadmodel->hulls[3]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -18; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 18; + hull->available = true; + } + else + { + hull = &loadmodel->hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 32; + hull->available = true; + + hull = &loadmodel->hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -32; + hull->clip_mins[1] = -32; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 32; + hull->clip_maxs[1] = 32; + hull->clip_maxs[2] = 64; + hull->available = true; + + hull = &loadmodel->hulls[3]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -6; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 30; + hull->available = false; + } + + for (i=0 ; iplanenum = LittleLong(in->planenum); + out->children[0] = LittleShort(in->children[0]); + out->children[1] = LittleShort(in->children[1]); + } + + if (numsuplementryclipnodes) //now load the crouch ones. + { + in = suplementryclipnodes; + hull->planes = suplementryplanes; + hull->clipnodes = out-1; + hull->lastclipnode = numsuplementryclipnodes; + hull->available = true; + + for (i=0 ; iplanenum = LittleLong(in->planenum); + out->children[0] = LittleShort(in->children[0]); + out->children[0] += out->children[0]>=0?1:0; + out->children[1] = LittleShort(in->children[1]); + out->children[1] += out->children[1]>=0?1:0; + } + } +} + +/* +================= +Mod_MakeHull0 + +Deplicate the drawing hull structure as a clipping hull +================= +*/ +void SWMod_MakeHull0 (void) +{ + mnode_t *in, *child; + dclipnode_t *out; + int i, j, count; + hull_t *hull; + + hull = &loadmodel->hulls[0]; + + in = loadmodel->nodes; + count = loadmodel->numnodes; + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + + for (i=0 ; iplanenum = in->plane - loadmodel->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; + } + } +} + +/* +================= +Mod_LoadMarksurfaces +================= +*/ +void SWMod_LoadMarksurfaces (lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for ( i=0 ; i= loadmodel->numsurfaces) + Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodel->surfaces + j; + } +} + +/* +================= +Mod_LoadSurfedges +================= +*/ +void SWMod_LoadSurfedges (lump_t *l) +{ + int i, count; + int *in, *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count+24)*sizeof(*out), loadname); //spare for skybox + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count+numsuplementryplanes)*2*sizeof(*out), loadname); + + loadmodel->planes = out; + loadmodel->numplanes = count+numsuplementryplanes; + + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } + + if (numsuplementryplanes) + { + in = suplementryplanes; + suplementryplanes = out; + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } + } +} + +/* +================= +RadiusFromBounds +================= +*/ + +float RadiusFromBounds (vec3_t mins, vec3_t maxs); +/* +{ + int i; + vec3_t corner; + + for (i=0 ; i<3 ; i++) + { + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + } + + return Length (corner); +} +*/ + + +void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node); +void Q1BSP_FatPVS (vec3_t org, qboolean add); +qboolean Q1BSP_EdictInFatPVS(edict_t *ent); +void Q1BSP_FindTouchedLeafs(edict_t *ent); +void SWQ1BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); + +void SWR_Q1BSP_StainNode (mnode_t *node, float *parms); +/* +================= +Mod_LoadBrushModel +================= +*/ +void SWMod_LoadBrushModel (model_t *mod, void *buffer) +{ + int i, j; + dheader_t *header; + mmodel_t *bm; + + loadmodel->type = mod_brush; + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + + if (i == BSPVERSION) + loadmodel->fromgame = fg_quake; + else if (i == BSPVERSIONHL) + loadmodel->fromgame = fg_halflife; + else + Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); +// if (i != BSPVERSION) +// Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + +// swap all the lumps + mod_base = (qbyte *)header; + + for (i=0 ; ichecksum = 0; + mod->checksum2 = 0; + +// checksum all of the map, except for entities + for (i = 0; i < HEADER_LUMPS; i++) { + if (i == LUMP_ENTITIES) + continue; + mod->checksum ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, + header->lumps[i].filelen); + + if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES) + continue; + mod->checksum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, + header->lumps[i].filelen); + } + +// load into heap +#ifndef SERVERONLY + if (!isDedicated) + { + SWMod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); + SWMod_LoadEdges (&header->lumps[LUMP_EDGES]); + SWMod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + SWMod_LoadLighting (&header->lumps[LUMP_LIGHTING]); //DMW, made lighting load first. (so we know if lighting is rgb or luminance) + SWMod_LoadTextures (&header->lumps[LUMP_TEXTURES]); + } +#endif + + SWMod_LoadSubmodels (&header->lumps[LUMP_MODELS]); //needs to come before we set the headnodes[3] + SWMod_LoadCrouchHull (); + SWMod_LoadPlanes (&header->lumps[LUMP_PLANES]); + +#ifndef SERVERONLY + if (!isDedicated) + { + SWMod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + SWMod_LoadFaces (&header->lumps[LUMP_FACES]); + SWMod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]); + } +#endif + + SWMod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); + SWMod_LoadLeafs (&header->lumps[LUMP_LEAFS]); + SWMod_LoadNodes (&header->lumps[LUMP_NODES]); + SWMod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]); + SWMod_LoadEntities (&header->lumps[LUMP_ENTITIES]); + + if (crouchhullfile) + { + BZ_Free(crouchhullfile); + crouchhullfile=NULL; + } + + mod->funcs.FatPVS = Q1BSP_FatPVS; + mod->funcs.EdictInFatPVS = Q1BSP_EdictInFatPVS; + mod->funcs.FindTouchedLeafs_Q1 = Q1BSP_FindTouchedLeafs; + mod->funcs.LightPointValues = SWQ1BSP_LightPointValues; + mod->funcs.StainNode = SWR_Q1BSP_StainNode; + mod->funcs.MarkLights = Q1BSP_MarkLights; + + mod->funcs.LeafForPoint = SWMod_LeafForPoint; + mod->funcs.LeafPVS = SWMod_LeafnumPVS; + +//We ONLY do this for the world model +#ifndef SERVERONLY +#ifndef CLIENTONLY + if (sv.state) //if the server is running + { + if (!strcmp(loadmodel->name, va("maps/%s.bsp", sv.name))) + Mod_ParseInfoFromEntityLump(mod_base + header->lumps[LUMP_ENTITIES].fileofs); + } + else +#endif + { + if (!cl.model_precache[1]) //not copied across yet + Mod_ParseInfoFromEntityLump(mod_base + header->lumps[LUMP_ENTITIES].fileofs); + } +#endif + + SWMod_MakeHull0 (); + + mod->numframes = 2; // regular and alternate animation + +// +// set up the submodels (FIXME: this is confusing) +// + for (i=0 ; inumsubmodels ; i++) + { + bm = &mod->submodels[i]; + + mod->hulls[0].firstclipnode = bm->headnode[0]; + Q1BSP_SetHullFuncs(&mod->hulls[0]); + for (j=1 ; jhulls[j].firstclipnode = bm->headnode[j]; + mod->hulls[j].lastclipnode = mod->numclipnodes-1; + Q1BSP_SetHullFuncs(&mod->hulls[j]); + } + + mod->firstmodelsurface = bm->firstface; + mod->nummodelsurfaces = bm->numfaces; + mod->radius = RadiusFromBounds (mod->mins, mod->maxs); + + VectorCopy (bm->maxs, mod->maxs); + VectorCopy (bm->mins, mod->mins); + + mod->numleafs = bm->visleafs; + + if (i < mod->numsubmodels-1) + { // duplicate the basic information + char name[10]; + + sprintf (name, "*%i", i+1); + loadmodel = SWMod_FindName (name); + *loadmodel = *mod; + strcpy (loadmodel->name, name); + mod = loadmodel; + + R_DefaultTrail(mod); + } + } +} +#ifndef SERVERONLY +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadAliasFrame +================= +*/ +void * SWMod_LoadAliasFrame (void * pin, int *pframeindex, int numv, + dtrivertx_t *pbboxmin, dtrivertx_t *pbboxmax, aliashdr_t *pheader, char *name) +{ + dtrivertx_t *pframe, *pinframe; + int i, j; + daliasframe_t *pdaliasframe; + + pdaliasframe = (daliasframe_t *)pin; + + strcpy (name, pdaliasframe->name); + + for (i=0 ; i<3 ; i++) + { + // these are qbyte values, so we don't have to worry about + // endianness + pbboxmin->v[i] = pdaliasframe->bboxmin.v[i]; + pbboxmax->v[i] = pdaliasframe->bboxmax.v[i]; + } + + pinframe = (dtrivertx_t *)(pdaliasframe + 1); + pframe = Hunk_AllocName (numv * sizeof(*pframe), loadname); + + *pframeindex = (qbyte *)pframe - (qbyte *)pheader; + + for (j=0 ; jnumframes); + + paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) + + (numframes - 1) * sizeof (paliasgroup->frames[0]), loadname); + + paliasgroup->numframes = numframes; + + for (i=0 ; i<3 ; i++) + { + // these are qbyte values, so we don't have to worry about endianness + pbboxmin->v[i] = pingroup->bboxmin.v[i]; + pbboxmax->v[i] = pingroup->bboxmax.v[i]; + } + + *pframeindex = (qbyte *)paliasgroup - (qbyte *)pheader; + + pin_intervals = (daliasinterval_t *)(pingroup + 1); + + poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + + paliasgroup->intervals = (qbyte *)poutintervals - (qbyte *)pheader; + + for (i=0 ; iinterval); + if (*poutintervals <= 0.0) + Sys_Error ("Mod_LoadAliasGroup: interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i=0 ; iframes[i].frame, + numv, + &paliasgroup->frames[i].bboxmin, + &paliasgroup->frames[i].bboxmax, + pheader, name); + } + + return ptemp; +} + + +/* +================= +Mod_LoadAliasSkin +================= +*/ +void * SWMod_LoadAliasSkin (void * pin, int *pskinindex, int skinsize, + aliashdr_t *pheader) +{ + int i; + qbyte *pskin, *pinskin; +// unsigned short *pusskin; + unsigned int *p32skin; + + pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname); + pinskin = (qbyte *)pin; + *pskinindex = (qbyte *)pskin - (qbyte *)pheader; + + if (r_pixbytes == 1 || r_pixbytes == 2) + { + Q_memcpy (pskin, pinskin, skinsize); + } + else if (r_pixbytes == 4) + { + extern qbyte *host_basepal; + p32skin = (unsigned int *)pskin; + + for (i=0 ; inumskins); + + paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) + + (numskins - 1) * sizeof (paliasskingroup->skindescs[0]), + loadname); + + paliasskingroup->numskins = numskins; + + *pskinindex = (qbyte *)paliasskingroup - (qbyte *)pheader; + + pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); + + poutskinintervals = Hunk_AllocName (numskins * sizeof (float),loadname); + + paliasskingroup->intervals = (qbyte *)poutskinintervals - (qbyte *)pheader; + + for (i=0 ; iinterval); + if (*poutskinintervals <= 0) + Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0"); + + poutskinintervals++; + pinskinintervals++; + } + + ptemp = (void *)pinskinintervals; + + for (i=0 ; iskindescs[i].skin, skinsize, pheader); + } + + return ptemp; +} + + +/* +================= +Mod_LoadAliasModel +================= +*/ +void SWMod_LoadAliasModel (model_t *mod, void *buffer) +{ + int i; + mmdl_t *pmodel; + dmdl_t *pinmodel; + mstvert_t *pstverts; + dstvert_t *pinstverts; + aliashdr_t *pheader; + mtriangle_t *ptri; + dtriangle_t *pintriangles; + int version, numframes, numskins; + int size; + daliasframetype_t *pframetype; + daliasskintype_t *pskintype; + maliasskindesc_t *pskindesc; + int skinsize; + int start, end, total; + + if (!strcmp(loadmodel->name, "progs/player.mdl") || + !strcmp(loadmodel->name, "progs/eyes.mdl")) { + unsigned short crc; + qbyte *p; + int len; + char st[40]; + + CRC_Init(&crc); + for (len = com_filesize, p = buffer; len; len--, p++) + CRC_ProcessByte(&crc, *p); + + sprintf(st, "%d", (int) crc); + Info_SetValueForKey (cls.userinfo, + !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, + st, MAX_INFO_STRING); + + if (cls.state >= ca_connected) { + MSG_WriteByte (&cls.netchan.message, clc_stringcmd); + sprintf(st, "setinfo %s %d", + !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, + (int)crc); + SZ_Print (&cls.netchan.message, st); + } + } + + start = Hunk_LowMark (); + + pinmodel = (dmdl_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + Sys_Error ("%s has wrong version number (%i should be %i)", + mod->name, version, ALIAS_VERSION); + +// +// allocate space for a working header, plus all the data except the frames, +// skin and group info +// + size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * + sizeof (pheader->frames[0]) + + sizeof (mmdl_t) + + LittleLong (pinmodel->numverts)*2 * sizeof (mstvert_t) + + LittleLong (pinmodel->numtris) * sizeof (mtriangle_t); + + pheader = Hunk_AllocName (size, loadname); + pmodel = (mmdl_t *) ((qbyte *)&pheader[1] + + (LittleLong (pinmodel->numframes) - 1) * + sizeof (pheader->frames[0])); + +// mod->cache.data = pheader; + mod->flags = LittleLong (pinmodel->flags); + +// +// endian-adjust and copy the data, starting with the alias model header +// + pmodel->boundingradius = LittleFloat (pinmodel->boundingradius); + pmodel->numskins = LittleLong (pinmodel->numskins); + pmodel->skinwidth = LittleLong (pinmodel->skinwidth); + pmodel->skinheight = LittleLong (pinmodel->skinheight); + + if (pmodel->skinheight > MAX_LBM_HEIGHT) + Sys_Error ("model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + pmodel->numstverts = pmodel->numverts = LittleLong (pinmodel->numverts); + + if (pmodel->numverts <= 0) + Sys_Error ("model %s has no vertices", mod->name); + + if (pmodel->numverts > MAXALIASVERTS) + Sys_Error ("model %s has too many vertices", mod->name); + + pmodel->numtris = LittleLong (pinmodel->numtris); + + if (pmodel->numtris <= 0) + Sys_Error ("model %s has no triangles", mod->name); + + pmodel->numframes = LittleLong (pinmodel->numframes); + pmodel->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; + mod->synctype = LittleLong (pinmodel->synctype); + mod->numframes = pmodel->numframes; + + for (i=0 ; i<3 ; i++) + { + pmodel->scale[i] = LittleFloat (pinmodel->scale[i]); + pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); + pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); + } + + numskins = pmodel->numskins; + numframes = pmodel->numframes; + + if (pmodel->skinwidth & 0x03) + Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4"); + + pheader->model = (qbyte *)pmodel - (qbyte *)pheader; + +// +// load the skins +// + skinsize = pmodel->skinheight * pmodel->skinwidth; + + if (numskins < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); + + pskintype = (daliasskintype_t *)&pinmodel[1]; + + pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), + loadname); + + pheader->skindesc = (qbyte *)pskindesc - (qbyte *)pheader; + + for (i=0 ; itype); + pskindesc[i].type = skintype; + + if (skintype == ALIAS_SKIN_SINGLE) + { + pskintype = (daliasskintype_t *) + SWMod_LoadAliasSkin (pskintype + 1, + &pskindesc[i].skin, + skinsize, pheader); + } + else + { + pskintype = (daliasskintype_t *) + SWMod_LoadAliasSkinGroup (pskintype + 1, + &pskindesc[i].skin, + skinsize, pheader); + } + } + +// +// set base s and t vertices +// + pstverts = (mstvert_t *)&pmodel[1]; + pinstverts = (dstvert_t *)pskintype; + + pheader->stverts = (qbyte *)pstverts - (qbyte *)pheader; + + for (i=0 ; inumverts ; i++) //fixme: really, we only need to duplicate the onseem ones. + { + // put s and t in 16.16 format + pstverts[i].s = LittleLong (pinstverts[i].s) << 16; + pstverts[i].t = LittleLong (pinstverts[i].t) << 16; + + if (LittleLong (pinstverts[i].onseam)) + pstverts[i+pmodel->numverts].s = pstverts[i].s + ((pmodel->skinwidth>>1) << 16); + else + pstverts[i+pmodel->numverts].s = pstverts[i].s; //FIXME: prevent duplication. + pstverts[i+pmodel->numverts].t = pstverts[i].t; + } + + pmodel->numstverts = pmodel->numverts*2; + +// +// set up the triangles +// + ptri = (mtriangle_t *)&pstverts[pmodel->numstverts]; + pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts]; + + pheader->triangles = (qbyte *)ptri - (qbyte *)pheader; + + for (i=0 ; inumtris ; i++) + { + int j; + + for (j=0 ; j<3 ; j++) + { + ptri[i].xyz_index[j] = + LittleLong (pintriangles[i].vertindex[j]); + if (LittleLong (pintriangles[i].facesfront)) + ptri[i].st_index[j] = ptri[i].xyz_index[j]; + else + ptri[i].st_index[j] = ptri[i].xyz_index[j]+pmodel->numverts; + } + } + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); + + pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris]; + + for (i=0 ; itype); + pheader->frames[i].type = frametype; + VectorCopy(pmodel->scale_origin, pheader->frames[i].scale_origin); + VectorCopy(pmodel->scale, pheader->frames[i].scale); + + + if (frametype == ALIAS_SINGLE) + { + pframetype = (daliasframetype_t *) + SWMod_LoadAliasFrame (pframetype + 1, + &pheader->frames[i].frame, + pmodel->numverts, + &pheader->frames[i].bboxmin, + &pheader->frames[i].bboxmax, + pheader, pheader->frames[i].name); + } + else + { + pframetype = (daliasframetype_t *) + SWMod_LoadAliasGroup (pframetype + 1, + &pheader->frames[i].frame, + pmodel->numverts, + &pheader->frames[i].bboxmin, + &pheader->frames[i].bboxmax, + pheader, pheader->frames[i].name); + } + } + + mod->type = mod_alias; + +// FIXME: do this right + + /* + mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; + mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; + */ + VectorCopy (pmodel->scale_origin, mod->mins); + VectorMA (mod->mins, 255, pmodel->scale, mod->maxs); + +// +// move the complete, relocatable alias model to the cache +// + end = Hunk_LowMark (); + total = end - start; + + Cache_Alloc (&mod->cache, total, loadname); + if (!mod->cache.data) + return; + memcpy (mod->cache.data, pheader, total); + + Hunk_FreeToLowMark (start); +} + +typedef struct +{ + float scale[3]; // multiply qbyte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} dmd2aliasframe_t; + +void SWMod_LoadAlias2Model (model_t *mod, void *buffer) +{ + int i, j; + mmdl_t *pmodel; + md2_t *pinmodel; + mstvert_t *pstverts; + dmd2stvert_t *pinstverts; + aliashdr_t *pheader; + mtriangle_t *ptri; + dmd2triangle_t *pintriangles; + int version, numframes, numskins; + int size; + dmd2aliasframe_t *pinframe; + maliasframedesc_t *poutframe; + maliasskindesc_t *pskindesc; + int skinsize; + int start, end, total; + dtrivertx_t *frameverts; + + vec3_t mins, maxs; + + + + + if (!strcmp(loadmodel->name, "progs/player.mdl") || + !strcmp(loadmodel->name, "progs/eyes.mdl")) { + unsigned short crc; + qbyte *p; + int len; + char st[40]; + + CRC_Init(&crc); + for (len = com_filesize, p = buffer; len; len--, p++) + CRC_ProcessByte(&crc, *p); + + sprintf(st, "%d", (int) crc); + Info_SetValueForKey (cls.userinfo, + !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, + st, MAX_INFO_STRING); + + if (cls.state >= ca_connected) { + MSG_WriteByte (&cls.netchan.message, clc_stringcmd); + sprintf(st, "setinfo %s %d", + !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, + (int)crc); + SZ_Print (&cls.netchan.message, st); + } + } + + start = Hunk_LowMark (); + + pinmodel = (md2_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != MD2ALIAS_VERSION) + Sys_Error ("%s has wrong version number (%i should be %i)", + mod->name, version, MD2ALIAS_VERSION); + +// +// allocate space for a working header, plus all the data except the frames, +// skin and group info +// + size = sizeof (aliashdr_t) + (LittleLong (pinmodel->num_frames) - 1) * + sizeof (pheader->frames[0]) + + sizeof (mmdl_t) + + LittleLong (pinmodel->num_st) * sizeof (mstvert_t) + + LittleLong (pinmodel->num_tris) * sizeof (mtriangle_t); + + pheader = Hunk_AllocName (size, loadname); + pmodel = (mmdl_t *) ((qbyte *)&pheader[1] + + (LittleLong (pinmodel->num_frames) - 1) * + sizeof (pheader->frames[0])); + + mod->flags = 0;//LittleLong (pinmodel->flags); + +// +// endian-adjust and copy the data, starting with the alias model header +// + pmodel->boundingradius = 100;//LittleFloat (pinmodel->boundingradius); + pmodel->numskins = LittleLong (pinmodel->num_skins); + pmodel->skinwidth = LittleLong (pinmodel->skinwidth); + pmodel->skinheight = LittleLong (pinmodel->skinheight); + + if (pmodel->skinheight > MAX_LBM_HEIGHT) + Sys_Error ("model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + pmodel->numverts = LittleLong (pinmodel->num_xyz); + pmodel->numstverts = LittleLong (pinmodel->num_st); + + if (pmodel->numverts <= 0) + Sys_Error ("model %s has no vertices", mod->name); + + if (pmodel->numverts > MAXALIASVERTS) + Sys_Error ("model %s has too many vertices", mod->name); + + pmodel->numtris = LittleLong (pinmodel->num_tris); + + if (pmodel->numtris <= 0) + Sys_Error ("model %s has no triangles", mod->name); + + pmodel->numframes = LittleLong (pinmodel->num_frames); + pmodel->size = 1000;//LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; + mod->synctype = 1;//LittleLong (pinmodel->synctype); + mod->numframes = pmodel->numframes; + + for (i=0 ; i<3 ; i++) + { + pmodel->scale[i] = 0; + pmodel->scale_origin[i] = 0; + pmodel->eyeposition[i] = 0; + } + + numskins = pmodel->numskins; + numframes = pmodel->numframes; + + if (pmodel->skinwidth & 0x03) + Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4"); + + pheader->model = (qbyte *)pmodel - (qbyte *)pheader; + +// +// set base s and t vertices +// + pstverts = (mstvert_t *)&pmodel[1]; + pinstverts = (dmd2stvert_t *)((qbyte *)pinmodel + LittleLong(pinmodel->ofs_st)); + + pheader->stverts = (qbyte *)pstverts - (qbyte *)pheader; + + for (i=0 ; inumstverts ; i++) + { + // put s and t in 16.16 format + pstverts[i].s = LittleShort (pinstverts[i].s)<<16; + pstverts[i].t = LittleShort (pinstverts[i].t)<<16; + } + +// +// set up the triangles +// + ptri = (mtriangle_t *)&pstverts[pmodel->numstverts]; + pintriangles = (dmd2triangle_t *)((qbyte *)pinmodel + LittleLong(pinmodel->ofs_tris)); + + pheader->triangles = (qbyte *)ptri - (qbyte *)pheader; + + for (i=0 ; inumtris ; i++) + { + int j; + + for (j=0 ; j<3 ; j++) + { + ptri[i].xyz_index[j] = LittleShort (pintriangles[i].xyz_index[j]); + ptri[i].st_index[j] = LittleShort (pintriangles[i].st_index[j]); + } + } + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); + + for (i=0 ; iofs_frames) + i * LittleLong(pinmodel->framesize)); + poutframe = &pheader->frames[i]; + + memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); + + for (j=0 ; j<3 ; j++) + { + poutframe->scale[j] = LittleFloat (pinframe->scale[j]); + poutframe->scale_origin[j] = LittleFloat (pinframe->translate[j]); + } + VectorCopy (poutframe->scale_origin, mins); //work out precise size. + VectorMA (mins, 255, poutframe->scale, maxs); + poutframe->bboxmin.v[0] = poutframe->bboxmin.v[1] = poutframe->bboxmin.v[2] = 0; + poutframe->bboxmax.v[0] = poutframe->bboxmax.v[1] = poutframe->bboxmax.v[2] = 255; + + if (i == 0) + { + VectorCopy (mins, mod->mins); //first frame - nothing to compare against. + VectorCopy (maxs, mod->maxs); + } + else + { + for (j = 0; j < 3; j++) + { + if (mod->mins[j] > mins[j]) //and make sure that the biggest ends up as the model size. + mod->mins[j] = mins[j]; + if (mod->maxs[j] < maxs[j]) + mod->maxs[j] = maxs[j]; + } + } + + // verts are all 8 bit, so no swapping needed + frameverts = Hunk_AllocName(pmodel->numverts*sizeof(dtrivertx_t), loadname); + poutframe->frame = (qbyte *)frameverts - (qbyte *)pheader; + for (j = 0; j < pmodel->numverts; j++) + { + frameverts[j].lightnormalindex = pinframe->verts[j].lightnormalindex; + frameverts[j].v[0] = pinframe->verts[j].v[0]; + frameverts[j].v[1] = pinframe->verts[j].v[1]; + frameverts[j].v[2] = pinframe->verts[j].v[2]; + } + + } + + VectorCopy (mod->mins, pmodel->scale_origin); //work out global scale + pmodel->scale[0] = (mod->maxs[0] - mod->mins[0])/255; + pmodel->scale[1] = (mod->maxs[1] - mod->mins[1])/255; + pmodel->scale[2] = (mod->maxs[2] - mod->mins[2])/255; + + { + int width; + int height; + int j; + qbyte *buffer; + qbyte *texture; + char *skinnames; + qbyte *skin; + pmodel->numskins = 0; + skinnames = Hunk_AllocName(numskins*MAX_SKINNAME, loadname); + memcpy(skinnames, (qbyte *)pinmodel + LittleLong(pinmodel->ofs_skins), numskins*MAX_SKINNAME); + + skinsize = pmodel->skinheight * pmodel->skinwidth; + pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), + loadname); + pheader->skindesc = (qbyte *)pskindesc - (qbyte *)pheader; + + for (i=0 ; iskinwidth || height != pmodel->skinheight) //FIXME: scale + { + BZ_Free(texture); + Con_Printf("Skin %s not same size as model specifies it should be\n", skinnames); + continue; + } + + skin = Hunk_AllocName(skinsize*r_pixbytes, loadname); + if (r_pixbytes == 4) + { + for (j = 0; j < skinsize*4; j+=4) + { + skin[j+0] = texture[j+2]; + skin[j+1] = texture[j+1]; + skin[j+2] = texture[j+0]; + skin[j+3] = texture[j+3]; + } + } + else + { + for (j = 0; j < skinsize; j++) //you know when you've been palettized. + { + skin[j+0] = GetPalette(texture[j*4+0], texture[j*4+1], texture[j*4+2]); + } + } + + BZ_Free(texture); + + pskindesc[pmodel->numskins].type = ALIAS_SKIN_SINGLE; + pskindesc[pmodel->numskins].skin = (qbyte *)skin - (qbyte *)pheader; + pmodel->numskins++; + } + } + + mod->type = mod_alias; + +// +// move the complete, relocatable alias model to the cache +// + end = Hunk_LowMark (); + total = end - start; + + Cache_Alloc (&mod->cache, total, loadname); + if (!mod->cache.data) + return; + memcpy (mod->cache.data, pheader, total); + + Hunk_FreeToLowMark (start); +} + + +//structures from Tenebrae +typedef struct { + int ident; + int version; + + char name[MAX_QPATH]; + + int flags; //Does anyone know what these are? + + int numFrames; + int numTags; + int numSurfaces; + + int numSkins; + + int ofsFrames; + int ofsTags; + int ofsSurfaces; + int ofsEnd; +} md3Header_t; + +//then has header->numFrames of these at header->ofs_Frames +typedef struct md3Frame_s { + vec3_t bounds[2]; + vec3_t localOrigin; + float radius; + char name[16]; +} md3Frame_t; + +//there are header->numSurfaces of these at header->ofsSurfaces, following from ofsEnd +typedef struct { + int ident; // + + char name[MAX_QPATH]; // polyset name + + int flags; + int numFrames; // all surfaces in a model should have the same + + int numShaders; // all surfaces in a model should have the same + int numVerts; + + int numTriangles; + int ofsTriangles; + + int ofsShaders; // offset from start of md3Surface_t + int ofsSt; // texture coords are common for all frames + int ofsXyzNormals; // numVerts * numFrames + + int ofsEnd; // next surface follows +} md3Surface_t; + +//at surf+surf->ofsXyzNormals +typedef struct { + short xyz[3]; + unsigned short normal; +} md3XyzNormal_t; + +//surf->numTriangles at surf+surf->ofsTriangles +typedef struct { + int indexes[3]; +} md3Triangle_t; + +//surf->numVerts at surf+surf->ofsSt +typedef struct { + float s; + float t; +} md3St_t; + +typedef struct { + char name[MAX_QPATH]; + int shaderIndex; +} md3Shader_t; +//End of Tenebrae 'assistance' + +typedef struct { + char name[MAX_QPATH]; + vec3_t org; + float ang[3][3]; +} md3tag_t; + + +void SWMod_LoadAlias3Model (model_t *mod, void *buffer) +{ + int i, j; + mmdl_t *pmodel; + aliashdr_t *pheader; + + md3Header_t *pinmodel; + mstvert_t *pstverts; + md3St_t *pinstverts; + mtriangle_t *ptri; + md3Triangle_t *pintriangles; + int version, numframes, numskins; + int size; + md3Frame_t *pinframe; + maliasframedesc_t *poutframe; + maliasskindesc_t *pskindesc; + int skinsize; + int start, end, total; + dtrivertx_t *frameverts; + md3XyzNormal_t *pinverts; + + md3Surface_t *surface; + + vec3_t mins, maxs; + + + + + if (!strcmp(loadmodel->name, "progs/player.mdl") || + !strcmp(loadmodel->name, "progs/eyes.mdl")) { + unsigned short crc; + qbyte *p; + int len; + char st[40]; + + CRC_Init(&crc); + for (len = com_filesize, p = buffer; len; len--, p++) + CRC_ProcessByte(&crc, *p); + + sprintf(st, "%d", (int) crc); + Info_SetValueForKey (cls.userinfo, + !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, + st, MAX_INFO_STRING); + + if (cls.state >= ca_connected) { + MSG_WriteByte (&cls.netchan.message, clc_stringcmd); + sprintf(st, "setinfo %s %d", + !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, + (int)crc); + SZ_Print (&cls.netchan.message, st); + } + } + + start = Hunk_LowMark (); + + pinmodel = (md3Header_t *)buffer; + + version = LittleLong (pinmodel->version); +// if (version != MD3ALIAS_VERSION) +// Sys_Error ("%s has wrong version number (%i should be %i)", +// mod->name, version, MD3ALIAS_VERSION); + + surface = (md3Surface_t*)((qbyte *)pinmodel + pinmodel->ofsSurfaces); + +// +// allocate space for a working header, plus all the data except the frames, +// skin and group info +// + size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numFrames) - 1) * + sizeof (pheader->frames[0]) + + sizeof (mmdl_t) + + LittleLong (surface->numVerts) * sizeof (mstvert_t) + + LittleLong (surface->numTriangles) * sizeof (mtriangle_t); + + pheader = Hunk_AllocName (size, loadname); + pmodel = (mmdl_t *) ((qbyte *)&pheader[1] + + (LittleLong (surface->numFrames) - 1) * + sizeof (pheader->frames[0])); + + mod->flags = 0;//LittleLong (pinmodel->flags); + +// +// endian-adjust and copy the data, starting with the alias model header +// + pmodel->boundingradius = 100;//LittleFloat (pinmodel->boundingradius); + pmodel->numskins = LittleLong (surface->numShaders); +// pmodel->skinwidth = LittleLong (pinmodel->skinwidth); //fill in later. +// pmodel->skinheight = LittleLong (pinmodel->skinheight); + + if (pmodel->skinheight > MAX_LBM_HEIGHT) + Sys_Error ("model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + pmodel->numverts = LittleLong (surface->numVerts); + pmodel->numstverts = LittleLong (surface->numVerts); + + if (surface->numVerts <= 0) + Sys_Error ("model %s has no vertices", mod->name); + + if (pmodel->numverts > MAXALIASVERTS) + Sys_Error ("model %s has too many vertices", mod->name); + + pmodel->numtris = LittleLong (surface->numTriangles); + + if (pmodel->numtris <= 0) + Sys_Error ("model %s has no triangles", mod->name); + + pmodel->numframes = LittleLong (surface->numFrames); + pmodel->size = 1000;//LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; + mod->synctype = 1;//LittleLong (pinmodel->synctype); + mod->numframes = pmodel->numframes; + + for (i=0 ; i<3 ; i++) + { + pmodel->scale[i] = 0; + pmodel->scale_origin[i] = 0; + pmodel->eyeposition[i] = 0; + } + + numskins = pmodel->numskins; + numframes = pmodel->numframes; + + + pheader->model = (qbyte *)pmodel - (qbyte *)pheader; + + { + int width; + int height; + int j; + qbyte *buffer; + qbyte *texture; + md3Shader_t *pinskin; + qbyte *skin; + pmodel->numskins = 0; + + pinskin = (md3Shader_t *)((qbyte *)surface + surface->ofsShaders); + + skinsize = pmodel->skinheight * pmodel->skinwidth; + pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), + loadname); + pheader->skindesc = (qbyte *)pskindesc - (qbyte *)pheader; + + for (i=0 ; iname); + if (!buffer) + { + char altname[256]; + strcpy(altname, mod->name); //backup + strcpy(COM_SkipPath(altname), COM_SkipPath(pinskin->name)); + buffer = COM_LoadMallocFile(altname); + } + + if (!buffer) + { + Con_Printf("Skin %s not found\n", pinskin->name); + continue; + } + texture = ReadTargaFile(buffer, com_filesize, &width, &height, false); +#ifdef AVAIL_JPEGLIB + if (!texture) + texture = ReadJPEGFile(buffer, com_filesize, &width, &height); +#endif +#ifdef AVAIL_PNGLIB + if (!texture) + texture = ReadPNGFile(buffer, com_filesize, &width, &height); +#endif + if (!texture) + texture = ReadPCXFile(buffer, com_filesize, &width, &height); + BZ_Free(buffer); + if (!texture) + { + Con_Printf("Skin %s filetype not recognised\n", pinskin->name); + continue; + } + if (!pmodel->numskins) //this is the first skin. + { + pmodel->skinwidth = width; + pmodel->skinheight = height; + } + skinsize = width*height; + if (width != pmodel->skinwidth || height != pmodel->skinheight) //FIXME: scale + { + BZ_Free(texture); + Con_Printf("Skin %s not same size as model specifies it should be\n", pinskin->name); + continue; + } + + skin = Hunk_AllocName(skinsize*r_pixbytes, loadname); + if (r_pixbytes == 4) + { + for (j = 0; j < skinsize*4; j+=4) + { + skin[j+0] = texture[j+2]; + skin[j+1] = texture[j+1]; + skin[j+2] = texture[j+0]; + skin[j+3] = texture[j+3]; + } + } + else + { + for (j = 0; j < skinsize; j++) //you know when you've been palettized. + { + skin[j+0] = GetPalette(texture[j*4+0], texture[j*4+1], texture[j*4+2]); + } + } + + BZ_Free(texture); + + pskindesc[pmodel->numskins].type = ALIAS_SKIN_SINGLE; + pskindesc[pmodel->numskins].skin = (qbyte *)skin - (qbyte *)pheader; + pmodel->numskins++; + } + } + + if (!pmodel->numskins) + Con_Printf("model %s has no skins\n", loadmodel->name); + + + if (pmodel->skinwidth & 0x03) + Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4"); + +// +// set base s and t vertices +// + pstverts = (mstvert_t *)&pmodel[1]; + pinstverts = (md3St_t *)((qbyte *)surface + LittleLong(surface->ofsSt)); + + pheader->stverts = (qbyte *)pstverts - (qbyte *)pheader; + + for (i=0 ; inumstverts ; i++) + { + // put s and t in 16.16 format + pstverts[i].s = (int)(LittleFloat (pinstverts[i].s)*pmodel->skinwidth)<<16; + pstverts[i].t = (int)(LittleFloat (pinstverts[i].t)*pmodel->skinheight)<<16; + } + +// +// set up the triangles +// + ptri = (mtriangle_t *)&pstverts[pmodel->numstverts]; + pintriangles = (md3Triangle_t *)((qbyte *)surface + LittleLong(surface->ofsTriangles)); + + pheader->triangles = (qbyte *)ptri - (qbyte *)pheader; + + for (i=0 ; inumtris ; i++) + { + int j; + + for (j=0 ; j<3 ; j++) + { + ptri[i].st_index[j] = ptri[i].xyz_index[j] = LittleLong (pintriangles[i].indexes[j]); + } + } + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); + + pinverts = (md3XyzNormal_t *)((qbyte *)surface + surface->ofsXyzNormals); + for (i=0 ; iofsFrames) + i * sizeof(md3Frame_t)); + poutframe = &pheader->frames[i]; + + memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); + + for (j=0 ; j<3 ; j++) + { + poutframe->scale_origin[j] = LittleFloat (pinframe->bounds[0][j]); + poutframe->scale[j] = (LittleFloat (pinframe->bounds[1][j])-poutframe->scale_origin[j])/255; + } + VectorCopy (poutframe->scale_origin, mins); //work out precise size. + VectorMA (mins, 255, poutframe->scale, maxs); + poutframe->bboxmin.v[0] = poutframe->bboxmin.v[1] = poutframe->bboxmin.v[2] = 0; + poutframe->bboxmax.v[0] = poutframe->bboxmax.v[1] = poutframe->bboxmax.v[2] = 255; + + if (i == 0) + { + VectorCopy (mins, mod->mins); //first frame - nothing to compare against. + VectorCopy (maxs, mod->maxs); + } + else + { + for (j = 0; j < 3; j++) + { + if (mod->mins[j] > mins[j]) //and make sure that the biggest ends up as the model size. + mod->mins[j] = mins[j]; + if (mod->maxs[j] < maxs[j]) + mod->maxs[j] = maxs[j]; + } + } + + // verts are all 8 bit, so no swapping needed + frameverts = Hunk_AllocName(pmodel->numverts*sizeof(dtrivertx_t), loadname); + poutframe->frame = (qbyte *)frameverts - (qbyte *)pheader; + for (j = 0; j < pmodel->numverts; j++) + { + frameverts[j].lightnormalindex = LittleShort(pinverts->normal)/256; + + //scale down to 0 - 255 within the scaleorigin and scaleorigin+scale*255 + // i/64 = scaleorigin+scale*o + // i/64-scaleorigin = scale*o + // i/64-scaleorigin/scale = 0 + frameverts[j].v[0] = ((double)LittleShort(pinverts[j].xyz[0])/64.0-poutframe->scale_origin[0])/(poutframe->scale[0]); + frameverts[j].v[1] = ((double)LittleShort(pinverts[j].xyz[1])/64.0-poutframe->scale_origin[1])/(poutframe->scale[1]); + frameverts[j].v[2] = ((double)LittleShort(pinverts[j].xyz[2])/64.0-poutframe->scale_origin[2])/(poutframe->scale[2]); + } + pinverts += pmodel->numverts; + + } + + VectorCopy (mod->mins, pmodel->scale_origin); //work out global scale + pmodel->scale[0] = (mod->maxs[0] - mod->mins[0])/255; + pmodel->scale[1] = (mod->maxs[1] - mod->mins[1])/255; + pmodel->scale[2] = (mod->maxs[2] - mod->mins[2])/255; + + mod->type = mod_alias; + +// +// move the complete, relocatable alias model to the cache +// + end = Hunk_LowMark (); + total = end - start; + + Cache_Alloc (&mod->cache, total, loadname); + if (!mod->cache.data) + return; + memcpy (mod->cache.data, pheader, total); + + Hunk_FreeToLowMark (start); +#ifdef RGLQUAKE + mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0); +#endif +} + + +//============================================================================= + +/* +================= +Mod_LoadSpriteFrame +================= +*/ +void * SWMod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int version) +{ + dspriteframe_t *pinframe; + mspriteframe_t *pspriteframe; + int i, width, height, size, origin[2]; + + pinframe = (dspriteframe_t *)pin; + + width = LittleLong (pinframe->width); + height = LittleLong (pinframe->height); + size = width * height; + + pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size*r_pixbytes, + loadname); + + Q_memset (pspriteframe, 0, sizeof (mspriteframe_t) + size); + *ppframe = pspriteframe; + + pspriteframe->width = width; + pspriteframe->height = height; + origin[0] = LittleLong (pinframe->origin[0]); + origin[1] = LittleLong (pinframe->origin[1]); + + pspriteframe->up = origin[1]; + pspriteframe->down = origin[1] - height; + pspriteframe->left = origin[0]; + pspriteframe->right = width + origin[0]; + + if (r_pixbytes == 1) + { + qbyte *ppixout, *ppixin; + + if (version == SPRITE32_VERSION) + { //downgrade quality + + ppixin = (unsigned char *)(pinframe + 1); + ppixout = (unsigned char *)&pspriteframe->pixels[0]; + + for (i=0 ; ipixels[0], (qbyte *)(pinframe + 1), size); + } + else if (r_pixbytes == 2) + { + qbyte *ppixin; + unsigned short *p16out; + if (version == SPRITE32_VERSION) + { //downgrade quality + + ppixin = (unsigned char *)(pinframe + 1); + p16out = (unsigned short *)&pspriteframe->pixels[0]; + + for (i=0 ; ipixels[0]; + for (i=0 ; ipixels[0]; + + for (i=0 ; ipixels[0]; + + for (i=0 ; inumframes); + + pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) + + (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname); + + pspritegroup->numframes = numframes; + + *ppframe = (mspriteframe_t *)pspritegroup; + + pin_intervals = (dspriteinterval_t *)(pingroup + 1); + + poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + + pspritegroup->intervals = poutintervals; + + for (i=0 ; iinterval); + if (*poutintervals <= 0.0) + Sys_Error ("Mod_LoadSpriteGroup: interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i=0 ; iframes[i], version); + } + + return ptemp; +} + + +/* +================= +Mod_LoadSpriteModel +================= +*/ +void SWMod_LoadSpriteModel (model_t *mod, void *buffer) +{ + int i; + int version; + dsprite_t *pin; + msprite_t *psprite; + int numframes; + int size; + dspriteframetype_t *pframetype; + + pin = (dsprite_t *)buffer; + + version = LittleLong (pin->version); + if (version != SPRITE32_VERSION) + if (version != SPRITE_VERSION) + Sys_Error ("%s has wrong version number " + "(%i should be %i)", mod->name, version, SPRITE_VERSION); + + numframes = LittleLong (pin->numframes); + + size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); + + psprite = Hunk_AllocName (size, loadname); + + mod->cache.data = psprite; + + psprite->type = LittleLong (pin->type); + psprite->maxwidth = LittleLong (pin->width); + psprite->maxheight = LittleLong (pin->height); + psprite->beamlength = LittleFloat (pin->beamlength); + mod->synctype = LittleLong (pin->synctype); + psprite->numframes = numframes; + + mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2; + mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2; + mod->mins[2] = -psprite->maxheight/2; + mod->maxs[2] = psprite->maxheight/2; + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); + + mod->numframes = numframes; + + pframetype = (dspriteframetype_t *)(pin + 1); + + for (i=0 ; itype); + psprite->frames[i].type = frametype; + + if (frametype == SPR_SINGLE) + { + pframetype = (dspriteframetype_t *) + SWMod_LoadSpriteFrame (pframetype + 1, + &psprite->frames[i].frameptr, version); + } + else + { + pframetype = (dspriteframetype_t *) + SWMod_LoadSpriteGroup (pframetype + 1, + &psprite->frames[i].frameptr, version); + } + } + + mod->type = mod_sprite; +} + +void SWMod_LoadSprite2Model (model_t *mod, void *buffer) +{ + int i, j; + int version; + dmd2sprite_t *pin; + msprite_t *psprite; + int numframes; + int size; + dmd2sprframe_t *pframetype; + mspriteframe_t *frame; + float origin[2]; + int width; + int height; + qbyte *framefile; + qbyte *framedata; + + pin = (dmd2sprite_t *)buffer; + + version = LittleLong (pin->version); + if (version != SPRITE2_VERSION) + Sys_Error ("%s has wrong version number " + "(%i should be %i)", mod->name, version, SPRITE2_VERSION); + + numframes = LittleLong (pin->numframes); + + size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); + + psprite = Hunk_AllocName (size, loadname); + + mod->cache.data = psprite; + + psprite->type = SPR_VP_PARALLEL; + psprite->maxwidth = 1; + psprite->maxheight = 1; + psprite->beamlength = 1; + mod->synctype = 0; + psprite->numframes = numframes; + + mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2; + mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2; + mod->mins[2] = -psprite->maxheight/2; + mod->maxs[2] = psprite->maxheight/2; + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); + + mod->numframes = 0; + + pframetype = pin->frames; + for (i=0 ; iframes[mod->numframes].type = SPR_SINGLE; + + width = LittleLong(pframetype->width); + height = LittleLong(pframetype->height); + + framefile = COM_LoadMallocFile(pframetype->name); + if (!framefile) + { + Con_Printf("Couldn't open sprite frame %s\n", pframetype->name); + continue; //skip this frame - is this a bad idea? + } + framedata = ReadPCXFile(framefile, com_filesize, &width, &height); + BZ_Free(framefile); + if (!framedata) + { + Con_Printf("Sprite frame %s is not a pcx\n", pframetype->name); + continue; //skip this frame - is this a bad idea? + } + + frame = psprite->frames[mod->numframes].frameptr = Hunk_AllocName(sizeof(mspriteframe_t)+width*r_pixbytes*height, loadname); + + frame->width = width; + frame->height = height; + origin[0] = LittleLong (pframetype->origin_x); + origin[1] = LittleLong (pframetype->origin_y); + + frame->up = -origin[1]; + frame->down = frame->height - origin[1]; + frame->left = -origin[0]; + frame->right = frame->width - origin[0]; + + if (r_pixbytes == 4) + { + for (j = 0; j < width*height; j++) + { + frame->pixels[j*4+0] = framedata[j*4+2]; + frame->pixels[j*4+1] = framedata[j*4+1]; + frame->pixels[j*4+2] = framedata[j*4+0]; + frame->pixels[j*4+3] = framedata[j*4+3]; + } + } + else + { + for (j = 0; j < width*height; j++) + { + if (!framedata[j*4+3]) //make sure + frame->pixels[j] = 255; + else + frame->pixels[j] = GetPalette(framedata[j*4+0], framedata[j*4+1], framedata[j*4+2]); + } + } + BZ_Free(framedata); + + mod->numframes++; + } + + mod->type = mod_sprite; +} + +//============================================================================= +#endif +/* +================ +Mod_Print +================ +*/ +void SWMod_Print (void) +{ + int i; + model_t *mod; + + Con_Printf ("Cached models:\n"); + for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) + { + Con_Printf ("%8p : %s\n",mod->cache.data, mod->name); + } +} + + diff --git a/engine/sw/sw_screen.c b/engine/sw/sw_screen.c new file mode 100644 index 000000000..5d3ba3a56 --- /dev/null +++ b/engine/sw/sw_screen.c @@ -0,0 +1,303 @@ +/* +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// screen.c -- master for refresh, status bar, console, chat, notify, etc + +#include "quakedef.h" +#include "r_local.h" + + + +extern qboolean scr_drawdialog; + +extern cvar_t gl_triplebuffer; +extern cvar_t scr_fov; + +extern qboolean scr_initialized; +extern float oldsbar; +extern qboolean scr_drawloading; + +extern float oldfov, oldscreensize; + + +extern int scr_chatmode; +extern cvar_t scr_chatmodecvar; + +/* +================== +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 SWSCR_UpdateScreen (void) +{ + int uimenu; + vrect_t vrect; + + if (scr_skipupdate || block_drawing) + return; + + if (scr_disabled_for_loading) + { + if (key_dest != key_console) + return; + } + +#ifdef _WIN32 + { // don't suck up any cpu if minimized + extern int Minimized; + + if (Minimized) + return; + } +#endif + + scr_copytop = 0; + scr_copyeverything = 0; + + if (!scr_initialized || !con_initialized) + return; // not initialized yet + + uimenu = UI_MenuState(); + +// +// check for vid changes +// + if (oldfov != scr_fov.value) + { + oldfov = scr_fov.value; + vid.recalc_refdef = true; + } + + if (scr_chatmode != scr_chatmodecvar.value) + vid.recalc_refdef = true; + + if (oldsbar != cl_sbar.value) + { + oldsbar = cl_sbar.value; + vid.recalc_refdef = true; + } +#ifdef TEXTEDITOR + if (editormodal) + { + Editor_Draw(); + SWV_UpdatePalette (); + + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + vrect.pnext = 0; + + SWVID_Update (&vrect); + return; + } +#endif + if (Media_ShowFilm()) + { + SWV_UpdatePalette (); + + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + vrect.pnext = 0; + + SWVID_Update (&vrect); + return; + } + + if (vid.recalc_refdef || scr_viewsize.modified) + { + // something changed, so reorder the screen + SCR_CalcRefdef (); + } + +// +// do 3D refresh drawing, and then update the screen +// + D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly + + SCR_TileClear(); + SCR_SetUpToDrawConsole (); + SCR_EraseCenterString (); + + D_DisableBackBufferAccess (); // for adapters that can't stay mapped in + // for linear writes all the time +#ifdef TEXTEDIT + if (!editormodal) //don't render view. +#endif + if (cl.worldmodel) + { + VID_LockBuffer (); + V_RenderView (); + VID_UnlockBuffer (); + } + + D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly + + if (scr_drawloading) + { + SCR_DrawLoading (); + Sbar_Draw (); + } + else if (scr_drawdialog) + { + Sbar_Draw (); + Draw_FadeScreen (); + SCR_DrawNotifyString (); + scr_copyeverything = true; + } + else if (cl.intermission == 1 && key_dest == key_game) + { + Sbar_IntermissionOverlay (); + } + else if (cl.intermission == 2 && key_dest == key_game) + { + Sbar_FinaleOverlay (); + SCR_CheckDrawCenterString (); + } + else + { + Draw_Crosshair(); + + SCR_DrawRam (); + SCR_DrawNet (); + SCR_DrawTurtle (); + SCR_DrawPause (); + SCR_DrawFPS (); + SCR_CheckDrawCenterString (); + Sbar_Draw (); +#ifdef TEXTEDITOR + if (editoractive) + Editor_Draw(); +#endif + SCR_DrawConsole (false); + M_Draw (uimenu); + } + + + D_DisableBackBufferAccess (); // for adapters that can't stay mapped in + // for linear writes all the time + + SWV_UpdatePalette (); + +// +// update one of three areas +// + if (scr_copyeverything) + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + vrect.pnext = 0; + + SWVID_Update (&vrect); + } + else if (scr_copytop) + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height - sb_lines; + vrect.pnext = 0; + + SWVID_Update (&vrect); + } + else + { + vrect.x = scr_vrect.x; + vrect.y = scr_vrect.y; + vrect.width = scr_vrect.width; + vrect.height = scr_vrect.height; + vrect.pnext = 0; + + SWVID_Update (&vrect); + } +} + +/* +================== +SCR_UpdateWholeScreen +================== +*/ +void SCR_UpdateWholeScreen (void) +{ + scr_fullupdate = 0; + SCR_UpdateScreen (); +} + + + + + + + +char *SWVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight) +{ //returns a BZ_Malloced array + qbyte *ret = BZ_Malloc(prepadbytes + vid.width*vid.height*3); + + qbyte *dest, *src; + int y, x; + + extern unsigned char vid_curpal[256*3]; + + if (r_pixbytes == 4) + { //32 bit to 24 + dest = ret+prepadbytes + vid.width*3*(vid.height-1); + + for (y=0 ; ylpVtbl->SetEntries( lpddpPalette, + 0, + 0, + 256, + palentries ) != DD_OK ) + { + Con_Printf( "DDRAW_SetPalette() - SetEntries failed\n" ); + } +} + + + +void DDRAW_Shutdown(void) +{ + if ( lpddsOffScreenBuffer ) + { + Con_SafePrintf( "...releasing offscreen buffer\n"); + lpddsOffScreenBuffer->lpVtbl->Unlock( lpddsOffScreenBuffer, vid.buffer ); + lpddsOffScreenBuffer->lpVtbl->Release( lpddsOffScreenBuffer ); + lpddsOffScreenBuffer = NULL; + } + if ( lpddsBackBuffer ) + { + Con_SafePrintf( "...releasing back buffer\n"); + lpddsBackBuffer->lpVtbl->Release( lpddsBackBuffer ); + lpddsBackBuffer = NULL; + } + if ( lpddsFrontBuffer ) + { + Con_SafePrintf( "...releasing front buffer\n"); + lpddsFrontBuffer->lpVtbl->Release( lpddsFrontBuffer ); + lpddsFrontBuffer = NULL; + } + if ( lpddpPalette) + { + Con_SafePrintf( "...releasing palette\n"); + lpddpPalette->lpVtbl->Release ( lpddpPalette ); + lpddpPalette = NULL; + } + if ( lpDirectDraw ) + { + Con_SafePrintf( "...restoring display mode\n"); + lpDirectDraw->lpVtbl->RestoreDisplayMode( lpDirectDraw ); + Con_SafePrintf( "...restoring normal coop mode\n"); + lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw, mainwindow, DDSCL_NORMAL ); + Con_SafePrintf( "...releasing lpDirectDraw\n"); + lpDirectDraw->lpVtbl->Release( lpDirectDraw ); + lpDirectDraw = NULL; + } + if ( hinstDDRAW ) + { + Con_SafePrintf( "...freeing library\n"); + FreeLibrary( hinstDDRAW ); + hinstDDRAW = NULL; + } + +} + + +unsigned short LowBitPos(DWORD dword) +{ + int i; + for (i = 0; ; i++) + { + if (dword & (1<lpVtbl->SetCooperativeLevel( lpDirectDraw, + mainwindow, + DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n",DDrawError (ddrval) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + + /* + ** try changing the display mode normally + */ + Con_SafePrintf( "...finding display mode\n" ); + Con_SafePrintf( "...setting linear mode: " ); + + if ( ( ddrval = lpDirectDraw->lpVtbl->SetDisplayMode( lpDirectDraw, vid.width, vid.height, r_pixbytes*8 ) ) == DD_OK ) + { + Con_SafePrintf( "ok\n" ); + } + /* + ** if no linear mode found, go for modex if we're trying 320x240 + */ + else if ( ( vid.width==320 && vid.height==240 ) && info->allow_modex ) + { + Con_SafePrintf( "failed\n" ); + Con_SafePrintf( "...attempting ModeX 320x240: "); + + /* + ** reset to normal cooperative level + */ + lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw, + mainwindow, + DDSCL_NORMAL ); + + /* + ** set exclusive mode + */ + if ( ( ddrval = lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw, + mainwindow, + DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES | DDSCL_ALLOWMODEX | DDSCL_ALLOWREBOOT) ) != DD_OK ) + { + Con_SafePrintf( "failed SCL - %s\n",DDrawError (ddrval) ); + goto fail; + } + + /* + ** change our display mode + */ + if ( ( ddrval = lpDirectDraw->lpVtbl->SetDisplayMode( lpDirectDraw, vid.width, vid.height, r_pixbytes*8 ) ) != DD_OK ) + { + Con_SafePrintf( "failed SDM - %s\n", DDrawError( ddrval ) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + + modex = true; + } + else + { + Con_SafePrintf( "failed\n" ); + goto fail; + } + + /* + ** create our front buffer + */ + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + + Con_SafePrintf( "...creating front buffer: "); + if ( ( ddrval = lpDirectDraw->lpVtbl->CreateSurface( lpDirectDraw, &ddsd, &lpddsFrontBuffer, NULL ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + +#else + Con_SafePrintf( "...setting normal mode: "); + if ( ( ddrval = lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw, + mainwindow, + DDSCL_NORMAL ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n",DDrawError (ddrval) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + + + i = r_pixbytes; + if (vid_use32bit.value) + r_pixbytes = 4; + else + r_pixbytes = 1; + + if (r_pixbytes != i && cls.state) + { + Con_Printf("Cannot change bpp when connected\n"); + r_pixbytes = i; + } + + /* + ** try changing the display mode + */ +/* if ( ( ddrval = lpDirectDraw->lpVtbl->SetDisplayMode( lpDirectDraw, vid.width, vid.height, r_pixbytes*8 ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n",DDrawError (ddrval) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); +*/ + + /* + ** create our front buffer + */ + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = /*DDSD_CAPS |*/ DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + + Con_SafePrintf( "...creating front buffer: "); + if ( ( ddrval = lpDirectDraw->lpVtbl->CreateSurface( lpDirectDraw, &ddsd, &lpddsFrontBuffer, NULL ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); +#endif + + /* + ** see if we're a ModeX mode + */ + lpddsFrontBuffer->lpVtbl->GetCaps( lpddsFrontBuffer, &ddscaps ); + if ( ddscaps.dwCaps & DDSCAPS_MODEX ) + Con_SafePrintf( "...using ModeX\n" ); + + /* + ** create our back buffer + */ + ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; + + Con_SafePrintf( "...creating back buffer: " ); + if ( ( ddrval = lpddsFrontBuffer->lpVtbl->GetAttachedSurface( lpddsFrontBuffer, &ddsd.ddsCaps, &lpddsBackBuffer ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + + /* + ** create our rendering buffer + */ + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwHeight = vid.height; + ddsd.dwWidth = vid.width; + ddsd.dwRefreshRate = info->rate; + if (ddsd.dwRefreshRate) + ddsd.dwFlags |= DDSD_REFRESHRATE; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + + Con_SafePrintf( "...creating offscreen buffer: " ); + if ( ( ddrval = lpDirectDraw->lpVtbl->CreateSurface( lpDirectDraw, &ddsd, &lpddsOffScreenBuffer, NULL ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + + if (r_pixbytes == 1) + { + /* + ** create our DIRECTDRAWPALETTE + */ + Con_SafePrintf( "...creating palette: " ); + if ( ( ddrval = lpDirectDraw->lpVtbl->CreatePalette( lpDirectDraw, + DDPCAPS_8BIT | DDPCAPS_ALLOW256, + palentries, + &lpddpPalette, + NULL ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + + Con_SafePrintf( "...setting palette: " ); + if ( ( ddrval = lpddsFrontBuffer->lpVtbl->SetPalette( lpddsFrontBuffer, + lpddpPalette ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + + DDRAW_SetPalette( ( const unsigned char * ) vid_curpal ); + + vid_palettized = true; + } + /* + ** lock the back buffer + */ + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + +Con_SafePrintf( "...locking backbuffer: " ); + if ( ( ddrval = lpddsOffScreenBuffer->lpVtbl->Lock( lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL ) ) != DD_OK ) + { + Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) ); + goto fail; + } +Con_SafePrintf( "ok\n" ); + + if (r_pixbytes == 2) + { + DDPIXELFORMAT format; + format.dwSize = sizeof(format); + Con_SafePrintf( "...getting pixel format: " ); + if (lpddsFrontBuffer->lpVtbl->GetPixelFormat(lpddsFrontBuffer, &format) == DD_OK) + { + int hi, lo; + lo = LowBitPos(format.dwRBitMask); + hi = HighBitPos(format.dwRBitMask); + Con_SafePrintf("Hi=%i, Low=%i\n", hi, lo); + redshift = lo; + redbits = hi-lo; + + lo = LowBitPos(format.dwGBitMask); + hi = HighBitPos(format.dwGBitMask); + Con_SafePrintf("Hi=%i, Low=%i\n", hi, lo); + greenshift = lo; + greenbits = hi-lo; + + lo = LowBitPos(format.dwBBitMask); + hi = HighBitPos(format.dwBBitMask); + Con_SafePrintf("Hi=%i, Low=%i\n", hi, lo); + blueshift = lo; + bluebits = hi-lo; + } + else + { + Con_SafePrintf( "failed\n" ); + goto fail; + } + Con_SafePrintf( "ok\n" ); + } + + *ppbuffer = ddsd.lpSurface; + *ppitch = ddsd.lPitch/r_pixbytes; + + for ( i = 0; i < vid.height; i++ ) + { + memset( *ppbuffer + i * *ppitch, 0, *ppitch ); + } + + return true; + +fail: + Con_SafePrintf( "*** DDraw init failure ***\n" ); + DDRAW_Shutdown(); + return false; +} + + + + + + + + + + + +static const char *DDrawError (int code) +{ + switch(code) { + case DD_OK: + return "DD_OK"; + case DDERR_ALREADYINITIALIZED: + return "DDERR_ALREADYINITIALIZED"; + case DDERR_BLTFASTCANTCLIP: + return "DDERR_BLTFASTCANTCLIP"; + case DDERR_CANNOTATTACHSURFACE: + return "DDER_CANNOTATTACHSURFACE"; + case DDERR_CANNOTDETACHSURFACE: + return "DDERR_CANNOTDETACHSURFACE"; + case DDERR_CANTCREATEDC: + return "DDERR_CANTCREATEDC"; + case DDERR_CANTDUPLICATE: + return "DDER_CANTDUPLICATE"; + case DDERR_CLIPPERISUSINGHWND: + return "DDER_CLIPPERUSINGHWND"; + case DDERR_COLORKEYNOTSET: + return "DDERR_COLORKEYNOTSET"; + case DDERR_CURRENTLYNOTAVAIL: + return "DDERR_CURRENTLYNOTAVAIL"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "DDERR_DIRECTDRAWALREADYCREATED"; + case DDERR_EXCEPTION: + return "DDERR_EXCEPTION"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "DDERR_EXCLUSIVEMODEALREADYSET"; + case DDERR_GENERIC: + return "DDERR_GENERIC"; + case DDERR_HEIGHTALIGN: + return "DDERR_HEIGHTALIGN"; + case DDERR_HWNDALREADYSET: + return "DDERR_HWNDALREADYSET"; + case DDERR_HWNDSUBCLASSED: + return "DDERR_HWNDSUBCLASSED"; + case DDERR_IMPLICITLYCREATED: + return "DDERR_IMPLICITLYCREATED"; + case DDERR_INCOMPATIBLEPRIMARY: + return "DDERR_INCOMPATIBLEPRIMARY"; + case DDERR_INVALIDCAPS: + return "DDERR_INVALIDCAPS"; + case DDERR_INVALIDCLIPLIST: + return "DDERR_INVALIDCLIPLIST"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "DDERR_INVALIDDIRECTDRAWGUID"; + case DDERR_INVALIDMODE: + return "DDERR_INVALIDMODE"; + case DDERR_INVALIDOBJECT: + return "DDERR_INVALIDOBJECT"; + case DDERR_INVALIDPARAMS: + return "DDERR_INVALIDPARAMS"; + case DDERR_INVALIDPIXELFORMAT: + return "DDERR_INVALIDPIXELFORMAT"; + case DDERR_INVALIDPOSITION: + return "DDERR_INVALIDPOSITION"; + case DDERR_INVALIDRECT: + return "DDERR_INVALIDRECT"; + case DDERR_LOCKEDSURFACES: + return "DDERR_LOCKEDSURFACES"; + case DDERR_NO3D: + return "DDERR_NO3D"; + case DDERR_NOALPHAHW: + return "DDERR_NOALPHAHW"; + case DDERR_NOBLTHW: + return "DDERR_NOBLTHW"; + case DDERR_NOCLIPLIST: + return "DDERR_NOCLIPLIST"; + case DDERR_NOCLIPPERATTACHED: + return "DDERR_NOCLIPPERATTACHED"; + case DDERR_NOCOLORCONVHW: + return "DDERR_NOCOLORCONVHW"; + case DDERR_NOCOLORKEY: + return "DDERR_NOCOLORKEY"; + case DDERR_NOCOLORKEYHW: + return "DDERR_NOCOLORKEYHW"; + case DDERR_NOCOOPERATIVELEVELSET: + return "DDERR_NOCOOPERATIVELEVELSET"; + case DDERR_NODC: + return "DDERR_NODC"; + case DDERR_NODDROPSHW: + return "DDERR_NODDROPSHW"; + case DDERR_NODIRECTDRAWHW: + return "DDERR_NODIRECTDRAWHW"; + case DDERR_NOEMULATION: + return "DDERR_NOEMULATION"; + case DDERR_NOEXCLUSIVEMODE: + return "DDERR_NOEXCLUSIVEMODE"; + case DDERR_NOFLIPHW: + return "DDERR_NOFLIPHW"; + case DDERR_NOGDI: + return "DDERR_NOGDI"; + case DDERR_NOHWND: + return "DDERR_NOHWND"; + case DDERR_NOMIRRORHW: + return "DDERR_NOMIRRORHW"; + case DDERR_NOOVERLAYDEST: + return "DDERR_NOOVERLAYDEST"; + case DDERR_NOOVERLAYHW: + return "DDERR_NOOVERLAYHW"; + case DDERR_NOPALETTEATTACHED: + return "DDERR_NOPALETTEATTACHED"; + case DDERR_NOPALETTEHW: + return "DDERR_NOPALETTEHW"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DDERR_NOT8BITCOLOR"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "DDERR_NOTFLIPPABLE"; + case DDERR_NOTFOUND: + return "DDERR_NOTFOUND"; + case DDERR_NOTLOCKED: + return "DDERR_NOTLOCKED"; + case DDERR_NOTPALETTIZED: + return "DDERR_NOTPALETTIZED"; + case DDERR_NOVSYNCHW: + return "DDERR_NOVSYNCHW"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DDERR_OUTOFMEMORY"; + case DDERR_OUTOFVIDEOMEMORY: + return "DDERR_OUTOFVIDEOMEMORY"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "DDERR_PALETTEBUSY"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "DDERR_PRIMARYSURFACEALREADYEXISTS"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "DDERR_SURFACEALREADYATTACHED"; + case DDERR_SURFACEALREADYDEPENDENT: + return "DDERR_SURFACEALREADYDEPENDENT"; + case DDERR_SURFACEBUSY: + return "DDERR_SURFACEBUSY"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "DDERR_SURFACELOST"; + case DDERR_SURFACENOTATTACHED: + return "DDERR_SURFACENOTATTACHED"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "DDERR_UNSUPPORTED"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "DDERR_WASSTILLDRAWING"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + default: + return "UNKNOWN\0"; + } +} + + + +void DDRAW_SwapBuffers (void) +{ + RECT r; + HRESULT rval; + DDSURFACEDESC ddsd; + + r.left = 0; + r.top = 0; + r.right = vid.width; + r.bottom = vid.height; + + lpddsOffScreenBuffer->lpVtbl->Unlock( lpddsOffScreenBuffer, vid.buffer ); + + if ( modex ) + { + if ( ( rval = lpddsBackBuffer->lpVtbl->BltFast( lpddsBackBuffer, + 0, 0, + lpddsOffScreenBuffer, + &r, + DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST ) + { + lpddsBackBuffer->lpVtbl->Restore( lpddsBackBuffer ); + lpddsBackBuffer->lpVtbl->BltFast( lpddsBackBuffer, + 0, 0, + lpddsOffScreenBuffer, + &r, + DDBLTFAST_WAIT ); + + Con_DPrintf("surface lost\n"); + } + + if ( ( rval = lpddsFrontBuffer->lpVtbl->Flip( lpddsFrontBuffer, + NULL, DDFLIP_WAIT ) ) == DDERR_SURFACELOST ) + { + lpddsFrontBuffer->lpVtbl->Restore( lpddsFrontBuffer ); + lpddsFrontBuffer->lpVtbl->Flip( lpddsFrontBuffer, NULL, DDFLIP_WAIT ); + } + } + else + { + if ( ( rval = lpddsBackBuffer->lpVtbl->BltFast( lpddsFrontBuffer, + 0, 0, + lpddsOffScreenBuffer, + &r, + DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST ) + { + lpddsBackBuffer->lpVtbl->Restore( lpddsFrontBuffer ); + lpddsBackBuffer->lpVtbl->BltFast( lpddsFrontBuffer, + 0, 0, + lpddsOffScreenBuffer, + &r, + DDBLTFAST_WAIT ); + + Con_DPrintf("surface lost\n"); + } + } + + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + + if (lpddsOffScreenBuffer->lpVtbl->Lock( lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL )) + Sys_Error("Failed to lock ddraw"); + vid.conbuffer = vid.buffer = ddsd.lpSurface; + vid.conrowbytes = vid.rowbytes = ddsd.lPitch/r_pixbytes; +} +#else +qboolean DDRAW_Init(rendererstate_t *info, unsigned char **ppbuffer, int *ppitch ) +{ + return false; +} +void DDRAW_SwapBuffers (void) +{ +} +void DDRAW_Shutdown(void) +{ +} +void DDRAW_SetPalette( const unsigned char *pal ) +{ +} +#endif + diff --git a/engine/sw/vid_dib.c b/engine/sw/vid_dib.c new file mode 100644 index 000000000..2f7324f3f --- /dev/null +++ b/engine/sw/vid_dib.c @@ -0,0 +1,412 @@ + +/* +** This handles DIB section management under Windows. +*/ +#include "quakedef.h" +#include "winquake.h" +#include "r_local.h" + +void DIB_Shutdown( void ); + +#ifndef _WIN32 +# error You should not be trying to compile this file on this platform +#endif + +HDC mainhDC, hdcDIBSection; +HBITMAP hDIBSection; +HPALETTE hPal, hpalOld; +qbyte *pDIBBase; +extern qboolean vid_palettized; +extern cvar_t vid_use32bit; + +static qboolean s_systemcolors_saved; + +extern int redbits, redshift; +extern int greenbits, greenshift; +extern int bluebits, blueshift; + +static HGDIOBJ previously_selected_GDI_obj; + +static int s_syspalindices[] = +{ + COLOR_ACTIVEBORDER, + COLOR_ACTIVECAPTION, + COLOR_APPWORKSPACE, + COLOR_BACKGROUND, + COLOR_BTNFACE, + COLOR_BTNSHADOW, + COLOR_BTNTEXT, + COLOR_CAPTIONTEXT, + COLOR_GRAYTEXT, + COLOR_HIGHLIGHT, + COLOR_HIGHLIGHTTEXT, + COLOR_INACTIVEBORDER, + + COLOR_INACTIVECAPTION, + COLOR_MENU, + COLOR_MENUTEXT, + COLOR_SCROLLBAR, + COLOR_WINDOW, + COLOR_WINDOWFRAME, + COLOR_WINDOWTEXT +}; + +#define NUM_SYS_COLORS ( sizeof( s_syspalindices ) / sizeof( int ) ) + +static COLORREF s_oldsyscolors[NUM_SYS_COLORS]; + +typedef struct dibinfo +{ + BITMAPINFOHEADER header; + RGBQUAD acolors[256]; +} dibinfo_t; + +typedef struct +{ + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palEntries[256]; +} identitypalette_t; + +static identitypalette_t s_ipal; + +static void DIB_SaveSystemColors( void ); +static void DIB_RestoreSystemColors( void ); + +/* +** DIB_Init +** +** Builds our DIB section +*/ +qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch ) +{ + dibinfo_t dibheader; + BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader; + int i; + + memset( &dibheader, 0, sizeof( dibheader ) ); + + /* + ** grab a DC + */ + if ( !mainhDC ) + { + if ( ( mainhDC = GetDC( mainwindow ) ) == NULL ) + return false; + } + + /* + ** figure out if we're running in an 8-bit display mode + */ + if ( GetDeviceCaps( mainhDC, RASTERCAPS ) & RC_PALETTE ) + { + vid_palettized = true; + + // save system colors + if ( !s_systemcolors_saved ) + { + DIB_SaveSystemColors(); + s_systemcolors_saved = true; + } + } + else + { + vid_palettized = false; + } + + /* + ** fill in the BITMAPINFO struct + */ + pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmiDIB->bmiHeader.biWidth = vid.width; + pbmiDIB->bmiHeader.biHeight = vid.height; + pbmiDIB->bmiHeader.biPlanes = 1; + pbmiDIB->bmiHeader.biBitCount = r_pixbytes*8; + pbmiDIB->bmiHeader.biCompression = BI_RGB; + pbmiDIB->bmiHeader.biSizeImage = 0; + pbmiDIB->bmiHeader.biXPelsPerMeter = 0; + pbmiDIB->bmiHeader.biYPelsPerMeter = 0; + pbmiDIB->bmiHeader.biClrUsed = 0; + pbmiDIB->bmiHeader.biClrImportant = 0; + + /* + ** fill in the palette + */ + for ( i = 0; i < 256; i++ ) + { + dibheader.acolors[i].rgbRed = ( d_8to24rgbtable[i] >> 0 ) & 0xff; + dibheader.acolors[i].rgbGreen = ( d_8to24rgbtable[i] >> 8 ) & 0xff; + dibheader.acolors[i].rgbBlue = ( d_8to24rgbtable[i] >> 16 ) & 0xff; + } + + /* + ** create the DIB section + */ + hDIBSection = CreateDIBSection( mainhDC, + pbmiDIB, + DIB_RGB_COLORS, + (void**)&pDIBBase, + NULL, + 0 ); + + if ( hDIBSection == NULL ) + { + Con_Printf( "DIB_Init() - CreateDIBSection failed\n" ); + goto fail; + } + + if ( pbmiDIB->bmiHeader.biHeight > 0 ) + { + // bottom up + *ppbuffer = pDIBBase + ( vid.height - 1 ) * vid.width * r_pixbytes; + *ppitch = -(int)vid.width; + } + else + { + // top down + *ppbuffer = pDIBBase; + *ppitch = vid.width; + } + + /* + ** clear the DIB memory buffer + */ + memset( pDIBBase, 0xff, vid.width * vid.height * r_pixbytes); + + if ( ( hdcDIBSection = CreateCompatibleDC( mainhDC ) ) == NULL ) + { + Con_Printf( "DIB_Init() - CreateCompatibleDC failed\n" ); + goto fail; + } + if ( ( previously_selected_GDI_obj = SelectObject( hdcDIBSection, hDIBSection ) ) == NULL ) + { + Con_Printf( "DIB_Init() - SelectObject failed\n" ); + goto fail; + } + + redbits = 5; redshift=10; + greenbits = 5; greenshift=5; + bluebits = 5; blueshift=0; + + return true; + +fail: + DIB_Shutdown(); + return false; + +} + +void DIB_Resized(void) +{ +} + +/* +** DIB_SetPalette +** +** Sets the color table in our DIB section, and also sets the system palette +** into an identity mode if we're running in an 8-bit palettized display mode. +** +** The palette is expected to be 1024 bytes, in the format: +** +** R = offset 0 +** G = offset 1 +** B = offset 2 +** A = offset 3 +*/ +void DIB_SetPalette( const unsigned char *_pal ) +{ + const unsigned char *pal = _pal; + LOGPALETTE *pLogPal = ( LOGPALETTE * ) &s_ipal; + RGBQUAD colors[256]; + int i; + int ret; + HDC hDC = mainhDC; + + /* + ** set the DIB color table + */ + if (r_pixbytes == 1 && hdcDIBSection ) + { + for ( i = 0; i < 256; i++, pal += 3 ) + { + colors[i].rgbRed = pal[0]; + colors[i].rgbGreen = pal[1]; + colors[i].rgbBlue = pal[2]; + colors[i].rgbReserved = 0; + } + + colors[0].rgbRed = 0; + colors[0].rgbGreen = 0; + colors[0].rgbBlue = 0; + + colors[255].rgbRed = 0xff; + colors[255].rgbGreen = 0xff; + colors[255].rgbBlue = 0xff; + + if ( SetDIBColorTable( hdcDIBSection, 0, 256, colors ) == 0 ) + { + Con_Printf( "DIB_SetPalette() - SetDIBColorTable failed\n" ); + } + } + + /* + ** for 8-bit color desktop modes we set up the palette for maximum + ** speed by going into an identity palette mode. + */ + if ( vid_palettized ) + { + int i; + HPALETTE hpalOld; + + if ( SetSystemPaletteUse( hDC, SYSPAL_NOSTATIC ) == SYSPAL_ERROR ) + { + Sys_Error( "DIB_SetPalette() - SetSystemPaletteUse() failed\n" ); + } + + /* + ** destroy our old palette + */ + if ( hPal ) + { + DeleteObject( hPal ); + hPal = 0; + } + + /* + ** take up all physical palette entries to flush out anything that's currently + ** in the palette + */ + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = 256; + + for ( i = 0, pal = _pal; i < 256; i++, pal += 3 ) + { + pLogPal->palPalEntry[i].peRed = pal[0]; + pLogPal->palPalEntry[i].peGreen = pal[1]; + pLogPal->palPalEntry[i].peBlue = pal[2]; + pLogPal->palPalEntry[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE; + } + pLogPal->palPalEntry[0].peRed = 0; + pLogPal->palPalEntry[0].peGreen = 0; + pLogPal->palPalEntry[0].peBlue = 0; + pLogPal->palPalEntry[0].peFlags = 0; + pLogPal->palPalEntry[255].peRed = 0xff; + pLogPal->palPalEntry[255].peGreen = 0xff; + pLogPal->palPalEntry[255].peBlue = 0xff; + pLogPal->palPalEntry[255].peFlags = 0; + + if ( ( hPal = CreatePalette( pLogPal ) ) == NULL ) + { + Sys_Error( "DIB_SetPalette() - CreatePalette failed(%x)\n", GetLastError() ); + } + + if ( ( hpalOld = SelectPalette( hDC, hPal, FALSE ) ) == NULL ) + { + Sys_Error( "DIB_SetPalette() - SelectPalette failed(%x)\n",GetLastError() ); + } + + if ( hpalOld == NULL ) + hpalOld = hpalOld; + + if ( ( ret = RealizePalette( hDC ) ) != pLogPal->palNumEntries ) + { + Sys_Error( "DIB_SetPalette() - RealizePalette set %d entries\n", ret ); + } + } +} + +/* +** DIB_Shutdown +*/ +void DIB_Shutdown( void ) +{ + if ( vid_palettized && s_systemcolors_saved ) + DIB_RestoreSystemColors(); + + if ( hPal ) + { + DeleteObject( hPal ); + hPal = NULL; + } + + if ( hpalOld ) + { + SelectPalette( mainhDC, hpalOld, FALSE ); + RealizePalette( mainhDC ); + hpalOld = NULL; + } + + if ( hdcDIBSection ) + { + SelectObject( hdcDIBSection, previously_selected_GDI_obj ); + DeleteDC( hdcDIBSection ); + hdcDIBSection = NULL; + } + + if ( hDIBSection ) + { + DeleteObject( hDIBSection ); + hDIBSection = NULL; + pDIBBase = NULL; + } + + if ( mainhDC ) + { + ReleaseDC( mainwindow, mainhDC ); + mainhDC = 0; + } +} + + +/* +** DIB_Save/RestoreSystemColors +*/ +static void DIB_RestoreSystemColors( void ) +{ + SetSystemPaletteUse( mainhDC, SYSPAL_STATIC ); + SetSysColors( NUM_SYS_COLORS, s_syspalindices, s_oldsyscolors ); +} + +static void DIB_SaveSystemColors( void ) +{ + int i; + + for ( i = 0; i < NUM_SYS_COLORS; i++ ) + s_oldsyscolors[i] = GetSysColor( s_syspalindices[i] ); +} + + + +void DIB_SwapBuffers(void) +{ + extern float usingstretch; + if ( vid_palettized ) + { +// holdpal = SelectPalette(hdcScreen, hpalDIB, FALSE); +// RealizePalette(hdcScreen); + } + + if (usingstretch == 1) + BitBlt( mainhDC, + 0, 0, + vid.width, + vid.height, + hdcDIBSection, + 0, 0, + SRCCOPY ); + else + StretchBlt( mainhDC, //Why is StretchBlt not optimised for a scale of 2? Surly that would be a frequently used quantity? + 0, 0, + vid.width*usingstretch, + vid.height*usingstretch, + hdcDIBSection, + 0, 0, + vid.width, vid.height, + SRCCOPY ); + + if ( vid_palettized ) + { +// SelectPalette(hdcScreen, holdpal, FALSE); + } +} + diff --git a/engine/sw/vid_win2.c b/engine/sw/vid_win2.c new file mode 100644 index 000000000..3fb01fd46 --- /dev/null +++ b/engine/sw/vid_win2.c @@ -0,0 +1,1066 @@ + +#include "quakedef.h" +#include "winquake.h" +#include "r_local.h" +#include "d_local.h" + + +HWND mainwindow; +int window_center_x, window_center_y, window_x, window_y, window_width, window_height; +RECT window_rect; + +#ifdef MGL +qboolean usingmgl=true; +#endif + +qboolean VID_AllocBuffers (int width, int height, int bpp); + +qboolean DDActive; + +qbyte vid_curpal[256*3]; + +//cvar_t _windowed_mouse = {"_windowed_mouse","1", true}; +float usingstretch; + + +qboolean vid_initializing; +extern qboolean vid_isfullscreen; + +static qbyte *vid_surfcache; +static int vid_surfcachesize; +static int VID_highhunkmark; + + + + + + +void SWimp_AppActivate( qboolean active ); +void SWimp_Shutdown( void ); + +qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch ); +void DIB_SwapBuffers(void); +void DIB_Shutdown( void ); +void DIB_SetPalette( const unsigned char *_pal ); + +qboolean DDRAW_Init(rendererstate_t *info, unsigned char **ppbuffer, int *ppitch ); +void DDRAW_SwapBuffers (void); +void DDRAW_Shutdown(void); +void DDRAW_SetPalette( const unsigned char *pal ); + + +extern int r_flushcache; + +void R_GammaCorrectAndSetPalette(const unsigned char *pal) +{ + int i; + int v; + int r,g,b, bgr; + int *table, *bgrt; + unsigned short *pal16 = d_8to16table; + qbyte *cp = vid_curpal; + + if (r_pixbytes == 2) //16 bit needs a 16 bit colormap. + { + extern qbyte gammatable[256]; + int j, i; + float f; + unsigned short *data; + r_flushcache++; + if (!vid.colormap16) + vid.colormap16 = BZ_Malloc(sizeof(short)*256*VID_GRADES+sizeof(int)); + data = vid.colormap16; + for (j = 0; j < VID_GRADES; j++) + { + f = (1 - ((float)j/VID_GRADES)); + f = (float)gammatable[(int)(f*255)]/255; + for (i = 0; i < 256; i++) + { + data[i] = ((int)(pal[i*3+0]*f*(1<value ) + { + WIN_EnableAltTab(); + } +*/ } + else + { + CDAudio_Resume (); + S_UnblockSound (); +/* if ( win_noalttab->value ) + { + WIN_DisableAltTab(); + } +*/ } +} + +void VID2_UpdateWindowStatus (void) +{ + + window_rect.left = window_x; + window_rect.top = window_y; + window_rect.right = window_x + window_width; + window_rect.bottom = window_y + window_height; + window_center_x = (window_rect.left + window_rect.right) / 2; + window_center_y = (window_rect.top + window_rect.bottom) / 2; + + IN_UpdateClipCursor (); +} + +LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +/* main window procedure */ +LONG WINAPI MainWndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 0; + int fActive, fMinimized, temp; + HDC hdc; + PAINTSTRUCT ps; + extern unsigned int uiWheelMessage; + static int recursiveflag; + + if ( uMsg == uiWheelMessage ) { + uMsg = WM_MOUSEWHEEL; + wParam <<= 16; + } + + + switch (uMsg) + { + case WM_CREATE: + break; + + case WM_SYSCOMMAND: + + // Check for maximize being hit + switch (wParam & ~0x0F) + { + case SC_MAXIMIZE: + Cbuf_AddText("vid_fullscreen 1;vid_restart\n", RESTRICT_LOCAL); + // if minimized, bring up as a window before going fullscreen, + // so MGL will have the right state to restore +/* if (Minimized) + { + force_mode_set = true; + VID_SetMode (vid_modenum, vid_curpal); + force_mode_set = false; + } + + VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal); +*/ break; + + case SC_SCREENSAVE: + case SC_MONITORPOWER: + if (vid_isfullscreen) + { + // don't call DefWindowProc() because we don't want to start + // the screen saver fullscreen + break; + } + + // fall through windowed and allow the screen saver to start + + default: +// if (!vid_initializing) +// { +// S_BlockSound (); +// } + + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + +// if (!vid_initializing) +// { +// S_UnblockSound (); +// } + } + break; + + case WM_MOVE: + window_x = (int) LOWORD(lParam); + window_y = (int) HIWORD(lParam); + VID2_UpdateWindowStatus (); + +// if ((modestate == MS_WINDOWED) && !in_mode_set && !Minimized) +// VID_RememberWindowPos (); + + break; + + case WM_SIZE: + Minimized = false; + + if (!(wParam & SIZE_RESTORED)) + { + if (wParam & SIZE_MINIMIZED) + Minimized = true; + } + + if (!Minimized && !vid_initializing && !vid_isfullscreen) + { + int nt, nl; + int nw, nh; + qboolean move = false; + RECT r; + GetClientRect (hWnd, &r); + nw = (int)((r.right - r.left)/usingstretch)&~3; + nh = (int)((r.bottom - r.top)/usingstretch)&~3; + + window_width = nw; + window_height = nh; + VID2_UpdateWindowStatus(); + + if (nw < 320) + { + move = true; + nw = 320; + } + if (nh < 200) + { + move = true; + nh = 200; + } + if (nh > MAXHEIGHT) + { + move = true; + nh = MAXHEIGHT; + } + if ((r.right - r.left) & 3) + move = true; + if ((r.bottom - r.top) & 3) + move = true; + + GetWindowRect (hWnd, &r); + nl = r.left; + nt = r.top; + r.left =0; + r.top = 0; + r.right = nw*usingstretch; + r.bottom = nh*usingstretch; + AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW, FALSE, 0); + vid.recalc_refdef = true; + if (move) + MoveWindow(hWnd, nl, nt, r.right - r.left, r.bottom - r.top, true); + else + { + if (vid.width != nw || vid.height != nh) + { + M_RemoveAllMenus(); //can cause probs + DIB_Shutdown(); + vid.conwidth = vid.width = nw;//vid_stretch.value; + vid.conheight = vid.height = nh;///vid_stretch.value; + + DIB_Init( &vid.buffer, &vid.rowbytes ); + vid.conbuffer = vid.buffer; + vid.conrowbytes = vid.rowbytes; + + if (VID_AllocBuffers(vid.width, vid.height, r_pixbytes)) + D_InitCaches (vid_surfcache, vid_surfcachesize); + + SCR_UpdateWholeScreen(); + } + else + SCR_UpdateWholeScreen(); + } + + } + break; + + case WM_SYSCHAR: + // keep Alt-Space from happening + break; + + case WM_ACTIVATE: + fActive = LOWORD(wParam); + fMinimized = (BOOL) HIWORD(wParam); + SWAppActivate(!(fActive == WA_INACTIVE), fMinimized); + + // fix the leftover Alt from any Alt-Tab or the like that switched us away +// ClearAllStates (); + + break; + + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + +// if (!in_mode_set && host_initialized) +// SCR_UpdateWholeScreen (); + + EndPaint(hWnd, &ps); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (!vid_initializing) + Key_Event (MapKey(lParam), true); + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + if (!vid_initializing) + Key_Event (MapKey(lParam), false); + break; + + // this is complicated because Win32 seems to pack multiple mouse events into + // one update sometimes, so we always check all states and look for events + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEMOVE: + if (!vid_initializing) + { + temp = 0; + + if (wParam & MK_LBUTTON) + temp |= 1; + + if (wParam & MK_RBUTTON) + temp |= 2; + + if (wParam & MK_MBUTTON) + temp |= 4; + + IN_MouseEvent (temp); + } + break; + // JACK: This is the mouse wheel with the Intellimouse + // Its delta is either positive or neg, and we generate the proper + // Event. + case WM_MOUSEWHEEL: + if ((short) HIWORD(wParam) > 0) { + Key_Event(K_MWHEELUP, true); + Key_Event(K_MWHEELUP, false); + } else { + Key_Event(K_MWHEELDOWN, true); + Key_Event(K_MWHEELDOWN, false); + } + break; + // KJB: Added these new palette functions +/* case WM_PALETTECHANGED: + if ((HWND)wParam == hWnd) + break; + // Fall through to WM_QUERYNEWPALETTE + case WM_QUERYNEWPALETTE: + hdc = GetDC(NULL); + + if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) + vid_palettized = true; + else + vid_palettized = false; + + ReleaseDC(NULL,hdc); + + scr_fullupdate = 0; + + if (vid_initialized && !in_mode_set && windc && MGL_activatePalette(windc,false) && !Minimized) + { + VID_SetPalette (vid_curpal); + InvalidateRect (mainwindow, NULL, false); + + // specifically required if WM_QUERYNEWPALETTE realizes a new palette + lRet = TRUE; + } + break; + +/* case WM_DISPLAYCHANGE: + if (!in_mode_set && (modestate == MS_WINDOWED) && !vid_fulldib_on_focus_mode) + { + force_mode_set = true; + VID_SetMode (vid_modenum, vid_curpal); + force_mode_set = false; + } + break; +*/ + case WM_CLOSE: + // this causes Close in the right-click task bar menu not to work, but right + // now bad things happen if Close is handled in that case (garbage and a + // crash on Win95) + if (!vid_initializing) + { + if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", + MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) + { + Sys_Quit (); + } + } + break; + + case MM_MCINOTIFY: + lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); + break; + + case WM_MWHOOK: + MW_Hook_Message (lParam); + break; + + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 0 if handled message, 1 if not */ + return lRet; +} + + + +/* +** VID_CreateWindow +*/ +#define WINDOW_CLASS_NAME "FTE QuakeWorld" +#define WINDOW_TITLE_NAME "FTE QuakeWorld" + + +void VID_CreateWindow( int width, int height, qboolean fullscreen) +{ + WNDCLASS wc; + RECT r; + int x, y, w, h; + int exstyle; + int stylebits; + + + if ( fullscreen ) + { + exstyle = WS_EX_TOPMOST; + stylebits = WS_POPUP; + } + else + { + exstyle = 0; + stylebits = WS_OVERLAPPEDWINDOW; + } + + /* Register the frame class */ + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = global_hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = (void *)COLOR_GRAYTEXT; + wc.lpszMenuName = 0; + wc.lpszClassName = WINDOW_CLASS_NAME; + + if (!RegisterClass (&wc) ) + Sys_Error ("Couldn't register window class"); + + r.left = 0; + r.top = 0; + r.right = width*usingstretch; + r.bottom = height*usingstretch; + + AdjustWindowRectEx (&r, stylebits, FALSE, exstyle); + + window_rect = r; + + w = r.right - r.left; + h = r.bottom - r.top; + x = 0;//vid_xpos.value; + y = 0;//vid_ypos.value; + + mainwindow = CreateWindowEx ( + exstyle, + WINDOW_CLASS_NAME, + WINDOW_TITLE_NAME, + stylebits, + x, y, w, h, + NULL, + NULL, + global_hInstance, + NULL); + + if (!mainwindow) + Sys_Error ( "Couldn't create window"); + + ShowWindow( mainwindow, SW_SHOWNORMAL ); + UpdateWindow( mainwindow ); + SetForegroundWindow( mainwindow ); + SetFocus( mainwindow ); + + window_x = x; + window_y = y; + window_width = w; + window_height = h; + + VID2_UpdateWindowStatus(); + + // let the sound and input subsystems know about the new window +// ri.Vid_NewWindow (width, height); +} + +/* +** SWimp_Init +** +** This routine is responsible for initializing the implementation +** specific stuff in a software rendering subsystem. +*/ +int SWimp_Init( void *hInstance, void *wndProc ) +{ +// sww_state.hInstance = ( HINSTANCE ) hInstance; +// sww_state.wndproc = wndProc; + + return true; +} + +/* +** SWimp_InitGraphics +** +** This initializes the software refresh's implementation specific +** graphics subsystem. In the case of Windows it creates DIB or +** DDRAW surfaces. +** +** The necessary width and height parameters are grabbed from +** vid.width and vid.height. +*/ +static qboolean SWimp_InitGraphics( rendererstate_t *info, qboolean fullscreen ) +{ + // free resources in use + SWimp_Shutdown (); + + usingstretch = info->streach; + if (fullscreen || usingstretch < 0.25) + usingstretch = 1; + + // create a new window + VID_CreateWindow (vid.width, vid.height, fullscreen); + + // initialize the appropriate subsystem + if ( !fullscreen ) + { + if (COM_CheckParm("-nodib")) + { + vid.buffer = 0; + vid.rowbytes = 0; + return false; + } + + if ( !DIB_Init( &vid.buffer, &vid.rowbytes ) ) + { + vid.buffer = 0; + vid.rowbytes = 0; + + return false; + } + } + else + { + if (COM_CheckParm("-noddraw")) + { + vid.buffer = 0; + vid.rowbytes = 0; + return false; + } + + if ( !DDRAW_Init( info, &vid.buffer, &vid.rowbytes ) ) + { + vid.buffer = 0; + vid.rowbytes = 0; + + return false; + } + } + + vid.conbuffer = vid.buffer; + vid.conrowbytes = vid.rowbytes; + + return true; +} + +/* +** SWimp_EndFrame +** +** This does an implementation specific copy from the backbuffer to the +** front buffer. In the Win32 case it uses BitBlt or BltFast depending +** on whether we're using DIB sections/GDI or DDRAW. +*/ +void SWimp_EndFrame (void) +{ + if ( !vid_isfullscreen ) + { + DIB_SwapBuffers (); + } + else + { + DDRAW_SwapBuffers(); + } + + vid.conbuffer = vid.buffer; + vid.conrowbytes = vid.rowbytes; +} + +qboolean VID_AllocBuffers (int width, int height, int bpp) +{ + int tsize, tbuffersize; + if (!bpp) + bpp = 1; + + tbuffersize = width * height * bpp * sizeof (*d_pzbuffer); + + tsize = D_SurfaceCacheForRes (width, height, bpp); + + tbuffersize += tsize; + +// see if there's enough memory, allowing for the normal mode 0x13 pixel, +// z, and surface buffers +/* if (host_parms.memsize - (Hunk_LowMark() + VID_highhunkmark) < tbuffersize && + (host_parms.memsize - tbuffersize + bpp*(SURFCACHE_SIZE_AT_320X200 + + 0x10000 * 3)) < MINIMUM_MEMORY) + { + Con_SafePrintf ("Not enough memory for video mode\n"); + return false; // not enough memory for mode + } +*/ + vid_surfcachesize = tsize; + + if (d_pzbuffer) + { + D_FlushCaches (); +// Hunk_FreeToHighMark (VID_highhunkmark); + BZ_Free(d_pzbuffer); + d_pzbuffer = NULL; + } + +// VID_highhunkmark = Hunk_HighMark (); + +// d_pzbuffer = Hunk_HighAllocName (tbuffersize, "video"); + d_pzbuffer = BZ_Malloc(tbuffersize); + + if (!d_pzbuffer) + return false; + + vid_surfcache = (qbyte *)d_pzbuffer + + width * height * bpp * sizeof (*d_pzbuffer); + + return true; +} + +/* +** SWimp_SetMode +*/ +typedef enum {err_ok, err_invalid_mode, err_invalid_fullscreen, err_unknown} err_t; +err_t SWimp_SetMode( rendererstate_t *info ) +{ + const char *win_fs[] = { "W", "FS" }; + err_t retval = err_ok; + + qboolean fullscreen = info->fullscreen; + + Con_SafePrintf ( "setting mode %i*%i:", info->width, info->height ); + + vid.conwidth = info->width; + vid.conheight = info->height; + vid.width = info->width; + vid.height = info->height; + + Con_SafePrintf( " %d %d %s\n", info->width, info->height, win_fs[info->fullscreen!=0] ); + + vid_initializing = true; + if ( fullscreen ) + { + if ( !SWimp_InitGraphics( info, true ) ) + { + if ( SWimp_InitGraphics( info, false ) ) + { + // mode is legal but not as fullscreen + fullscreen = false; + retval = err_invalid_fullscreen; + } + else + { + // failed to set a valid mode in windowed mode + vid_initializing = true; + return err_unknown; + } + } + } + else + { + // failure to set a valid mode in windowed mode + if ( !SWimp_InitGraphics( info, false ) ) + { + vid_initializing = true; + return err_unknown; + } + } + + VID_AllocBuffers(info->width, info->height, r_pixbytes); + D_InitCaches (vid_surfcache, vid_surfcachesize); + + vid.conbuffer = vid.buffer; + + vid_isfullscreen = fullscreen; +#if 0 + if ( retval != rserr_unknown ) + { + if ( retval == rserr_invalid_fullscreen || + ( retval == rserr_ok && !fullscreen ) ) + { + SetWindowLong( sww_state.hWnd, GWL_STYLE, WINDOW_STYLE ); + } + } +#endif + R_GammaCorrectAndSetPalette( ( const unsigned char * ) vid_curpal ); + vid_initializing = false; + + vid.recalc_refdef = 1; + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + vid.aspect = ((float)vid.height / (float)vid.width) * + (320.0 / 240.0); + + vid.numpages = 1; + + window_center_x = vid.width/2; + window_center_y = vid.height/2; + + Cache_Flush(); + + return retval; +} + +/* +** SWimp_SetPalette +** +** System specific palette setting routine. A NULL palette means +** to use the existing palette. The palette is expected to be in +** a padded 4-qbyte xRGB format. +*/ +void SWimp_SetPalette( const unsigned char *palette ) +{ + // MGL - what the fuck was kendall doing here?! + // clear screen to black and change palette + // for (i=0 ; iheight > MAXHEIGHT) + return false; + + usingstretch = info->streach; + if (usingstretch <= 0.25) + usingstretch = 1; + + if (info->bpp >= 32) + r_pixbytes = 4; + else if (info->bpp >= 16) + r_pixbytes = 2; + else + r_pixbytes = 1; + + vid.colormap = host_colormap; + + SWimp_Init(global_hInstance, MainWndProc); + SWimp_SetPalette(palette); + + if (hwnd_dialog) + DestroyWindow (hwnd_dialog); + + if (SWimp_SetMode(info)) + { + Sys_Error("Failed to set video mode\n"); + return false; + } + + S_Restart_f (); + + return true; +} + +void SWVID_Shutdown (void) +{ +#ifdef MGL + if (usingmgl) + { + MGL_Shutdown(); + return; + } +#endif + IN_DeactivateMouse(); + IN_ShowMouse(); + SWimp_Shutdown(); +} + +void SWVID_Update (vrect_t *rects) //end frame... +{ + extern qboolean mouseactive; + qboolean mouse; +#ifdef MGL + if (usingmgl) + { + MGL_Update(rects); + return; + } +#endif + SWimp_EndFrame(); + + // handle the mouse state when windowed if that's changed + if (!vid_isfullscreen) + { + mouse = false; + if (_windowed_mouse.value) + if (key_dest == key_game)// || key_dest == key_menu) + mouse = true; + } + else + { + if (key_dest == key_menu) + mouse = false; + else + mouse = true; + } + if (!ActiveApp) + mouse = false; //nope can't have it. + if (mouse != mouseactive) + { + if (mouse) + { + IN_ActivateMouse(); + IN_HideMouse(); + IN_UpdateClipCursor(); + } + else + { + IN_DeactivateMouse(); + IN_ShowMouse(); + } + } +} + +void SWVID_HandlePause (qboolean pause) //release mouse +{ +#ifdef MGL + if (usingmgl) + { + MGL_HandlePause(pause); + return; + } +#endif +} + +void SWVID_LockBuffer (void) //ignored +{ +#ifdef MGL + if (usingmgl) + { + MGL_LockBuffer(); + return; + } +#endif +} +void SWVID_UnlockBuffer (void) //ignored +{ +#ifdef MGL + if (usingmgl) + { + MGL_UnlockBuffer(); + return; + } +#endif +} + +void SWD_BeginDirectRect (int x, int y, qbyte *pbitmap, int width, int height) +{ +#ifdef MGL + if (usingmgl) + { + MGL_BeginDirectRect(x, y, pbitmap, width, height); + return; + } +#endif +} +void SWD_EndDirectRect (int x, int y, int width, int height) +{ +#ifdef MGL + if (usingmgl) + { + MGL_EndDirectRect(x, y, width, height); + return; + } +#endif +} + + +void SWVID_ForceLockState (int lk) +{ +#ifdef MGL + if (usingmgl) + { + MGL_ForceLockState(lk); + return; + } +#endif +} +int SWVID_ForceUnlockedAndReturnState (void) +{ +#ifdef MGL + if (usingmgl) + { + return MGL_ForceUnlockedAndReturnState(); + } +#endif + return 0; +} + + + + +void SWVID_SetPalette (unsigned char *palette) +{ +#ifdef MGL + if (usingmgl) + { + VMGL_SetPalette(palette); + return; + } +#endif + SWimp_SetPalette(palette); +} + +void SWVID_ShiftPalette (unsigned char *palette) +{ +#ifdef MGL + if (usingmgl) + { + MGL_ShiftPalette(palette); + return; + } +#endif + SWimp_SetPalette(palette); +} + + + + +