diff --git a/src/refresh/opengl/constants/anorms.h b/src/refresh/opengl/constants/anorms.h new file mode 100644 index 00000000..011582eb --- /dev/null +++ b/src/refresh/opengl/constants/anorms.h @@ -0,0 +1,181 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/src/refresh/opengl/constants/anormtab.h b/src/refresh/opengl/constants/anormtab.h new file mode 100644 index 00000000..fc08f558 --- /dev/null +++ b/src/refresh/opengl/constants/anormtab.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +{ +{1.23,1.30,1.47,1.35,1.56,1.71,1.37,1.38,1.59,1.60,1.79,1.97,1.88,1.92,1.79,1.02,0.93,1.07,0.82,0.87,0.88,0.94,0.96,1.14,1.11,0.82,0.83,0.89,0.89,0.86,0.94,0.91,1.00,1.21,0.98,1.48,1.30,1.57,0.96,1.07,1.14,1.60,1.61,1.40,1.37,1.72,1.78,1.79,1.93,1.99,1.90,1.68,1.71,1.86,1.60,1.68,1.78,1.86,1.93,1.99,1.97,1.44,1.22,1.49,0.93,0.99,0.99,1.23,1.22,1.44,1.49,0.89,0.89,0.97,0.91,0.98,1.19,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.19,0.98,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.87,0.93,0.94,1.02,1.30,1.07,1.35,1.38,1.11,1.56,1.92,1.79,1.79,1.59,1.60,1.72,1.90,1.79,0.80,0.85,0.79,0.93,0.80,0.85,0.77,0.74,0.72,0.77,0.74,0.72,0.70,0.70,0.71,0.76,0.73,0.79,0.79,0.73,0.76,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.26,1.26,1.48,1.23,1.50,1.71,1.14,1.19,1.38,1.46,1.64,1.94,1.87,1.84,1.71,1.02,0.92,1.00,0.79,0.85,0.84,0.91,0.90,0.98,0.99,0.77,0.77,0.83,0.82,0.79,0.86,0.84,0.92,0.99,0.91,1.24,1.03,1.33,0.88,0.94,0.97,1.41,1.39,1.18,1.11,1.51,1.61,1.59,1.80,1.91,1.76,1.54,1.65,1.76,1.70,1.70,1.85,1.85,1.97,1.99,1.93,1.28,1.09,1.39,0.92,0.97,0.99,1.18,1.26,1.52,1.48,0.83,0.85,0.90,0.88,0.93,1.00,0.77,0.73,0.78,0.72,0.71,0.74,0.75,0.79,0.86,0.81,0.75,0.81,0.79,0.96,0.88,0.94,0.86,0.93,0.92,0.85,1.08,1.33,1.05,1.55,1.31,1.01,1.05,1.27,1.31,1.60,1.47,1.70,1.54,1.76,1.76,1.57,0.93,0.90,0.99,0.88,0.88,0.95,0.97,1.11,1.39,1.20,0.92,0.97,1.01,1.10,1.39,1.22,1.51,1.58,1.32,1.64,1.97,1.85,1.91,1.77,1.74,1.88,1.99,1.91,0.79,0.86,0.80,0.94,0.84,0.88,0.74,0.74,0.71,0.82,0.77,0.76,0.70,0.73,0.72,0.73,0.70,0.74,0.85,0.77,0.82,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.34,1.27,1.53,1.17,1.46,1.71,0.98,1.05,1.20,1.34,1.48,1.86,1.82,1.71,1.62,1.09,0.94,0.99,0.79,0.85,0.82,0.90,0.87,0.93,0.96,0.76,0.74,0.79,0.76,0.74,0.79,0.78,0.85,0.92,0.85,1.00,0.93,1.06,0.81,0.86,0.89,1.16,1.12,0.97,0.95,1.28,1.38,1.35,1.60,1.77,1.57,1.33,1.50,1.58,1.69,1.63,1.82,1.74,1.91,1.92,1.80,1.04,0.97,1.21,0.90,0.93,0.97,1.05,1.21,1.48,1.37,0.77,0.80,0.84,0.85,0.88,0.92,0.73,0.71,0.74,0.74,0.71,0.75,0.73,0.79,0.84,0.78,0.79,0.86,0.81,1.05,0.94,0.99,0.90,0.95,0.92,0.86,1.24,1.44,1.14,1.59,1.34,1.02,1.27,1.50,1.49,1.80,1.69,1.86,1.72,1.87,1.80,1.69,1.00,0.98,1.23,0.95,0.96,1.09,1.16,1.37,1.63,1.46,0.99,1.10,1.25,1.24,1.51,1.41,1.67,1.77,1.55,1.72,1.95,1.89,1.98,1.91,1.86,1.97,1.99,1.94,0.81,0.89,0.85,0.98,0.90,0.94,0.75,0.78,0.73,0.89,0.83,0.82,0.72,0.77,0.76,0.72,0.70,0.71,0.91,0.83,0.89,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.46,1.34,1.60,1.16,1.46,1.71,0.94,0.99,1.05,1.26,1.33,1.74,1.76,1.57,1.54,1.23,0.98,1.05,0.83,0.89,0.84,0.92,0.87,0.91,0.96,0.78,0.74,0.79,0.72,0.72,0.75,0.76,0.80,0.88,0.83,0.94,0.87,0.95,0.76,0.80,0.82,0.97,0.96,0.89,0.88,1.08,1.11,1.10,1.37,1.59,1.37,1.07,1.27,1.34,1.57,1.45,1.69,1.55,1.77,1.79,1.60,0.93,0.90,0.99,0.86,0.87,0.93,0.96,1.07,1.35,1.18,0.73,0.76,0.77,0.81,0.82,0.85,0.70,0.71,0.72,0.78,0.73,0.77,0.73,0.79,0.82,0.76,0.83,0.90,0.84,1.18,0.98,1.03,0.92,0.95,0.90,0.86,1.32,1.45,1.15,1.53,1.27,0.99,1.42,1.65,1.58,1.93,1.83,1.94,1.81,1.88,1.74,1.70,1.19,1.17,1.44,1.11,1.15,1.36,1.41,1.61,1.81,1.67,1.22,1.34,1.50,1.42,1.65,1.61,1.82,1.91,1.75,1.80,1.89,1.89,1.98,1.99,1.94,1.98,1.92,1.87,0.86,0.95,0.92,1.14,0.98,1.03,0.79,0.84,0.77,0.97,0.90,0.89,0.76,0.82,0.82,0.74,0.72,0.71,0.98,0.89,0.97,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.60,1.44,1.68,1.22,1.49,1.71,0.93,0.99,0.99,1.23,1.22,1.60,1.68,1.44,1.49,1.40,1.14,1.19,0.89,0.96,0.89,0.97,0.89,0.91,0.98,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.91,0.83,0.89,0.72,0.76,0.76,0.89,0.89,0.82,0.82,0.98,0.96,0.97,1.14,1.40,1.19,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.70,0.72,0.73,0.77,0.76,0.79,0.70,0.72,0.71,0.82,0.77,0.80,0.74,0.79,0.80,0.74,0.87,0.93,0.85,1.23,1.02,1.02,0.93,0.93,0.87,0.85,1.30,1.35,1.07,1.38,1.11,0.94,1.47,1.71,1.56,1.97,1.88,1.92,1.79,1.79,1.59,1.60,1.30,1.35,1.56,1.37,1.38,1.59,1.60,1.79,1.92,1.79,1.48,1.57,1.72,1.61,1.78,1.79,1.93,1.99,1.90,1.86,1.78,1.86,1.93,1.99,1.97,1.90,1.79,1.72,0.94,1.07,1.00,1.37,1.21,1.30,0.86,0.91,0.83,1.14,0.98,0.96,0.82,0.88,0.89,0.79,0.76,0.73,1.07,0.94,1.11,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.74,1.57,1.76,1.33,1.54,1.71,0.94,1.05,0.99,1.26,1.16,1.46,1.60,1.34,1.46,1.59,1.37,1.37,0.97,1.11,0.96,1.10,0.95,0.94,1.08,0.89,0.82,0.88,0.72,0.76,0.75,0.80,0.80,0.88,0.87,0.91,0.83,0.87,0.72,0.76,0.74,0.83,0.84,0.78,0.79,0.96,0.89,0.92,0.98,1.23,1.05,0.86,0.92,0.95,1.11,0.98,1.22,1.03,1.34,1.42,1.14,0.79,0.77,0.84,0.78,0.76,0.82,0.82,0.89,0.97,0.90,0.70,0.71,0.71,0.73,0.72,0.74,0.73,0.76,0.72,0.86,0.81,0.82,0.76,0.79,0.77,0.73,0.90,0.95,0.86,1.18,1.03,0.98,0.92,0.90,0.83,0.84,1.19,1.17,0.98,1.15,0.97,0.89,1.42,1.65,1.44,1.93,1.83,1.81,1.67,1.61,1.36,1.41,1.32,1.45,1.58,1.57,1.53,1.74,1.70,1.88,1.94,1.81,1.69,1.77,1.87,1.79,1.89,1.92,1.98,1.99,1.98,1.89,1.65,1.80,1.82,1.91,1.94,1.75,1.61,1.50,1.07,1.34,1.27,1.60,1.45,1.55,0.93,0.99,0.90,1.35,1.18,1.07,0.87,0.93,0.96,0.85,0.82,0.77,1.15,0.99,1.27,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.86,1.71,1.82,1.48,1.62,1.71,0.98,1.20,1.05,1.34,1.17,1.34,1.53,1.27,1.46,1.77,1.60,1.57,1.16,1.38,1.12,1.35,1.06,1.00,1.28,0.97,0.89,0.95,0.76,0.81,0.79,0.86,0.85,0.92,0.93,0.93,0.85,0.87,0.74,0.78,0.74,0.79,0.82,0.76,0.79,0.96,0.85,0.90,0.94,1.09,0.99,0.81,0.85,0.89,0.95,0.90,0.99,0.94,1.10,1.24,0.98,0.75,0.73,0.78,0.74,0.72,0.77,0.76,0.82,0.89,0.83,0.73,0.71,0.71,0.71,0.70,0.72,0.77,0.80,0.74,0.90,0.85,0.84,0.78,0.79,0.75,0.73,0.92,0.95,0.86,1.05,0.99,0.94,0.90,0.86,0.79,0.81,1.00,0.98,0.91,0.96,0.89,0.83,1.27,1.50,1.23,1.80,1.69,1.63,1.46,1.37,1.09,1.16,1.24,1.44,1.49,1.69,1.59,1.80,1.69,1.87,1.86,1.72,1.82,1.91,1.94,1.92,1.95,1.99,1.98,1.91,1.97,1.89,1.51,1.72,1.67,1.77,1.86,1.55,1.41,1.25,1.33,1.58,1.50,1.80,1.63,1.74,1.04,1.21,0.97,1.48,1.37,1.21,0.93,0.97,1.05,0.92,0.88,0.84,1.14,1.02,1.34,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.94,1.84,1.87,1.64,1.71,1.71,1.14,1.38,1.19,1.46,1.23,1.26,1.48,1.26,1.50,1.91,1.80,1.76,1.41,1.61,1.39,1.59,1.33,1.24,1.51,1.18,0.97,1.11,0.82,0.88,0.86,0.94,0.92,0.99,1.03,0.98,0.91,0.90,0.79,0.84,0.77,0.79,0.84,0.77,0.83,0.99,0.85,0.91,0.92,1.02,1.00,0.79,0.80,0.86,0.88,0.84,0.92,0.88,0.97,1.10,0.94,0.74,0.71,0.74,0.72,0.70,0.73,0.72,0.76,0.82,0.77,0.77,0.73,0.74,0.71,0.70,0.73,0.83,0.85,0.78,0.92,0.88,0.86,0.81,0.79,0.74,0.75,0.92,0.93,0.85,0.96,0.94,0.88,0.86,0.81,0.75,0.79,0.93,0.90,0.85,0.88,0.82,0.77,1.05,1.27,0.99,1.60,1.47,1.39,1.20,1.11,0.95,0.97,1.08,1.33,1.31,1.70,1.55,1.76,1.57,1.76,1.70,1.54,1.85,1.97,1.91,1.99,1.97,1.99,1.91,1.77,1.88,1.85,1.39,1.64,1.51,1.58,1.74,1.32,1.22,1.01,1.54,1.76,1.65,1.93,1.70,1.85,1.28,1.39,1.09,1.52,1.48,1.26,0.97,0.99,1.18,1.00,0.93,0.90,1.05,1.01,1.31,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.97,1.92,1.88,1.79,1.79,1.71,1.37,1.59,1.38,1.60,1.35,1.23,1.47,1.30,1.56,1.99,1.93,1.90,1.60,1.78,1.61,1.79,1.57,1.48,1.72,1.40,1.14,1.37,0.89,0.96,0.94,1.07,1.00,1.21,1.30,1.14,0.98,0.96,0.86,0.91,0.83,0.82,0.88,0.82,0.89,1.11,0.87,0.94,0.93,1.02,1.07,0.80,0.79,0.85,0.82,0.80,0.87,0.85,0.93,1.02,0.93,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.82,0.76,0.79,0.72,0.73,0.76,0.89,0.89,0.82,0.93,0.91,0.86,0.83,0.79,0.73,0.76,0.91,0.89,0.83,0.89,0.89,0.82,0.82,0.76,0.72,0.76,0.86,0.83,0.79,0.82,0.76,0.73,0.94,1.00,0.91,1.37,1.21,1.14,0.98,0.96,0.88,0.89,0.96,1.14,1.07,1.60,1.40,1.61,1.37,1.57,1.48,1.30,1.78,1.93,1.79,1.99,1.92,1.90,1.79,1.59,1.72,1.79,1.30,1.56,1.35,1.38,1.60,1.11,1.07,0.94,1.68,1.86,1.71,1.97,1.68,1.86,1.44,1.49,1.22,1.44,1.49,1.22,0.99,0.99,1.23,1.19,0.98,0.97,0.97,0.98,1.19,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.94,1.97,1.87,1.91,1.85,1.71,1.60,1.77,1.58,1.74,1.51,1.26,1.48,1.39,1.64,1.99,1.97,1.99,1.70,1.85,1.76,1.91,1.76,1.70,1.88,1.55,1.33,1.57,0.96,1.08,1.05,1.31,1.27,1.47,1.54,1.39,1.20,1.11,0.93,0.99,0.90,0.88,0.95,0.88,0.97,1.32,0.92,1.01,0.97,1.10,1.22,0.84,0.80,0.88,0.79,0.79,0.85,0.86,0.92,1.02,0.94,0.82,0.76,0.77,0.72,0.73,0.70,0.72,0.71,0.74,0.74,0.88,0.81,0.85,0.75,0.77,0.82,0.94,0.93,0.86,0.92,0.92,0.86,0.85,0.79,0.74,0.79,0.88,0.85,0.81,0.82,0.83,0.77,0.78,0.73,0.71,0.75,0.79,0.77,0.74,0.77,0.73,0.70,0.86,0.92,0.84,1.14,0.99,0.98,0.91,0.90,0.84,0.83,0.88,0.97,0.94,1.41,1.18,1.39,1.11,1.33,1.24,1.03,1.61,1.80,1.59,1.91,1.84,1.76,1.64,1.38,1.51,1.71,1.26,1.50,1.23,1.19,1.46,0.99,1.00,0.91,1.70,1.85,1.65,1.93,1.54,1.76,1.52,1.48,1.26,1.28,1.39,1.09,0.99,0.97,1.18,1.31,1.01,1.05,0.90,0.93,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.86,1.95,1.82,1.98,1.89,1.71,1.80,1.91,1.77,1.86,1.67,1.34,1.53,1.51,1.72,1.92,1.91,1.99,1.69,1.82,1.80,1.94,1.87,1.86,1.97,1.59,1.44,1.69,1.05,1.24,1.27,1.49,1.50,1.69,1.72,1.63,1.46,1.37,1.00,1.23,0.98,0.95,1.09,0.96,1.16,1.55,0.99,1.25,1.10,1.24,1.41,0.90,0.85,0.94,0.79,0.81,0.85,0.89,0.94,1.09,0.98,0.89,0.82,0.83,0.74,0.77,0.72,0.76,0.73,0.75,0.78,0.94,0.86,0.91,0.79,0.83,0.89,0.99,0.95,0.90,0.90,0.92,0.84,0.86,0.79,0.75,0.81,0.85,0.80,0.78,0.76,0.77,0.73,0.74,0.71,0.71,0.73,0.74,0.74,0.71,0.76,0.72,0.70,0.79,0.85,0.78,0.98,0.92,0.93,0.85,0.87,0.82,0.79,0.81,0.89,0.86,1.16,0.97,1.12,0.95,1.06,1.00,0.93,1.38,1.60,1.35,1.77,1.71,1.57,1.48,1.20,1.28,1.62,1.27,1.46,1.17,1.05,1.34,0.96,0.99,0.90,1.63,1.74,1.50,1.80,1.33,1.58,1.48,1.37,1.21,1.04,1.21,0.97,0.97,0.93,1.05,1.34,1.02,1.14,0.84,0.88,0.92,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.74,1.89,1.76,1.98,1.89,1.71,1.93,1.99,1.91,1.94,1.82,1.46,1.60,1.65,1.80,1.79,1.77,1.92,1.57,1.69,1.74,1.87,1.88,1.94,1.98,1.53,1.45,1.70,1.18,1.32,1.42,1.58,1.65,1.83,1.81,1.81,1.67,1.61,1.19,1.44,1.17,1.11,1.36,1.15,1.41,1.75,1.22,1.50,1.34,1.42,1.61,0.98,0.92,1.03,0.83,0.86,0.89,0.95,0.98,1.23,1.14,0.97,0.89,0.90,0.78,0.82,0.76,0.82,0.77,0.79,0.84,0.98,0.90,0.98,0.83,0.89,0.97,1.03,0.95,0.92,0.86,0.90,0.82,0.86,0.79,0.77,0.84,0.81,0.76,0.76,0.72,0.73,0.70,0.72,0.71,0.73,0.73,0.72,0.74,0.71,0.78,0.74,0.72,0.75,0.80,0.76,0.94,0.88,0.91,0.83,0.87,0.84,0.79,0.76,0.82,0.80,0.97,0.89,0.96,0.88,0.95,0.94,0.87,1.11,1.37,1.10,1.59,1.57,1.37,1.33,1.05,1.08,1.54,1.34,1.46,1.16,0.99,1.26,0.96,1.05,0.92,1.45,1.55,1.27,1.60,1.07,1.34,1.35,1.18,1.07,0.93,0.99,0.90,0.93,0.87,0.96,1.27,0.99,1.15,0.77,0.82,0.85,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.60,1.78,1.68,1.93,1.86,1.71,1.97,1.99,1.99,1.97,1.93,1.60,1.68,1.78,1.86,1.61,1.57,1.79,1.37,1.48,1.59,1.72,1.79,1.92,1.90,1.38,1.35,1.60,1.23,1.30,1.47,1.56,1.71,1.88,1.79,1.92,1.79,1.79,1.30,1.56,1.35,1.37,1.59,1.38,1.60,1.90,1.48,1.72,1.57,1.61,1.79,1.21,1.00,1.30,0.89,0.94,0.96,1.07,1.14,1.40,1.37,1.14,0.96,0.98,0.82,0.88,0.82,0.89,0.83,0.86,0.91,1.02,0.93,1.07,0.87,0.94,1.11,1.02,0.93,0.93,0.82,0.87,0.80,0.85,0.79,0.80,0.85,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.72,0.76,0.73,0.82,0.79,0.76,0.73,0.79,0.76,0.93,0.86,0.91,0.83,0.89,0.89,0.82,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.44,1.19,1.22,0.99,0.98,1.49,1.44,1.49,1.22,0.99,1.23,0.98,1.19,0.97,1.21,1.30,1.00,1.37,0.94,1.07,1.14,0.98,0.96,0.86,0.91,0.83,0.88,0.82,0.89,1.11,0.94,1.07,0.73,0.76,0.79,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.46,1.65,1.60,1.82,1.80,1.71,1.93,1.91,1.99,1.94,1.98,1.74,1.76,1.89,1.89,1.42,1.34,1.61,1.11,1.22,1.36,1.50,1.61,1.81,1.75,1.15,1.17,1.41,1.18,1.19,1.42,1.44,1.65,1.83,1.67,1.94,1.81,1.88,1.32,1.58,1.45,1.57,1.74,1.53,1.70,1.98,1.69,1.87,1.77,1.79,1.92,1.45,1.27,1.55,0.97,1.07,1.11,1.34,1.37,1.59,1.60,1.35,1.07,1.18,0.86,0.93,0.87,0.96,0.90,0.93,0.99,1.03,0.95,1.15,0.90,0.99,1.27,0.98,0.90,0.92,0.78,0.83,0.77,0.84,0.79,0.82,0.86,0.73,0.71,0.73,0.72,0.70,0.73,0.72,0.76,0.81,0.76,0.76,0.82,0.77,0.89,0.85,0.82,0.75,0.80,0.80,0.94,0.88,0.94,0.87,0.95,0.96,0.88,0.72,0.74,0.76,0.83,0.78,0.84,0.79,0.87,0.91,0.83,0.89,0.98,0.92,1.23,1.34,1.05,1.16,0.99,0.96,1.46,1.57,1.54,1.33,1.05,1.26,1.08,1.37,1.10,0.98,1.03,0.92,1.14,0.86,0.95,0.97,0.90,0.89,0.79,0.84,0.77,0.82,0.76,0.82,0.97,0.89,0.98,0.71,0.72,0.74,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.34,1.51,1.53,1.67,1.72,1.71,1.80,1.77,1.91,1.86,1.98,1.86,1.82,1.95,1.89,1.24,1.10,1.41,0.95,0.99,1.09,1.25,1.37,1.63,1.55,0.96,0.98,1.16,1.05,1.00,1.27,1.23,1.50,1.69,1.46,1.86,1.72,1.87,1.24,1.49,1.44,1.69,1.80,1.59,1.69,1.97,1.82,1.94,1.91,1.92,1.99,1.63,1.50,1.74,1.16,1.33,1.38,1.58,1.60,1.77,1.80,1.48,1.21,1.37,0.90,0.97,0.93,1.05,0.97,1.04,1.21,0.99,0.95,1.14,0.92,1.02,1.34,0.94,0.86,0.90,0.74,0.79,0.75,0.81,0.79,0.84,0.86,0.71,0.71,0.73,0.76,0.73,0.77,0.74,0.80,0.85,0.78,0.81,0.89,0.84,0.97,0.92,0.88,0.79,0.85,0.86,0.98,0.92,1.00,0.93,1.06,1.12,0.95,0.74,0.74,0.78,0.79,0.76,0.82,0.79,0.87,0.93,0.85,0.85,0.94,0.90,1.09,1.27,0.99,1.17,1.05,0.96,1.46,1.71,1.62,1.48,1.20,1.34,1.28,1.57,1.35,0.90,0.94,0.85,0.98,0.81,0.89,0.89,0.83,0.82,0.75,0.78,0.73,0.77,0.72,0.76,0.89,0.83,0.91,0.71,0.70,0.72,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.26,1.39,1.48,1.51,1.64,1.71,1.60,1.58,1.77,1.74,1.91,1.94,1.87,1.97,1.85,1.10,0.97,1.22,0.88,0.92,0.95,1.01,1.11,1.39,1.32,0.88,0.90,0.97,0.96,0.93,1.05,0.99,1.27,1.47,1.20,1.70,1.54,1.76,1.08,1.31,1.33,1.70,1.76,1.55,1.57,1.88,1.85,1.91,1.97,1.99,1.99,1.70,1.65,1.85,1.41,1.54,1.61,1.76,1.80,1.91,1.93,1.52,1.26,1.48,0.92,0.99,0.97,1.18,1.09,1.28,1.39,0.94,0.93,1.05,0.92,1.01,1.31,0.88,0.81,0.86,0.72,0.75,0.74,0.79,0.79,0.86,0.85,0.71,0.73,0.75,0.82,0.77,0.83,0.78,0.85,0.88,0.81,0.88,0.97,0.90,1.18,1.00,0.93,0.86,0.92,0.94,1.14,0.99,1.24,1.03,1.33,1.39,1.11,0.79,0.77,0.84,0.79,0.77,0.84,0.83,0.90,0.98,0.91,0.85,0.92,0.91,1.02,1.26,1.00,1.23,1.19,0.99,1.50,1.84,1.71,1.64,1.38,1.46,1.51,1.76,1.59,0.84,0.88,0.80,0.94,0.79,0.86,0.82,0.77,0.76,0.74,0.74,0.71,0.73,0.70,0.72,0.82,0.77,0.85,0.74,0.70,0.73,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00} +} diff --git a/src/refresh/opengl/constants/warpsin.h b/src/refresh/opengl/constants/warpsin.h new file mode 100644 index 00000000..17289e17 --- /dev/null +++ b/src/refresh/opengl/constants/warpsin.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + 0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677, + 1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916, + 3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998, + 4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632, + 5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068, + 6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368, + 7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562, + 7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759, + 8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222, + 7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394, + 7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883, + 6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398, + 5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647, + 4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193, + 3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281, + 1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633, + 9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677, + -1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916, + -3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998, + -4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632, + -5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068, + -6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368, + -7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562, + -7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759, + -8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222, + -7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394, + -7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883, + -6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398, + -5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647, + -4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193, + -3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281, + -1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633, diff --git a/src/refresh/opengl/gl_draw.c b/src/refresh/opengl/gl_draw.c new file mode 100644 index 00000000..d194b99b --- /dev/null +++ b/src/refresh/opengl/gl_draw.c @@ -0,0 +1,415 @@ +/* +Copyright (C) 1997-2001 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 + +#include "gl_local.h" + +image_t *draw_chars; + +extern qboolean scrap_dirty; +void Scrap_Upload (void); + + +/* +=============== +Draw_InitLocal +=============== +*/ +void Draw_InitLocal (void) +{ + // load console characters (don't bilerp characters) + draw_chars = GL_FindImage ("pics/conchars.pcx", it_pic); + GL_Bind( draw_chars->texnum ); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + + + +/* +================ +Draw_Char + +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 Draw_Char (int x, int y, int num) +{ + int row, col; + float frow, fcol, size; + + num &= 255; + + if ( (num&127) == 32 ) + return; // space + + if (y <= -8) + return; // totally off screen + + row = num>>4; + col = num&15; + + frow = row*0.0625; + fcol = col*0.0625; + size = 0.0625; + + GL_Bind (draw_chars->texnum); + + qglBegin (GL_QUADS); + qglTexCoord2f (fcol, frow); + qglVertex2f (x, y); + qglTexCoord2f (fcol + size, frow); + qglVertex2f (x+8, y); + qglTexCoord2f (fcol + size, frow + size); + qglVertex2f (x+8, y+8); + qglTexCoord2f (fcol, frow + size); + qglVertex2f (x, y+8); + qglEnd (); +} + +/* +============= +Draw_FindPic +============= +*/ +image_t *Draw_FindPic (char *name) +{ + image_t *gl; + char fullname[MAX_QPATH]; + + if (name[0] != '/' && name[0] != '\\') + { + Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name); + gl = GL_FindImage (fullname, it_pic); + } + else + gl = GL_FindImage (name+1, it_pic); + + return gl; +} + +/* +============= +Draw_GetPicSize +============= +*/ +void Draw_GetPicSize (int *w, int *h, char *pic) +{ + image_t *gl; + + gl = Draw_FindPic (pic); + if (!gl) + { + *w = *h = -1; + return; + } + *w = gl->width; + *h = gl->height; +} + +/* +============= +Draw_StretchPic +============= +*/ +void Draw_StretchPic (int x, int y, int w, int h, char *pic) +{ + image_t *gl; + + gl = Draw_FindPic (pic); + if (!gl) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic); + return; + } + + if (scrap_dirty) + Scrap_Upload (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglDisable (GL_ALPHA_TEST); + + GL_Bind (gl->texnum); + qglBegin (GL_QUADS); + qglTexCoord2f (gl->sl, gl->tl); + qglVertex2f (x, y); + qglTexCoord2f (gl->sh, gl->tl); + qglVertex2f (x+w, y); + qglTexCoord2f (gl->sh, gl->th); + qglVertex2f (x+w, y+h); + qglTexCoord2f (gl->sl, gl->th); + qglVertex2f (x, y+h); + qglEnd (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglEnable (GL_ALPHA_TEST); +} + + +/* +============= +Draw_Pic +============= +*/ +void Draw_Pic (int x, int y, char *pic) +{ + image_t *gl; + + gl = Draw_FindPic (pic); + if (!gl) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic); + return; + } + if (scrap_dirty) + Scrap_Upload (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglDisable (GL_ALPHA_TEST); + + GL_Bind (gl->texnum); + qglBegin (GL_QUADS); + qglTexCoord2f (gl->sl, gl->tl); + qglVertex2f (x, y); + qglTexCoord2f (gl->sh, gl->tl); + qglVertex2f (x+gl->width, y); + qglTexCoord2f (gl->sh, gl->th); + qglVertex2f (x+gl->width, y+gl->height); + qglTexCoord2f (gl->sl, gl->th); + qglVertex2f (x, y+gl->height); + qglEnd (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglEnable (GL_ALPHA_TEST); +} + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void Draw_TileClear (int x, int y, int w, int h, char *pic) +{ + image_t *image; + + image = Draw_FindPic (pic); + if (!image) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic); + return; + } + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !image->has_alpha) + qglDisable (GL_ALPHA_TEST); + + GL_Bind (image->texnum); + qglBegin (GL_QUADS); + qglTexCoord2f (x/64.0, y/64.0); + qglVertex2f (x, y); + qglTexCoord2f ( (x+w)/64.0, y/64.0); + qglVertex2f (x+w, y); + qglTexCoord2f ( (x+w)/64.0, (y+h)/64.0); + qglVertex2f (x+w, y+h); + qglTexCoord2f ( x/64.0, (y+h)/64.0 ); + qglVertex2f (x, y+h); + qglEnd (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !image->has_alpha) + qglEnable (GL_ALPHA_TEST); +} + + +/* +============= +Draw_Fill + +Fills a box of pixels with a single color +============= +*/ +void Draw_Fill (int x, int y, int w, int h, int c) +{ + union + { + unsigned c; + byte v[4]; + } color; + + if ( (unsigned)c > 255) + ri.Sys_Error (ERR_FATAL, "Draw_Fill: bad color"); + + qglDisable (GL_TEXTURE_2D); + + color.c = d_8to24table[c]; + qglColor3f (color.v[0]/255.0, + color.v[1]/255.0, + color.v[2]/255.0); + + qglBegin (GL_QUADS); + + qglVertex2f (x,y); + qglVertex2f (x+w, y); + qglVertex2f (x+w, y+h); + qglVertex2f (x, y+h); + + qglEnd (); + qglColor3f (1,1,1); + qglEnable (GL_TEXTURE_2D); +} + +//============================================================================= + +/* +================ +Draw_FadeScreen + +================ +*/ +void Draw_FadeScreen (void) +{ + qglEnable (GL_BLEND); + qglDisable (GL_TEXTURE_2D); + qglColor4f (0, 0, 0, 0.8); + qglBegin (GL_QUADS); + + qglVertex2f (0,0); + qglVertex2f (vid.width, 0); + qglVertex2f (vid.width, vid.height); + qglVertex2f (0, vid.height); + + qglEnd (); + qglColor4f (1,1,1,1); + qglEnable (GL_TEXTURE_2D); + qglDisable (GL_BLEND); +} + + +//==================================================================== + + +/* +============= +Draw_StretchRaw +============= +*/ +extern unsigned r_rawpalette[256]; + +void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data) +{ + unsigned image32[256*256]; + unsigned char image8[256*256]; + int i, j, trows; + byte *source; + int frac, fracstep; + float hscale; + int row; + float t; + + GL_Bind (0); + + if (rows<=256) + { + hscale = 1; + trows = rows; + } + else + { + hscale = rows/256.0; + trows = 256; + } + t = rows*hscale / 256 - 1.0/512.0; + + if ( !qglColorTableEXT ) + { + unsigned *dest; + + for (i=0 ; i rows) + break; + source = data + cols*row; + dest = &image32[i*256]; + fracstep = cols*0x10000/256; + frac = fracstep >> 1; + for (j=0 ; j<256 ; j++) + { + dest[j] = r_rawpalette[source[frac>>16]]; + frac += fracstep; + } + } + + qglTexImage2D (GL_TEXTURE_2D, 0, gl_tex_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, image32); + } + else + { + unsigned char *dest; + + for (i=0 ; i rows) + break; + source = data + cols*row; + dest = &image8[i*256]; + fracstep = cols*0x10000/256; + frac = fracstep >> 1; + for (j=0 ; j<256 ; j++) + { + dest[j] = source[frac>>16]; + frac += fracstep; + } + } + + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + 256, 256, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + image8 ); + } + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) + qglDisable (GL_ALPHA_TEST); + + qglBegin (GL_QUADS); + qglTexCoord2f (1.0/512.0, 1.0/512.0); + qglVertex2f (x, y); + qglTexCoord2f (511.0/512.0, 1.0/512.0); + qglVertex2f (x+w, y); + qglTexCoord2f (511.0/512.0, t); + qglVertex2f (x+w, y+h); + qglTexCoord2f (1.0/512.0, t); + qglVertex2f (x, y+h); + qglEnd (); + + if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) + qglEnable (GL_ALPHA_TEST); +} + diff --git a/src/refresh/opengl/gl_image.c b/src/refresh/opengl/gl_image.c new file mode 100644 index 00000000..77bde769 --- /dev/null +++ b/src/refresh/opengl/gl_image.c @@ -0,0 +1,1623 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +#include "gl_local.h" + +image_t gltextures[MAX_GLTEXTURES]; +int numgltextures; +int base_textureid; // gltextures[i] = base_textureid+i + +static byte intensitytable[256]; +static unsigned char gammatable[256]; + +cvar_t *intensity; + +unsigned d_8to24table[256]; + +qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ); +qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap); + + +int gl_solid_format = 3; +int gl_alpha_format = 4; + +int gl_tex_solid_format = 3; +int gl_tex_alpha_format = 4; + +int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; +int gl_filter_max = GL_LINEAR; + +void GL_SetTexturePalette( unsigned palette[256] ) +{ + int i; + unsigned char temptable[768]; + + if ( qglColorTableEXT && gl_ext_palettedtexture->value ) + { + for ( i = 0; i < 256; i++ ) + { + temptable[i*3+0] = ( palette[i] >> 0 ) & 0xff; + temptable[i*3+1] = ( palette[i] >> 8 ) & 0xff; + temptable[i*3+2] = ( palette[i] >> 16 ) & 0xff; + } + + qglColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT, + GL_RGB, + 256, + GL_RGB, + GL_UNSIGNED_BYTE, + temptable ); + } +} + +void GL_EnableMultitexture( qboolean enable ) +{ + if ( !qglSelectTextureSGIS && !qglActiveTextureARB ) + return; + + if ( enable ) + { + GL_SelectTexture( QGL_TEXTURE1 ); + qglEnable( GL_TEXTURE_2D ); + GL_TexEnv( GL_REPLACE ); + } + else + { + GL_SelectTexture( QGL_TEXTURE1 ); + qglDisable( GL_TEXTURE_2D ); + GL_TexEnv( GL_REPLACE ); + } + GL_SelectTexture( QGL_TEXTURE0 ); + GL_TexEnv( GL_REPLACE ); +} + +void GL_SelectTexture( GLenum texture ) +{ + int tmu; + + if ( !qglSelectTextureSGIS && !qglActiveTextureARB ) + return; + + if ( texture == QGL_TEXTURE0 ) + { + tmu = 0; + } + else + { + tmu = 1; + } + + if ( tmu == gl_state.currenttmu ) + { + return; + } + + gl_state.currenttmu = tmu; + + if ( qglSelectTextureSGIS ) + { + qglSelectTextureSGIS( texture ); + } + else if ( qglActiveTextureARB ) + { + qglActiveTextureARB( texture ); + qglClientActiveTextureARB( texture ); + } +} + +void GL_TexEnv( GLenum mode ) +{ + static int lastmodes[2] = { -1, -1 }; + + if ( mode != lastmodes[gl_state.currenttmu] ) + { + qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode ); + lastmodes[gl_state.currenttmu] = mode; + } +} + +void GL_Bind (int texnum) +{ + extern image_t *draw_chars; + + if (gl_nobind->value && draw_chars) // performance evaluation option + texnum = draw_chars->texnum; + if ( gl_state.currenttextures[gl_state.currenttmu] == texnum) + return; + gl_state.currenttextures[gl_state.currenttmu] = texnum; + qglBindTexture (GL_TEXTURE_2D, texnum); +} + +void GL_MBind( GLenum target, int texnum ) +{ + GL_SelectTexture( target ); + if ( target == QGL_TEXTURE0 ) + { + if ( gl_state.currenttextures[0] == texnum ) + return; + } + else + { + if ( gl_state.currenttextures[1] == texnum ) + return; + } + GL_Bind( texnum ); +} + +typedef struct +{ + char *name; + int minimize, maximize; +} glmode_t; + +glmode_t modes[] = { + {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, + {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, + {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, + {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, + {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, + {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} +}; + +#define NUM_GL_MODES (sizeof(modes) / sizeof (glmode_t)) + +typedef struct +{ + char *name; + int mode; +} gltmode_t; + +gltmode_t gl_alpha_modes[] = { + {"default", 4}, + {"GL_RGBA", GL_RGBA}, + {"GL_RGBA8", GL_RGBA8}, + {"GL_RGB5_A1", GL_RGB5_A1}, + {"GL_RGBA4", GL_RGBA4}, + {"GL_RGBA2", GL_RGBA2}, +}; + +#define NUM_GL_ALPHA_MODES (sizeof(gl_alpha_modes) / sizeof (gltmode_t)) + +gltmode_t gl_solid_modes[] = { + {"default", 3}, + {"GL_RGB", GL_RGB}, + {"GL_RGB8", GL_RGB8}, + {"GL_RGB5", GL_RGB5}, + {"GL_RGB4", GL_RGB4}, + {"GL_R3_G3_B2", GL_R3_G3_B2}, +#ifdef GL_RGB2_EXT + {"GL_RGB2", GL_RGB2_EXT}, +#endif +}; + +#define NUM_GL_SOLID_MODES (sizeof(gl_solid_modes) / sizeof (gltmode_t)) + +/* +=============== +GL_TextureMode +=============== +*/ +void GL_TextureMode( char *string ) +{ + int i; + image_t *glt; + + for (i=0 ; i< NUM_GL_MODES ; i++) + { + if ( !Q_stricmp( modes[i].name, string ) ) + break; + } + + if (i == NUM_GL_MODES) + { + ri.Con_Printf (PRINT_ALL, "bad filter name\n"); + return; + } + + gl_filter_min = modes[i].minimize; + gl_filter_max = modes[i].maximize; + + // change all the existing mipmap texture objects + for (i=0, glt=gltextures ; itype != it_pic && glt->type != it_sky ) + { + GL_Bind (glt->texnum); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + } +} + +/* +=============== +GL_TextureAlphaMode +=============== +*/ +void GL_TextureAlphaMode( char *string ) +{ + int i; + + for (i=0 ; i< NUM_GL_ALPHA_MODES ; i++) + { + if ( !Q_stricmp( gl_alpha_modes[i].name, string ) ) + break; + } + + if (i == NUM_GL_ALPHA_MODES) + { + ri.Con_Printf (PRINT_ALL, "bad alpha texture mode name\n"); + return; + } + + gl_tex_alpha_format = gl_alpha_modes[i].mode; +} + +/* +=============== +GL_TextureSolidMode +=============== +*/ +void GL_TextureSolidMode( char *string ) +{ + int i; + + for (i=0 ; i< NUM_GL_SOLID_MODES ; i++) + { + if ( !Q_stricmp( gl_solid_modes[i].name, string ) ) + break; + } + + if (i == NUM_GL_SOLID_MODES) + { + ri.Con_Printf (PRINT_ALL, "bad solid texture mode name\n"); + return; + } + + gl_tex_solid_format = gl_solid_modes[i].mode; +} + +/* +=============== +GL_ImageList_f +=============== +*/ +void GL_ImageList_f (void) +{ + int i; + image_t *image; + int texels; + const char *palstrings[2] = + { + "RGB", + "PAL" + }; + + ri.Con_Printf (PRINT_ALL, "------------------\n"); + texels = 0; + + for (i=0, image=gltextures ; itexnum <= 0) + continue; + texels += image->upload_width*image->upload_height; + switch (image->type) + { + case it_skin: + ri.Con_Printf (PRINT_ALL, "M"); + break; + case it_sprite: + ri.Con_Printf (PRINT_ALL, "S"); + break; + case it_wall: + ri.Con_Printf (PRINT_ALL, "W"); + break; + case it_pic: + ri.Con_Printf (PRINT_ALL, "P"); + break; + default: + ri.Con_Printf (PRINT_ALL, " "); + break; + } + + ri.Con_Printf (PRINT_ALL, " %3i %3i %s: %s\n", + image->upload_width, image->upload_height, palstrings[image->paletted], image->name); + } + ri.Con_Printf (PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels); +} + + +/* +============================================================================= + + scrap allocation + + Allocate all the little status bar obejcts into a single texture + to crutch up inefficient hardware / drivers + +============================================================================= +*/ + +#define MAX_SCRAPS 1 +#define BLOCK_WIDTH 256 +#define BLOCK_HEIGHT 256 + +int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; +byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT]; +qboolean scrap_dirty; + +// returns a texture number and the position inside it +int Scrap_AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + int texnum; + + for (texnum=0 ; texnum= best) + break; + if (scrap_allocated[texnum][i+j] > best2) + best2 = scrap_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 ; ixmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + raw = &pcx->data; + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + { + ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename); + return; + } + + out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + + *pic = out; + + pix = out; + + if (palette) + { + *palette = malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + { + for (x=0 ; x<=pcx->xmax ; ) + { + dataByte = *raw++; + + if((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else + runLength = 1; + + while(runLength-- > 0) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len) + { + ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); + free (*pic); + *pic = NULL; + } + + ri.FS_FreeFile (pcx); +} + +/* +========================================================= + +TARGA LOADING + +========================================================= +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + +/* +============= +LoadTGA +============= +*/ +void LoadTGA (char *name, byte **pic, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + int length; + TargaHeader targa_header; + byte *targa_rgba; + byte tmp[2]; + + *pic = NULL; + + // + // load the file + // + length = ri.FS_LoadFile (name, (void **)&buffer); + if (!buffer) + { + ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name); + return; + } + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + tmp[0] = buf_p[0]; + tmp[1] = buf_p[1]; + targa_header.colormap_index = LittleShort ( *((short *)tmp) ); + buf_p+=2; + tmp[0] = buf_p[0]; + tmp[1] = buf_p[1]; + targa_header.colormap_length = LittleShort ( *((short *)tmp) ); + buf_p+=2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.y_origin = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.width = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.height = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if (targa_header.image_type!=2 + && targa_header.image_type!=10) + ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type !=0 + || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) + ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + targa_rgba = malloc (numPixels*4); + *pic = targa_rgba; + + if (targa_header.id_length != 0) + buf_p += targa_header.id_length; // skip TARGA image comment + + if (targa_header.image_type==2) { // Uncompressed, RGB images + for(row=rows-1; row>=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + + ri.FS_FreeFile (buffer); +} + + +/* +==================================================================== + +IMAGE FLOOD FILLING + +==================================================================== +*/ + + +/* +================= +Mod_FloodFillSkin + +Fill background pixels so mipmapping doesn't have haloes +================= +*/ + +typedef struct +{ + short x, y; +} floodfill_t; + +// must be a power of 2 +#define FLOODFILL_FIFO_SIZE 0x1000 +#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) + +#define FLOODFILL_STEP( off, dx, dy ) \ +{ \ + if (pos[off] == fillcolor) \ + { \ + pos[off] = 255; \ + fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ + } \ + else if (pos[off] != 255) fdc = pos[off]; \ +} + +void R_FloodFillSkin( byte *skin, int skinwidth, int skinheight ) +{ + byte fillcolor = *skin; // assume this is the pixel to fill + floodfill_t fifo[FLOODFILL_FIFO_SIZE]; + int inpt = 0, outpt = 0; + int filledcolor = -1; + int i; + + if (filledcolor == -1) + { + filledcolor = 0; + // attempt to find opaque black + for (i = 0; i < 256; ++i) + /* if (d_8to24table[i] == (255 << 0)) // alpha 1.0 + * ENDIAN problem, fix by xvi + */ + if (LittleLong(d_8to24table[i]) == (255 << 0)) // alpha 1.0 + { + filledcolor = i; + break; + } + } + + // can't fill to filled color or to transparent color (used as visited marker) + if ((fillcolor == filledcolor) || (fillcolor == 255)) + { + //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor ); + return; + } + + fifo[inpt].x = 0, fifo[inpt].y = 0; + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + + while (outpt != inpt) + { + int x = fifo[outpt].x, y = fifo[outpt].y; + int fdc = filledcolor; + byte *pos = &skin[x + skinwidth * y]; + + outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; + + if (x > 0) FLOODFILL_STEP( -1, -1, 0 ); + if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 ); + if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 ); + if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 ); + skin[x + skinwidth * y] = fdc; + } +} + +//======================================================= + + +/* +================ +GL_ResampleTexture +================ +*/ +void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) +{ + int i, j; + unsigned *inrow, *inrow2; + unsigned frac, fracstep; + unsigned p1[1024], p2[1024]; + byte *pix1, *pix2, *pix3, *pix4; + + fracstep = inwidth*0x10000/outwidth; + + frac = fracstep>>2; + for (i=0 ; i>16); + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i>16); + frac += fracstep; + } + + for (i=0 ; i> 1; + for (j=0 ; j>2; + ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; + ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; + ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; + } + } +} + +/* +================ +GL_LightScaleTexture + +Scale up the pixel values in a texture to increase the +lighting range +================ +*/ +void GL_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma ) +{ + if ( only_gamma ) + { + int i, c; + byte *p; + + p = (byte *)in; + + c = inwidth*inheight; + for (i=0 ; i>= 1; + out = in; + for (i=0 ; i>2; + out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; + out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; + out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; + } + } +} + +/* +=============== +GL_Upload32 + +Returns has_alpha +=============== +*/ +void GL_BuildPalettedTexture( unsigned char *paletted_texture, unsigned char *scaled, int scaled_width, int scaled_height ) +{ + int i; + + for ( i = 0; i < scaled_width * scaled_height; i++ ) + { + unsigned int r, g, b, c; + + r = ( scaled[0] >> 3 ) & 31; + g = ( scaled[1] >> 2 ) & 63; + b = ( scaled[2] >> 3 ) & 31; + + c = r | ( g << 5 ) | ( b << 11 ); + + paletted_texture[i] = gl_state.d_16to8table[c]; + + scaled += 4; + } +} + +int upload_width, upload_height; +qboolean uploaded_paletted; + +qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap) +{ + int samples; + unsigned scaled[256*256]; + unsigned char paletted_texture[256*256]; + int scaled_width, scaled_height; + int i, c; + byte *scan; + int comp; + + uploaded_paletted = false; + + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + if (gl_round_down->value && scaled_width > width && mipmap) + scaled_width >>= 1; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if (gl_round_down->value && scaled_height > height && mipmap) + scaled_height >>= 1; + + // let people sample down the world textures for speed + if (mipmap) + { + scaled_width >>= (int)gl_picmip->value; + scaled_height >>= (int)gl_picmip->value; + } + + // don't ever bother with >256 textures + if (scaled_width > 256) + scaled_width = 256; + if (scaled_height > 256) + scaled_height = 256; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + upload_width = scaled_width; + upload_height = scaled_height; + + if (scaled_width * scaled_height > sizeof(scaled)/4) + ri.Sys_Error (ERR_DROP, "GL_Upload32: too big"); + + // scan the texture for any non-255 alpha + c = width*height; + scan = ((byte *)data) + 3; + samples = gl_solid_format; + for (i=0 ; ivalue && samples == gl_solid_format ) + { + uploaded_paletted = true; + GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) data, scaled_width, scaled_height ); + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + scaled_width, + scaled_height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + paletted_texture ); + } + else + { + qglTexImage2D (GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + } + goto done; + } + memcpy (scaled, data, width*height*4); + } + else + GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); + + GL_LightScaleTexture (scaled, scaled_width, scaled_height, !mipmap ); + + if ( qglColorTableEXT && gl_ext_palettedtexture->value && ( samples == gl_solid_format ) ) + { + uploaded_paletted = true; + GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) scaled, scaled_width, scaled_height ); + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + scaled_width, + scaled_height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + paletted_texture ); + } + else + { + qglTexImage2D( GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled ); + } + + if (mipmap) + { + int miplevel; + + miplevel = 0; + while (scaled_width > 1 || scaled_height > 1) + { + GL_MipMap ((byte *)scaled, scaled_width, scaled_height); + scaled_width >>= 1; + scaled_height >>= 1; + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + miplevel++; + if ( qglColorTableEXT && gl_ext_palettedtexture->value && samples == gl_solid_format ) + { + uploaded_paletted = true; + GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) scaled, scaled_width, scaled_height ); + qglTexImage2D( GL_TEXTURE_2D, + miplevel, + GL_COLOR_INDEX8_EXT, + scaled_width, + scaled_height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + paletted_texture ); + } + else + { + qglTexImage2D (GL_TEXTURE_2D, miplevel, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); + } + } + } +done: ; +#endif + + + if (mipmap) + { + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + else + { + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + + return (samples == gl_alpha_format); +} + +/* +=============== +GL_Upload8 + +Returns has_alpha +=============== +*/ +/* +static qboolean IsPowerOf2( int value ) +{ + int i = 1; + + + while ( 1 ) + { + if ( value == i ) + return true; + if ( i > value ) + return false; + i <<= 1; + } +} +*/ + +qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ) +{ + unsigned trans[512*256]; + int i, s; + int p; + + s = width*height; + + if (s > sizeof(trans)/4) + ri.Sys_Error (ERR_DROP, "GL_Upload8: too large"); + + if ( qglColorTableEXT && + gl_ext_palettedtexture->value && + is_sky ) + { + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + width, + height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + data ); + + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + + return false; // SBF: FIXME - what is the correct return value? + } + else + { + for (i=0 ; i width && data[i-width] != 255) + p = data[i-width]; + else if (i < s-width && data[i+width] != 255) + p = data[i+width]; + else if (i > 0 && data[i-1] != 255) + p = data[i-1]; + else if (i < s-1 && data[i+1] != 255) + p = data[i+1]; + else + p = 0; + // copy rgb components + ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; + ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; + ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; + } + } + + return GL_Upload32 (trans, width, height, mipmap); + } +} + + +/* +================ +GL_LoadPic + +This is also used as an entry point for the generated r_notexture +================ +*/ +image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits) +{ + image_t *image; + int i; +#ifdef RETEX + miptex_t *mt; + int len; + char s[128]; +#endif + + // find a free image_t + for (i=0, image=gltextures ; itexnum) + break; + } + if (i == numgltextures) + { + if (numgltextures == MAX_GLTEXTURES) + ri.Sys_Error (ERR_DROP, "MAX_GLTEXTURES"); + numgltextures++; + } + image = &gltextures[i]; + + if (strlen(name) >= sizeof(image->name)) + ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name); + strcpy (image->name, name); + image->registration_sequence = registration_sequence; + + image->width = width; + image->height = height; + image->type = type; + +#ifdef RETEX + len = strlen(name); + strcpy(s,name); + + if (!strcmp(s+len-4, ".tga") || !strcmp(s+len-4, ".jpg") || !strcmp(s+len-4, ".png")) + { + s[len-3] = 'w'; s[len-2] = 'a'; s[len-1] = 'l'; + ri.FS_LoadFile (s, (void **)&mt); //load .wal file + + if (mt) { + image->width = LittleLong (mt->width); + image->height = LittleLong (mt->height); + ri.FS_FreeFile ((void *)mt); + } + } +#endif + + if (type == it_skin && bits == 8) + R_FloodFillSkin(pic, width, height); + + // load little pics into the scrap + if (image->type == it_pic && bits == 8 + && image->width < 64 && image->height < 64) + { + int x, y; + int i, j, k; + int texnum; + + texnum = Scrap_AllocBlock (image->width, image->height, &x, &y); + if (texnum == -1) + goto nonscrap; + scrap_dirty = true; + + // copy the texels into the scrap block + k = 0; + for (i=0 ; iheight ; i++) + for (j=0 ; jwidth ; j++, k++) + scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = pic[k]; + image->texnum = TEXNUM_SCRAPS + texnum; + image->scrap = true; + image->has_alpha = true; + image->sl = (x+0.01)/(float)BLOCK_WIDTH; + image->sh = (x+image->width-0.01)/(float)BLOCK_WIDTH; + image->tl = (y+0.01)/(float)BLOCK_WIDTH; + image->th = (y+image->height-0.01)/(float)BLOCK_WIDTH; + } + else + { +nonscrap: + image->scrap = false; + image->texnum = TEXNUM_IMAGES + (image - gltextures); + GL_Bind(image->texnum); + if (bits == 8) + image->has_alpha = GL_Upload8 (pic, width, height, (image->type != it_pic && image->type != it_sky), image->type == it_sky ); + else + image->has_alpha = GL_Upload32 ((unsigned *)pic, width, height, (image->type != it_pic && image->type != it_sky) ); + image->upload_width = upload_width; // after power of 2 and scales + image->upload_height = upload_height; + image->paletted = uploaded_paletted; + image->sl = 0; + image->sh = 1; + image->tl = 0; + image->th = 1; + } + + return image; +} + + +/* +================ +GL_LoadWal +================ +*/ +image_t *GL_LoadWal (char *name) +{ + miptex_t *mt; + int width, height, ofs; + image_t *image; + + ri.FS_LoadFile (name, (void **)&mt); + if (!mt) + { + ri.Con_Printf (PRINT_ALL, "GL_FindImage: can't load %s\n", name); + return r_notexture; + } + + width = LittleLong (mt->width); + height = LittleLong (mt->height); + ofs = LittleLong (mt->offsets[0]); + + image = GL_LoadPic (name, (byte *)mt + ofs, width, height, it_wall, 8); + + ri.FS_FreeFile ((void *)mt); + + return image; +} + +/* +=============== +GL_FindImage + +Finds or loads the given image +=============== +*/ +image_t *GL_FindImage (char *name, imagetype_t type) +{ + image_t *image; + int i, len; + byte *pic, *palette; + int width, height; + char *ptr; + + if (!name) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: NULL name"); + len = strlen(name); + if (len<5) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: bad name: %s", name); + +#ifndef _WIN32 + // fix backslashes + while ((ptr=strchr(name,'\\'))) { + *ptr = '/'; + } +#endif + + // look for it + for (i=0, image=gltextures ; iname)) + { + image->registration_sequence = registration_sequence; + return image; + } + } + + // + // load the pic from disk + // + pic = NULL; + palette = NULL; + if (!strcmp(name+len-4, ".pcx")) + { + LoadPCX (name, &pic, &palette, &width, &height); + if (!pic) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); + image = GL_LoadPic (name, pic, width, height, type, 8); + } + else if (!strcmp(name+len-4, ".wal")) + { + image = GL_LoadWal (name); + } + else if (!strcmp(name+len-4, ".tga")) + { + LoadTGA (name, &pic, &width, &height); + if (!pic) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); + image = GL_LoadPic (name, pic, width, height, type, 32); + } + else + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: bad extension on: %s", name); + + + if (pic) + free(pic); + if (palette) + free(palette); + + return image; +} + + + +/* +=============== +R_RegisterSkin +=============== +*/ +struct image_s *R_RegisterSkin (char *name) +{ + return GL_FindImage (name, it_skin); +} + + +/* +================ +GL_FreeUnusedImages + +Any image that was not touched on this registration sequence +will be freed. +================ +*/ +void GL_FreeUnusedImages (void) +{ + int i; + image_t *image; + + // never free r_notexture or particle texture + r_notexture->registration_sequence = registration_sequence; + r_particletexture->registration_sequence = registration_sequence; + + for (i=0, image=gltextures ; iregistration_sequence == registration_sequence) + continue; // used this sequence + if (!image->registration_sequence) + continue; // free image_t slot + if (image->type == it_pic) + continue; // don't free pics + // free it + qglDeleteTextures (1, (GLuint *)&image->texnum); + memset (image, 0, sizeof(*image)); + } +} + + +/* +=============== +Draw_GetPalette +=============== +*/ +int Draw_GetPalette (void) +{ + int i; + int r, g, b; + unsigned v; + byte *pic, *pal; + int width, height; + + // get the palette + + LoadPCX ("pics/colormap.pcx", &pic, &pal, &width, &height); + if (!pal) + ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx"); + + for (i=0 ; i<256 ; i++) + { + r = pal[i*3+0]; + g = pal[i*3+1]; + b = pal[i*3+2]; + + v = (255<<24) + (r<<0) + (g<<8) + (b<<16); + d_8to24table[i] = LittleLong(v); + } + + d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent + + free (pic); + free (pal); + + return 0; +} + + +/* +=============== +GL_InitImages +=============== +*/ +void GL_InitImages (void) +{ + int i, j; + float g = vid_gamma->value; + + registration_sequence = 1; + + // init intensity conversions + intensity = ri.Cvar_Get ("intensity", "2", 0); + + if ( intensity->value <= 1 ) + ri.Cvar_Set( "intensity", "1" ); + + gl_state.inverse_intensity = 1 / intensity->value; + + Draw_GetPalette (); + + if ( qglColorTableEXT ) + { + ri.FS_LoadFile( "pics/16to8.dat", (void **)&gl_state.d_16to8table ); + if ( !gl_state.d_16to8table ) + ri.Sys_Error( ERR_FATAL, "Couldn't load pics/16to8.pcx"); + } + + if ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) ) + { + g = 1.0F; + } + + for ( i = 0; i < 256; i++ ) + { + if ( g == 1 || gl_state.hwgamma ) + { + gammatable[i] = i; + } + else + { + float inf; + + inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5; + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } + } + + for (i=0 ; i<256 ; i++) + { + j = i*intensity->value; + if (j > 255) + j = 255; + intensitytable[i] = j; + } +} + +/* +=============== +GL_ShutdownImages +=============== +*/ +void GL_ShutdownImages (void) +{ + int i; + image_t *image; + + for (i=0, image=gltextures ; iregistration_sequence) + continue; // free image_t slot + // free it + qglDeleteTextures (1, (GLuint *)&image->texnum); + memset (image, 0, sizeof(*image)); + } +} + diff --git a/src/refresh/opengl/gl_light.c b/src/refresh/opengl/gl_light.c new file mode 100644 index 00000000..041d8077 --- /dev/null +++ b/src/refresh/opengl/gl_light.c @@ -0,0 +1,729 @@ +/* +Copyright (C) 1997-2001 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 "gl_local.h" + +int r_dlightframecount; + +#define DLIGHT_CUTOFF 64 + +/* +============================================================================= + +DYNAMIC LIGHTS BLEND RENDERING + +============================================================================= +*/ + +void R_RenderDlight (dlight_t *light) +{ + int i, j; + float a; + vec3_t v; + float rad; + + rad = light->intensity * 0.35; + + VectorSubtract (light->origin, r_origin, v); +#if 0 + // FIXME? + if (VectorLength (v) < rad) + { // view is inside the dlight + V_AddBlend (light->color[0], light->color[1], light->color[2], light->intensity * 0.0003, v_blend); + return; + } +#endif + + qglBegin (GL_TRIANGLE_FAN); + qglColor3f (light->color[0]*0.2, light->color[1]*0.2, light->color[2]*0.2); + for (i=0 ; i<3 ; i++) + v[i] = light->origin[i] - vpn[i]*rad; + qglVertex3fv (v); + qglColor3f (0,0,0); + for (i=16 ; i>=0 ; i--) + { + a = i/16.0 * M_PI*2; + for (j=0 ; j<3 ; j++) + v[j] = light->origin[j] + vright[j]*cos(a)*rad + + vup[j]*sin(a)*rad; + qglVertex3fv (v); + } + qglEnd (); +} + +/* +============= +R_RenderDlights +============= +*/ +void R_RenderDlights (void) +{ + int i; + dlight_t *l; + + if (!gl_flashblend->value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + qglDepthMask (0); + qglDisable (GL_TEXTURE_2D); + qglShadeModel (GL_SMOOTH); + qglEnable (GL_BLEND); + qglBlendFunc (GL_ONE, GL_ONE); + + l = r_newrefdef.dlights; + for (i=0 ; icontents != -1) + return; + + splitplane = node->plane; + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + + if (dist > light->intensity-DLIGHT_CUTOFF) + { + R_MarkLights (light, bit, node->children[0]); + return; + } + if (dist < -light->intensity+DLIGHT_CUTOFF) + { + R_MarkLights (light, bit, node->children[1]); + return; + } + +// mark the polygons + surf = r_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; + } + + R_MarkLights (light, bit, node->children[0]); + R_MarkLights (light, bit, node->children[1]); +} + + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights (void) +{ + int i; + dlight_t *l; + + if (gl_flashblend->value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + l = r_newrefdef.dlights; + for (i=0 ; inodes ); +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +vec3_t pointcolor; +cplane_t *lightplane; // used as shadow plane +vec3_t lightspot; + +int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) +{ + float front, back, frac; + int side; + cplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + byte *lightmap; + int maps; + int r; + + if (node->contents != -1) + 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 RecursiveLightPoint (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 = RecursiveLightPoint (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 + VectorCopy (mid, lightspot); + lightplane = plane; + + surf = r_worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) + 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; + VectorCopy (vec3_origin, pointcolor); + if (lightmap) + { + vec3_t scale; + + lightmap += 3*(dt * ((surf->extents[0]>>4)+1) + ds); + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + pointcolor[0] += lightmap[0] * scale[0] * (1.0/255); + pointcolor[1] += lightmap[1] * scale[1] * (1.0/255); + pointcolor[2] += lightmap[2] * scale[2] * (1.0/255); + lightmap += 3*((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + } + + return 1; + } + +// go down back side + return RecursiveLightPoint (node->children[!side], mid, end); +} + +/* +=============== +R_LightPoint +=============== +*/ +void R_LightPoint (vec3_t p, vec3_t color) +{ + vec3_t end; + float r; + int lnum; + dlight_t *dl; + float light; + vec3_t dist; + float add; + + if (!r_worldmodel->lightdata) + { + color[0] = color[1] = color[2] = 1.0; + return; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + r = RecursiveLightPoint (r_worldmodel->nodes, p, end); + + if (r == -1) + { + VectorCopy (vec3_origin, color); + } + else + { + VectorCopy (pointcolor, color); + } + + // + // add dynamic lights + // + light = 0; + dl = r_newrefdef.dlights; + for (lnum=0 ; lnumorigin, + dl->origin, + dist); + add = dl->intensity - VectorLength(dist); + add *= (1.0/256); + if (add > 0) + { + VectorMA (color, add, dl->color, color); + } + } + + VectorScale (color, gl_modulate->value, color); +} + + +//=================================================================== + +static float s_blocklights[34*34*3]; +/* +=============== +R_AddDynamicLights +=============== +*/ +void R_AddDynamicLights (msurface_t *surf) +{ + int lnum; + int sd, td; + float fdist, frad, fminlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + dlight_t *dl; + float *pfBL; + float fsacc, ftacc; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<intensity; + fdist = DotProduct (dl->origin, surf->plane->normal) - + surf->plane->dist; + frad -= fabs(fdist); + // rad is now the highest intensity on the plane + + fminlight = DLIGHT_CUTOFF; // FIXME: make configurable? + if (frad < fminlight) + continue; + fminlight = frad - fminlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = dl->origin[i] - + surf->plane->normal[i]*fdist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1]; + + pfBL = s_blocklights; + for (t = 0, ftacc = 0 ; t td) + fdist = sd + (td>>1); + else + fdist = td + (sd>>1); + + if ( fdist < fminlight ) + { + pfBL[0] += ( frad - fdist ) * dl->color[0]; + pfBL[1] += ( frad - fdist ) * dl->color[1]; + pfBL[2] += ( frad - fdist ) * dl->color[2]; + } + } + } + } +} + + +/* +** R_SetCacheState +*/ +void R_SetCacheState( msurface_t *surf ) +{ + int maps; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + surf->cached_light[maps] = r_newrefdef.lightstyles[surf->styles[maps]].white; + } +} + +/* +=============== +R_BuildLightMap + +Combine and scale multiple lightmaps into the floating format in blocklights +=============== +*/ +void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) +{ + int smax, tmax; + int r, g, b, a, max; + int i, j, size; + byte *lightmap; + float scale[4]; + int nummaps; + float *bl; + lightstyle_t *style; + int monolightmap; + + if ( surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) ) + ri.Sys_Error (ERR_DROP, "R_BuildLightMap called for non-lit surface"); + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + if (size > (sizeof(s_blocklights)>>4) ) + ri.Sys_Error (ERR_DROP, "Bad s_blocklights size"); + +// set to full bright if no light data + if (!surf->samples) + { + int maps; + + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + style = &r_newrefdef.lightstyles[surf->styles[maps]]; + } + goto store; + } + + // count the # of maps + for ( nummaps = 0 ; nummaps < MAXLIGHTMAPS && surf->styles[nummaps] != 255 ; + nummaps++) + ; + + lightmap = surf->samples; + + // add all the lightmaps + if ( nummaps == 1 ) + { + int maps; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + bl = s_blocklights; + + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + bl = s_blocklights; + + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLights (surf); + +// put into texture format +store: + stride -= (smax<<2); + bl = s_blocklights; + + monolightmap = gl_monolightmap->string[0]; + + if ( monolightmap == '0' ) + { + for (i=0 ; i g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + ** alpha is ONLY used for the mono lightmap case. For this reason + ** we set it to the brightest of the color components so that + ** things don't get too dim. + */ + a = max; + + /* + ** rescale all the color components if the intensity of the greatest + ** channel exceeds 1.0 + */ + if (max > 255) + { + float t = 255.0F / max; + + r = r*t; + g = g*t; + b = b*t; + a = a*t; + } + + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; + + bl += 3; + dest += 4; + } + } + } + else + { + for (i=0 ; i g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + ** alpha is ONLY used for the mono lightmap case. For this reason + ** we set it to the brightest of the color components so that + ** things don't get too dim. + */ + a = max; + + /* + ** rescale all the color components if the intensity of the greatest + ** channel exceeds 1.0 + */ + if (max > 255) + { + float t = 255.0F / max; + + r = r*t; + g = g*t; + b = b*t; + a = a*t; + } + + /* + ** So if we are doing alpha lightmaps we need to set the R, G, and B + ** components to 0 and we need to set alpha to 1-alpha. + */ + switch ( monolightmap ) + { + case 'L': + case 'I': + r = a; + g = b = 0; + break; + case 'C': + // try faking colored lighting + a = 255 - ((r+g+b)/3); + r *= a/255.0; + g *= a/255.0; + b *= a/255.0; + break; + case 'A': + default: + r = g = b = 0; + a = 255 - a; + break; + } + + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; + + bl += 3; + dest += 4; + } + } + } +} + diff --git a/src/refresh/opengl/gl_local.h b/src/refresh/opengl/gl_local.h new file mode 100644 index 00000000..3fff49c9 --- /dev/null +++ b/src/refresh/opengl/gl_local.h @@ -0,0 +1,470 @@ +#ifndef __GL_LOCAL__ +#define __GL_LOCAL__ +/* +Copyright (C) 1997-2001 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 _WIN32 +# include +#endif + +#include +#include + +#include +#ifndef SOLARIS +//#include +#else +#include +#ifndef GL_COLOR_INDEX8_EXT +#define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX +#endif +#endif +#include + +#ifndef _WIN32 +char *strlwr (char *s); +#endif + +#include "../client/ref.h" + +#include "qgl.h" + +#define REF_VERSION "GL 0.01" + +// up / down +#define PITCH 0 + +// left / right +#define YAW 1 + +// fall over +#define ROLL 2 + + +#ifndef __VIDDEF_T +#define __VIDDEF_T +typedef struct +{ + int width, height; // coordinates from main game +} viddef_t; +#endif + +extern viddef_t vid; + + +/* + + skins will be outline flood filled and mip mapped + pics and sprites with alpha will be outline flood filled + pic won't be mip mapped + + model skin + sprite frame + wall texture + pic + +*/ + +typedef enum +{ + it_skin, + it_sprite, + it_wall, + it_pic, + it_sky +} imagetype_t; + +typedef struct image_s +{ + char name[MAX_QPATH]; // game path, including extension + imagetype_t type; + int width, height; // source image + int upload_width, upload_height; // after power of two and picmip + int registration_sequence; // 0 = free + struct msurface_s *texturechain; // for sort-by-texture world drawing + int texnum; // gl texture binding + float sl, tl, sh, th; // 0,0 - 1,1 unless part of the scrap + qboolean scrap; + qboolean has_alpha; + + qboolean paletted; +} image_t; + +#define TEXNUM_LIGHTMAPS 1024 +#define TEXNUM_SCRAPS 1152 +#define TEXNUM_IMAGES 1153 + +#define MAX_GLTEXTURES 1024 + +//=================================================================== + +typedef enum +{ + rserr_ok, + + rserr_invalid_fullscreen, + rserr_invalid_mode, + + rserr_unknown +} rserr_t; + +#include "gl_model.h" + +void GL_BeginRendering (int *x, int *y, int *width, int *height); +void GL_EndRendering (void); + +void GL_SetDefaultState( void ); +void GL_UpdateSwapInterval( void ); + +extern float gldepthmin, gldepthmax; + +typedef struct +{ + float x, y, z; + float s, t; + float r, g, b; +} glvert_t; + + +#define MAX_LBM_HEIGHT 480 + +#define BACKFACE_EPSILON 0.01 + + +//==================================================== + +extern image_t gltextures[MAX_GLTEXTURES]; +extern int numgltextures; + + +extern image_t *r_notexture; +extern image_t *r_particletexture; +extern entity_t *currententity; +extern model_t *currentmodel; +extern int r_visframecount; +extern int r_framecount; +extern cplane_t frustum[4]; +extern int c_brush_polys, c_alias_polys; + + +extern int gl_filter_min, gl_filter_max; + +// +// view origin +// +extern vec3_t vup; +extern vec3_t vpn; +extern vec3_t vright; +extern vec3_t r_origin; + +// +// screen size info +// +extern refdef_t r_newrefdef; +extern int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; + +extern cvar_t *r_norefresh; +extern cvar_t *r_lefthand; +extern cvar_t *r_drawentities; +extern cvar_t *r_drawworld; +extern cvar_t *r_speeds; +extern cvar_t *r_fullbright; +extern cvar_t *r_novis; +extern cvar_t *r_nocull; +extern cvar_t *r_lerpmodels; + +extern cvar_t *r_lightlevel; // FIXME: This is a HACK to get the client's light level + +extern cvar_t *gl_vertex_arrays; + +extern cvar_t *gl_ext_swapinterval; +extern cvar_t *gl_ext_palettedtexture; +extern cvar_t *gl_ext_multitexture; +extern cvar_t *gl_ext_pointparameters; +extern cvar_t *gl_ext_compiled_vertex_array; + +extern cvar_t *gl_particle_min_size; +extern cvar_t *gl_particle_max_size; +extern cvar_t *gl_particle_size; +extern cvar_t *gl_particle_att_a; +extern cvar_t *gl_particle_att_b; +extern cvar_t *gl_particle_att_c; + +extern cvar_t *gl_nosubimage; +extern cvar_t *gl_bitdepth; +extern cvar_t *gl_mode; +extern cvar_t *gl_log; +extern cvar_t *gl_lightmap; +extern cvar_t *gl_shadows; +extern cvar_t *gl_stencilshadow; +extern cvar_t *gl_dynamic; +extern cvar_t *gl_monolightmap; +extern cvar_t *gl_nobind; +extern cvar_t *gl_round_down; +extern cvar_t *gl_picmip; +extern cvar_t *gl_skymip; +extern cvar_t *gl_showtris; +extern cvar_t *gl_finish; +extern cvar_t *gl_ztrick; +extern cvar_t *gl_clear; +extern cvar_t *gl_cull; +extern cvar_t *gl_poly; +extern cvar_t *gl_texsort; +extern cvar_t *gl_polyblend; +extern cvar_t *gl_flashblend; +extern cvar_t *gl_lightmaptype; +extern cvar_t *gl_modulate; +extern cvar_t *gl_playermip; +extern cvar_t *gl_drawbuffer; +extern cvar_t *gl_3dlabs_broken; +extern cvar_t *gl_driver; +extern cvar_t *gl_swapinterval; +extern cvar_t *gl_texturemode; +extern cvar_t *gl_texturealphamode; +extern cvar_t *gl_texturesolidmode; +extern cvar_t *gl_saturatelighting; +extern cvar_t *gl_lockpvs; + +extern cvar_t *vid_fullscreen; +extern cvar_t *vid_gamma; + +extern cvar_t *intensity; + +extern int gl_lightmap_format; +extern int gl_solid_format; +extern int gl_alpha_format; +extern int gl_tex_solid_format; +extern int gl_tex_alpha_format; + +extern int c_visible_lightmaps; +extern int c_visible_textures; + +extern float r_world_matrix[16]; + +void R_TranslatePlayerSkin (int playernum); +void GL_Bind (int texnum); +void GL_MBind( GLenum target, int texnum ); +void GL_TexEnv( GLenum value ); +void GL_EnableMultitexture( qboolean enable ); +void GL_SelectTexture( GLenum ); + +void R_LightPoint (vec3_t p, vec3_t color); +void R_PushDlights (void); + +//==================================================================== + +extern model_t *r_worldmodel; + +extern unsigned d_8to24table[256]; + +extern int registration_sequence; + + +void V_AddBlend (float r, float g, float b, float a, float *v_blend); + +int R_Init( void *hinstance, void *hWnd ); +void R_Shutdown( void ); + +void R_RenderView (refdef_t *fd); +void GL_ScreenShot_f (void); +void R_DrawAliasModel (entity_t *e); +void R_DrawBrushModel (entity_t *e); +void R_DrawSpriteModel (entity_t *e); +void R_DrawBeam( entity_t *e ); +void R_DrawWorld (void); +void R_RenderDlights (void); +void R_DrawAlphaSurfaces (void); +void R_RenderBrushPoly (msurface_t *fa); +void R_InitParticleTexture (void); +void Draw_InitLocal (void); +void GL_SubdivideSurface (msurface_t *fa); +qboolean R_CullBox (vec3_t mins, vec3_t maxs); +void R_RotateForEntity (entity_t *e); +void R_MarkLeaves (void); + +glpoly_t *WaterWarpPolyVerts (glpoly_t *p); +void EmitWaterPolys (msurface_t *fa); +void R_AddSkySurface (msurface_t *fa); +void R_ClearSkyBox (void); +void R_DrawSkyBox (void); +void R_MarkLights (dlight_t *light, int bit, mnode_t *node); + +#if 0 +short LittleShort (short l); +short BigShort (short l); +int LittleLong (int l); +float LittleFloat (float f); + +char *va(char *format, ...); +// does a varargs printf into a temp buffer +#endif + +void COM_StripExtension (char *in, char *out); + +void Draw_GetPicSize (int *w, int *h, char *name); +void Draw_Pic (int x, int y, char *name); +void Draw_StretchPic (int x, int y, int w, int h, char *name); +void Draw_Char (int x, int y, int c); +void Draw_TileClear (int x, int y, int w, int h, char *name); +void Draw_Fill (int x, int y, int w, int h, int c); +void Draw_FadeScreen (void); +void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data); + +void R_BeginFrame( float camera_separation ); +void R_SwapBuffers( int ); +void R_SetPalette ( const unsigned char *palette); + +int Draw_GetPalette (void); + +void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight); + +struct image_s *R_RegisterSkin (char *name); + +void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height); +image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits); +image_t *GL_FindImage (char *name, imagetype_t type); +void GL_TextureMode( char *string ); +void GL_ImageList_f (void); + +void GL_SetTexturePalette( unsigned palette[256] ); + +void GL_InitImages (void); +void GL_ShutdownImages (void); + +void GL_FreeUnusedImages (void); + +void GL_TextureAlphaMode( char *string ); +void GL_TextureSolidMode( char *string ); + +/* +** GL extension emulation functions +*/ +void GL_DrawParticles( int n, const particle_t particles[], const unsigned colortable[768] ); + +/* +** GL config stuff +*/ +#define GL_RENDERER_VOODOO 0x00000001 +#define GL_RENDERER_VOODOO2 0x00000002 +#define GL_RENDERER_VOODOO_RUSH 0x00000004 +#define GL_RENDERER_BANSHEE 0x00000008 +#define GL_RENDERER_3DFX 0x0000000F + +#define GL_RENDERER_PCX1 0x00000010 +#define GL_RENDERER_PCX2 0x00000020 +#define GL_RENDERER_PMX 0x00000040 +#define GL_RENDERER_POWERVR 0x00000070 + +#define GL_RENDERER_PERMEDIA2 0x00000100 +#define GL_RENDERER_GLINT_MX 0x00000200 +#define GL_RENDERER_GLINT_TX 0x00000400 +#define GL_RENDERER_3DLABS_MISC 0x00000800 +#define GL_RENDERER_3DLABS 0x00000F00 + +#define GL_RENDERER_REALIZM 0x00001000 +#define GL_RENDERER_REALIZM2 0x00002000 +#define GL_RENDERER_INTERGRAPH 0x00003000 + +#define GL_RENDERER_3DPRO 0x00004000 +#define GL_RENDERER_REAL3D 0x00008000 +#define GL_RENDERER_RIVA128 0x00010000 +#define GL_RENDERER_DYPIC 0x00020000 + +#define GL_RENDERER_V1000 0x00040000 +#define GL_RENDERER_V2100 0x00080000 +#define GL_RENDERER_V2200 0x00100000 +#define GL_RENDERER_RENDITION 0x001C0000 + +#define GL_RENDERER_O2 0x00100000 +#define GL_RENDERER_IMPACT 0x00200000 +#define GL_RENDERER_RE 0x00400000 +#define GL_RENDERER_IR 0x00800000 +#define GL_RENDERER_SGI 0x00F00000 + +#define GL_RENDERER_MCD 0x01000000 +#define GL_RENDERER_OTHER 0x80000000 + +typedef struct +{ + int renderer; + const char *renderer_string; + const char *vendor_string; + const char *version_string; + const char *extensions_string; + + qboolean allow_cds; +} glconfig_t; + +typedef struct +{ + float inverse_intensity; + qboolean fullscreen; + + int prev_mode; + + unsigned char *d_16to8table; + + int lightmap_textures; + + int currenttextures[2]; + int currenttmu; + + float camera_separation; + qboolean stereo_enabled; + + qboolean hwgamma; + + unsigned char originalRedGammaTable[256]; + unsigned char originalGreenGammaTable[256]; + unsigned char originalBlueGammaTable[256]; +} glstate_t; + +extern glconfig_t gl_config; +extern glstate_t gl_state; + +/* +==================================================================== + +IMPORTED FUNCTIONS + +==================================================================== +*/ + +extern refimport_t ri; + + +/* +==================================================================== + +IMPLEMENTATION SPECIFIC FUNCTIONS + +==================================================================== +*/ + +void GLimp_BeginFrame( float camera_separation ); +void GLimp_EndFrame( void ); +int GLimp_Init( void *hinstance, void *hWnd ); +void GLimp_Shutdown( void ); +int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ); +void GLimp_AppActivate( qboolean active ); +void GLimp_EnableLogging( qboolean enable ); +void GLimp_LogNewFrame( void ); + +#endif diff --git a/src/refresh/opengl/gl_mesh.c b/src/refresh/opengl/gl_mesh.c new file mode 100644 index 00000000..3d9e895f --- /dev/null +++ b/src/refresh/opengl/gl_mesh.c @@ -0,0 +1,880 @@ +/* $Id: gl_mesh.c,v 1.3 2002/09/25 13:22:55 bburns Exp $ + * + * triangle model functions + * + * Copyright (C) 1997-2001 Id Software, Inc. + * Copyright (c) 2002 The Quakeforge Project. + * + * 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. + */ + +#include "gl_local.h" + +/* +============================================================= + + ALIAS MODELS + +============================================================= +*/ + +#define NUMVERTEXNORMALS 162 + +float r_avertexnormals[NUMVERTEXNORMALS][3] = { +#include "anorms.h" +}; + +typedef float vec4_t[4]; + +static vec4_t s_lerped[MAX_VERTS]; +//static vec3_t lerped[MAX_VERTS]; + +vec3_t shadevector; +float shadelight[3]; + +// precalculated dot products for quantized angles +#define SHADEDOT_QUANT 16 +float r_avertexnormal_dots[SHADEDOT_QUANT][256] = +#include "anormtab.h" +; + +float *shadedots = r_avertexnormal_dots[0]; + +void GL_LerpVerts( int nverts, dtrivertx_t *v, dtrivertx_t *ov, dtrivertx_t *verts, float *lerp, float move[3], float frontv[3], float backv[3] ) +{ + int i; + + //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4 ) + { + float *normal = r_avertexnormals[verts[i].lightnormalindex]; + + lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0] + normal[0] * POWERSUIT_SCALE; + lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1] + normal[1] * POWERSUIT_SCALE; + lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2] + normal[2] * POWERSUIT_SCALE; + } + } + else + { + for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4) + { + lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0]; + lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1]; + lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2]; + } + } + +} + +/* +============= +GL_DrawAliasFrameLerp + +interpolates between two frames and origins +FIXME: batch lerp all vertexes +============= +*/ +void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp) +{ + float l; + daliasframe_t *frame, *oldframe; + dtrivertx_t *v, *ov, *verts; + int *order; + int count; + float frontlerp; + float alpha; + vec3_t move, delta, vectors[3]; + vec3_t frontv, backv; + int i; + int index_xyz; + float *lerp; + + frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->frame * paliashdr->framesize); + verts = v = frame->verts; + + oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->oldframe * paliashdr->framesize); + ov = oldframe->verts; + + order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); + +// glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]); +// glScalef (frame->scale[0], frame->scale[1], frame->scale[2]); + + if (currententity->flags & RF_TRANSLUCENT) + alpha = currententity->alpha; + else + alpha = 1.0; + + // PMM - added double shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + qglDisable( GL_TEXTURE_2D ); + + frontlerp = 1.0 - backlerp; + + // move should be the delta back to the previous frame * backlerp + VectorSubtract (currententity->oldorigin, currententity->origin, delta); + AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); + + move[0] = DotProduct (delta, vectors[0]); // forward + move[1] = -DotProduct (delta, vectors[1]); // left + move[2] = DotProduct (delta, vectors[2]); // up + + VectorAdd (move, oldframe->translate, move); + + for (i=0 ; i<3 ; i++) + { + move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; + } + + for (i=0 ; i<3 ; i++) + { + frontv[i] = frontlerp*frame->scale[i]; + backv[i] = backlerp*oldframe->scale[i]; + } + + lerp = s_lerped[0]; + + GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv ); + + if ( gl_vertex_arrays->value ) + { + float colorArray[MAX_VERTS*4]; + + qglEnableClientState( GL_VERTEX_ARRAY ); + qglVertexPointer( 3, GL_FLOAT, 16, s_lerped ); // padded for SIMD + +// if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) + // PMM - added double damage shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha ); + } + else + { + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 3, GL_FLOAT, 0, colorArray ); + + // + // pre light everything + // + for ( i = 0; i < paliashdr->num_xyz; i++ ) + { + float l = shadedots[verts[i].lightnormalindex]; + + colorArray[i*3+0] = l * shadelight[0]; + colorArray[i*3+1] = l * shadelight[1]; + colorArray[i*3+2] = l * shadelight[2]; + } + } + + if ( qglLockArraysEXT != 0 ) + qglLockArraysEXT( 0, paliashdr->num_xyz ); + + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + qglBegin (GL_TRIANGLE_FAN); + } + else + { + qglBegin (GL_TRIANGLE_STRIP); + } + + // PMM - added double damage shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + do + { + index_xyz = order[2]; + order += 3; + + qglVertex3fv( s_lerped[index_xyz] ); + + } while (--count); + } + else + { + do + { + // texture coordinates come from the draw list + qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); + index_xyz = order[2]; + + order += 3; + + // normals and vertexes come from the frame list +// l = shadedots[verts[index_xyz].lightnormalindex]; + +// qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); + qglArrayElement( index_xyz ); + + } while (--count); + } + qglEnd (); + } + + if ( qglUnlockArraysEXT != 0 ) + qglUnlockArraysEXT(); + } + else + { + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + qglBegin (GL_TRIANGLE_FAN); + } + else + { + qglBegin (GL_TRIANGLE_STRIP); + } + + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) + { + do + { + index_xyz = order[2]; + order += 3; + + qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha); + qglVertex3fv (s_lerped[index_xyz]); + + } while (--count); + } + else + { + do + { + // texture coordinates come from the draw list + qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); + index_xyz = order[2]; + order += 3; + + // normals and vertexes come from the frame list + l = shadedots[verts[index_xyz].lightnormalindex]; + + qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); + qglVertex3fv (s_lerped[index_xyz]); + } while (--count); + } + + qglEnd (); + } + } + +// if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) + // PMM - added double damage shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + qglEnable( GL_TEXTURE_2D ); +} + + +#if 1 +/* +============= +GL_DrawAliasShadow +============= +*/ +extern vec3_t lightspot; +/* stencilbuffer shadows */ +extern qboolean have_stencil; + +void GL_DrawAliasShadow (dmdl_t *paliashdr, int posenum) +{ + dtrivertx_t *verts; + int *order; + vec3_t point; + float height, lheight; + int count; + daliasframe_t *frame; + + lheight = currententity->origin[2] - lightspot[2]; + + frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->frame * paliashdr->framesize); + verts = frame->verts; + + height = 0; + + order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); + + height = -lheight + 0.1f; + + /* stencilbuffer shadows */ + if (have_stencil && gl_stencilshadow->value) { + qglEnable(GL_STENCIL_TEST); + qglStencilFunc(GL_EQUAL, 1, 2); + qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + } + + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + qglBegin (GL_TRIANGLE_FAN); + } + else + qglBegin (GL_TRIANGLE_STRIP); + + do + { + // normals and vertexes come from the frame list +/* + point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0]; + point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1]; + point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2]; +*/ + + memcpy( point, s_lerped[order[2]], sizeof( point ) ); + + point[0] -= shadevector[0]*(point[2]+lheight); + point[1] -= shadevector[1]*(point[2]+lheight); + point[2] = height; +// height -= 0.001; + qglVertex3fv (point); + + order += 3; + +// verts++; + + } while (--count); + + qglEnd (); + } + + /* stencilbuffer shadows */ + if (have_stencil && gl_stencilshadow->value) + qglDisable(GL_STENCIL_TEST); +} + +#endif + +/* +** R_CullAliasModel +*/ +static qboolean R_CullAliasModel( vec3_t bbox[8], entity_t *e ) +{ + int i; + vec3_t mins, maxs; + dmdl_t *paliashdr; + vec3_t vectors[3]; + vec3_t thismins, oldmins, thismaxs, oldmaxs; + daliasframe_t *pframe, *poldframe; + vec3_t angles; + + paliashdr = (dmdl_t *)currentmodel->extradata; + + if ( ( e->frame >= paliashdr->num_frames ) || ( e->frame < 0 ) ) + { + ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such frame %d\n", + currentmodel->name, e->frame); + e->frame = 0; + } + if ( ( e->oldframe >= paliashdr->num_frames ) || ( e->oldframe < 0 ) ) + { + ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such oldframe %d\n", + currentmodel->name, e->oldframe); + e->oldframe = 0; + } + + pframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + + paliashdr->ofs_frames + + e->frame * paliashdr->framesize); + + poldframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + + paliashdr->ofs_frames + + e->oldframe * paliashdr->framesize); + + /* + ** compute axially aligned mins and maxs + */ + if ( pframe == poldframe ) + { + for ( i = 0; i < 3; i++ ) + { + mins[i] = pframe->translate[i]; + maxs[i] = mins[i] + pframe->scale[i]*255; + } + } + else + { + for ( i = 0; i < 3; i++ ) + { + thismins[i] = pframe->translate[i]; + thismaxs[i] = thismins[i] + pframe->scale[i]*255; + + oldmins[i] = poldframe->translate[i]; + oldmaxs[i] = oldmins[i] + poldframe->scale[i]*255; + + if ( thismins[i] < oldmins[i] ) + mins[i] = thismins[i]; + else + mins[i] = oldmins[i]; + + if ( thismaxs[i] > oldmaxs[i] ) + maxs[i] = thismaxs[i]; + else + maxs[i] = oldmaxs[i]; + } + } + + /* + ** compute a full bounding box + */ + for ( i = 0; i < 8; i++ ) + { + vec3_t tmp; + + 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]; + + VectorCopy( tmp, bbox[i] ); + } + + /* + ** rotate the bounding box + */ + VectorCopy( e->angles, angles ); + angles[YAW] = -angles[YAW]; + AngleVectors( angles, vectors[0], vectors[1], vectors[2] ); + + for ( i = 0; i < 8; i++ ) + { + vec3_t tmp; + + VectorCopy( bbox[i], tmp ); + + bbox[i][0] = DotProduct( vectors[0], tmp ); + bbox[i][1] = -DotProduct( vectors[1], tmp ); + bbox[i][2] = DotProduct( vectors[2], tmp ); + + VectorAdd( e->origin, bbox[i], bbox[i] ); + } + + { + int p, f, aggregatemask = ~0; + + for ( p = 0; p < 8; p++ ) + { + int mask = 0; + + for ( f = 0; f < 4; f++ ) + { + float dp = DotProduct( frustum[f].normal, bbox[p] ); + + if ( ( dp - frustum[f].dist ) < 0 ) + { + mask |= ( 1 << f ); + } + } + + aggregatemask &= mask; + } + + if ( aggregatemask ) + { + return true; + } + + return false; + } +} + +/* +================= +R_DrawAliasModel + +================= +*/ +void R_DrawAliasModel (entity_t *e) +{ + int i; + dmdl_t *paliashdr; + float an; + vec3_t bbox[8]; + image_t *skin; + + if ( !( e->flags & RF_WEAPONMODEL ) ) + { + if ( R_CullAliasModel( bbox, e ) ) + return; + } + + if ( e->flags & RF_WEAPONMODEL ) + { + if ( r_lefthand->value == 2 ) + return; + } + + paliashdr = (dmdl_t *)currentmodel->extradata; + + // + // get lighting information + // + // PMM - rewrote, reordered to handle new shells & mixing + // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy + // + if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) + { + VectorClear (shadelight); + if (currententity->flags & RF_SHELL_HALF_DAM) + { + shadelight[0] = 0.56; + shadelight[1] = 0.59; + shadelight[2] = 0.45; + } + if ( currententity->flags & RF_SHELL_DOUBLE ) + { + shadelight[0] = 0.9; + shadelight[1] = 0.7; + } + if ( currententity->flags & RF_SHELL_RED ) + shadelight[0] = 1.0; + if ( currententity->flags & RF_SHELL_GREEN ) + shadelight[1] = 1.0; + if ( currententity->flags & RF_SHELL_BLUE ) + shadelight[2] = 1.0; + } +/* + // PMM -special case for godmode + if ( (currententity->flags & RF_SHELL_RED) && + (currententity->flags & RF_SHELL_BLUE) && + (currententity->flags & RF_SHELL_GREEN) ) + { + for (i=0 ; i<3 ; i++) + shadelight[i] = 1.0; + } + else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) + { + VectorClear (shadelight); + + if ( currententity->flags & RF_SHELL_RED ) + { + shadelight[0] = 1.0; + if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) ) + shadelight[2] = 1.0; + } + else if ( currententity->flags & RF_SHELL_BLUE ) + { + if ( currententity->flags & RF_SHELL_DOUBLE ) + { + shadelight[1] = 1.0; + shadelight[2] = 1.0; + } + else + { + shadelight[2] = 1.0; + } + } + else if ( currententity->flags & RF_SHELL_DOUBLE ) + { + shadelight[0] = 0.9; + shadelight[1] = 0.7; + } + } + else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) ) + { + VectorClear (shadelight); + // PMM - new colors + if ( currententity->flags & RF_SHELL_HALF_DAM ) + { + shadelight[0] = 0.56; + shadelight[1] = 0.59; + shadelight[2] = 0.45; + } + if ( currententity->flags & RF_SHELL_GREEN ) + { + shadelight[1] = 1.0; + } + } + } + //PMM - ok, now flatten these down to range from 0 to 1.0. + // max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2])); + // if (max_shell_val > 0) + // { + // for (i=0; i<3; i++) + // { + // shadelight[i] = shadelight[i] / max_shell_val; + // } + // } + // pmm +*/ + else if ( currententity->flags & RF_FULLBRIGHT ) + { + for (i=0 ; i<3 ; i++) + shadelight[i] = 1.0; + } + else + { + R_LightPoint (currententity->origin, shadelight); + + // player lighting hack for communication back to server + // big hack! + if ( currententity->flags & RF_WEAPONMODEL ) + { + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) + { + if (shadelight[0] > shadelight[2]) + r_lightlevel->value = 150*shadelight[0]; + else + r_lightlevel->value = 150*shadelight[2]; + } + else + { + if (shadelight[1] > shadelight[2]) + r_lightlevel->value = 150*shadelight[1]; + else + r_lightlevel->value = 150*shadelight[2]; + } + + } + + if ( gl_monolightmap->string[0] != '0' ) + { + float s = shadelight[0]; + + if ( s < shadelight[1] ) + s = shadelight[1]; + if ( s < shadelight[2] ) + s = shadelight[2]; + + shadelight[0] = s; + shadelight[1] = s; + shadelight[2] = s; + } + } + + if ( currententity->flags & RF_MINLIGHT ) + { + for (i=0 ; i<3 ; i++) + if (shadelight[i] > 0.1) + break; + if (i == 3) + { + shadelight[0] = 0.1; + shadelight[1] = 0.1; + shadelight[2] = 0.1; + } + } + + if ( currententity->flags & RF_GLOW ) + { // bonus items will pulse with time + float scale; + float min; + + scale = 0.1 * sin(r_newrefdef.time*7); + for (i=0 ; i<3 ; i++) + { + min = shadelight[i] * 0.8; + shadelight[i] += scale; + if (shadelight[i] < min) + shadelight[i] = min; + } + } + +// ================= +// PGM ir goggles color override + if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) + { + shadelight[0] = 1.0; + shadelight[1] = 0.0; + shadelight[2] = 0.0; + } +// PGM +// ================= + + shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; + + an = currententity->angles[1]/180*M_PI; + shadevector[0] = cos(-an); + shadevector[1] = sin(-an); + shadevector[2] = 1; + VectorNormalize (shadevector); + + // + // locate the proper data + // + + c_alias_polys += paliashdr->num_tris; + + // + // draw all the triangles + // + if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls + qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); + + qglMatrixMode( GL_PROJECTION ); + qglPushMatrix(); + qglLoadIdentity(); + qglScalef( -1, 1, 1 ); + MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); + qglMatrixMode( GL_MODELVIEW ); + + qglCullFace( GL_BACK ); + } + + qglPushMatrix (); + e->angles[PITCH] = -e->angles[PITCH]; // sigh. + R_RotateForEntity (e); + e->angles[PITCH] = -e->angles[PITCH]; // sigh. + + // select skin + if (currententity->skin) + skin = currententity->skin; // custom player skin + else + { + if (currententity->skinnum >= MAX_MD2SKINS) + skin = currentmodel->skins[0]; + else + { + skin = currentmodel->skins[currententity->skinnum]; + if (!skin) + skin = currentmodel->skins[0]; + } + } + if (!skin) + skin = r_notexture; // fallback... + GL_Bind(skin->texnum); + + // draw it + + qglShadeModel (GL_SMOOTH); + + GL_TexEnv( GL_MODULATE ); + if ( currententity->flags & RF_TRANSLUCENT ) + { + qglEnable (GL_BLEND); + } + + + if ( (currententity->frame >= paliashdr->num_frames) + || (currententity->frame < 0) ) + { + ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", + currentmodel->name, currententity->frame); + currententity->frame = 0; + currententity->oldframe = 0; + } + + if ( (currententity->oldframe >= paliashdr->num_frames) + || (currententity->oldframe < 0)) + { + ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", + currentmodel->name, currententity->oldframe); + currententity->frame = 0; + currententity->oldframe = 0; + } + + if ( !r_lerpmodels->value ) + currententity->backlerp = 0; + GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp); + + GL_TexEnv( GL_REPLACE ); + qglShadeModel (GL_FLAT); + + qglPopMatrix (); + +#if 0 + qglDisable( GL_CULL_FACE ); + qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + qglDisable( GL_TEXTURE_2D ); + qglBegin( GL_TRIANGLE_STRIP ); + for ( i = 0; i < 8; i++ ) + { + qglVertex3fv( bbox[i] ); + } + qglEnd(); + qglEnable( GL_TEXTURE_2D ); + qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + qglEnable( GL_CULL_FACE ); +#endif + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + qglMatrixMode( GL_PROJECTION ); + qglPopMatrix(); + qglMatrixMode( GL_MODELVIEW ); + qglCullFace( GL_FRONT ); + } + + if ( currententity->flags & RF_TRANSLUCENT ) + { + qglDisable (GL_BLEND); + } + + if (currententity->flags & RF_DEPTHHACK) + qglDepthRange (gldepthmin, gldepthmax); + +//#if 1 + if (gl_shadows->value && + !(currententity->flags & (RF_TRANSLUCENT|RF_WEAPONMODEL|RF_NOSHADOW))) { + qglPushMatrix (); + + /* don't rotate shadows on ungodly axes */ + qglTranslatef(e->origin[0], e->origin[1], e->origin[2]); + qglRotatef(e->angles[1], 0, 0, 1); + + qglDisable (GL_TEXTURE_2D); + qglEnable (GL_BLEND); + qglColor4f (0,0,0,0.5); + GL_DrawAliasShadow (paliashdr, currententity->frame ); + qglEnable (GL_TEXTURE_2D); + qglDisable (GL_BLEND); + qglPopMatrix (); + } +//#endif + qglColor4f (1,1,1,1); +} + + diff --git a/src/refresh/opengl/gl_model.c b/src/refresh/opengl/gl_model.c new file mode 100644 index 00000000..af69d577 --- /dev/null +++ b/src/refresh/opengl/gl_model.c @@ -0,0 +1,1223 @@ +/* +Copyright (C) 1997-2001 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 + +#include "gl_local.h" + +model_t *loadmodel; +int modfilelen; + +void Mod_LoadSpriteModel (model_t *mod, void *buffer); +void Mod_LoadBrushModel (model_t *mod, void *buffer); +void Mod_LoadAliasModel (model_t *mod, void *buffer); +model_t *Mod_LoadModel (model_t *mod, qboolean crash); + +byte mod_novis[MAX_MAP_LEAFS/8]; + +#define MAX_MOD_KNOWN 512 +model_t mod_known[MAX_MOD_KNOWN]; +int mod_numknown; + +// the inline * models from the current map are kept seperate +model_t mod_inline[MAX_MOD_KNOWN]; + +int registration_sequence; + +/* +=============== +Mod_PointInLeaf +=============== +*/ +mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +{ + mnode_t *node; + float d; + cplane_t *plane; + + if (!model || !model->nodes) + ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model"); + + node = model->nodes; + while (1) + { + if (node->contents != -1) + return (mleaf_t *)node; + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return NULL; // never reached +} + + +/* +=================== +Mod_DecompressVis +=================== +*/ +byte *Mod_DecompressVis (byte *in, model_t *model) +{ + static byte decompressed[MAX_MAP_LEAFS/8]; + int c; + byte *out; + int row; + + row = (model->vis->numclusters+7)>>3; + out = decompressed; + + 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); + + return decompressed; +} + +/* +============== +Mod_ClusterPVS +============== +*/ +byte *Mod_ClusterPVS (int cluster, model_t *model) +{ + if (cluster == -1 || !model->vis) + return mod_novis; + return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS], + model); +} + + +//=============================================================================== + +/* +================ +Mod_Modellist_f +================ +*/ +void Mod_Modellist_f (void) +{ + int i; + model_t *mod; + int total; + + total = 0; + ri.Con_Printf (PRINT_ALL,"Loaded models:\n"); + for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) + { + if (!mod->name[0]) + continue; + ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name); + total += mod->extradatasize; + } + ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total); +} + +/* +=============== +Mod_Init +=============== +*/ +void Mod_Init (void) +{ + memset (mod_novis, 0xff, sizeof(mod_novis)); +} + + + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +model_t *Mod_ForName (char *name, qboolean crash) +{ + model_t *mod; + unsigned *buf; + int i; + + if (!name[0]) + ri.Sys_Error (ERR_DROP, "Mod_ForName: NULL name"); + + // + // inline models are grabbed only from worldmodel + // + if (name[0] == '*') + { + i = atoi(name+1); + if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels) + ri.Sys_Error (ERR_DROP, "bad inline model number"); + return &mod_inline[i]; + } + + // + // search the currently loaded models + // + for (i=0 , mod=mod_known ; iname[0]) + continue; + if (!strcmp (mod->name, name) ) + return mod; + } + + // + // find a free model slot spot + // + for (i=0 , mod=mod_known ; iname[0]) + break; // free spot + } + if (i == mod_numknown) + { + if (mod_numknown == MAX_MOD_KNOWN) + ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN"); + mod_numknown++; + } + strcpy (mod->name, name); + + // + // load the file + // + modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf); + if (!buf) + { + if (crash) + ri.Sys_Error (ERR_DROP, "Mod_NumForName: %s not found", mod->name); + memset (mod->name, 0, sizeof(mod->name)); + return NULL; + } + + loadmodel = mod; + + // + // fill it in + // + + + // call the apropriate loader + + switch (LittleLong(*(unsigned *)buf)) + { + case IDALIASHEADER: + loadmodel->extradata = Hunk_Begin (0x200000); + Mod_LoadAliasModel (mod, buf); + break; + + case IDSPRITEHEADER: + loadmodel->extradata = Hunk_Begin (0x10000); + Mod_LoadSpriteModel (mod, buf); + break; + + case IDBSPHEADER: + loadmodel->extradata = Hunk_Begin (0x1000000); + Mod_LoadBrushModel (mod, buf); + break; + + default: + ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name); + break; + } + + loadmodel->extradatasize = Hunk_End (); + + ri.FS_FreeFile (buf); + + return mod; +} + +/* +=============================================================================== + + BRUSHMODEL LOADING + +=============================================================================== +*/ + +byte *mod_base; + + +/* +================= +Mod_LoadLighting +================= +*/ +void Mod_LoadLighting (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = Hunk_Alloc ( l->filelen); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); +} + + +/* +================= +Mod_LoadVisibility +================= +*/ +void Mod_LoadVisibility (lump_t *l) +{ + int i; + + if (!l->filelen) + { + loadmodel->vis = NULL; + return; + } + loadmodel->vis = Hunk_Alloc ( l->filelen); + memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen); + + loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters); + for (i=0 ; ivis->numclusters ; i++) + { + loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]); + loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]); + } +} + + +/* +================= +Mod_LoadVertexes +================= +*/ +void Mod_LoadVertexes (lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + 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]); + } +} + +/* +================= +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 VectorLength (corner); +} + + +/* +================= +Mod_LoadSubmodels +================= +*/ +void Mod_LoadSubmodels (lump_t *l) +{ + dmodel_t *in; + mmodel_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + out->radius = RadiusFromBounds (out->mins, out->maxs); + out->headnode = LittleLong (in->headnode); + out->firstface = LittleLong (in->firstface); + out->numfaces = LittleLong (in->numfaces); + } +} + +/* +================= +Mod_LoadEdges +================= +*/ +void Mod_LoadEdges (lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count + 1) * sizeof(*out)); + + 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 +================= +*/ +void Mod_LoadTexinfo (lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out, *step; + int i, j, count; + char name[MAX_QPATH]; + int next; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); + + out->flags = LittleLong (in->flags); + next = LittleLong (in->nexttexinfo); + if (next > 0) + out->next = loadmodel->texinfo + next; + else + out->next = NULL; + Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture); + + out->image = GL_FindImage (name, it_wall); + if (!out->image) + { + ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name); + out->image = r_notexture; + } + } + + // count animation frames + for (i=0 ; itexinfo[i]; + out->numframes = 1; + for (step = out->next ; step && step != out ; step=step->next) + out->numframes++; + } +} + +/* +================ +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 ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512 /* 256 */ ) +// ri.Sys_Error (ERR_DROP, "Bad surface extents"); + } +} + + +void GL_BuildPolygonFromSurface(msurface_t *fa); +void GL_CreateSurfaceLightmap (msurface_t *surf); +void GL_EndBuildingLightmaps (void); +void GL_BeginBuildingLightmaps (model_t *m); + +/* +================= +Mod_LoadFaces +================= +*/ +void Mod_LoadFaces (lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + int ti; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + currentmodel = loadmodel; + + GL_BeginBuildingLightmaps (loadmodel); + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->flags = 0; + out->polys = NULL; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + ti = LittleShort (in->texinfo); + if (ti < 0 || ti >= loadmodel->numtexinfo) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: bad texinfo number"); + out->texinfo = loadmodel->texinfo + ti; + + CalcSurfaceExtents (out); + + // lighting info + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodel->lightdata + i; + + // set the drawing flags + + if (out->texinfo->flags & SURF_WARP) + { + out->flags |= SURF_DRAWTURB; + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + GL_SubdivideSurface (out); // cut up polygon for warps + } + + // create lightmaps and polygons + if ( !(out->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) ) ) + GL_CreateSurfaceLightmap (out); + + if (! (out->texinfo->flags & SURF_WARP) ) + GL_BuildPolygonFromSurface(out); + + } + + GL_EndBuildingLightmaps (); +} + + +/* +================= +Mod_SetParent +================= +*/ +void Mod_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents != -1) + return; + Mod_SetParent (node->children[0], node); + Mod_SetParent (node->children[1], node); +} + +/* +================= +Mod_LoadNodes +================= +*/ +void Mod_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)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + 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); + out->contents = -1; // differentiate from leafs + + for (j=0 ; j<2 ; j++) + { + p = LittleLong (in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs +} + +/* +================= +Mod_LoadLeafs +================= +*/ +void Mod_LoadLeafs (lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count, p; +// glpoly_t *poly; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + 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->cluster = LittleShort(in->cluster); + out->area = LittleShort(in->area); + + out->firstmarksurface = loadmodel->marksurfaces + + LittleShort(in->firstleafface); + out->nummarksurfaces = LittleShort(in->numleaffaces); + + // gl underwater warp +#if 0 + if (out->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_THINWATER) ) + { + for (j=0 ; jnummarksurfaces ; j++) + { + out->firstmarksurface[j]->flags |= SURF_UNDERWATER; + for (poly = out->firstmarksurface[j]->polys ; poly ; poly=poly->next) + poly->flags |= SURF_UNDERWATER; + } + } +#endif + } +} + +/* +================= +Mod_LoadMarksurfaces +================= +*/ +void Mod_LoadMarksurfaces (lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for ( i=0 ; i= loadmodel->numsurfaces) + ri.Sys_Error (ERR_DROP, "Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodel->surfaces + j; + } +} + +/* +================= +Mod_LoadSurfedges +================= +*/ +void Mod_LoadSurfedges (lump_t *l) +{ + int i, count; + int *in, *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + if (count < 1 || count >= MAX_MAP_SURFEDGES) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: bad surfedges count in %s: %i", + loadmodel->name, count); + + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*2*sizeof(*out)); + + loadmodel->planes = out; + loadmodel->numplanes = count; + + 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; + } +} + +/* +================= +Mod_LoadBrushModel +================= +*/ +void Mod_LoadBrushModel (model_t *mod, void *buffer) +{ + int i; + dheader_t *header; + mmodel_t *bm; + + loadmodel->type = mod_brush; + if (loadmodel != mod_known) + ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world"); + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + if (i != BSPVERSION) + ri.Sys_Error (ERR_DROP, "Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + +// swap all the lumps + mod_base = (byte *)header; + + for (i=0 ; ilumps[LUMP_VERTEXES]); + Mod_LoadEdges (&header->lumps[LUMP_EDGES]); + Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); + Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces (&header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]); + Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]); + Mod_LoadNodes (&header->lumps[LUMP_NODES]); + Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); + mod->numframes = 2; // regular and alternate animation + +// +// set up the submodels +// + for (i=0 ; inumsubmodels ; i++) + { + model_t *starmod; + + bm = &mod->submodels[i]; + starmod = &mod_inline[i]; + + *starmod = *loadmodel; + + starmod->firstmodelsurface = bm->firstface; + starmod->nummodelsurfaces = bm->numfaces; + starmod->firstnode = bm->headnode; + if (starmod->firstnode >= loadmodel->numnodes) + ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i); + + VectorCopy (bm->maxs, starmod->maxs); + VectorCopy (bm->mins, starmod->mins); + starmod->radius = bm->radius; + + if (i == 0) + *loadmodel = *starmod; + + starmod->numleafs = bm->visleafs; + } +} + +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadAliasModel +================= +*/ +void Mod_LoadAliasModel (model_t *mod, void *buffer) +{ + int i, j; + dmdl_t *pinmodel, *pheader; + dstvert_t *pinst, *poutst; + dtriangle_t *pintri, *pouttri; + daliasframe_t *pinframe, *poutframe; + int *pincmd, *poutcmd; + int version; + + pinmodel = (dmdl_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", + mod->name, version, ALIAS_VERSION); + + pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end)); + + // byte swap the header fields and sanity check + for (i=0 ; iskinheight > MAX_LBM_HEIGHT) + ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + if (pheader->num_xyz <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name); + + if (pheader->num_xyz > MAX_VERTS) + ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name); + + if (pheader->num_st <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name); + + if (pheader->num_tris <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name); + + if (pheader->num_frames <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name); + +// +// load base s and t vertices (not used in gl version) +// + pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st); + poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st); + + for (i=0 ; inum_st ; i++) + { + poutst[i].s = LittleShort (pinst[i].s); + poutst[i].t = LittleShort (pinst[i].t); + } + +// +// load triangle lists +// + pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris); + pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris); + + for (i=0 ; inum_tris ; i++) + { + for (j=0 ; j<3 ; j++) + { + pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]); + pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]); + } + } + +// +// load the frames +// + for (i=0 ; inum_frames ; i++) + { + pinframe = (daliasframe_t *) ((byte *)pinmodel + + pheader->ofs_frames + i * pheader->framesize); + poutframe = (daliasframe_t *) ((byte *)pheader + + pheader->ofs_frames + i * pheader->framesize); + + memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); + for (j=0 ; j<3 ; j++) + { + poutframe->scale[j] = LittleFloat (pinframe->scale[j]); + poutframe->translate[j] = LittleFloat (pinframe->translate[j]); + } + // verts are all 8 bit, so no swapping needed + memcpy (poutframe->verts, pinframe->verts, + pheader->num_xyz*sizeof(dtrivertx_t)); + + } + + mod->type = mod_alias; + + // + // load the glcmds + // + pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds); + poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds); + for (i=0 ; inum_glcmds ; i++) + poutcmd[i] = LittleLong (pincmd[i]); + + + // register all skins + memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins, + pheader->num_skins*MAX_SKINNAME); + for (i=0 ; inum_skins ; i++) + { + mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME + , it_skin); + } + + mod->mins[0] = -32; + mod->mins[1] = -32; + mod->mins[2] = -32; + mod->maxs[0] = 32; + mod->maxs[1] = 32; + mod->maxs[2] = 32; +} + +/* +============================================================================== + +SPRITE MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadSpriteModel +================= +*/ +void Mod_LoadSpriteModel (model_t *mod, void *buffer) +{ + dsprite_t *sprin, *sprout; + int i; + + sprin = (dsprite_t *)buffer; + sprout = Hunk_Alloc (modfilelen); + + sprout->ident = LittleLong (sprin->ident); + sprout->version = LittleLong (sprin->version); + sprout->numframes = LittleLong (sprin->numframes); + + if (sprout->version != SPRITE_VERSION) + ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", + mod->name, sprout->version, SPRITE_VERSION); + + if (sprout->numframes > MAX_MD2SKINS) + ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)", + mod->name, sprout->numframes, MAX_MD2SKINS); + + // byte swap everything + for (i=0 ; inumframes ; i++) + { + sprout->frames[i].width = LittleLong (sprin->frames[i].width); + sprout->frames[i].height = LittleLong (sprin->frames[i].height); + sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x); + sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y); + memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME); + mod->skins[i] = GL_FindImage (sprout->frames[i].name, + it_sprite); + } + + mod->type = mod_sprite; +} + +//============================================================================= + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_BeginRegistration + +Specifies the model that will be used as the world +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_BeginRegistration (char *model) +{ + char fullname[MAX_QPATH]; + cvar_t *flushmap; + + registration_sequence++; + r_oldviewcluster = -1; // force markleafs + + Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model); + + // explicitly free the old map if different + // this guarantees that mod_known[0] is the world map + flushmap = ri.Cvar_Get ("flushmap", "0", 0); + if ( strcmp(mod_known[0].name, fullname) || flushmap->value) + Mod_Free (&mod_known[0]); + r_worldmodel = Mod_ForName(fullname, true); + + r_viewcluster = -1; +} + + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_RegisterModel + +@@@@@@@@@@@@@@@@@@@@@ +*/ +struct model_s *R_RegisterModel (char *name) +{ + model_t *mod; + int i; + dsprite_t *sprout; + dmdl_t *pheader; + + mod = Mod_ForName (name, false); + if (mod) + { + mod->registration_sequence = registration_sequence; + + // register any images used by the models + if (mod->type == mod_sprite) + { + sprout = (dsprite_t *)mod->extradata; + for (i=0 ; inumframes ; i++) + mod->skins[i] = GL_FindImage (sprout->frames[i].name, it_sprite); + } + else if (mod->type == mod_alias) + { + pheader = (dmdl_t *)mod->extradata; + for (i=0 ; inum_skins ; i++) + mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin); +//PGM + mod->numframes = pheader->num_frames; +//PGM + } + else if (mod->type == mod_brush) + { + for (i=0 ; inumtexinfo ; i++) + mod->texinfo[i].image->registration_sequence = registration_sequence; + } + } + return mod; +} + + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_EndRegistration + +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_EndRegistration (void) +{ + int i; + model_t *mod; + + for (i=0, mod=mod_known ; iname[0]) + continue; + if (mod->registration_sequence != registration_sequence) + { // don't need this model + Mod_Free (mod); + } + } + + GL_FreeUnusedImages (); +} + + +//============================================================================= + + +/* +================ +Mod_Free +================ +*/ +void Mod_Free (model_t *mod) +{ + Hunk_Free (mod->extradata); + memset (mod, 0, sizeof(*mod)); +} + +/* +================ +Mod_FreeAll +================ +*/ +void Mod_FreeAll (void) +{ + int i; + + for (i=0 ; isurfedges[], negative numbers + int numedges; // are backwards edges + + short texturemins[2]; + short extents[2]; + + int light_s, light_t; // gl lightmap coordinates + int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps + + glpoly_t *polys; // multiple if warped + struct msurface_s *texturechain; + struct msurface_s *lightmapchain; + + mtexinfo_t *texinfo; + +// lighting info + int dlightframe; + int dlightbits; + + int lightmaptexturenum; + byte styles[MAXLIGHTMAPS]; + float cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + byte *samples; // [numstyles*surfsize] +} msurface_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // -1, to differentiate from leafs + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// node specific + cplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + + + +typedef struct mleaf_s +{ +// common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + int cluster; + int area; + + msurface_t **firstmarksurface; + int nummarksurfaces; +} mleaf_t; + + +//=================================================================== + +// +// Whole model +// + +typedef enum {mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t; + +typedef struct model_s +{ + char name[MAX_QPATH]; + + int registration_sequence; + + modtype_t type; + int numframes; + + int flags; + +// +// volume occupied by the model graphics +// + vec3_t mins, maxs; + float radius; + +// +// solid volume for clipping +// + qboolean clipbox; + vec3_t clipmins, clipmaxs; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + int lightmap; // only for submodels + + int numsubmodels; + mmodel_t *submodels; + + int numplanes; + cplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + int firstnode; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int nummarksurfaces; + msurface_t **marksurfaces; + + dvis_t *vis; + + byte *lightdata; + + // for alias models and skins + image_t *skins[MAX_MD2SKINS]; + + int extradatasize; + void *extradata; +} model_t; + +//============================================================================ + +void Mod_Init (void); +void Mod_ClearAll (void); +model_t *Mod_ForName (char *name, qboolean crash); +mleaf_t *Mod_PointInLeaf (float *p, model_t *model); +byte *Mod_ClusterPVS (int cluster, model_t *model); + +void Mod_Modellist_f (void); + +void *Hunk_Begin (int maxsize); +void *Hunk_Alloc (int size); +int Hunk_End (void); +void Hunk_Free (void *base); + +void Mod_FreeAll (void); +void Mod_Free (model_t *mod); diff --git a/src/refresh/opengl/gl_rmain.c b/src/refresh/opengl/gl_rmain.c new file mode 100644 index 00000000..dbaf0644 --- /dev/null +++ b/src/refresh/opengl/gl_rmain.c @@ -0,0 +1,1770 @@ +/* +Copyright (C) 1997-2001 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 +#include "gl_local.h" + +void R_Clear (void); + +viddef_t vid; + +refimport_t ri; + +int QGL_TEXTURE0, QGL_TEXTURE1; + +model_t *r_worldmodel; + +float gldepthmin, gldepthmax; + +glconfig_t gl_config; +glstate_t gl_state; + +image_t *r_notexture; // use for bad textures +image_t *r_particletexture; // little dot for particles + +entity_t *currententity; +model_t *currentmodel; + +cplane_t frustum[4]; + +int r_visframecount; // bumped when going to a new PVS +int r_framecount; // used for dlight push checking + +int c_brush_polys, c_alias_polys; + +float v_blend[4]; // final blending color + +void GL_Strings_f( void ); + +// +// view origin +// +vec3_t vup; +vec3_t vpn; +vec3_t vright; +vec3_t r_origin; + +float r_world_matrix[16]; +float r_base_world_matrix[16]; + +// +// screen size info +// +refdef_t r_newrefdef; + +int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; + +cvar_t *r_norefresh; +cvar_t *r_drawentities; +cvar_t *r_drawworld; +cvar_t *r_speeds; +cvar_t *r_fullbright; +cvar_t *r_novis; +cvar_t *r_nocull; +cvar_t *r_lerpmodels; +cvar_t *r_lefthand; + +cvar_t *r_lightlevel; // FIXME: This is a HACK to get the client's light level + +cvar_t *gl_nosubimage; +cvar_t *gl_allow_software; + +cvar_t *gl_vertex_arrays; + +cvar_t *gl_particle_min_size; +cvar_t *gl_particle_max_size; +cvar_t *gl_particle_size; +cvar_t *gl_particle_att_a; +cvar_t *gl_particle_att_b; +cvar_t *gl_particle_att_c; + +cvar_t *gl_ext_swapinterval; +cvar_t *gl_ext_palettedtexture; +cvar_t *gl_ext_multitexture; +cvar_t *gl_ext_pointparameters; +cvar_t *gl_ext_compiled_vertex_array; + +cvar_t *gl_log; +cvar_t *gl_bitdepth; +cvar_t *gl_drawbuffer; +cvar_t *gl_driver; +cvar_t *gl_lightmap; +cvar_t *gl_shadows; +cvar_t * gl_stencilshadow; +cvar_t *gl_mode; +cvar_t *gl_dynamic; +cvar_t *gl_monolightmap; +cvar_t *gl_modulate; +cvar_t *gl_nobind; +cvar_t *gl_round_down; +cvar_t *gl_picmip; +cvar_t *gl_skymip; +cvar_t *gl_showtris; +cvar_t *gl_ztrick; +cvar_t *gl_finish; +cvar_t *gl_clear; +cvar_t *gl_cull; +cvar_t *gl_polyblend; +cvar_t *gl_flashblend; +cvar_t *gl_playermip; +cvar_t *gl_saturatelighting; +cvar_t *gl_swapinterval; +cvar_t *gl_texturemode; +cvar_t *gl_texturealphamode; +cvar_t *gl_texturesolidmode; +cvar_t *gl_lockpvs; + +cvar_t *gl_3dlabs_broken; + +cvar_t *vid_fullscreen; +cvar_t *vid_gamma; +cvar_t *vid_ref; + +/* +================= +R_CullBox + +Returns true if the box is completely outside the frustom +================= +*/ +qboolean R_CullBox (vec3_t mins, vec3_t maxs) +{ + int i; + + if (r_nocull->value) + return false; + + for (i=0 ; i<4 ; i++) + if ( BOX_ON_PLANE_SIDE(mins, maxs, &frustum[i]) == 2) + return true; + return false; +} + + +void R_RotateForEntity (entity_t *e) +{ + qglTranslatef (e->origin[0], e->origin[1], e->origin[2]); + + qglRotatef (e->angles[1], 0, 0, 1); + qglRotatef (-e->angles[0], 0, 1, 0); + qglRotatef (-e->angles[2], 1, 0, 0); +} + +/* +============================================================= + + SPRITE MODELS + +============================================================= +*/ + + +/* +================= +R_DrawSpriteModel + +================= +*/ +void R_DrawSpriteModel (entity_t *e) +{ + float alpha = 1.0F; + vec3_t point; + dsprframe_t *frame; + float *up, *right; + dsprite_t *psprite; + + // don't even bother culling, because it's just a single + // polygon without a surface cache + + psprite = (dsprite_t *)currentmodel->extradata; + +#if 0 + if (e->frame < 0 || e->frame >= psprite->numframes) + { + ri.Con_Printf (PRINT_ALL, "no such sprite frame %i\n", e->frame); + e->frame = 0; + } +#endif + e->frame %= psprite->numframes; + + frame = &psprite->frames[e->frame]; + +#if 0 + if (psprite->type == SPR_ORIENTED) + { // bullet marks on walls + vec3_t v_forward, v_right, v_up; + + AngleVectors (currententity->angles, v_forward, v_right, v_up); + up = v_up; + right = v_right; + } + else +#endif + { // normal sprite + up = vup; + right = vright; + } + + if ( e->flags & RF_TRANSLUCENT ) + alpha = e->alpha; + + if ( alpha != 1.0F ) + qglEnable( GL_BLEND ); + + qglColor4f( 1, 1, 1, alpha ); + + GL_Bind(currentmodel->skins[e->frame]->texnum); + + GL_TexEnv( GL_MODULATE ); + + if ( alpha == 1.0 ) + qglEnable (GL_ALPHA_TEST); + else + qglDisable( GL_ALPHA_TEST ); + + qglBegin (GL_QUADS); + + qglTexCoord2f (0, 1); + VectorMA (e->origin, -frame->origin_y, up, point); + VectorMA (point, -frame->origin_x, right, point); + qglVertex3fv (point); + + qglTexCoord2f (0, 0); + VectorMA (e->origin, frame->height - frame->origin_y, up, point); + VectorMA (point, -frame->origin_x, right, point); + qglVertex3fv (point); + + qglTexCoord2f (1, 0); + VectorMA (e->origin, frame->height - frame->origin_y, up, point); + VectorMA (point, frame->width - frame->origin_x, right, point); + qglVertex3fv (point); + + qglTexCoord2f (1, 1); + VectorMA (e->origin, -frame->origin_y, up, point); + VectorMA (point, frame->width - frame->origin_x, right, point); + qglVertex3fv (point); + + qglEnd (); + + qglDisable (GL_ALPHA_TEST); + GL_TexEnv( GL_REPLACE ); + + if ( alpha != 1.0F ) + qglDisable( GL_BLEND ); + + qglColor4f( 1, 1, 1, 1 ); +} + +//================================================================================== + +/* +============= +R_DrawNullModel +============= +*/ +void R_DrawNullModel (void) +{ + vec3_t shadelight; + int i; + + if ( currententity->flags & RF_FULLBRIGHT ) + shadelight[0] = shadelight[1] = shadelight[2] = 1.0F; + else + R_LightPoint (currententity->origin, shadelight); + + qglPushMatrix (); + R_RotateForEntity (currententity); + + qglDisable (GL_TEXTURE_2D); + qglColor3fv (shadelight); + + qglBegin (GL_TRIANGLE_FAN); + qglVertex3f (0, 0, -16); + for (i=0 ; i<=4 ; i++) + qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0); + qglEnd (); + + qglBegin (GL_TRIANGLE_FAN); + qglVertex3f (0, 0, 16); + for (i=4 ; i>=0 ; i--) + qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0); + qglEnd (); + + qglColor3f (1,1,1); + qglPopMatrix (); + qglEnable (GL_TEXTURE_2D); +} + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (void) +{ + int i; + + if (!r_drawentities->value) + return; + + // draw non-transparent first + for (i=0 ; iflags & RF_TRANSLUCENT) + continue; // solid + + if ( currententity->flags & RF_BEAM ) + { + R_DrawBeam( currententity ); + } + else + { + currentmodel = currententity->model; + if (!currentmodel) + { + R_DrawNullModel (); + continue; + } + switch (currentmodel->type) + { + case mod_alias: + R_DrawAliasModel (currententity); + break; + case mod_brush: + R_DrawBrushModel (currententity); + break; + case mod_sprite: + R_DrawSpriteModel (currententity); + break; + default: + ri.Sys_Error (ERR_DROP, "Bad modeltype"); + break; + } + } + } + + // draw transparent entities + // we could sort these if it ever becomes a problem... + qglDepthMask (0); // no z writes + for (i=0 ; iflags & RF_TRANSLUCENT)) + continue; // solid + + if ( currententity->flags & RF_BEAM ) + { + R_DrawBeam( currententity ); + } + else + { + currentmodel = currententity->model; + + if (!currentmodel) + { + R_DrawNullModel (); + continue; + } + switch (currentmodel->type) + { + case mod_alias: + R_DrawAliasModel (currententity); + break; + case mod_brush: + R_DrawBrushModel (currententity); + break; + case mod_sprite: + R_DrawSpriteModel (currententity); + break; + default: + ri.Sys_Error (ERR_DROP, "Bad modeltype"); + break; + } + } + } + qglDepthMask (1); // back to writing + +} + +/* +** GL_DrawParticles +** +*/ +void GL_DrawParticles( int num_particles, const particle_t particles[], const unsigned colortable[768] ) +{ + const particle_t *p; + int i; + vec3_t up, right; + float scale; + byte color[4]; + + GL_Bind(r_particletexture->texnum); + qglDepthMask( GL_FALSE ); // no z buffering + qglEnable( GL_BLEND ); + GL_TexEnv( GL_MODULATE ); + qglBegin( GL_TRIANGLES ); + + VectorScale (vup, 1.5, up); + VectorScale (vright, 1.5, right); + + for ( p = particles, i=0 ; i < num_particles ; i++,p++) + { + // hack a scale up to keep particles from disapearing + scale = ( p->origin[0] - r_origin[0] ) * vpn[0] + + ( p->origin[1] - r_origin[1] ) * vpn[1] + + ( p->origin[2] - r_origin[2] ) * vpn[2]; + + if (scale < 20) + scale = 1; + else + scale = 1 + scale * 0.004; + + *(int *)color = colortable[p->color]; + color[3] = p->alpha*255; + + qglColor4ubv( color ); + + qglTexCoord2f( 0.0625, 0.0625 ); + qglVertex3fv( p->origin ); + + qglTexCoord2f( 1.0625, 0.0625 ); + qglVertex3f( p->origin[0] + up[0]*scale, + p->origin[1] + up[1]*scale, + p->origin[2] + up[2]*scale); + + qglTexCoord2f( 0.0625, 1.0625 ); + qglVertex3f( p->origin[0] + right[0]*scale, + p->origin[1] + right[1]*scale, + p->origin[2] + right[2]*scale); + } + + qglEnd (); + qglDisable( GL_BLEND ); + qglColor4f( 1,1,1,1 ); + qglDepthMask( 1 ); // back to normal Z buffering + GL_TexEnv( GL_REPLACE ); +} + +/* +=============== +R_DrawParticles +=============== +*/ +void R_DrawParticles (void) +{ + if ( gl_ext_pointparameters->value && qglPointParameterfEXT ) + { + int i; + unsigned char color[4]; + const particle_t *p; + + qglDepthMask( GL_FALSE ); + qglEnable( GL_BLEND ); + qglDisable( GL_TEXTURE_2D ); + + qglPointSize( gl_particle_size->value ); + + qglBegin( GL_POINTS ); + for ( i = 0, p = r_newrefdef.particles; i < r_newrefdef.num_particles; i++, p++ ) + { + *(int *)color = d_8to24table[p->color]; + color[3] = p->alpha*255; + + qglColor4ubv( color ); + + qglVertex3fv( p->origin ); + } + qglEnd(); + + qglDisable( GL_BLEND ); + qglColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); + qglDepthMask( GL_TRUE ); + qglEnable( GL_TEXTURE_2D ); + + } + else + { + GL_DrawParticles( r_newrefdef.num_particles, r_newrefdef.particles, d_8to24table ); + } +} + +/* +============ +R_PolyBlend +============ +*/ +void R_PolyBlend (void) +{ + if (!gl_polyblend->value) + return; + if (!v_blend[3]) + return; + + qglDisable (GL_ALPHA_TEST); + qglEnable (GL_BLEND); + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_TEXTURE_2D); + + qglLoadIdentity (); + + // FIXME: get rid of these + qglRotatef (-90, 1, 0, 0); // put Z going up + qglRotatef (90, 0, 0, 1); // put Z going up + + qglColor4fv (v_blend); + + qglBegin (GL_QUADS); + + qglVertex3f (10, 100, 100); + qglVertex3f (10, -100, 100); + qglVertex3f (10, -100, -100); + qglVertex3f (10, 100, -100); + qglEnd (); + + qglDisable (GL_BLEND); + qglEnable (GL_TEXTURE_2D); + qglEnable (GL_ALPHA_TEST); + + qglColor4f(1,1,1,1); +} + +//======================================================================= + +int SignbitsForPlane (cplane_t *out) +{ + int bits, j; + + // for fast box on planeside test + + bits = 0; + for (j=0 ; j<3 ; j++) + { + if (out->normal[j] < 0) + bits |= 1<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 = Mod_PointInLeaf (temp, r_worldmodel); + if ( !(leaf->contents & CONTENTS_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 = Mod_PointInLeaf (temp, r_worldmodel); + if ( !(leaf->contents & CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2) ) + r_viewcluster2 = leaf->cluster; + } + } + + for (i=0 ; i<4 ; i++) + v_blend[i] = r_newrefdef.blend[i]; + + c_brush_polys = 0; + c_alias_polys = 0; + + // clear out the portion of the screen that the NOWORLDMODEL defines + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + { + qglEnable( GL_SCISSOR_TEST ); + qglClearColor( 0.3, 0.3, 0.3, 1 ); + qglScissor( r_newrefdef.x, vid.height - r_newrefdef.height - r_newrefdef.y, r_newrefdef.width, r_newrefdef.height ); + qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + qglClearColor( 1, 0, 0.5, 0.5 ); + qglDisable( GL_SCISSOR_TEST ); + } +} + + +void MYgluPerspective( GLdouble fovy, GLdouble aspect, + GLdouble zNear, GLdouble zFar ) +{ + GLdouble xmin, xmax, ymin, ymax; + + ymax = zNear * tan( fovy * M_PI / 360.0 ); + ymin = -ymax; + + xmin = ymin * aspect; + xmax = ymax * aspect; + + xmin += -( 2 * gl_state.camera_separation ) / zNear; + xmax += -( 2 * gl_state.camera_separation ) / zNear; + + qglFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); +} + + +/* +============= +R_SetupGL +============= +*/ +void R_SetupGL (void) +{ + float screenaspect; +// float yfov; + int x, x2, y2, y, w, h; + + // + // set up viewport + // + x = floor(r_newrefdef.x * vid.width / vid.width); + x2 = ceil((r_newrefdef.x + r_newrefdef.width) * vid.width / vid.width); + y = floor(vid.height - r_newrefdef.y * vid.height / vid.height); + y2 = ceil(vid.height - (r_newrefdef.y + r_newrefdef.height) * vid.height / vid.height); + + w = x2 - x; + h = y - y2; + + qglViewport (x, y2, w, h); + + // + // set up projection matrix + // + screenaspect = (float)r_newrefdef.width/r_newrefdef.height; +// yfov = 2*atan((float)r_newrefdef.height/r_newrefdef.width)*180/M_PI; + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + MYgluPerspective (r_newrefdef.fov_y, screenaspect, 4, 4096); + + qglCullFace(GL_FRONT); + + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + + qglRotatef (-90, 1, 0, 0); // put Z going up + qglRotatef (90, 0, 0, 1); // put Z going up + qglRotatef (-r_newrefdef.viewangles[2], 1, 0, 0); + qglRotatef (-r_newrefdef.viewangles[0], 0, 1, 0); + qglRotatef (-r_newrefdef.viewangles[1], 0, 0, 1); + qglTranslatef (-r_newrefdef.vieworg[0], -r_newrefdef.vieworg[1], -r_newrefdef.vieworg[2]); + +// if ( gl_state.camera_separation != 0 && gl_state.stereo_enabled ) +// qglTranslatef ( gl_state.camera_separation, 0, 0 ); + + qglGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); + + // + // set drawing parms + // + if (gl_cull->value) + qglEnable(GL_CULL_FACE); + else + qglDisable(GL_CULL_FACE); + + qglDisable(GL_BLEND); + qglDisable(GL_ALPHA_TEST); + qglEnable(GL_DEPTH_TEST); +} + +/* +============= +R_Clear +============= +*/ +extern qboolean have_stencil; + +void R_Clear (void) +{ + if (gl_ztrick->value) + { + static int trickframe; + + if (gl_clear->value) + qglClear (GL_COLOR_BUFFER_BIT); + + trickframe++; + if (trickframe & 1) + { + gldepthmin = 0; + gldepthmax = 0.49999; + qglDepthFunc (GL_LEQUAL); + } + else + { + gldepthmin = 1; + gldepthmax = 0.5; + qglDepthFunc (GL_GEQUAL); + } + } + else + { + if (gl_clear->value) + qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + else + qglClear (GL_DEPTH_BUFFER_BIT); + gldepthmin = 0; + gldepthmax = 1; + qglDepthFunc (GL_LEQUAL); + } + + qglDepthRange (gldepthmin, gldepthmax); + + /* stencilbuffer shadows */ + if (gl_shadows->value && have_stencil && gl_stencilshadow->value) { + qglClearStencil(1); + qglClear(GL_STENCIL_BUFFER_BIT); + } +} + +void R_Flash( void ) +{ + R_PolyBlend (); +} + +/* +================ +R_RenderView + +r_newrefdef must be set before the first call +================ +*/ +void R_RenderView (refdef_t *fd) +{ + if (r_norefresh->value) + return; + + r_newrefdef = *fd; + + if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) + ri.Sys_Error (ERR_DROP, "R_RenderView: NULL worldmodel"); + + if (r_speeds->value) + { + c_brush_polys = 0; + c_alias_polys = 0; + } + + R_PushDlights (); + + if (gl_finish->value) + qglFinish (); + + R_SetupFrame (); + + R_SetFrustum (); + + R_SetupGL (); + + R_MarkLeaves (); // done here so we know if we're in water + + R_DrawWorld (); + + R_DrawEntitiesOnList (); + + R_RenderDlights (); + + R_DrawParticles (); + + R_DrawAlphaSurfaces (); + + R_Flash(); + + if (r_speeds->value) + { + ri.Con_Printf (PRINT_ALL, "%4i wpoly %4i epoly %i tex %i lmaps\n", + c_brush_polys, + c_alias_polys, + c_visible_textures, + c_visible_lightmaps); + } +} + + +void R_SetGL2D (void) +{ + // set 2D virtual screen size + qglViewport (0,0, vid.width, vid.height); + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + qglOrtho (0, vid.width, vid.height, 0, -99999, 99999); + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_CULL_FACE); + qglDisable (GL_BLEND); + qglEnable (GL_ALPHA_TEST); + qglColor4f (1,1,1,1); +} + +#if 0 // Not used. +static void GL_DrawColoredStereoLinePair( float r, float g, float b, float y ) +{ + qglColor3f( r, g, b ); + qglVertex2f( 0, y ); + qglVertex2f( vid.width, y ); + qglColor3f( 0, 0, 0 ); + qglVertex2f( 0, y + 1 ); + qglVertex2f( vid.width, y + 1 ); +} + +static void GL_DrawStereoPattern( void ) +{ + int i; + + if ( !( gl_config.renderer & GL_RENDERER_INTERGRAPH ) ) + return; + + if ( !gl_state.stereo_enabled ) + return; + + R_SetGL2D(); + + qglDrawBuffer( GL_BACK_LEFT ); + + for ( i = 0; i < 20; i++ ) + { + qglBegin( GL_LINES ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 0 ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 2 ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 4 ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 6 ); + GL_DrawColoredStereoLinePair( 0, 1, 0, 8 ); + GL_DrawColoredStereoLinePair( 1, 1, 0, 10); + GL_DrawColoredStereoLinePair( 1, 1, 0, 12); + GL_DrawColoredStereoLinePair( 0, 1, 0, 14); + qglEnd(); + + GLimp_EndFrame(); + } +} +#endif + +/* +==================== +R_SetLightLevel + +==================== +*/ +void R_SetLightLevel (void) +{ + vec3_t shadelight; + + if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) + return; + + // save off light value for server to look at (BIG HACK!) + + R_LightPoint (r_newrefdef.vieworg, shadelight); + + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) + { + if (shadelight[0] > shadelight[2]) + r_lightlevel->value = 150*shadelight[0]; + else + r_lightlevel->value = 150*shadelight[2]; + } + else + { + if (shadelight[1] > shadelight[2]) + r_lightlevel->value = 150*shadelight[1]; + else + r_lightlevel->value = 150*shadelight[2]; + } + +} + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_RenderFrame + +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_RenderFrame (refdef_t *fd) +{ + R_RenderView( fd ); + R_SetLightLevel (); + R_SetGL2D (); +} + + +void R_Register( void ) +{ + r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE ); + r_norefresh = ri.Cvar_Get ("r_norefresh", "0", 0); + r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0); + r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0); + r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0); + r_novis = ri.Cvar_Get ("r_novis", "0", 0); + r_nocull = ri.Cvar_Get ("r_nocull", "0", 0); + r_lerpmodels = ri.Cvar_Get ("r_lerpmodels", "1", 0); + r_speeds = ri.Cvar_Get ("r_speeds", "0", 0); + + r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0); + + gl_nosubimage = ri.Cvar_Get( "gl_nosubimage", "0", 0 ); + gl_allow_software = ri.Cvar_Get( "gl_allow_software", "0", 0 ); + + gl_particle_min_size = ri.Cvar_Get( "gl_particle_min_size", "2", CVAR_ARCHIVE ); + gl_particle_max_size = ri.Cvar_Get( "gl_particle_max_size", "40", CVAR_ARCHIVE ); + gl_particle_size = ri.Cvar_Get( "gl_particle_size", "40", CVAR_ARCHIVE ); + gl_particle_att_a = ri.Cvar_Get( "gl_particle_att_a", "0.01", CVAR_ARCHIVE ); + gl_particle_att_b = ri.Cvar_Get( "gl_particle_att_b", "0.0", CVAR_ARCHIVE ); + gl_particle_att_c = ri.Cvar_Get( "gl_particle_att_c", "0.01", CVAR_ARCHIVE ); + + gl_modulate = ri.Cvar_Get ("gl_modulate", "1", CVAR_ARCHIVE ); + gl_log = ri.Cvar_Get( "gl_log", "0", 0 ); + gl_bitdepth = ri.Cvar_Get( "gl_bitdepth", "0", 0 ); + gl_mode = ri.Cvar_Get( "gl_mode", "3", CVAR_ARCHIVE ); + gl_lightmap = ri.Cvar_Get ("gl_lightmap", "0", 0); + gl_shadows = ri.Cvar_Get ("gl_shadows", "0", CVAR_ARCHIVE ); + gl_stencilshadow = ri.Cvar_Get("gl_stencilshadow", "0", CVAR_ARCHIVE); + gl_dynamic = ri.Cvar_Get ("gl_dynamic", "1", 0); + gl_nobind = ri.Cvar_Get ("gl_nobind", "0", 0); + gl_round_down = ri.Cvar_Get ("gl_round_down", "1", 0); + gl_picmip = ri.Cvar_Get ("gl_picmip", "0", 0); + gl_skymip = ri.Cvar_Get ("gl_skymip", "0", 0); + gl_showtris = ri.Cvar_Get ("gl_showtris", "0", 0); + gl_ztrick = ri.Cvar_Get ("gl_ztrick", "0", 0); + gl_finish = ri.Cvar_Get ("gl_finish", "0", CVAR_ARCHIVE); + gl_clear = ri.Cvar_Get ("gl_clear", "0", 0); + gl_cull = ri.Cvar_Get ("gl_cull", "1", 0); + gl_polyblend = ri.Cvar_Get ("gl_polyblend", "1", 0); + gl_flashblend = ri.Cvar_Get ("gl_flashblend", "0", 0); + gl_playermip = ri.Cvar_Get ("gl_playermip", "0", 0); + gl_monolightmap = ri.Cvar_Get( "gl_monolightmap", "0", 0 ); +#ifdef _WIN32 + gl_driver = ri.Cvar_Get( "gl_driver", "opengl32", CVAR_ARCHIVE ); +#else + gl_driver = ri.Cvar_Get( "gl_driver", "libGL.so", CVAR_ARCHIVE ); +#endif + gl_texturemode = ri.Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); + gl_texturealphamode = ri.Cvar_Get( "gl_texturealphamode", "default", CVAR_ARCHIVE ); + gl_texturesolidmode = ri.Cvar_Get( "gl_texturesolidmode", "default", CVAR_ARCHIVE ); + gl_lockpvs = ri.Cvar_Get( "gl_lockpvs", "0", 0 ); + + gl_vertex_arrays = ri.Cvar_Get( "gl_vertex_arrays", "0", CVAR_ARCHIVE ); + + gl_ext_swapinterval = ri.Cvar_Get( "gl_ext_swapinterval", "1", CVAR_ARCHIVE ); + gl_ext_palettedtexture = ri.Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE ); + gl_ext_multitexture = ri.Cvar_Get( "gl_ext_multitexture", "1", CVAR_ARCHIVE ); + gl_ext_pointparameters = ri.Cvar_Get( "gl_ext_pointparameters", "1", CVAR_ARCHIVE ); + gl_ext_compiled_vertex_array = ri.Cvar_Get( "gl_ext_compiled_vertex_array", "1", CVAR_ARCHIVE ); + + gl_drawbuffer = ri.Cvar_Get( "gl_drawbuffer", "GL_BACK", 0 ); + gl_swapinterval = ri.Cvar_Get( "gl_swapinterval", "1", CVAR_ARCHIVE ); + + gl_saturatelighting = ri.Cvar_Get( "gl_saturatelighting", "0", 0 ); + + gl_3dlabs_broken = ri.Cvar_Get( "gl_3dlabs_broken", "1", CVAR_ARCHIVE ); + + vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE ); + vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE ); + vid_ref = ri.Cvar_Get( "vid_ref", "soft", CVAR_ARCHIVE ); + + ri.Cmd_AddCommand( "imagelist", GL_ImageList_f ); + ri.Cmd_AddCommand( "screenshot", GL_ScreenShot_f ); + ri.Cmd_AddCommand( "modellist", Mod_Modellist_f ); + ri.Cmd_AddCommand( "gl_strings", GL_Strings_f ); +} + +/* +================== +R_SetMode +================== +*/ +qboolean R_SetMode (void) +{ + rserr_t err; + qboolean fullscreen; + +#ifdef _WIN32 + if ( vid_fullscreen->modified && !gl_config.allow_cds ) + { + ri.Con_Printf( PRINT_ALL, "R_SetMode() - CDS not allowed with this driver\n" ); + ri.Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value ); + vid_fullscreen->modified = false; + } +#endif + fullscreen = vid_fullscreen->value; + + vid_fullscreen->modified = false; + gl_mode->modified = false; + + if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, fullscreen ) ) == rserr_ok ) + { + gl_state.prev_mode = gl_mode->value; + } + else + { + if ( err == rserr_invalid_fullscreen ) + { + ri.Cvar_SetValue( "vid_fullscreen", 0); + vid_fullscreen->modified = false; + ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - fullscreen unavailable in this mode\n" ); + if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, false ) ) == rserr_ok ) + return true; + } + else if ( err == rserr_invalid_mode ) + { + ri.Cvar_SetValue( "gl_mode", gl_state.prev_mode ); + gl_mode->modified = false; + ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n" ); + } + + // try setting it back to something safe + if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_state.prev_mode, false ) ) != rserr_ok ) + { + ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - could not revert to safe mode\n" ); + return false; + } + } + return true; +} + +/* +=============== +R_Init +=============== +*/ +int R_Init( void *hinstance, void *hWnd ) +{ + char renderer_buffer[1000]; + char vendor_buffer[1000]; + int err; + int j; + extern float r_turbsin[256]; + + for ( j = 0; j < 256; j++ ) + { + r_turbsin[j] *= 0.5; + } + + ri.Con_Printf (PRINT_ALL, "ref_gl version: "REF_VERSION"\n"); + + Draw_GetPalette (); + + R_Register(); + + // initialize our QGL dynamic bindings + if ( !QGL_Init( gl_driver->string ) ) + { + QGL_Shutdown(); + ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not load \"%s\"\n", gl_driver->string ); + return -1; + } + + // initialize OS-specific parts of OpenGL + if ( !GLimp_Init( hinstance, hWnd ) ) + { + QGL_Shutdown(); + return -1; + } + + // set our "safe" modes + gl_state.prev_mode = 3; + + // create the window and set up the context + if ( !R_SetMode () ) + { + QGL_Shutdown(); + ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not R_SetMode()\n" ); + return -1; + } + + ri.Vid_MenuInit(); + + /* + ** get our various GL strings + */ + gl_config.vendor_string = (char *)qglGetString (GL_VENDOR); + ri.Con_Printf (PRINT_ALL, "GL_VENDOR: %s\n", gl_config.vendor_string ); + gl_config.renderer_string = (char *)qglGetString (GL_RENDERER); + ri.Con_Printf (PRINT_ALL, "GL_RENDERER: %s\n", gl_config.renderer_string ); + gl_config.version_string = (char *)qglGetString (GL_VERSION); + ri.Con_Printf (PRINT_ALL, "GL_VERSION: %s\n", gl_config.version_string ); + gl_config.extensions_string = (char *)qglGetString (GL_EXTENSIONS); + ri.Con_Printf (PRINT_ALL, "GL_EXTENSIONS: %s\n", gl_config.extensions_string ); + + strncpy( renderer_buffer, gl_config.renderer_string, sizeof(renderer_buffer) ); + renderer_buffer[sizeof(renderer_buffer)-1] = 0; + strlwr( renderer_buffer ); + + strncpy( vendor_buffer, gl_config.vendor_string, sizeof(vendor_buffer) ); + vendor_buffer[sizeof(vendor_buffer)-1] = 0; + strlwr( vendor_buffer ); + + if ( strstr( renderer_buffer, "voodoo" ) ) + { + if ( !strstr( renderer_buffer, "rush" ) ) + gl_config.renderer = GL_RENDERER_VOODOO; + else + gl_config.renderer = GL_RENDERER_VOODOO_RUSH; + } + else if ( strstr( vendor_buffer, "sgi" ) ) + gl_config.renderer = GL_RENDERER_SGI; + else if ( strstr( renderer_buffer, "permedia" ) ) + gl_config.renderer = GL_RENDERER_PERMEDIA2; + else if ( strstr( renderer_buffer, "glint" ) ) + gl_config.renderer = GL_RENDERER_GLINT_MX; + else if ( strstr( renderer_buffer, "glzicd" ) ) + gl_config.renderer = GL_RENDERER_REALIZM; + else if ( strstr( renderer_buffer, "gdi" ) ) + gl_config.renderer = GL_RENDERER_MCD; + else if ( strstr( renderer_buffer, "pcx2" ) ) + gl_config.renderer = GL_RENDERER_PCX2; + else if ( strstr( renderer_buffer, "verite" ) ) + gl_config.renderer = GL_RENDERER_RENDITION; + else + gl_config.renderer = GL_RENDERER_OTHER; + + if ( toupper( gl_monolightmap->string[1] ) != 'F' ) + { + if ( gl_config.renderer == GL_RENDERER_PERMEDIA2 ) + { + ri.Cvar_Set( "gl_monolightmap", "A" ); + ri.Con_Printf( PRINT_ALL, "...using gl_monolightmap 'a'\n" ); + } + else if ( gl_config.renderer & GL_RENDERER_POWERVR ) + { + ri.Cvar_Set( "gl_monolightmap", "0" ); + } + else + { + ri.Cvar_Set( "gl_monolightmap", "0" ); + } + } + + // power vr can't have anything stay in the framebuffer, so + // the screen needs to redraw the tiled background every frame + if ( gl_config.renderer & GL_RENDERER_POWERVR ) + { + ri.Cvar_Set( "scr_drawall", "1" ); + } + else + { + ri.Cvar_Set( "scr_drawall", "0" ); + } + +#if 0 && defined(__linux__) + ri.Cvar_SetValue( "gl_finish", 1 ); +#endif + + // MCD has buffering issues + if ( gl_config.renderer == GL_RENDERER_MCD ) + { + ri.Cvar_SetValue( "gl_finish", 1 ); + } + + if ( gl_config.renderer & GL_RENDERER_3DLABS ) + { + if ( gl_3dlabs_broken->value ) + gl_config.allow_cds = false; + else + gl_config.allow_cds = true; + } + else + { + gl_config.allow_cds = true; + } + +#ifdef _WIN32 + if ( gl_config.allow_cds ) + ri.Con_Printf( PRINT_ALL, "...allowing CDS\n" ); + else + ri.Con_Printf( PRINT_ALL, "...disabling CDS\n" ); +#endif + /* + ** grab extensions + */ + if ( strstr( gl_config.extensions_string, "GL_EXT_compiled_vertex_array" ) || + strstr( gl_config.extensions_string, "GL_SGI_compiled_vertex_array" ) ) + { + ri.Con_Printf( PRINT_ALL, "...enabling GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void * ) qwglGetProcAddress( "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void * ) qwglGetProcAddress( "glUnlockArraysEXT" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + +#ifdef _WIN32 + if ( strstr( gl_config.extensions_string, "WGL_EXT_swap_control" ) ) + { + qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" ); + ri.Con_Printf( PRINT_ALL, "...enabling WGL_EXT_swap_control\n" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" ); + } +#endif + + if ( strstr( gl_config.extensions_string, "GL_EXT_point_parameters" ) ) + { + if ( gl_ext_pointparameters->value ) + { + qglPointParameterfEXT = ( void (APIENTRY *)( GLenum, GLfloat ) ) qwglGetProcAddress( "glPointParameterfEXT" ); + qglPointParameterfvEXT = ( void (APIENTRY *)( GLenum, const GLfloat * ) ) qwglGetProcAddress( "glPointParameterfvEXT" ); + ri.Con_Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_point_parameters\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" ); + } + +#ifdef __linux__ + if ( strstr( gl_config.extensions_string, "3DFX_set_global_palette" )) + { + if ( gl_ext_palettedtexture->value ) + { + ri.Con_Printf( PRINT_ALL, "...using 3DFX_set_global_palette\n" ); + qgl3DfxSetPaletteEXT = ( void ( APIENTRY * ) (GLuint *) )qwglGetProcAddress( "gl3DfxSetPaletteEXT" ); + qglColorTableEXT = Fake_glColorTableEXT; + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring 3DFX_set_global_palette\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...3DFX_set_global_palette not found\n" ); + } +#endif + + if ( !qglColorTableEXT && + strstr( gl_config.extensions_string, "GL_EXT_paletted_texture" ) && + strstr( gl_config.extensions_string, "GL_EXT_shared_texture_palette" ) ) + { + if ( gl_ext_palettedtexture->value ) + { + ri.Con_Printf( PRINT_ALL, "...using GL_EXT_shared_texture_palette\n" ); + qglColorTableEXT = ( void ( APIENTRY * ) ( GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid * ) ) qwglGetProcAddress( "glColorTableEXT" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_shared_texture_palette\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_EXT_shared_texture_palette not found\n" ); + } + + if ( strstr( gl_config.extensions_string, "GL_ARB_multitexture" ) ) + { + if ( gl_ext_multitexture->value ) + { + ri.Con_Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + qglMTexCoord2fSGIS = ( void * ) qwglGetProcAddress( "glMultiTexCoord2fARB" ); + qglActiveTextureARB = ( void * ) qwglGetProcAddress( "glActiveTextureARB" ); + qglClientActiveTextureARB = ( void * ) qwglGetProcAddress( "glClientActiveTextureARB" ); + QGL_TEXTURE0 = GL_TEXTURE0_ARB; + QGL_TEXTURE1 = GL_TEXTURE1_ARB; + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + if ( strstr( gl_config.extensions_string, "GL_SGIS_multitexture" ) ) + { + if ( qglActiveTextureARB ) + { + ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture deprecated in favor of ARB_multitexture\n" ); + } + else if ( gl_ext_multitexture->value ) + { + ri.Con_Printf( PRINT_ALL, "...using GL_SGIS_multitexture\n" ); + qglMTexCoord2fSGIS = ( void * ) qwglGetProcAddress( "glMTexCoord2fSGIS" ); + qglSelectTextureSGIS = ( void * ) qwglGetProcAddress( "glSelectTextureSGIS" ); + QGL_TEXTURE0 = GL_TEXTURE0_SGIS; + QGL_TEXTURE1 = GL_TEXTURE1_SGIS; + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring GL_SGIS_multitexture\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture not found\n" ); + } + + GL_SetDefaultState(); + + /* + ** draw our stereo patterns + */ +#if 0 // commented out until H3D pays us the money they owe us + GL_DrawStereoPattern(); +#endif + + GL_InitImages (); + Mod_Init (); + R_InitParticleTexture (); + Draw_InitLocal (); + + err = qglGetError(); + if ( err != GL_NO_ERROR ) + ri.Con_Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); + + return true; +} + +/* +=============== +R_Shutdown +=============== +*/ +void R_Shutdown (void) +{ + ri.Cmd_RemoveCommand ("modellist"); + ri.Cmd_RemoveCommand ("screenshot"); + ri.Cmd_RemoveCommand ("imagelist"); + ri.Cmd_RemoveCommand ("gl_strings"); + + Mod_FreeAll (); + + GL_ShutdownImages (); + + /* + ** shut down OS specific OpenGL stuff like contexts, etc. + */ + GLimp_Shutdown(); + + /* + ** shutdown our QGL subsystem + */ + QGL_Shutdown(); +} + + + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_BeginFrame +@@@@@@@@@@@@@@@@@@@@@ +*/ +extern void UpdateHardwareGamma(); + +void R_BeginFrame( float camera_separation ) +{ + + gl_state.camera_separation = camera_separation; + + /* + ** change modes if necessary + */ + if ( gl_mode->modified || vid_fullscreen->modified ) + { // FIXME: only restart if CDS is required + cvar_t *ref; + + ref = ri.Cvar_Get ("vid_ref", "gl", 0); + ref->modified = true; + } + + if ( gl_log->modified ) + { + GLimp_EnableLogging( gl_log->value ); + gl_log->modified = false; + } + + if ( gl_log->value ) + { + GLimp_LogNewFrame(); + } + + /* + ** update 3Dfx gamma -- it is expected that a user will do a vid_restart + ** after tweaking this value + */ + if ( vid_gamma->modified ) + { + vid_gamma->modified = false; + + if ( gl_state.hwgamma ) { + UpdateHardwareGamma(); + } else if ( gl_config.renderer & ( GL_RENDERER_VOODOO ) ) + { + char envbuffer[1024]; + float g; + + g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F; + Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g ); + putenv( envbuffer ); + Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g ); + putenv( envbuffer ); + } + } + + GLimp_BeginFrame( camera_separation ); + + /* + ** go into 2D mode + */ + qglViewport (0,0, vid.width, vid.height); + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + qglOrtho (0, vid.width, vid.height, 0, -99999, 99999); + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_CULL_FACE); + qglDisable (GL_BLEND); + qglEnable (GL_ALPHA_TEST); + qglColor4f (1,1,1,1); + + /* + ** draw buffer stuff + */ + if ( gl_drawbuffer->modified ) + { + gl_drawbuffer->modified = false; + + if ( gl_state.camera_separation == 0 || !gl_state.stereo_enabled ) + { + if ( Q_stricmp( gl_drawbuffer->string, "GL_FRONT" ) == 0 ) + qglDrawBuffer( GL_FRONT ); + else + qglDrawBuffer( GL_BACK ); + } + } + + /* + ** texturemode stuff + */ + if ( gl_texturemode->modified ) + { + GL_TextureMode( gl_texturemode->string ); + gl_texturemode->modified = false; + } + + if ( gl_texturealphamode->modified ) + { + GL_TextureAlphaMode( gl_texturealphamode->string ); + gl_texturealphamode->modified = false; + } + + if ( gl_texturesolidmode->modified ) + { + GL_TextureSolidMode( gl_texturesolidmode->string ); + gl_texturesolidmode->modified = false; + } + + /* + ** swapinterval stuff + */ + GL_UpdateSwapInterval(); + + // + // clear screen if desired + // + R_Clear (); +} + +/* +============= +R_SetPalette +============= +*/ +unsigned r_rawpalette[256]; + +void R_SetPalette ( const unsigned char *palette) +{ + int i; + + byte *rp = ( byte * ) r_rawpalette; + + if ( palette ) + { + for ( i = 0; i < 256; i++ ) + { + rp[i*4+0] = palette[i*3+0]; + rp[i*4+1] = palette[i*3+1]; + rp[i*4+2] = palette[i*3+2]; + rp[i*4+3] = 0xff; + } + } + else + { + for ( i = 0; i < 256; i++ ) + { + rp[i*4+0] = LittleLong(d_8to24table[i]) & 0xff; + rp[i*4+1] = ( LittleLong(d_8to24table[i]) >> 8 ) & 0xff; + rp[i*4+2] = ( LittleLong(d_8to24table[i]) >> 16 ) & 0xff; + rp[i*4+3] = 0xff; + } + } + GL_SetTexturePalette( r_rawpalette ); + + qglClearColor (0,0,0,0); + qglClear (GL_COLOR_BUFFER_BIT); + qglClearColor (1,0, 0.5 , 0.5); +} + +/* +** R_DrawBeam +*/ +void R_DrawBeam( entity_t *e ) +{ +#define NUM_BEAM_SEGS 6 + + int i; + float r, g, b; + + vec3_t perpvec; + vec3_t direction, normalized_direction; + vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; + vec3_t oldorigin, origin; + + oldorigin[0] = e->oldorigin[0]; + oldorigin[1] = e->oldorigin[1]; + oldorigin[2] = e->oldorigin[2]; + + origin[0] = e->origin[0]; + origin[1] = e->origin[1]; + origin[2] = e->origin[2]; + + normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; + normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; + normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; + + if ( VectorNormalize( normalized_direction ) == 0 ) + return; + + PerpendicularVector( perpvec, normalized_direction ); + VectorScale( perpvec, e->frame / 2, perpvec ); + + for ( i = 0; i < 6; i++ ) + { + RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); + VectorAdd( start_points[i], origin, start_points[i] ); + VectorAdd( start_points[i], direction, end_points[i] ); + } + + qglDisable( GL_TEXTURE_2D ); + qglEnable( GL_BLEND ); + qglDepthMask( GL_FALSE ); + + r = ( LittleLong(d_8to24table[e->skinnum & 0xFF]) ) & 0xFF; + g = ( LittleLong(d_8to24table[e->skinnum & 0xFF]) >> 8 ) & 0xFF; + b = ( LittleLong(d_8to24table[e->skinnum & 0xFF]) >> 16 ) & 0xFF; + + r *= 1/255.0F; + g *= 1/255.0F; + b *= 1/255.0F; + + qglColor4f( r, g, b, e->alpha ); + + qglBegin( GL_TRIANGLE_STRIP ); + for ( i = 0; i < NUM_BEAM_SEGS; i++ ) + { + qglVertex3fv( start_points[i] ); + qglVertex3fv( end_points[i] ); + qglVertex3fv( start_points[(i+1)%NUM_BEAM_SEGS] ); + qglVertex3fv( end_points[(i+1)%NUM_BEAM_SEGS] ); + } + qglEnd(); + + qglEnable( GL_TEXTURE_2D ); + qglDisable( GL_BLEND ); + qglDepthMask( GL_TRUE ); +} + +//=================================================================== + + +void R_BeginRegistration (char *map); +struct model_s *R_RegisterModel (char *name); +struct image_s *R_RegisterSkin (char *name); +void R_SetSky (char *name, float rotate, vec3_t axis); +void R_EndRegistration (void); + +void R_RenderFrame (refdef_t *fd); + +struct image_s *Draw_FindPic (char *name); + +void Draw_Pic (int x, int y, char *name); +void Draw_Char (int x, int y, int c); +void Draw_TileClear (int x, int y, int w, int h, char *name); +void Draw_Fill (int x, int y, int w, int h, int c); +void Draw_FadeScreen (void); + +/* +@@@@@@@@@@@@@@@@@@@@@ +GetRefAPI + +@@@@@@@@@@@@@@@@@@@@@ +*/ +refexport_t GetRefAPI (refimport_t rimp ) +{ + refexport_t re; + + ri = rimp; + + re.api_version = API_VERSION; + + re.BeginRegistration = R_BeginRegistration; + re.RegisterModel = R_RegisterModel; + re.RegisterSkin = R_RegisterSkin; + re.RegisterPic = Draw_FindPic; + re.SetSky = R_SetSky; + re.EndRegistration = R_EndRegistration; + + re.RenderFrame = R_RenderFrame; + + re.DrawGetPicSize = Draw_GetPicSize; + re.DrawPic = Draw_Pic; + re.DrawStretchPic = Draw_StretchPic; + re.DrawChar = Draw_Char; + re.DrawTileClear = Draw_TileClear; + re.DrawFill = Draw_Fill; + re.DrawFadeScreen= Draw_FadeScreen; + + re.DrawStretchRaw = Draw_StretchRaw; + + re.Init = R_Init; + re.Shutdown = R_Shutdown; + + re.CinematicSetPalette = R_SetPalette; + re.BeginFrame = R_BeginFrame; + re.EndFrame = GLimp_EndFrame; + + re.AppActivate = GLimp_AppActivate; + + Swap_Init (); + + return re; +} + + +#ifndef REF_HARD_LINKED +// this is only here so the functions in q_shared.c and q_shwin.c can link +void Sys_Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + ri.Sys_Error (ERR_FATAL, "%s", text); +} + +void Com_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, fmt); + vsprintf (text, fmt, argptr); + va_end (argptr); + + ri.Con_Printf (PRINT_ALL, "%s", text); +} + +#endif diff --git a/src/refresh/opengl/gl_rmisc.c b/src/refresh/opengl/gl_rmisc.c new file mode 100644 index 00000000..a6f461ce --- /dev/null +++ b/src/refresh/opengl/gl_rmisc.c @@ -0,0 +1,246 @@ +/* +Copyright (C) 1997-2001 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_misc.c + +#include "gl_local.h" + +/* +================== +R_InitParticleTexture +================== +*/ +byte dottexture[8][8] = +{ + {0,0,0,0,0,0,0,0}, + {0,0,1,1,0,0,0,0}, + {0,1,1,1,1,0,0,0}, + {0,1,1,1,1,0,0,0}, + {0,0,1,1,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}, +}; + +void R_InitParticleTexture (void) +{ + int x,y; + byte data[8][8][4]; + + // + // particle texture + // + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + data[y][x][0] = 255; + data[y][x][1] = 255; + data[y][x][2] = 255; + data[y][x][3] = dottexture[x][y]*255; + } + } + r_particletexture = GL_LoadPic ("***particle***", (byte *)data, 8, 8, it_sprite, 32); + + // + // also use this for bad textures, but without alpha + // + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + data[y][x][0] = dottexture[x&3][y&3]*255; + data[y][x][1] = 0; // dottexture[x&3][y&3]*255; + data[y][x][2] = 0; //dottexture[x&3][y&3]*255; + data[y][x][3] = 255; + } + } + r_notexture = GL_LoadPic ("***r_notexture***", (byte *)data, 8, 8, it_wall, 32); +} + + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + +/* +================== +GL_ScreenShot_f +================== +*/ +void GL_ScreenShot_f (void) +{ + byte *buffer; + char picname[80]; + char checkname[MAX_OSPATH]; + int i, c, temp; + FILE *f; + + // create the scrnshots directory if it doesn't exist + Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir()); + Sys_Mkdir (checkname); + +// +// find a file name to save it to +// + strcpy(picname,"quake00.tga"); + + for (i=0 ; i<=99 ; i++) + { + picname[5] = i/10 + '0'; + picname[6] = i%10 + '0'; + Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname); + f = fopen (checkname, "rb"); + if (!f) + break; // file doesn't exist + fclose (f); + } + if (i==100) + { + ri.Con_Printf (PRINT_ALL, "SCR_ScreenShot_f: Couldn't create a file\n"); + return; + } + + + buffer = malloc(vid.width*vid.height*3 + 18); + memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = vid.width&255; + buffer[13] = vid.width>>8; + buffer[14] = vid.height&255; + buffer[15] = vid.height>>8; + buffer[16] = 24; // pixel size + + qglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); + + // swap rgb to bgr + c = 18+vid.width*vid.height*3; + for (i=18 ; istring ); + GL_TextureAlphaMode( gl_texturealphamode->string ); + GL_TextureSolidMode( gl_texturesolidmode->string ); + + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + GL_TexEnv( GL_REPLACE ); + + if ( qglPointParameterfEXT ) + { + float attenuations[3]; + + attenuations[0] = gl_particle_att_a->value; + attenuations[1] = gl_particle_att_b->value; + attenuations[2] = gl_particle_att_c->value; + + qglEnable( GL_POINT_SMOOTH ); + qglPointParameterfEXT( GL_POINT_SIZE_MIN_EXT, gl_particle_min_size->value ); + qglPointParameterfEXT( GL_POINT_SIZE_MAX_EXT, gl_particle_max_size->value ); + qglPointParameterfvEXT( GL_DISTANCE_ATTENUATION_EXT, attenuations ); + } + + if ( qglColorTableEXT && gl_ext_palettedtexture->value ) + { + qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); + + GL_SetTexturePalette( d_8to24table ); + } + + GL_UpdateSwapInterval(); +} + +void GL_UpdateSwapInterval( void ) +{ + if ( gl_swapinterval->modified ) + { + gl_swapinterval->modified = false; + + if ( !gl_state.stereo_enabled ) + { +#ifdef _WIN32 + if ( qwglSwapIntervalEXT ) + qwglSwapIntervalEXT( gl_swapinterval->value ); +#endif + } + } +} diff --git a/src/refresh/opengl/gl_rsurf.c b/src/refresh/opengl/gl_rsurf.c new file mode 100644 index 00000000..7f001615 --- /dev/null +++ b/src/refresh/opengl/gl_rsurf.c @@ -0,0 +1,1670 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// GL_RSURF.C: surface-related refresh code +#include + +#include "gl_local.h" + +static vec3_t modelorg; // relative to viewpoint + +msurface_t *r_alpha_surfaces; + +#define DYNAMIC_LIGHT_WIDTH 128 +#define DYNAMIC_LIGHT_HEIGHT 128 + +#define LIGHTMAP_BYTES 4 + +#define BLOCK_WIDTH 128 +#define BLOCK_HEIGHT 128 + +#define MAX_LIGHTMAPS 128 + +int c_visible_lightmaps; +int c_visible_textures; + +#define GL_LIGHTMAP_FORMAT GL_RGBA + +typedef struct +{ + int internal_format; + int current_lightmap_texture; + + msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; + + int allocated[BLOCK_WIDTH]; + + // the lightmap texture data needs to be kept in + // main memory so texsubimage can update properly + byte lightmap_buffer[4*BLOCK_WIDTH*BLOCK_HEIGHT]; +} gllightmapstate_t; + +static gllightmapstate_t gl_lms; + + +static void LM_InitBlock( void ); +static void LM_UploadBlock( qboolean dynamic ); +static qboolean LM_AllocBlock (int w, int h, int *x, int *y); + +extern void R_SetCacheState( msurface_t *surf ); +extern void R_BuildLightMap (msurface_t *surf, byte *dest, int stride); + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + +/* +=============== +R_TextureAnimation + +Returns the proper texture for a given time and base texture +=============== +*/ +image_t *R_TextureAnimation (mtexinfo_t *tex) +{ + int c; + + if (!tex->next) + return tex->image; + + c = currententity->frame % tex->numframes; + while (c) + { + tex = tex->next; + c--; + } + + return tex->image; +} + +#if 0 +/* +================= +WaterWarpPolyVerts + +Mangles the x and y coordinates in a copy of the poly +so that any drawing routine can be water warped +================= +*/ +glpoly_t *WaterWarpPolyVerts (glpoly_t *p) +{ + int i; + float *v, *nv; + static byte buffer[1024]; + glpoly_t *out; + + out = (glpoly_t *)buffer; + + out->numverts = p->numverts; + v = p->verts[0]; + nv = out->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE, nv+=VERTEXSIZE) + { + nv[0] = v[0] + 4*sin(v[1]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time); + nv[1] = v[1] + 4*sin(v[0]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time); + + nv[2] = v[2]; + nv[3] = v[3]; + nv[4] = v[4]; + nv[5] = v[5]; + nv[6] = v[6]; + } + + return out; +} + +/* +================ +DrawGLWaterPoly + +Warp the vertex coordinates +================ +*/ +void DrawGLWaterPoly (glpoly_t *p) +{ + int i; + float *v; + + p = WaterWarpPolyVerts (p); + qglBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[3], v[4]); + qglVertex3fv (v); + } + qglEnd (); +} +void DrawGLWaterPolyLightmap (glpoly_t *p) +{ + int i; + float *v; + + p = WaterWarpPolyVerts (p); + qglBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); +} +#endif + +/* +================ +DrawGLPoly +================ +*/ +void DrawGLPoly (glpoly_t *p) +{ + int i; + float *v; + + qglBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[3], v[4]); + qglVertex3fv (v); + } + qglEnd (); +} + +//============ +//PGM +/* +================ +DrawGLFlowingPoly -- version of DrawGLPoly that handles scrolling texture +================ +*/ +void DrawGLFlowingPoly (msurface_t *fa) +{ + int i; + float *v; + glpoly_t *p; + float scroll; + + p = fa->polys; + + scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) ); + if(scroll == 0.0) + scroll = -64.0; + + qglBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f ((v[3] + scroll), v[4]); + qglVertex3fv (v); + } + qglEnd (); +} +//PGM +//============ + +/* +** R_DrawTriangleOutlines +*/ +void R_DrawTriangleOutlines (void) +{ + int i, j; + glpoly_t *p; + + if (!gl_showtris->value) + return; + + qglDisable (GL_TEXTURE_2D); + qglDisable (GL_DEPTH_TEST); + qglColor4f (1,1,1,1); + + for (i=0 ; ilightmapchain ) + { + p = surf->polys; + for ( ; p ; p=p->chain) + { + for (j=2 ; jnumverts ; j++ ) + { + qglBegin (GL_LINE_STRIP); + qglVertex3fv (p->verts[0]); + qglVertex3fv (p->verts[j-1]); + qglVertex3fv (p->verts[j]); + qglVertex3fv (p->verts[0]); + qglEnd (); + } + } + } + } + + qglEnable (GL_DEPTH_TEST); + qglEnable (GL_TEXTURE_2D); +} + +/* +** DrawGLPolyChain +*/ +void DrawGLPolyChain( glpoly_t *p, float soffset, float toffset ) +{ + if ( soffset == 0 && toffset == 0 ) + { + for ( ; p != 0; p = p->chain ) + { + float *v; + int j; + + /* There is a crash somewheres around old line 282. + * I am trying to find a workaround. + * -- Phil Brown + */ + v = p->verts[0]; + if(v==NULL){ + fprintf(stderr,"BUGFIX: DrawGLPolyChain: v==NULL\n"); + return; + } + qglBegin (GL_POLYGON); + for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[5], v[6] ); + qglVertex3fv (v); + } + qglEnd (); + } + } + else + { + for ( ; p != 0; p = p->chain ) + { + float *v; + int j; + + qglBegin (GL_POLYGON); + v = p->verts[0]; + for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[5] - soffset, v[6] - toffset ); + qglVertex3fv (v); + } + qglEnd (); + } + } +} + +/* +** R_BlendLightMaps +** +** This routine takes all the given light mapped surfaces in the world and +** blends them into the framebuffer. +*/ +void R_BlendLightmaps (void) +{ + int i; + msurface_t *surf, *newdrawsurf = 0; + + // don't bother if we're set to fullbright + if (r_fullbright->value) + return; + if (!r_worldmodel->lightdata) + return; + + // don't bother writing Z + qglDepthMask( 0 ); + + /* + ** set the appropriate blending mode unless we're only looking at the + ** lightmaps. + */ + if (!gl_lightmap->value) + { + qglEnable (GL_BLEND); + + if ( gl_saturatelighting->value ) + { + qglBlendFunc( GL_ONE, GL_ONE ); + } + else + { + if ( gl_monolightmap->string[0] != '0' ) + { + switch ( toupper( gl_monolightmap->string[0] ) ) + { + case 'I': + qglBlendFunc (GL_ZERO, GL_SRC_COLOR ); + break; + case 'L': + qglBlendFunc (GL_ZERO, GL_SRC_COLOR ); + break; + case 'A': + default: + qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + break; + } + } + else + { + qglBlendFunc (GL_ZERO, GL_SRC_COLOR ); + } + } + } + + if ( currentmodel == r_worldmodel ) + c_visible_lightmaps = 0; + + /* + ** render static lightmaps first + */ + for ( i = 1; i < MAX_LIGHTMAPS; i++ ) + { + if ( gl_lms.lightmap_surfaces[i] ) + { + if (currentmodel == r_worldmodel) + c_visible_lightmaps++; + GL_Bind( gl_state.lightmap_textures + i); + + for ( surf = gl_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain ) + { + if ( surf->polys ) + DrawGLPolyChain( surf->polys, 0, 0 ); + } + } + } + + /* + ** render dynamic lightmaps + */ + if ( gl_dynamic->value ) + { + LM_InitBlock(); + + GL_Bind( gl_state.lightmap_textures+0 ); + + if (currentmodel == r_worldmodel) + c_visible_lightmaps++; + + newdrawsurf = gl_lms.lightmap_surfaces[0]; + + for ( surf = gl_lms.lightmap_surfaces[0]; surf != 0; surf = surf->lightmapchain ) + { + int smax, tmax; + byte *base; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + if ( LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) ) + { + base = gl_lms.lightmap_buffer; + base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES; + + R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES); + } + else + { + msurface_t *drawsurf; + + // upload what we have so far + LM_UploadBlock( true ); + + // draw all surfaces that use this lightmap + for ( drawsurf = newdrawsurf; drawsurf != surf; drawsurf = drawsurf->lightmapchain ) + { + if ( drawsurf->polys ) + DrawGLPolyChain( drawsurf->polys, + ( drawsurf->light_s - drawsurf->dlight_s ) * ( 1.0 / 128.0 ), + ( drawsurf->light_t - drawsurf->dlight_t ) * ( 1.0 / 128.0 ) ); + } + + newdrawsurf = drawsurf; + + // clear the block + LM_InitBlock(); + + // try uploading the block now + if ( !LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) ) + { + ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed (dynamic)\n", smax, tmax ); + } + + base = gl_lms.lightmap_buffer; + base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES; + + R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES); + } + } + + /* + ** draw remainder of dynamic lightmaps that haven't been uploaded yet + */ + if ( newdrawsurf ) + LM_UploadBlock( true ); + + for ( surf = newdrawsurf; surf != 0; surf = surf->lightmapchain ) + { + if ( surf->polys ) + DrawGLPolyChain( surf->polys, ( surf->light_s - surf->dlight_s ) * ( 1.0 / 128.0 ), ( surf->light_t - surf->dlight_t ) * ( 1.0 / 128.0 ) ); + } + } + + /* + ** restore state + */ + qglDisable (GL_BLEND); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDepthMask( 1 ); +} + +/* +================ +R_RenderBrushPoly +================ +*/ +void R_RenderBrushPoly (msurface_t *fa) +{ + int maps; + image_t *image; + qboolean is_dynamic = false; + + c_brush_polys++; + + image = R_TextureAnimation (fa->texinfo); + + if (fa->flags & SURF_DRAWTURB) + { + GL_Bind( image->texnum ); + + // warp texture, no lightmaps + GL_TexEnv( GL_MODULATE ); + qglColor4f( gl_state.inverse_intensity, + gl_state.inverse_intensity, + gl_state.inverse_intensity, + 1.0F ); + EmitWaterPolys (fa); + GL_TexEnv( GL_REPLACE ); + + return; + } + else + { + GL_Bind( image->texnum ); + + GL_TexEnv( GL_REPLACE ); + } + +//====== +//PGM + if(fa->texinfo->flags & SURF_FLOWING) + DrawGLFlowingPoly (fa); + else + DrawGLPoly (fa->polys); +//PGM +//====== + + /* + ** check for lightmap modification + */ + for ( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ ) + { + if ( r_newrefdef.lightstyles[fa->styles[maps]].white != fa->cached_light[maps] ) + goto dynamic; + } + + // dynamic this frame or dynamic previously + if ( ( fa->dlightframe == r_framecount ) ) + { +dynamic: + if ( gl_dynamic->value ) + { + if (!( fa->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) ) + { + is_dynamic = true; + } + } + } + + if ( is_dynamic ) + { + if ( ( fa->styles[maps] >= 32 || fa->styles[maps] == 0 ) && ( fa->dlightframe != r_framecount ) ) + { + unsigned temp[34*34]; + int smax, tmax; + + smax = (fa->extents[0]>>4)+1; + tmax = (fa->extents[1]>>4)+1; + + R_BuildLightMap( fa, (void *)temp, smax*4 ); + R_SetCacheState( fa ); + + GL_Bind( gl_state.lightmap_textures + fa->lightmaptexturenum ); + + qglTexSubImage2D( GL_TEXTURE_2D, 0, + fa->light_s, fa->light_t, + smax, tmax, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, temp ); + + fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } + else + { + fa->lightmapchain = gl_lms.lightmap_surfaces[0]; + gl_lms.lightmap_surfaces[0] = fa; + } + } + else + { + fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } +} + + +/* +================ +R_DrawAlphaSurfaces + +Draw water surfaces and windows. +The BSP tree is waled front to back, so unwinding the chain +of alpha_surfaces will draw back to front, giving proper ordering. +================ +*/ +void R_DrawAlphaSurfaces (void) +{ + msurface_t *s; + float intens; + + // + // go back to the world matrix + // + qglLoadMatrixf (r_world_matrix); + + qglEnable (GL_BLEND); + GL_TexEnv( GL_MODULATE ); + + // the textures are prescaled up for a better lighting range, + // so scale it back down + intens = gl_state.inverse_intensity; + + for (s=r_alpha_surfaces ; s ; s=s->texturechain) + { + GL_Bind(s->texinfo->image->texnum); + c_brush_polys++; + if (s->texinfo->flags & SURF_TRANS33) + qglColor4f (intens,intens,intens,0.33); + else if (s->texinfo->flags & SURF_TRANS66) + qglColor4f (intens,intens,intens,0.66); + else + qglColor4f (intens,intens,intens,1); + if (s->flags & SURF_DRAWTURB) + EmitWaterPolys (s); + else if(s->texinfo->flags & SURF_FLOWING) // PGM 9/16/98 + DrawGLFlowingPoly (s); // PGM + else + DrawGLPoly (s->polys); + } + + GL_TexEnv( GL_REPLACE ); + qglColor4f (1,1,1,1); + qglDisable (GL_BLEND); + + r_alpha_surfaces = NULL; +} + +/* +================ +DrawTextureChains +================ +*/ +void DrawTextureChains (void) +{ + int i; + msurface_t *s; + image_t *image; + + c_visible_textures = 0; + +// GL_TexEnv( GL_REPLACE ); + + if ( !qglSelectTextureSGIS && !qglActiveTextureARB ) + { + for ( i = 0, image=gltextures ; iregistration_sequence) + continue; + s = image->texturechain; + if (!s) + continue; + c_visible_textures++; + + for ( ; s ; s=s->texturechain) + R_RenderBrushPoly (s); + + image->texturechain = NULL; + } + } + else + { + for ( i = 0, image=gltextures ; iregistration_sequence) + continue; + if (!image->texturechain) + continue; + c_visible_textures++; + + for ( s = image->texturechain; s ; s=s->texturechain) + { + if ( !( s->flags & SURF_DRAWTURB ) ) + R_RenderBrushPoly (s); + } + } + + GL_EnableMultitexture( false ); + for ( i = 0, image=gltextures ; iregistration_sequence) + continue; + s = image->texturechain; + if (!s) + continue; + + for ( ; s ; s=s->texturechain) + { + if ( s->flags & SURF_DRAWTURB ) + R_RenderBrushPoly (s); + } + + image->texturechain = NULL; + } +// GL_EnableMultitexture( true ); + } + + GL_TexEnv( GL_REPLACE ); +} + + +static void GL_RenderLightmappedPoly( msurface_t *surf ) +{ + int i, nv = surf->polys->numverts; + int map; + float *v; + image_t *image = R_TextureAnimation( surf->texinfo ); + qboolean is_dynamic = false; + unsigned lmtex = surf->lightmaptexturenum; + glpoly_t *p; + + for ( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ ) + { + if ( r_newrefdef.lightstyles[surf->styles[map]].white != surf->cached_light[map] ) + goto dynamic; + } + + // dynamic this frame or dynamic previously + if ( ( surf->dlightframe == r_framecount ) ) + { +dynamic: + if ( gl_dynamic->value ) + { + if ( !(surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) ) + { + is_dynamic = true; + } + } + } + + if ( is_dynamic ) + { + unsigned temp[128*128]; + int smax, tmax; + + if ( ( surf->styles[map] >= 32 || surf->styles[map] == 0 ) && ( surf->dlightframe != r_framecount ) ) + { + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + R_BuildLightMap( surf, (void *)temp, smax*4 ); + R_SetCacheState( surf ); + + GL_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + surf->lightmaptexturenum ); + + lmtex = surf->lightmaptexturenum; + + qglTexSubImage2D( GL_TEXTURE_2D, 0, + surf->light_s, surf->light_t, + smax, tmax, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, temp ); + + } + else + { + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + R_BuildLightMap( surf, (void *)temp, smax*4 ); + + GL_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + 0 ); + + lmtex = 0; + + qglTexSubImage2D( GL_TEXTURE_2D, 0, + surf->light_s, surf->light_t, + smax, tmax, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, temp ); + + } + + c_brush_polys++; + + GL_MBind( QGL_TEXTURE0, image->texnum ); + GL_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + lmtex ); + +//========== +//PGM + if (surf->texinfo->flags & SURF_FLOWING) + { + float scroll; + + scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) ); + if(scroll == 0.0) + scroll = -64.0; + + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( QGL_TEXTURE0, (v[3]+scroll), v[4]); + qglMTexCoord2fSGIS( QGL_TEXTURE1, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } + } + else + { + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( QGL_TEXTURE0, v[3], v[4]); + qglMTexCoord2fSGIS( QGL_TEXTURE1, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } + } +//PGM +//========== + } + else + { + c_brush_polys++; + + GL_MBind( QGL_TEXTURE0, image->texnum ); + GL_MBind( QGL_TEXTURE1, gl_state.lightmap_textures + lmtex ); + +//========== +//PGM + if (surf->texinfo->flags & SURF_FLOWING) + { + float scroll; + + scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) ); + if(scroll == 0.0) + scroll = -64.0; + + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( QGL_TEXTURE0, (v[3]+scroll), v[4]); + qglMTexCoord2fSGIS( QGL_TEXTURE1, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } + } + else + { +//PGM +//========== + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( QGL_TEXTURE0, v[3], v[4]); + qglMTexCoord2fSGIS( QGL_TEXTURE1, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } +//========== +//PGM + } +//PGM +//========== + } +} + +/* +================= +R_DrawInlineBModel +================= +*/ +void R_DrawInlineBModel (void) +{ + int i, k; + cplane_t *pplane; + float dot; + msurface_t *psurf; + dlight_t *lt; + + // calculate dynamic lighting for bmodel + if ( !gl_flashblend->value ) + { + lt = r_newrefdef.dlights; + for (k=0 ; knodes + currentmodel->firstnode); + } + } + + psurf = ¤tmodel->surfaces[currentmodel->firstmodelsurface]; + + if ( currententity->flags & RF_TRANSLUCENT ) + { + qglEnable (GL_BLEND); + qglColor4f (1,1,1,0.25); + GL_TexEnv( GL_MODULATE ); + } + + // + // draw texture + // + for (i=0 ; inummodelsurfaces ; i++, psurf++) + { + // find which side of the node we are on + pplane = psurf->plane; + + 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))) + { + if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66) ) + { // add to the translucent chain + psurf->texturechain = r_alpha_surfaces; + r_alpha_surfaces = psurf; + } + else if ( qglMTexCoord2fSGIS && !( psurf->flags & SURF_DRAWTURB ) ) + { + GL_RenderLightmappedPoly( psurf ); + } + else + { + GL_EnableMultitexture( false ); + R_RenderBrushPoly( psurf ); + GL_EnableMultitexture( true ); + } + } + } + + if ( !(currententity->flags & RF_TRANSLUCENT) ) + { + if ( !qglMTexCoord2fSGIS ) + R_BlendLightmaps (); + } + else + { + qglDisable (GL_BLEND); + qglColor4f (1,1,1,1); + GL_TexEnv( GL_REPLACE ); + } +} + +/* +================= +R_DrawBrushModel +================= +*/ +void R_DrawBrushModel (entity_t *e) +{ + vec3_t mins, maxs; + int i; + qboolean rotated; + + if (currentmodel->nummodelsurfaces == 0) + return; + + currententity = e; + gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; + + if (e->angles[0] || e->angles[1] || e->angles[2]) + { + rotated = true; + for (i=0 ; i<3 ; i++) + { + mins[i] = e->origin[i] - currentmodel->radius; + maxs[i] = e->origin[i] + currentmodel->radius; + } + } + else + { + rotated = false; + VectorAdd (e->origin, currentmodel->mins, mins); + VectorAdd (e->origin, currentmodel->maxs, maxs); + } + + if (R_CullBox (mins, maxs)) + return; + + qglColor3f (1,1,1); + memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces)); + + VectorSubtract (r_newrefdef.vieworg, e->origin, modelorg); + if (rotated) + { + vec3_t temp; + vec3_t forward, right, up; + + VectorCopy (modelorg, temp); + AngleVectors (e->angles, forward, right, up); + modelorg[0] = DotProduct (temp, forward); + modelorg[1] = -DotProduct (temp, right); + modelorg[2] = DotProduct (temp, up); + } + + qglPushMatrix (); + e->angles[0] = -e->angles[0]; // stupid quake bug + e->angles[2] = -e->angles[2]; // stupid quake bug + R_RotateForEntity (e); + e->angles[0] = -e->angles[0]; // stupid quake bug + e->angles[2] = -e->angles[2]; // stupid quake bug + + GL_EnableMultitexture( true ); + GL_SelectTexture( QGL_TEXTURE0); + GL_TexEnv( GL_REPLACE ); + GL_SelectTexture( QGL_TEXTURE1); + GL_TexEnv( GL_MODULATE ); + + R_DrawInlineBModel (); + GL_EnableMultitexture( false ); + + qglPopMatrix (); +} + +/* +============================================================= + + WORLD MODEL + +============================================================= +*/ + +/* +================ +R_RecursiveWorldNode +================ +*/ +void R_RecursiveWorldNode (mnode_t *node) +{ + int c, side, sidebit; + cplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + float dot; + image_t *image; + + if (node->contents == CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + if (R_CullBox (node->minmaxs, node->minmaxs+3)) + return; + +// if a leaf node, draw stuff + if (node->contents != -1) + { + pleaf = (mleaf_t *)node; + + // check for door connected areas + if (r_newrefdef.areabits) + { + if (! (r_newrefdef.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); + } + + return; + } + +// 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; + sidebit = 0; + } + else + { + side = 1; + sidebit = SURF_PLANEBACK; + } + +// recurse down the children, front side first + R_RecursiveWorldNode (node->children[side]); + + // draw stuff + for ( c = node->numsurfaces, surf = r_worldmodel->surfaces + node->firstsurface; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; // wrong side + + if (surf->texinfo->flags & SURF_SKY) + { // just adds to visible sky bounds + R_AddSkySurface (surf); + } + else if (surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) + { // add to the translucent chain + surf->texturechain = r_alpha_surfaces; + r_alpha_surfaces = surf; + } + else + { + if ( qglMTexCoord2fSGIS && !( surf->flags & SURF_DRAWTURB ) ) + { + GL_RenderLightmappedPoly( surf ); + } + else + { + // the polygon is visible, so add it to the texture + // sorted chain + // FIXME: this is a hack for animation + image = R_TextureAnimation (surf->texinfo); + surf->texturechain = image->texturechain; + image->texturechain = surf; + } + } + } + + // recurse down the back side + R_RecursiveWorldNode (node->children[!side]); +/* + for ( ; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; // wrong side + + if (surf->texinfo->flags & SURF_SKY) + { // just adds to visible sky bounds + R_AddSkySurface (surf); + } + else if (surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) + { // add to the translucent chain +// surf->texturechain = alpha_surfaces; +// alpha_surfaces = surf; + } + else + { + if ( qglMTexCoord2fSGIS && !( surf->flags & SURF_DRAWTURB ) ) + { + GL_RenderLightmappedPoly( surf ); + } + else + { + // the polygon is visible, so add it to the texture + // sorted chain + // FIXME: this is a hack for animation + image = R_TextureAnimation (surf->texinfo); + surf->texturechain = image->texturechain; + image->texturechain = surf; + } + } + } +*/ +} + + +/* +============= +R_DrawWorld +============= +*/ +void R_DrawWorld (void) +{ + entity_t ent; + + if (!r_drawworld->value) + return; + + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + return; + + currentmodel = r_worldmodel; + + VectorCopy (r_newrefdef.vieworg, modelorg); + + // auto cycle the world frame for texture animation + memset (&ent, 0, sizeof(ent)); + ent.frame = (int)(r_newrefdef.time*2); + currententity = &ent; + + gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; + + qglColor3f (1,1,1); + memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces)); + R_ClearSkyBox (); + + if ( qglMTexCoord2fSGIS ) + { + GL_EnableMultitexture( true ); + + GL_SelectTexture( QGL_TEXTURE0); + GL_TexEnv( GL_REPLACE ); + GL_SelectTexture( QGL_TEXTURE1); + + if ( gl_lightmap->value ) + GL_TexEnv( GL_REPLACE ); + else + GL_TexEnv( GL_MODULATE ); + + R_RecursiveWorldNode (r_worldmodel->nodes); + + GL_EnableMultitexture( false ); + } + else + { + R_RecursiveWorldNode (r_worldmodel->nodes); + } + + /* + ** theoretically nothing should happen in the next two functions + ** if multitexture is enabled + */ + DrawTextureChains (); + R_BlendLightmaps (); + + R_DrawSkyBox (); + + R_DrawTriangleOutlines (); +} + + +/* +=============== +R_MarkLeaves + +Mark the leaves and nodes that are in the PVS for the current +cluster +=============== +*/ +void R_MarkLeaves (void) +{ + byte *vis; + byte fatvis[MAX_MAP_LEAFS/8]; + mnode_t *node; + int i, c; + mleaf_t *leaf; + int cluster; + + if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2 && !r_novis->value && r_viewcluster != -1) + return; + + // development aid to let you run around and see exactly where + // the pvs ends + if (gl_lockpvs->value) + return; + + r_visframecount++; + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + + if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis) + { + // mark everything + for (i=0 ; inumleafs ; i++) + r_worldmodel->leafs[i].visframe = r_visframecount; + for (i=0 ; inumnodes ; i++) + r_worldmodel->nodes[i].visframe = r_visframecount; + return; + } + + vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel); + // may have to combine two clusters because of solid water boundaries + if (r_viewcluster2 != r_viewcluster) + { + memcpy (fatvis, vis, (r_worldmodel->numleafs+7)/8); + vis = Mod_ClusterPVS (r_viewcluster2, r_worldmodel); + c = (r_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); + } + } + +#if 0 + for (i=0 ; ivis->numclusters ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +#endif +} + + + +/* +============================================================================= + + LIGHTMAP ALLOCATION + +============================================================================= +*/ + +static void LM_InitBlock( void ) +{ + memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated ) ); +} + +static void LM_UploadBlock( qboolean dynamic ) +{ + int texture; + int height = 0; + + if ( dynamic ) + { + texture = 0; + } + else + { + texture = gl_lms.current_lightmap_texture; + } + + GL_Bind( gl_state.lightmap_textures + texture ); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if ( dynamic ) + { + int i; + + for ( i = 0; i < BLOCK_WIDTH; i++ ) + { + if ( gl_lms.allocated[i] > height ) + height = gl_lms.allocated[i]; + } + + qglTexSubImage2D( GL_TEXTURE_2D, + 0, + 0, 0, + BLOCK_WIDTH, height, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, + gl_lms.lightmap_buffer ); + } + else + { + qglTexImage2D( GL_TEXTURE_2D, + 0, + gl_lms.internal_format, + BLOCK_WIDTH, BLOCK_HEIGHT, + 0, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, + gl_lms.lightmap_buffer ); + if ( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS ) + ri.Sys_Error( ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n" ); + } +} + +// returns a texture number and the position inside it +static qboolean LM_AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + + best = BLOCK_HEIGHT; + + for (i=0 ; i= best) + break; + if (gl_lms.allocated[i+j] > best2) + best2 = gl_lms.allocated[i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + return false; + + for (i=0 ; iedges; + lnumverts = fa->numedges; + vertpage = 0; + + VectorClear (total); + // + // draw texture + // + poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); + poly->next = fa->polys; + poly->flags = fa->flags; + fa->polys = poly; + poly->numverts = lnumverts; + + 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; + } + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s /= fa->texinfo->image->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t /= fa->texinfo->image->height; + + VectorAdd (total, vec, total); + VectorCopy (vec, poly->verts[i]); + poly->verts[i][3] = s; + poly->verts[i][4] = t; + + // + // lightmap texture coordinates + // + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s -= fa->texturemins[0]; + s += fa->light_s*16; + s += 8; + s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t -= fa->texturemins[1]; + t += fa->light_t*16; + t += 8; + t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height; + + poly->verts[i][5] = s; + poly->verts[i][6] = t; + } + + poly->numverts = lnumverts; + +} + +/* +======================== +GL_CreateSurfaceLightmap +======================== +*/ +void GL_CreateSurfaceLightmap (msurface_t *surf) +{ + int smax, tmax; + byte *base; + + if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) + return; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + { + LM_UploadBlock( false ); + LM_InitBlock(); + if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + { + ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed\n", smax, tmax ); + } + } + + surf->lightmaptexturenum = gl_lms.current_lightmap_texture; + + base = gl_lms.lightmap_buffer; + base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES; + + R_SetCacheState( surf ); + R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES); +} + + +/* +================== +GL_BeginBuildingLightmaps + +================== +*/ +void GL_BeginBuildingLightmaps (model_t *m) +{ + static lightstyle_t lightstyles[MAX_LIGHTSTYLES]; + int i; + unsigned dummy[128*128]; + + memset( gl_lms.allocated, 0, sizeof(gl_lms.allocated) ); + + r_framecount = 1; // no dlightcache + + GL_EnableMultitexture( true ); + GL_SelectTexture( QGL_TEXTURE1); + + /* + ** setup the base lightstyles so the lightmaps won't have to be regenerated + ** the first time they're seen + */ + for (i=0 ; istring[0] ) == 'A' ) + { + gl_lms.internal_format = gl_tex_alpha_format; + } + /* + ** try to do hacked colored lighting with a blended texture + */ + else if ( toupper( gl_monolightmap->string[0] ) == 'C' ) + { + gl_lms.internal_format = gl_tex_alpha_format; + } + else if ( toupper( gl_monolightmap->string[0] ) == 'I' ) + { + gl_lms.internal_format = GL_INTENSITY8; + } + else if ( toupper( gl_monolightmap->string[0] ) == 'L' ) + { + gl_lms.internal_format = GL_LUMINANCE8; + } + else + { + gl_lms.internal_format = gl_tex_solid_format; + } + + /* + ** initialize the dynamic lightmap texture + */ + GL_Bind( gl_state.lightmap_textures + 0 ); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexImage2D( GL_TEXTURE_2D, + 0, + gl_lms.internal_format, + BLOCK_WIDTH, BLOCK_HEIGHT, + 0, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, + dummy ); +} + +/* +======================= +GL_EndBuildingLightmaps +======================= +*/ +void GL_EndBuildingLightmaps (void) +{ + LM_UploadBlock( false ); + GL_EnableMultitexture( false ); +} + diff --git a/src/refresh/opengl/gl_warp.c b/src/refresh/opengl/gl_warp.c new file mode 100644 index 00000000..3a35d772 --- /dev/null +++ b/src/refresh/opengl/gl_warp.c @@ -0,0 +1,662 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// gl_warp.c -- sky and water polygons + +#include "gl_local.h" + +extern model_t *loadmodel; + +char skyname[MAX_QPATH]; +float skyrotate; +vec3_t skyaxis; +image_t *sky_images[6]; + +msurface_t *warpface; + +#define SUBDIVIDE_SIZE 64 +//#define SUBDIVIDE_SIZE 1024 + +void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) +{ + int i, j; + float *v; + + mins[0] = mins[1] = mins[2] = 9999; + maxs[0] = maxs[1] = maxs[2] = -9999; + v = verts; + for (i=0 ; i maxs[j]) + maxs[j] = *v; + } +} + +void SubdividePolygon (int numverts, float *verts) +{ + int i, j, k; + vec3_t mins, maxs; + float m; + float *v; + vec3_t front[64], back[64]; + int f, b; + float dist[64]; + float frac; + glpoly_t *poly; + float s, t; + vec3_t total; + float total_s, total_t; + + if (numverts > 60) + ri.Sys_Error (ERR_DROP, "numverts = %i", numverts); + + BoundPoly (numverts, verts, mins, maxs); + + for (i=0 ; i<3 ; i++) + { + m = (mins[i] + maxs[i]) * 0.5; + m = SUBDIVIDE_SIZE * floor (m/SUBDIVIDE_SIZE + 0.5); + if (maxs[i] - m < 8) + continue; + if (m - mins[i] < 8) + continue; + + // cut it + v = verts + i; + for (j=0 ; j= 0) + { + VectorCopy (v, front[f]); + f++; + } + if (dist[j] <= 0) + { + VectorCopy (v, back[b]); + b++; + } + if (dist[j] == 0 || dist[j+1] == 0) + continue; + if ( (dist[j] > 0) != (dist[j+1] > 0) ) + { + // clip point + frac = dist[j] / (dist[j] - dist[j+1]); + for (k=0 ; k<3 ; k++) + front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]); + f++; + b++; + } + } + + SubdividePolygon (f, front[0]); + SubdividePolygon (b, back[0]); + return; + } + + // add a point in the center to help keep warp valid + poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float)); + poly->next = warpface->polys; + warpface->polys = poly; + poly->numverts = numverts+2; + VectorClear (total); + total_s = 0; + total_t = 0; + for (i=0 ; iverts[i+1]); + s = DotProduct (verts, warpface->texinfo->vecs[0]); + t = DotProduct (verts, warpface->texinfo->vecs[1]); + + total_s += s; + total_t += t; + VectorAdd (total, verts, total); + + poly->verts[i+1][3] = s; + poly->verts[i+1][4] = t; + } + + VectorScale (total, (1.0/numverts), poly->verts[0]); + poly->verts[0][3] = total_s/numverts; + poly->verts[0][4] = total_t/numverts; + + // copy first vertex to last + memcpy (poly->verts[i+1], poly->verts[1], sizeof(poly->verts[0])); +} + +/* +================ +GL_SubdivideSurface + +Breaks a polygon up along axial 64 unit +boundaries so that turbulent and sky warps +can be done reasonably. +================ +*/ +void GL_SubdivideSurface (msurface_t *fa) +{ + vec3_t verts[64]; + int numverts; + int i; + int lindex; + float *vec; + + warpface = fa; + + // + // convert edges back to a normal polygon + // + numverts = 0; + for (i=0 ; inumedges ; i++) + { + lindex = loadmodel->surfedges[fa->firstedge + i]; + + if (lindex > 0) + vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; + else + vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; + VectorCopy (vec, verts[numverts]); + numverts++; + } + + SubdividePolygon (numverts, verts[0]); +} + +//========================================================= + + + +// speed up sin calculations - Ed +float r_turbsin[] = +{ + #include "warpsin.h" +}; +#define TURBSCALE (256.0 / (2 * M_PI)) + +/* +============= +EmitWaterPolys + +Does a water warp on the pre-fragmented glpoly_t chain +============= +*/ +void EmitWaterPolys (msurface_t *fa) +{ + glpoly_t *p, *bp; + float *v; + int i; + float s, t, os, ot; + float scroll; + float rdt = r_newrefdef.time; + + if (fa->texinfo->flags & SURF_FLOWING) + scroll = -64 * ( (r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5) ); + else + scroll = 0; + for (bp=fa->polys ; bp ; bp=bp->next) + { + p = bp; + + qglBegin (GL_TRIANGLE_FAN); + for (i=0,v=p->verts[0] ; inumverts ; i++, v+=VERTEXSIZE) + { + os = v[3]; + ot = v[4]; + +#if !id386 + s = os + r_turbsin[(int)((ot*0.125+r_newrefdef.time) * TURBSCALE) & 255]; +#else + s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255]; +#endif + s += scroll; + s *= (1.0/64); + +#if !id386 + t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255]; +#else + t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255]; +#endif + t *= (1.0/64); + + qglTexCoord2f (s, t); + qglVertex3fv (v); + } + qglEnd (); + } +} + + +//=================================================================== + + +vec3_t skyclip[6] = { + {1,1,0}, + {1,-1,0}, + {0,-1,1}, + {0,1,1}, + {1,0,1}, + {-1,0,1} +}; +int c_sky; + +// 1 = s, 2 = t, 3 = 2048 +int st_to_vec[6][3] = +{ + {3,-1,2}, + {-3,1,2}, + + {1,3,2}, + {-1,-3,2}, + + {-2,-1,3}, // 0 degrees yaw, look straight up + {2,-1,-3} // look straight down + +// {-1,2,3}, +// {1,2,-3} +}; + +// s = [0]/[2], t = [1]/[2] +int vec_to_st[6][3] = +{ + {-2,3,1}, + {2,3,-1}, + + {1,3,2}, + {-1,3,-2}, + + {-2,-1,3}, + {-2,1,-3} + +// {-1,2,3}, +// {1,2,-3} +}; + +float skymins[2][6], skymaxs[2][6]; +float sky_min, sky_max; + +void DrawSkyPolygon (int nump, vec3_t vecs) +{ + int i,j; + vec3_t v, av; + float s, t, dv; + int axis; + float *vp; + + c_sky++; +#if 0 +glBegin (GL_POLYGON); +for (i=0 ; i av[1] && av[0] > av[2]) + { + if (v[0] < 0) + axis = 1; + else + axis = 0; + } + else if (av[1] > av[2] && av[1] > av[0]) + { + if (v[1] < 0) + axis = 3; + else + axis = 2; + } + else + { + if (v[2] < 0) + axis = 5; + else + axis = 4; + } + + // project new texture coords + for (i=0 ; i 0) + dv = vecs[j - 1]; + else + dv = -vecs[-j - 1]; + if (dv < 0.001) + continue; // don't divide by zero + j = vec_to_st[axis][0]; + if (j < 0) + s = -vecs[-j -1] / dv; + else + s = vecs[j-1] / dv; + j = vec_to_st[axis][1]; + if (j < 0) + t = -vecs[-j -1] / dv; + else + t = vecs[j-1] / dv; + + if (s < skymins[0][axis]) + skymins[0][axis] = s; + if (t < skymins[1][axis]) + skymins[1][axis] = t; + if (s > skymaxs[0][axis]) + skymaxs[0][axis] = s; + if (t > skymaxs[1][axis]) + skymaxs[1][axis] = t; + } +} + +#define ON_EPSILON 0.1 // point on plane side epsilon +#define MAX_CLIP_VERTS 64 +void ClipSkyPolygon (int nump, vec3_t vecs, int stage) +{ + float *norm; + float *v; + qboolean front, back; + float d, e; + float dists[MAX_CLIP_VERTS]; + int sides[MAX_CLIP_VERTS]; + vec3_t newv[2][MAX_CLIP_VERTS]; + int newc[2]; + int i, j; + + if (nump > MAX_CLIP_VERTS-2) + ri.Sys_Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); + if (stage == 6) + { // fully clipped, so draw it + DrawSkyPolygon (nump, vecs); + return; + } + + front = back = false; + norm = skyclip[stage]; + for (i=0, v = vecs ; i ON_EPSILON) + { + front = true; + sides[i] = SIDE_FRONT; + } + else if (d < -ON_EPSILON) + { + back = true; + sides[i] = SIDE_BACK; + } + else + sides[i] = SIDE_ON; + dists[i] = d; + } + + if (!front || !back) + { // not clipped + ClipSkyPolygon (nump, vecs, stage+1); + return; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + VectorCopy (vecs, (vecs+(i*3)) ); + newc[0] = newc[1] = 0; + + for (i=0, v = vecs ; ipolys ; p ; p=p->next) + { + for (i=0 ; inumverts ; i++) + { + VectorSubtract (p->verts[i], r_origin, verts[i]); + } + ClipSkyPolygon (p->numverts, verts[0], 0); + } +} + + +/* +============== +R_ClearSkyBox +============== +*/ +void R_ClearSkyBox (void) +{ + int i; + + for (i=0 ; i<6 ; i++) + { + skymins[0][i] = skymins[1][i] = 9999; + skymaxs[0][i] = skymaxs[1][i] = -9999; + } +} + + +void MakeSkyVec (float s, float t, int axis) +{ + vec3_t v, b; + int j, k; + + b[0] = s*2300; + b[1] = t*2300; + b[2] = 2300; + + for (j=0 ; j<3 ; j++) + { + k = st_to_vec[axis][j]; + if (k < 0) + v[j] = -b[-k - 1]; + else + v[j] = b[k - 1]; + } + + // avoid bilerp seam + s = (s+1)*0.5; + t = (t+1)*0.5; + + if (s < sky_min) + s = sky_min; + else if (s > sky_max) + s = sky_max; + if (t < sky_min) + t = sky_min; + else if (t > sky_max) + t = sky_max; + + t = 1.0 - t; + qglTexCoord2f (s, t); + qglVertex3fv (v); +} + +/* +============== +R_DrawSkyBox +============== +*/ +int skytexorder[6] = {0,2,1,3,4,5}; +void R_DrawSkyBox (void) +{ + int i; + +#if 0 +qglEnable (GL_BLEND); +GL_TexEnv( GL_MODULATE ); +qglColor4f (1,1,1,0.5); +qglDisable (GL_DEPTH_TEST); +#endif + if (skyrotate) + { // check for no sky at all + for (i=0 ; i<6 ; i++) + if (skymins[0][i] < skymaxs[0][i] + && skymins[1][i] < skymaxs[1][i]) + break; + if (i == 6) + return; // nothing visible + } + +qglPushMatrix (); +qglTranslatef (r_origin[0], r_origin[1], r_origin[2]); +qglRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); + + for (i=0 ; i<6 ; i++) + { + if (skyrotate) + { // hack, forces full sky to draw when rotating + skymins[0][i] = -1; + skymins[1][i] = -1; + skymaxs[0][i] = 1; + skymaxs[1][i] = 1; + } + + if (skymins[0][i] >= skymaxs[0][i] + || skymins[1][i] >= skymaxs[1][i]) + continue; + + GL_Bind (sky_images[skytexorder[i]]->texnum); + + qglBegin (GL_QUADS); + MakeSkyVec (skymins[0][i], skymins[1][i], i); + MakeSkyVec (skymins[0][i], skymaxs[1][i], i); + MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i); + MakeSkyVec (skymaxs[0][i], skymins[1][i], i); + qglEnd (); + } +qglPopMatrix (); +#if 0 +glDisable (GL_BLEND); +glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +glColor4f (1,1,1,0.5); +glEnable (GL_DEPTH_TEST); +#endif +} + + +/* +============ +R_SetSky +============ +*/ +// 3dstudio environment map names +char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; +void R_SetSky (char *name, float rotate, vec3_t axis) +{ + int i; + char pathname[MAX_QPATH]; + + strncpy (skyname, name, sizeof(skyname)-1); + skyrotate = rotate; + VectorCopy (axis, skyaxis); + + for (i=0 ; i<6 ; i++) + { + // chop down rotating skies for less memory + if (gl_skymip->value || skyrotate) + gl_picmip->value++; + + if ( qglColorTableEXT && gl_ext_palettedtexture->value ) + Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]); + else + Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]); + + sky_images[i] = GL_FindImage (pathname, it_sky); + if (!sky_images[i]) + sky_images[i] = r_notexture; + + if (gl_skymip->value || skyrotate) + { // take less memory + gl_picmip->value--; + sky_min = 1.0/256; + sky_max = 255.0/256; + } + else + { + sky_min = 1.0/512; + sky_max = 511.0/512; + } + } +} diff --git a/src/refresh/opengl/header/qgl.h b/src/refresh/opengl/header/qgl.h new file mode 100644 index 00000000..bfeb6027 --- /dev/null +++ b/src/refresh/opengl/header/qgl.h @@ -0,0 +1,468 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +/* +** QGL.H +*/ + +#ifndef __QGL_H__ +#define __QGL_H__ + +#ifdef _WIN32 +# include +#endif + +#include +#ifndef SOLARIS +//#include +#endif + +qboolean QGL_Init( const char *dllname ); +void QGL_Shutdown( void ); + +#ifndef APIENTRY +# define APIENTRY +#endif + +extern void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +extern void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +extern GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +extern void ( APIENTRY * qglArrayElement )(GLint i); +extern void ( APIENTRY * qglBegin )(GLenum mode); +extern void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +extern void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +extern void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +extern void ( APIENTRY * qglCallList )(GLuint list); +extern void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +extern void ( APIENTRY * qglClear )(GLbitfield mask); +extern void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +extern void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +extern void ( APIENTRY * qglClearDepth )(GLclampd depth); +extern void ( APIENTRY * qglClearIndex )(GLfloat c); +extern void ( APIENTRY * qglClearStencil )(GLint s); +extern void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +extern void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +extern void ( APIENTRY * qglColor3bv )(const GLbyte *v); +extern void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +extern void ( APIENTRY * qglColor3dv )(const GLdouble *v); +extern void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +extern void ( APIENTRY * qglColor3fv )(const GLfloat *v); +extern void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +extern void ( APIENTRY * qglColor3iv )(const GLint *v); +extern void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +extern void ( APIENTRY * qglColor3sv )(const GLshort *v); +extern void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +extern void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +extern void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +extern void ( APIENTRY * qglColor3uiv )(const GLuint *v); +extern void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +extern void ( APIENTRY * qglColor3usv )(const GLushort *v); +extern void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +extern void ( APIENTRY * qglColor4bv )(const GLbyte *v); +extern void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +extern void ( APIENTRY * qglColor4dv )(const GLdouble *v); +extern void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +extern void ( APIENTRY * qglColor4fv )(const GLfloat *v); +extern void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +extern void ( APIENTRY * qglColor4iv )(const GLint *v); +extern void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +extern void ( APIENTRY * qglColor4sv )(const GLshort *v); +extern void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +extern void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +extern void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +extern void ( APIENTRY * qglColor4uiv )(const GLuint *v); +extern void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +extern void ( APIENTRY * qglColor4usv )(const GLushort *v); +extern void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +extern void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +extern void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +extern void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +extern void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +extern void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +extern void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +extern void ( APIENTRY * qglCullFace )(GLenum mode); +extern void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +extern void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +extern void ( APIENTRY * qglDepthFunc )(GLenum func); +extern void ( APIENTRY * qglDepthMask )(GLboolean flag); +extern void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +extern void ( APIENTRY * qglDisable )(GLenum cap); +extern void ( APIENTRY * qglDisableClientState )(GLenum array); +extern void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +extern void ( APIENTRY * qglDrawBuffer )(GLenum mode); +extern void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +extern void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +extern void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +extern void ( APIENTRY * qglEnable )(GLenum cap); +extern void ( APIENTRY * qglEnableClientState )(GLenum array); +extern void ( APIENTRY * qglEnd )(void); +extern void ( APIENTRY * qglEndList )(void); +extern void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +extern void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +extern void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +extern void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +extern void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +extern void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +extern void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +extern void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +extern void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +extern void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +extern void ( APIENTRY * qglEvalPoint1 )(GLint i); +extern void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +extern void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +extern void ( APIENTRY * qglFinish )(void); +extern void ( APIENTRY * qglFlush )(void); +extern void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +extern void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +extern void ( APIENTRY * qglFrontFace )(GLenum mode); +extern void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +extern GLuint ( APIENTRY * qglGenLists )(GLsizei range); +extern void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +extern void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +extern void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +extern void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +extern GLenum ( APIENTRY * qglGetError )(void); +extern void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +extern void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +extern void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +extern void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +extern void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +extern void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +extern void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +extern void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +extern const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +extern void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +extern void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +extern void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +extern void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +extern void ( APIENTRY * qglIndexMask )(GLuint mask); +extern void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglIndexd )(GLdouble c); +extern void ( APIENTRY * qglIndexdv )(const GLdouble *c); +extern void ( APIENTRY * qglIndexf )(GLfloat c); +extern void ( APIENTRY * qglIndexfv )(const GLfloat *c); +extern void ( APIENTRY * qglIndexi )(GLint c); +extern void ( APIENTRY * qglIndexiv )(const GLint *c); +extern void ( APIENTRY * qglIndexs )(GLshort c); +extern void ( APIENTRY * qglIndexsv )(const GLshort *c); +extern void ( APIENTRY * qglIndexub )(GLubyte c); +extern void ( APIENTRY * qglIndexubv )(const GLubyte *c); +extern void ( APIENTRY * qglInitNames )(void); +extern void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +extern GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +extern GLboolean ( APIENTRY * qglIsList )(GLuint list); +extern GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +extern void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +extern void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +extern void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +extern void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +extern void ( APIENTRY * qglLineWidth )(GLfloat width); +extern void ( APIENTRY * qglListBase )(GLuint base); +extern void ( APIENTRY * qglLoadIdentity )(void); +extern void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +extern void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +extern void ( APIENTRY * qglLoadName )(GLuint name); +extern void ( APIENTRY * qglLogicOp )(GLenum opcode); +extern void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +extern void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +extern void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +extern void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +extern void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +extern void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +extern void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +extern void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +extern void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +extern void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglMatrixMode )(GLenum mode); +extern void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +extern void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +extern void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +extern void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +extern void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +extern void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +extern void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +extern void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +extern void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +extern void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +extern void ( APIENTRY * qglNormal3iv )(const GLint *v); +extern void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +extern void ( APIENTRY * qglNormal3sv )(const GLshort *v); +extern void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +extern void ( APIENTRY * qglPassThrough )(GLfloat token); +extern void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +extern void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +extern void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +extern void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +extern void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +extern void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +extern void ( APIENTRY * qglPointSize )(GLfloat size); +extern void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +extern void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +extern void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +extern void ( APIENTRY * qglPopAttrib )(void); +extern void ( APIENTRY * qglPopClientAttrib )(void); +extern void ( APIENTRY * qglPopMatrix )(void); +extern void ( APIENTRY * qglPopName )(void); +extern void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +extern void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +extern void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +extern void ( APIENTRY * qglPushMatrix )(void); +extern void ( APIENTRY * qglPushName )(GLuint name); +extern void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +extern void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +extern void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +extern void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +extern void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +extern void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +extern void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +extern void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +extern void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +extern void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +extern void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +extern void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +extern void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +extern void ( APIENTRY * qglReadBuffer )(GLenum mode); +extern void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +extern void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +extern void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +extern void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +extern void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +extern void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +extern void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +extern void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +extern void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +extern GLint ( APIENTRY * qglRenderMode )(GLenum mode); +extern void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +extern void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +extern void ( APIENTRY * qglShadeModel )(GLenum mode); +extern void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +extern void ( APIENTRY * qglStencilMask )(GLuint mask); +extern void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +extern void ( APIENTRY * qglTexCoord1d )(GLdouble s); +extern void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord1f )(GLfloat s); +extern void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord1i )(GLint s); +extern void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord1s )(GLshort s); +extern void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +extern void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +extern void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +extern void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +extern void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +extern void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +extern void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +extern void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +extern void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +extern void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +extern void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +extern void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +extern void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +extern void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +extern void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +extern void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +extern void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +extern void ( APIENTRY * qglVertex2iv )(const GLint *v); +extern void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +extern void ( APIENTRY * qglVertex2sv )(const GLshort *v); +extern void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +extern void ( APIENTRY * qglVertex3iv )(const GLint *v); +extern void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +extern void ( APIENTRY * qglVertex3sv )(const GLshort *v); +extern void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +extern void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +extern void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +extern void ( APIENTRY * qglVertex4iv )(const GLint *v); +extern void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +extern void ( APIENTRY * qglVertex4sv )(const GLshort *v); +extern void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +extern void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +extern void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +extern void ( APIENTRY * qglColorTableEXT)( GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid * ); + +extern void ( APIENTRY * qglLockArraysEXT) (int , int); +extern void ( APIENTRY * qglUnlockArraysEXT) (void); + +extern void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); +extern void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); + +extern void ( APIENTRY * qglActiveTextureARB)( GLenum ); +extern void ( APIENTRY * qglClientActiveTextureARB)( GLenum ); + +#ifdef _WIN32 + +extern int ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *); +extern int ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); +extern int ( WINAPI * qwglGetPixelFormat)(HDC); +extern BOOL ( WINAPI * qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *); +extern BOOL ( WINAPI * qwglSwapBuffers)(HDC); + +extern BOOL ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT); +extern HGLRC ( WINAPI * qwglCreateContext)(HDC); +extern HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int); +extern BOOL ( WINAPI * qwglDeleteContext)(HGLRC); +extern HGLRC ( WINAPI * qwglGetCurrentContext)(VOID); +extern HDC ( WINAPI * qwglGetCurrentDC)(VOID); +extern PROC ( WINAPI * qwglGetProcAddress)(LPCSTR); +extern BOOL ( WINAPI * qwglMakeCurrent)(HDC, HGLRC); +extern BOOL ( WINAPI * qwglShareLists)(HGLRC, HGLRC); +extern BOOL ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD); + +extern BOOL ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT, + FLOAT, int, LPGLYPHMETRICSFLOAT); + +extern BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT, + LPLAYERPLANEDESCRIPTOR); +extern int ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int, + CONST COLORREF *); +extern int ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int, + COLORREF *); +extern BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL); +extern BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT); + +extern BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval ); + +extern BOOL ( WINAPI * qwglGetDeviceGammaRampEXT ) ( unsigned char *pRed, unsigned char *pGreen, unsigned char *pBlue ); +extern BOOL ( WINAPI * qwglSetDeviceGammaRampEXT ) ( const unsigned char *pRed, const unsigned char *pGreen, const unsigned char *pBlue ); + +#endif + +#ifdef __linux__ + +// local function in dll +extern void *qwglGetProcAddress(char *symbol); + +extern void (*qgl3DfxSetPaletteEXT)(GLuint *); + +// 3dfxSetPaletteEXT shunt +void Fake_glColorTableEXT( GLenum target, GLenum internalformat, + GLsizei width, GLenum format, GLenum type, + const GLvoid *table ); + +#endif // linux + +/* deprecated */ +#define GL_TEXTURE0_SGIS 0x835E +#define GL_TEXTURE1_SGIS 0x835F + +extern int QGL_TEXTURE0, QGL_TEXTURE1; /* ARB/SGIS texture defs */ + +#ifdef SOLARIS /* these are in glext.h, on platforms that have it */ +/* +** extension constants +*/ +#define GL_POINT_SIZE_MIN_EXT 0x8126 +#define GL_POINT_SIZE_MAX_EXT 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 +#define GL_DISTANCE_ATTENUATION_EXT 0x8129 +#endif + +#ifdef __sgi +#define GL_SHARED_TEXTURE_PALETTE_EXT GL_TEXTURE_COLOR_TABLE_SGI +#else +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#endif + +#endif +