#ifndef         U3D_H_INCLUDED
#define         U3D_H_INCLUDED

#ifndef         _PENTIUM_AND_ABOVE_
#define         _PENTIUM_AND_ABOVE_
#endif

#include        <malloc.h>
#include        <math.h>
#pragma         hdrstop

/* ==================================================================== *\
                   Написание кода начато: 10.01.1999 г.
                      (замысел был уже года 2 назад)
   Дополнительно использованы источники:
    - код из Heretic2 (Josh Heitzman - jheitzman@mail.ravensoft.com,1998);
      явные преобразования заменяются макросами.
    - код из примеров к библиотеке 3DR (Intel, 1995) (карта окружения)
   31.01.99 - готова версия 1.0 (1080 строк заголовок, 700 строк код).
   11.04.99 - то, что работает, использовано в программе "Градиент"
   23.04.99 - обнаружено, что не работает очень многое. Регрессивное
   тестирование. Исправлен баг: было n=v/abs(vv), а не v/|v|=v/sqrt(vv).
   01.05.99 - Процедуры составления матриц поворота переименованы, а про-
   цедуры нахождения углов по направлению и верху удалены. Это связано с
   использованием различных систем координат: я в программе взял систему
   координат OpenGL (вверх второй орт). В Quake и иже с ним вверх третий
   орт; проще все переделать заново, чем каждый раз заниматься преобра-
   зованиями.
\* ==================================================================== */

#ifdef  DECLSPEC
#define OLD_DECLSPEC      DECLSPEC
#undef  DECLSPEC
#endif

#ifdef  DECLSPEC_INT
#define OLD_DECLSPEC_INT  DECLSPEC_INT
#undef  DECLSPEC_INT
#endif

#ifdef  DECLSPEC_PTR
#define OLD_DECLSPEC_PTR  DECLSPEC_PTR
#undef  DECLSPEC_PTR 
#endif

#ifdef  __WATCOMC__
#ifdef  CPLUSPLUS
#define DECLSPEC      extern "C" void __pascal __export
#define DECLSPEC_INT  extern "C" int __pascal __export
#define DECLSPEC_PTR  extern "C" void* __pascal __export
#else   // !CPLUSPLUS
#define DECLSPEC      void  __pascal __export
#define DECLSPEC_INT  int   __pascal __export
#define DECLSPEC_PTR  void*  __pascal __export
#endif  // CPLUSPLUS
//      Включить специфичнеы для компилятора WATCOM макосы
#define ASM_PRAGMAS
#else   // На самом деле, если !__WATCOMC__, то компилироваться не будет. Извините.
#ifdef  CPLUSPLUS
#define DECLSPEC      extern "C" __declspec(dllexport) pascal void
#define DECLSPEC_INT  extern "C" __declspec(dllexport) pascal int 
#define DECLSPEC_PTR  extern "C" __declspec(dllexport) pascal void *
#else   // !CPLUSPLUS
#define DECLSPEC      __declspec(dllexport) pascal void  
#define DECLSPEC_INT  __declspec(dllexport) pascal int   
#define DECLSPEC_PTR  __declspec(dllexport) pascal void  *
#endif  // CPLUSPLUS
#endif  // WATCOM

//        ================================================================
//        Соглашения о записи типов данных и имен функций.
//        Венгерская нотация не используется. Данный код не следует согла-
//        шениям о именах и не специфичен для ОС Windows.
//        Типы данных - в старом стиле (как у Id Software в DOOM - е).
//        Макроподстановки записываются в верхнем регистре.
//        Префиксы имен функций:
//          mem - операции с памятью
//          vt - векторные операции (обычные векторы)
//          vth - векторные операции (однородные векторы)
//          mt - матричные операции (обычные матрицы)
//          mth - матричные операции (однородные матрицы)
//          mtt - матричные операции (матрицы 3 Х 4)
//          vtx - операции с вершинами примитива
//          nr - операции с нормалями примитива
//          tex - операции с координатами текстуры
//          ms - операции с примитивами (сетками)
//          surf - операции с экструзионными сетками
//        ================================================================
//                   * * *             КОНСТАНТЫ             * * *
//        ================================================================
//        Ноль
#define   U3D_ZERO_EPSILON              U3DVAL(0.0005)
//        Число PI
#ifdef    M_PI
#undef    M_PI
#endif
#ifdef    M_2PI
#undef    M_2PI
#endif
#define   M_PI                          U3DVAL(3.14159265359)
#define   M_2PI                         U3DVAL(6.28318530718)
#define   M_PI2                         U3DVAL(1.570796326795)
#define   M_PI3                         U3DVAL(1.047197551197)
#define   M_PI4                         U3DVAL(0.7853981633975)
#define   M_PI6                         U3DVAL(0.5235987755983)
//        Углы в радианах; после черты в макросе - угол в градусах
#define   ANGLE_0                       U3DVAL(0.0)
#define   ANGLE_1                       U3DVAL(0.017453292)
#define   ANGLE_5                       U3DVAL(0.087266462)
#define   ANGLE_10                      U3DVAL(0.174532925)
#define   ANGLE_15                      U3DVAL(0.261799387)
#define   ANGLE_20                      U3DVAL(0.392699081)
#define   ANGLE_30                      U3DVAL(0.523598775)
#define   ANGLE_45                      U3DVAL(0.785398163)
#define   ANGLE_60                      U3DVAL(1.047197551)
#define   ANGLE_72                      U3DVAL(1.256637061)
#define   ANGLE_90                      U3DVAL(1.570796327)
#define   ANGLE_120                     U3DVAL(2.094395102)
#define   ANGLE_135                     U3DVAL(2.35619449)
#define   ANGLE_144                     U3DVAL(2.513274123)
#define   ANGLE_180                     U3DVAL(3.141592653)
#define   ANGLE_225                     U3DVAL(3.926990817)
#define   ANGLE_270                     U3DVAL(4.71238898)
#define   ANGLE_315                     U3DVAL(5.497787144)
#define   ANGLE_360                     U3DVAL(6.283185307)
//        Число радиан в градусе и масштабный коэффициент перевода гр->рад
#define   RAD_IN_ANGLE                  ANGLE_TO_RAD
#define   ANGLE_TO_RAD                  U3DVAL(0.01745329251994)
//        Число градусов в радиане и коэффициент перевода рад->гр
#define   ANGLE_IN_RAD                  RAD_TO_ANGLE
#define   RAD_TO_ANGLE                  U3DVAL(57.29577951618)
//        ================================================================
//                   * * *      ОПРЕДЕЛЕНИЯ ТИПОВ ДАННЫХ     * * *
//        ================================================================
//        Основной скалярный тип данных
typedef   float                         u3dval;
//        Векторы - обычный и однородный
typedef   struct  { u3dval x,y,z; }     vector_t;
typedef   struct  { u3dval x,y,z,w; }   hvector_t;
//        Матрицы - обычная, однородная, неполная однородная
typedef   u3dval                        matrix_t[3*3];
typedef   u3dval                        hmatrix_t[4*4];
typedef   u3dval                        transform_t[3*4];
//        Координаты текстуры
typedef   struct  { u3dval u,v; }       texcoord_t;
//        Цвета RGB и с альфа - составляющей
typedef   struct  { u3dval r,g,b; }     rgb_t;
typedef   struct  { u3dval r,g,b,a; }   rgba_t;
//        Байтовые цвета RGB и с альфа - составляющей
typedef   struct  { char b,g,r;}        bytebgr_t;
typedef   struct  { char a,b,g,r;}      byteabgr_t;
typedef   struct  { char r,g,b;}        bytergb_t;
typedef   struct  { char r,g,b,a;}      bytergba_t;
//        Обсчитанная и освещенная вершина - как передается акселератору.
//        Примечение. Массив таких вершин можно сразу передавать 
//        методу 'DrawPrimitive' интерфейса IDirect3DDevice2.
typedef   struct  
{ 
  struct {float x,y,z;} sc;             // Экранные координаты
  float  rw;                            // 1 / w - компоненту
  byteabgr_t cl;                        // Цвет вершины
  byteabgr_t sp;                        // Цвет бликов
  struct {float u,v;} tx;               // Координаты текстуры
}                                       tlvertexf_t;
//        Минимальный набор данных для сетки
typedef   struct
{
  //            Количество вершин (нормалей, цветов)
  int           nvertices;
  //            Вершины
  vector_t      *vertex;
  //            Нормали к вершинам (выполняется закраска Гуро)
  vector_t      *normal;
  //            Цвета вершин (материал сетки один для всей сетки)
  rgb_t         *color;
  //            Координаты текстуры
  texcoord_t    *texcoord;
}                                       generic_mesh_t;
//        ================================================================
//                       * * *      МАКРОПОДСТАНОВКИ     * * *
//        ================================================================
//        Общие ==========================================================
//        Приведение к основному типу 
#define   U3DVAL(v)                     ((u3dval)(v))
//        Перевод градусов в радианы
#define   U3DRADIANS(a)                 (U3DVAL(a)*RAD_IN_ANGLE)
//        Перевод радиан в градусы
#define   U3DDEGREES(a)                 (U3DVAL(a)*ANGLE_IN_RAD)
//        ================================================================
//        Векторные операции
//        ================================================================
//        Доступ к компонентам по индексу (0 - x,1 - y,2 - z,3 - w)
#define   VTIND(vec,ind)\
(\
  ((u3dval*)&(vec))[ind]\
)
//        Запись составляющих в вектор
#define   VTSET(vec,_x,_y,_z)\
{\
  (vec).x=U3DVAL(_x);\
  (vec).y=U3DVAL(_y);\
  (vec).z=U3DVAL(_z);\
}
#define   VTHSET(vec,_x,_y,_z,_w)\
{\
  (vec).x=U3DVAL(_x);\
  (vec).y=U3DVAL(_y);\
  (vec).z=U3DVAL(_z);\
  (vec).w=U3DVAL(_w);\
}
//        Обнуление вектора
#define   VTZERO(vec)\
{\
  MEMZERO4(&(vec),3*sizeof(u3dval)/4);\
}
#define   VTHZERO(vec)\
{\
  MEMZERO4(&(vec),4*sizeof(u3dval)/4);\
}
//        Копирование вектора
#define   VTCOPY(dst,src)\
{\
  MEMCOPY4(&(dst),&(src),3*sizeof(u3dval)/4);\
}
#define   VTHCOPY(dst,src)\
{\
  MEMCOPY4(&(dst),&(src),4*sizeof(u3dval)/4);\
}
//        Сложение векторов
#define   VTADD(dst,v1,v2)\
{\
  (dst).x=(v1).x+(v2).x;\
  (dst).y=(v1).y+(v2).y;\
  (dst).z=(v1).z+(v2).z;\
}
#define   VTHADD(dst,v1,v2)\
{\
  (dst).x=(v1).x+(v2).x;\
  (dst).y=(v1).y+(v2).y;\
  (dst).z=(v1).z+(v2).z;\
  (dst).w=(v1).w+(v2).w;\
}
//        Вычитание векторов
#define   VTSUB(dst,v1,v2)\
{\
  (dst).x=(v1).x-(v2).x;\
  (dst).y=(v1).y-(v2).y;\
  (dst).z=(v1).z-(v2).z;\
}
#define   VTHSUB(dst,v1,v2)\
{\
  (dst).x=(v1).x-(v2).x;\
  (dst).y=(v1).y-(v2).y;\
  (dst).z=(v1).z-(v2).z;\
  (dst).w=(v1).w-(v2).w;\
}
//        Умножение вектора на -1 с копированием результата в новый вектор
#define   VTNEGATE(dst,src)\
{\
  (dst).x=-(src).x;\
  (dst).y=-(src).y;\
  (dst).z=-(src).z;\
}
#define   VTHNEGATE(dst,src)\
{\
  (dst).x=-(src).x;\
  (dst).y=-(src).y;\
  (dst).z=-(src).z;\
  (dst).w=-(src).w;\
}
//        Умножение вектора на число
#define   VTMUL(dst,vec,ml)\
{\
  (dst).x=(vec).x*U3DVAL(ml);\
  (dst).y=(vec).y*U3DVAL(ml);\
  (dst).z=(vec).z*U3DVAL(ml);\
}
#define   VTHMUL(dst,vec,ml)\
{\
  (dst).x=(vec).x*U3DVAL(ml);\
  (dst).y=(vec).y*U3DVAL(ml);\
  (dst).z=(vec).z*U3DVAL(ml);\
  (dst).w=(vec).w*U3DVAL(ml);\
}
//        Скалярное произведение
#define   VTDOT(v1,v2)\
(\
  (v1).x*(v2).x+(v1).y*(v2).y+(v1).z*(v2).z\
)
#define   VTHDOT(v1,v2)\
(\
  (v1).x*(v2).x+(v1).y*(v2).y+(v1).z*(v2).z+(v1).w*(v2).w\
)
//        Модуль вектора
#define   VTABS(vec)\
(\
  U3DVAL(sqrt(VTDOT(vec,vec)))\
)
//        Нормализация (масштабирование до единичной длины)
#define   VTNORMALIZE(vec)\
{\
  u3dval rabs;\
  rabs=1/VTABS(vec);\
  (vec).x*=rabs;\
  (vec).y*=rabs;\
  (vec).z*=rabs;\
}
#define   VTHNORMALIZE(vec)\
{\
  VTNORMALIZE(vec);\
  (vec).w=U3DVAL(1);\
}
//        Ободнороднивание (деление всех элементов на четвертый)
#define   VTHHOMOGENIZE(vec)\
{\
  u3dval rhw=1/(vec).w;\
  (vec).x*=rhw;\
  (vec).y*=rhw;\
  (vec).z*=rhw;\
  (vec).w=U3DVAL(1);\
}
//        Векторное произведение
#define   VTCROSS(dst,v1,v2)\
{\
  (dst).x=(v1).y*(v2).z-(v1).z*(v2).y;\
  (dst).y=(v1).z*(v2).x-(v1).x*(v2).z;\
  (dst).z=(v1).x*(v2).y-(v1).y*(v2).x;\
}
// Получение минимальной и максимальной составляющих
#define   VTMIN(vec)\
(\
  ((vec).x<(vec).y)?(((vec).z<(vec).x)?(vec).z:(vec).x):\
  (((vec).z<(vec).y)?(vec).z:(vec).y)\
)
#define   VTMAX(vec)\
(\
  ((vec).x>(vec).y)?(((vec).z>(vec).x)?(vec).z:(vec).x):\
  (((vec).z>(vec).y)?(vec).z:(vec).y)\
)
// Проверка вектора на равенство нулю
#define   VTISZERO(vec)\
(\
  (fabs((vec).x)<U3D_ZERO_EPSILON)&&\
  (fabs((vec).y)<U3D_ZERO_EPSILON)&&\
  (fabs((vec).z)<U3D_ZERO_EPSILON)\
)
#define   VTHISZERO(vec)\
(\
  (fabs((vec).x)<U3D_ZERO_EPSILON)&&\
  (fabs((vec).y)<U3D_ZERO_EPSILON)&&\
  (fabs((vec).z)<U3D_ZERO_EPSILON)&&\
  (fabs((vec).w)<U3D_ZERO_EPSILON)\
)
// Проверка двух векторов на равенство
#define   VTISEQUAL(v1,v2)\
(\
  (fabs((v1).x-(v2).x)<U3D_ZERO_EPSILON)&&\
  (fabs((v1).y-(v2).y)<U3D_ZERO_EPSILON)&&\
  (fabs((v1).z-(v2).z)<U3D_ZERO_EPSILON)\
)
#define   VTHISEQUAL(v1,v2)\
(\
  (fabs((v1).x-(v2).x)<U3D_ZERO_EPSILON)&&\
  (fabs((v1).y-(v2).y)<U3D_ZERO_EPSILON)&&\
  (fabs((v1).z-(v2).z)<U3D_ZERO_EPSILON)&&\
  (fabs((v1).w-(v2).w)<U3D_ZERO_EPSILON)\
)
// Построение вектора с компонентами - произведениями
#define   VTSCALEBY(dst,v1,v2)\
{\
  (dst).x=(v1).x*(v2).x;\
  (dst).y=(v1).y*(v2).y;\
  (dst).z=(v1).z*(v2).z;\
}
#define   VTHSCALEBY(dst,v1,v2)\
{\
  (dst).x=(v1).x*(v2).x;\
  (dst).y=(v1).y*(v2).y;\
  (dst).z=(v1).z*(v2).z;\
  (dst).w=(v1).w*(v2).w;\
}
// Построение вектора с компонентами - частными
#define   VTZOOMIF(zoom,initial,final)\
{\
  (zoom).x=(final).x/(initial).x;\
  (zoom).y=(final).y/(initial).y;\
  (zoom).z=(final).z/(initial).z;\
}
#define   VTHZOOMIF(zoom,initial,final)\
{\
  (zoom).x=(final).x/(initial).x;\
  (zoom).y=(final).y/(initial).y;\
  (zoom).z=(final).z/(initial).z;\
  (zoom).w=(final).w/(initial).w;\
}
//        Перевод градусов в радианы
#define   VTDEGTORAD(dst,src)\
{\
  (dst).x=(src).x*ANGLE_TO_RAD;\
  (dst).y=(src).y*ANGLE_TO_RAD;\
  (dst).z=(src).z*ANGLE_TO_RAD;\
}
//        Перевод радиан в градусы
#define   VTRADTODEG(dst,src)\
{\
  (dst).x=(src).x*RAD_TO_ANGLE;\
  (dst).y=(src).y*RAD_TO_ANGLE;\
  (dst).z=(src).z*RAD_TO_ANGLE;\
}
//        Ссылка на первую компоненту вектора (считается углом наклона)
#define   PITCH(angles)                 ((angles).x)
//        Ссылка на вторую компоненту вектора (считается углом поворота)
#define   YAW(angles)                   ((angles).y)
//        Ссылка на третью компоненту вектора (угол опрокидывания)
#define   ROLL(angles)                  ((angles).z)
//        ================================================================
//        Матричные операции
//        ================================================================
//        Ссылки на элементы в формате строка - столбец
#ifdef    _PENTIUM_AND_ABOVE_
#define   MTELEM(mt,r,c)                 ((mt)[r*3+c])
#else
#define   MTELEM(mt,r,c)                 ((mt)[(((r)<<1)+r+c)])
#endif
#define   MTHELEM(mt,r,c)                ((mt)[(((r)<<2)+c)])
//        Обнуление матрицы
#define   MTZERO(mat)\
{\
  MEMZERO4((mat),9*sizeof(u3dval)/4);\
}
#define   MTHZERO(mat)\
{\
  MEMZERO4((mat),4*sizeof(u3dval));\
}
#define   MTTZERO(mat)\
{\
  MEMZERO4((mat),3*sizeof(u3dval));\
}
//        Копирование матрицы
#define   MTCOPY(dst,src)\
{\
  MEMCOPY4((dst),(src),9*sizeof(u3dval)/4);\
}
#define   MTHCOPY\
{\
  MEMCOPY4((dst),(src),4*sizeof(u3dval));\
}
#define   MTTCOPY\
{\
  MEMCOPY4((dst),(src),3*sizeof(u3dval));\
}
//        Установка в единицу
#define   MTIDENTITY(mat)\
{\
  MTZERO(mat);\
  (mat)[0]=(mat)[4]=(mat)[8]=U3DVAL(1);\
}
#define   MTHIDENTITY(mat)\
{\
  MTHZERO(mat);\
  (mat)[0]=(mat)[5]=(mat)[10]=(mat)[15]=U3DVAL(1);\
}
#define   MTTIDENTITY\
{\
  MTTZERO(mat);\
  (mat)[0]=(mat)[5]=(mat)[10]=U3DVAL(1);\
}
//        Копирование матрицы 3х3 в LU - угол матрицы 4х4 или 3х4
#define   MTSETLU(hmat,mat)\
{\
  (hmat)[0]=(mat)[0];\
  (hmat)[1]=(mat)[1];\
  (hmat)[2]=(mat)[2];\
  (hmat)[4]=(mat)[3];\
  (hmat)[5]=(mat)[4];\
  (hmat)[6]=(mat)[5];\
  (hmat)[8]=(mat)[6];\
  (hmat)[9]=(mat)[7];\
  (hmat)[10]=(mat)[8];\
}
//        Копирование LU - угла матрицы 4х4 или 3х4 в матрицу 3х3
#define   MTGETLU(mat,hmat)\
{\
  (mat)[0]=(hmat)[0];\
  (mat)[1]=(hmat)[1];\
  (mat)[2]=(hmat)[2];\
  (mat)[3]=(hmat)[4];\
  (mat)[4]=(hmat)[5];\
  (mat)[5]=(hmat)[6];\
  (mat)[6]=(hmat)[8];\
  (mat)[7]=(hmat)[9];\
  (mat)[8]=(hmat)[10];\
}
//        Вставка вектора в строку матрицы 3х3
#define   MTVECTOROW1(mat,vec)\
{\
  (mat)[0]=(vec).x;\
  (mat)[1]=(vec).y;\
  (mat)[2]=(vec).z;\
}
#define   MTVECTOROW2(mat,vec)\
{\
  (mat)[3]=(vec).x;\
  (mat)[4]=(vec).y;\
  (mat)[5]=(vec).z;\
}
#define   MTVECTOROW3(mat,vec)\
{\
  (mat)[6]=(vec).x;\
  (mat)[7]=(vec).y;\
  (mat)[8]=(vec).z;\
}
//        Вставка вектора (обычного) в строку матрицы 4х4 или 3х4
#define   MTHVECTOROW1(mat,vec)\
{\
  (mat)[0]=(vec).x;\
  (mat)[1]=(vec).y;\
  (mat)[2]=(vec).z;\
}
#define   MTHVECTOROW2(mat,vec)\
{\
  (mat)[4]=(vec).x;\
  (mat)[5]=(vec).y;\
  (mat)[6]=(vec).z;\
}
#define   MTHVECTOROW3(mat,vec)\
{\
  (mat)[8]=(vec).x;\
  (mat)[9]=(vec).y;\
  (mat)[10]=(vec).z;\
}
//        Вставка векторов во все строки матрицы 3х3
#define   MTVECTOROWS(mat,v1,v2,v3)\
{\
  MTVECTOROW1(mat,v1);\
  MTVECTOROW2(mat,v2);\
  MTVECTOROW3(mat,v3);\
}
//        Вставка векторов в три строки матрицы 4х4 или 3х4
#define   MTHVECTOROWS(mat,v1,v2,v3)\
{\
  MTHVECTOROW1(mat,v1);\
  MTHVECTOROW2(mat,v2);\
  MTHVECTOROW3(mat,v3);\
}
//        Вставка вектора в столбец матрицы 3х3
#define   MTVECTOCOL1(mat,vec)\
{\
  (mat)[0]=(vec).x;\
  (mat)[3]=(vec).y;\
  (mat)[6]=(vec).z;\
}
#define   MTVECTOCOL2(mat,vec)\
{\
  (mat)[1]=(vec).x;\
  (mat)[4]=(vec).y;\
  (mat)[7]=(vec).z;\
}
#define   MTVECTOCOL3(mat,vec)\
{\
  (mat)[2]=(vec).x;\
  (mat)[5]=(vec).y;\
  (mat)[8]=(vec).z;\
}
//        Вставка вектора (обычного) в столбец матрицы 4х4 или 3х4
#define   MTHVECTOCOL1(mat,vec)\
{\
  (mat)[0]=(vec).x;\
  (mat)[4]=(vec).y;\
  (mat)[8]=(vec).z;\
}
#define   MTHVECTOCOL2(mat,vec)\
{\
  (mat)[1]=(vec).x;\
  (mat)[5]=(vec).y;\
  (mat)[9]=(vec).z;\
}
#define   MTHVECTOCOL3(mat,vec)\
{\
  (mat)[2]=(vec).x;\
  (mat)[6]=(vec).y;\
  (mat)[10]=(vec).z;\
}
//        Вставка векторов во все столбцы матрицы 3х3
#define   MTVECTOCOLS(mat,v1,v2,v3)\
{\
  MTVECTOCOL1(mat,v1);\
  MTVECTOCOL2(mat,v2);\
  MTVECTOCOL3(mat,v3);\
}
//        Вставка векторов в три столбца матрицы 4х4 или 3х4
#define   MTHVECTOCOLS(mat,v1,v2,v3)\
{\
  MTHVECTOCOL1(mat,v1);\
  MTHVECTOCOL2(mat,v2);\
  MTHVECTOCOL3(mat,v3);\
}
//        Транспонирование матрицы
#define   MTTRANSPOSE(dst,src)\
{\
  (dst)[0]=(src)[0];\
  (dst)[1]=(src)[3];\
  (dst)[2]=(src)[6];\
  (dst)[3]=(src)[1];\
  (dst)[4]=(src)[4];\
  (dst)[5]=(src)[7];\
  (dst)[6]=(src)[2];\
  (dst)[7]=(src)[5];\
  (dst)[8]=(src)[8];\
}
#define   MTHTRANSPOSE(dst,src)\
{\
  (dst)[0]=(src)[0];\
  (dst)[1]=(src)[4];\
  (dst)[2]=(src)[8];\
  (dst)[3]=(src)[12];\
  (dst)[4]=(src)[1];\
  (dst)[5]=(src)[5];\
  (dst)[6]=(src)[9];\
  (dst)[7]=(src)[13];\
  (dst)[8]=(src)[2];\
  (dst)[9]=(src)[6];\
  (dst)[10]=(src)[10];\
  (dst)[11]=(src)[14];\
  (dst)[12]=(src)[3];\
  (dst)[13]=(src)[7];\
  (dst)[14]=(src)[11];\
  (dst)[15]=(src)[15];\
}
//        Транспонирование матрицы с присваиванием
#define   MTSELFTRANSPOSE(mat)\
{\
  u3dval  temp;\
  temp=(mat)[1];(mat)[1]=(mat)[3];(mat)[3]=temp;\
  temp=(mat)[2];(mat)[2]=(mat)[6];(mat)[6]=temp;\
  temp=(mat)[5];(mat)[5]=(mat)[7];(mat)[7]=temp;\
}
#define   MTHSELFTRANSPOSE(mat)\
{\
  u3dval  temp;\
  temp=(mat)[1];(mat)[1]=(mat)[4];(mat)[4]=temp;\
  temp=(mat)[2];(mat)[2]=(mat)[8];(mat)[8]=temp;\
  temp=(mat)[3];(mat)[3]=(mat)[12];(mat)[12]=temp;\
  temp=(mat)[6];(mat)[6]=(mat)[9];(mat)[9]=temp;\
  temp=(mat)[7];(mat)[7]=(mat)[13];(mat)[13]=temp;\
  temp=(mat)[11];(mat)[11]=(mat)[14];(mat)[14]=temp;\
}
//        Умножение матрицы на вектор
#define   MTVECMUL(dst,mat,v)\
{\
  (dst).x=(mat)[0]*(v).x+(mat)[1]*(v).y+(mat)[2]*(v).z;\
  (dst).y=(mat)[3]*(v).x+(mat)[4]*(v).y+(mat)[5]*(v).z;\
  (dst).z=(mat)[6]*(v).x+(mat)[7]*(v).y+(mat)[8]*(v).z;\
}
#define   MTHVECMUL(dst,mat,v)\
{\
  (dst).x=(mat)[0]*(v).x+(mat)[1]*(v).y+(mat)[2]*(v).z+(mat)[3]*(v).w;\
  (dst).y=(mat)[4]*(v).x+(mat)[5]*(v).y+(mat)[6]*(v).z+(mat)[7]*(v).w;\
  (dst).y=(mat)[8]*(v).x+(mat)[9]*(v).y+(mat)[10]*(v).z+(mat)[11]*(v).w;\
  (dst).y=(mat)[12]*(v).x+(mat)[13]*(v).y+(mat)[14]*(v).z+(mat)[15]*(v).w;\
}
//        Частичное умножение. На вход передается или однородная матрица,
//        или матрица из 3-х строк и 4-х столбцов (transform_t), и обычный
//        или однородный вектор (w - компонента остается без изменения).
//        Эта операция аналогична "MTHVECMUL", но работает быстрее.
#define   MTHVECTRANSFORM(dst,mat,v)\
{\
  (dst).x=(mat)[0]*(v).x+(mat)[1]*(v).y+(mat)[2]*(v).z+(mat)[3];\
  (dst).y=(mat)[4]*(v).x+(mat)[5]*(v).y+(mat)[6]*(v).z+(mat)[7];\
  (dst).y=(mat)[8]*(v).x+(mat)[9]*(v).y+(mat)[10]*(v).z+(mat)[11];\
}
#define   MTMUL(dst,m1,m2)\
{\
  (dst)[0]=(m1)[0]*(m2)[0]+(m1)[1]*(m2)[3]+(m1)[2]*(m2)[6];\
  (dst)[1]=(m1)[0]*(m2)[1]+(m1)[1]*(m2)[4]+(m1)[2]*(m2)[7];\
  (dst)[2]=(m1)[0]*(m2)[2]+(m1)[1]*(m2)[5]+(m1)[2]*(m2)[8];\
  (dst)[3]=(m1)[3]*(m2)[0]+(m1)[4]*(m2)[3]+(m1)[5]*(m2)[6];\
  (dst)[4]=(m1)[3]*(m2)[1]+(m1)[4]*(m2)[4]+(m1)[5]*(m2)[7];\
  (dst)[5]=(m1)[3]*(m2)[2]+(m1)[4]*(m2)[5]+(m1)[5]*(m2)[8];\
  (dst)[6]=(m1)[6]*(m2)[0]+(m1)[7]*(m2)[3]+(m1)[8]*(m2)[6];\
  (dst)[7]=(m1)[6]*(m2)[1]+(m1)[7]*(m2)[4]+(m1)[8]*(m2)[7];\
  (dst)[8]=(m1)[6]*(m2)[2]+(m1)[7]*(m2)[5]+(m1)[8]*(m2)[8];\
}
//        килограмм кода :)
#define   MTHMUL(dst,m1,m2)\
{\
  (dst)[0]=(m1)[0]*(m2)[0]+(m1)[1]*(m2)[4]+(m1)[2]*(m2)[8]+\
    (m1)[3]*(m2)[12];\
  (dst)[1]=(m1)[0]*(m2)[1]+(m1)[1]*(m2)[5]+(m1)[2]*(m2)[9]+\
    (m1)[3]*(m2)[13];\
  (dst)[2]=(m1)[0]*(m2)[2]+(m1)[1]*(m2)[6]+(m1)[2]*(m2)[10]+\
    (m1)[3]*(m2)[14];\
  (dst)[3]=(m1)[0]*(m2)[3]+(m1)[1]*(m2)[7]+(m1)[2]*(m2)[11]+\
     (m1)[3]*(m2)[15];\
  (dst)[4]=(m1)[4]*(m2)[0]+(m1)[5]*(m2)[4]+(m1)[6]*(m2)[8]+\
    (m1)[7]*(m2)[12];\
  (dst)[5]=(m1)[4]*(m2)[1]+(m1)[5]*(m2)[5]+(m1)[6]*(m2)[9]+\
    (m1)[7]*(m2)[13];\
  (dst)[6]=(m1)[4]*(m2)[2]+(m1)[5]*(m2)[6]+(m1)[6]*(m2)[10]+\
    (m1)[7]*(m2)[14];\
  (dst)[7]=(m1)[4]*(m2)[3]+(m1)[5]*(m2)[7]+(m1)[6]*(m2)[11]+\
    (m1)[7]*(m2)[15];\
  (dst)[8]=(m1)[8]*(m2)[0]+(m1)[9]*(m2)[4]+(m1)[10]*(m2)[8]+\
    (m1)[11]*(m2)[12];\
  (dst)[9]=(m1)[8]*(m2)[1]+(m1)[9]*(m2)[5]+(m1)[10]*(m2)[9]+\
    (m1)[11]*(m2)[13];\
  (dst)[10]=(m1)[8]*(m2)[2]+(m1)[9]*(m2)[6]+(m1)[10]*(m2)[10]+\
    (m1)[11]*(m2)[14];\
  (dst)[11]=(m1)[8]*(m2)[3]+(m1)[9]*(m2)[7]+(m1)[10]*(m2)[11]+\
    (m1)[11]*(m2)[15];\
  (dst)[12]=(m1)[12]*(m2)[0]+(m1)[13]*(m2)[4]+(m1)[14]*(m2)[8]+\
    (m1)[15]*(m2)[12];\
  (dst)[13]=(m1)[12]*(m2)[1]+(m1)[13]*(m2)[5]+(m1)[14]*(m2)[9]+\
    (m1)[15]*(m2)[13];\
  (dst)[14]=(m1)[12]*(m2)[2]+(m1)[13]*(m2)[6]+(m1)[14]*(m2)[10]+\
    (m1)[15]*(m2)[14];\
  (dst)[15]=(m1)[12]*(m2)[3]+(m1)[13]*(m2)[7]+(m1)[14]*(m2)[11]+\
    (m1)[15]*(m2)[15];\
}
//        Частичное умножение. На вход передаются или однородные матрицы,
//        или матрицы из 3-х строк и 4-х столбцов (transform_t).
#define   MTHMULTRANSFORMS(dst,m1,m2)\
{\
  (dst)[0]=(m1)[0]*(m2)[0]+(m1)[1]*(m2)[4]+(m1)[2]*(m2)[8];\
  (dst)[1]=(m1)[0]*(m2)[1]+(m1)[1]*(m2)[5]+(m1)[2]*(m2)[9];\
  (dst)[2]=(m1)[0]*(m2)[2]+(m1)[1]*(m2)[6]+(m1)[2]*(m2)[10];\
  (dst)[3]=(m1)[0]*(m2)[3]+(m1)[1]*(m2)[7]+(m1)[2]*(m2)[11]+(m1)[3];\
  (dst)[4]=(m1)[4]*(m2)[0]+(m1)[5]*(m2)[4]+(m1)[6]*(m2)[8];\
  (dst)[5]=(m1)[4]*(m2)[1]+(m1)[5]*(m2)[5]+(m1)[6]*(m2)[9];\
  (dst)[6]=(m1)[4]*(m2)[2]+(m1)[5]*(m2)[6]+(m1)[6]*(m2)[10];\
  (dst)[7]=(m1)[4]*(m2)[3]+(m1)[5]*(m2)[7]+(m1)[6]*(m2)[11]+(m1)[7];\
  (dst)[8]=(m1)[8]*(m2)[0]+(m1)[9]*(m2)[4]+(m1)[10]*(m2)[8];\
  (dst)[9]=(m1)[8]*(m2)[1]+(m1)[9]*(m2)[5]+(m1)[10]*(m2)[9];\
  (dst)[10]=(m1)[8]*(m2)[2]+(m1)[9]*(m2)[6]+(m1)[10]*(m2)[10];\
  (dst)[11]=(m1)[8]*(m2)[3]+(m1)[9]*(m2)[7]+(m1)[10]*(m2)[11]+(m1)[11];\
}
#define   MTHCONCATTRANSFORM(dst,tr)\
{\
  hmatrix_t tmp;\
  (tmp)[0]=(dst)[0]*(tr)[0]+(dst)[1]*(tr)[4]+(dst)[2]*(tr)[8];\
  (tmp)[1]=(dst)[0]*(tr)[1]+(dst)[1]*(tr)[5]+(dst)[2]*(tr)[9];\
  (tmp)[2]=(dst)[0]*(tr)[2]+(dst)[1]*(tr)[6]+(dst)[2]*(tr)[10];\
  (tmp)[3]=(dst)[0]*(tr)[3]+(dst)[1]*(tr)[7]+(dst)[2]*(tr)[11]+(dst)[3];\
  (tmp)[4]=(dst)[4]*(tr)[0]+(dst)[5]*(tr)[4]+(dst)[6]*(tr)[8];\
  (tmp)[5]=(dst)[4]*(tr)[1]+(dst)[5]*(tr)[5]+(dst)[6]*(tr)[9];\
  (tmp)[6]=(dst)[4]*(tr)[2]+(dst)[5]*(tr)[6]+(dst)[6]*(tr)[10];\
  (tmp)[7]=(dst)[4]*(tr)[3]+(dst)[5]*(tr)[7]+(dst)[6]*(tr)[11]+(dst)[7];\
  (tmp)[8]=(dst)[8]*(tr)[0]+(dst)[9]*(tr)[4]+(dst)[10]*(tr)[8];\
  (tmp)[9]=(dst)[8]*(tr)[1]+(dst)[9]*(tr)[5]+(dst)[10]*(tr)[9];\
  (tmp)[10]=(dst)[8]*(tr)[2]+(dst)[9]*(tr)[6]+(dst)[10]*(tr)[10];\
  (tmp)[11]=(dst)[8]*(tr)[3]+(dst)[9]*(tr)[7]+(dst)[10]*(tr)[11]+(dst)[11];\
  MTCOPY((dst),(tmp));\
}
//        ================================================================
//        Действия с текстурами
//        ================================================================
//        Запись составляющих в координаты текстуры
#define   TEXSET(tex,_u,_v)               {(tex).u=_u;(tex).v=_v;}
//        Копирование
#define   TEXCOPY(dst,src)              {(dst).u=(src).u;(dst).v=(src).v;}
//        ================================================================
//        Действия с цветами
//        ================================================================
//        Запись трех составялющих в цвет
#define   RGBSET(rgb,_r,_g,_b)\
{\
  (rgb).r=_r;\
  (rgb).g=_g;\
  (rgb).b=_b;\
}
#define   RGBASET(rgb,_r,_g,_b,_a)\
{\
  (rgb).r=_r;\
  (rgb).g=_g;\
  (rgb).b=_b;\
  (rgb).a=_a;\
}
//        Копирование
#define   RGBCOPY(dst,src)\
{\
  (dst).r=(src).r;\
  (dst).g=(src).g;\
  (dst).b=(src).b;\
}
#define   RGBACOPY(dst,src)\
{\
  (dst).r=(src).r;\
  (dst).g=(src).g;\
  (dst).b=(src).b;\
  (dst).a=(src).a;\
}
//        Преобразование байтового цвета в основной формат
#define   RGBBYTETOU3D(rgb,brgb)\
{\
  (rgb).r=U3DVAL((brgb).r)/255;\
  (rgb).g=U3DVAL((brgb).g)/255;\
  (rgb).b=U3DVAL((brgb).b)/255;\
}
#define   RGBABYTETOU3D(rgba,brgba)\
{\
  (rgba).r=U3DVAL((brgba).r)/255;\
  (rgba).g=U3DVAL((brgba).g)/255;\
  (rgba).b=U3DVAL((brgba).b)/255;\
  (rgba).a=U3DVAL((brgba).a)/255;\
}
//        Преобразование основного формата в байтовый цвет
#define   RGBU3DTOBYTE(brgb,rgb)\
{\
  (brgb).r=(unsigned char)((rgb).r*255);\
  (brgb).g=(unsigned char)((rgb).g*255);\
  (brgb).b=(unsigned char)((rgb).b*255);\
}
#define   RGBAU3DTOBYTE(brgba,rgba)\
{\
  (brgba).r=(unsigned char)((rgba).r*255);\
  (brgba).g=(unsigned char)((rgba).g*255);\
  (brgba).b=(unsigned char)((rgba).b*255);\
  (brgba).a=(unsigned char)((rgba).a*255);\
}
//        ================================================================
//        Действия с TL - вершинами
//        ================================================================
//        Построение TL - вершины
#define   MAKE_TLVERTEX(vtx,_sc,_cl,_sp,_tx)\
{\
  (vtx).sc.x=(float)(_sc).x;\
  (vtx).sc.y=(float)(_sc).y;\
  (vtx).sc.z=(float)(_sc).z;\
  (vtx).rw=(float)(1/(_sc).w);\
  RGBAU3DTOBYTE((vtx).cl,(_cl));\
  RGBAU3DTOBYTE((vtx).sp,(_sp));\
  (vtx).tx.u=(float)(tx).u;\
  (vtx).tx.v=(float)(tx).v;\
}
//        ================================================================
//        Действия с сетками общего формата
//        ================================================================
//        Пареллельный перенос сетки
#define   MESHTRANSLATE(ms,ts)\
{\
  int i;\
  for(i=0;i<(ms).nvertices;i++)\
  {\
    (ms).vertex[i].x+=(ts).x;\
    (ms).vertex[i].y+=(ts).y;\
    (ms).vertex[i].z+=(ts).z;\
  }\
}
//        Масштабирование сетки
#define   MESHSCALE(ms,sc)\
{\
  int i;\
  for(i=0;i<(ms).nvertices;i++)\
  {\
    (ms).vertex[i].x*=(sc).x;\
    (ms).vertex[i].y*=(sc).y;\
    (ms).vertex[i].z*=(sc).z;\
  }\
}
//        Умножение каждой вершины справа на 3Х3 - матрицу (поворот)
#define   MESHMUL(ms,ml)\
{\
  int i;\
  vector_t v;\
  for(i=0;i<(ms).nvertices;i++)\
  {\
    MTVECMUL(v,(ml),(ms).vertex[i]);\
    VTCOPY((ms).vertex[i],v);\
  }\
}
//        Билинейное преобразование
#define   MESHHMUL(ms,hml)\
{\
  int i;\
  vector_t v1,v2;\
  for(i=0;i<(ms).nvertices;i++)\
  {\
    VTCOPY(v1,(ms).vertex[i]);\
    MTHVECTRANSFORM(v2,hml,v1);\
    VTCOPY((ms).vertex[i],v2);\
  }\
}
//        Работа с памятью ===============================================
//        Если используется компилятор WATCOM, то определяем встраиваемые
//        макросы для заполнения/обнуления/копирования/сравнения блоков.
#ifdef    ASM_PRAGMAS
//        Заполнения блока памяти
void      MEMFILL(void *blk, int value, int length);
#pragma   aux MEMFILL=\
  "push   edi"\
  "push   ebx"\
  "or     eax, eax"\
  "je     Bye"\
  "mov    edi, eax"\
  "or     ecx, ecx"\
  "jle    Bye"\
  "mov    dh, dl"\
  "mov    ax, dx"\
  "shl    eax, 16"\
  "mov    ax, dx"\
  "mov    ebx, ecx"\
  "shr    ecx, 2"\
  "rep    stosd"\
  "mov    ecx, ebx"\
  "and    ecx, 3"\
  "rep    stosb"\
  "Bye:   pop  ebx"\
  "pop    edi"\
  parm[EAX] [EDX] [ECX] modify[EAX ECX EDX];
//
void      MEMFILL4(void *blk, int value, int length_by_4);
#pragma   aux MEMFILL4=\
  "rep    stosd"\
  parm[EDI] [EAX] [ECX] modify[ECX EDI];
//        Обнуление блока памяти
void      MEMZERO(void *blk, int length);
#pragma   aux MEMZERO=\
  "push   edi"\
  "push   ebx"\
  "or     eax, eax"\
  "je     Bye"\
  "or     edx, edx"\
  "jle    Bye"\   
  "mov    edi, eax"\
  "xor    eax, eax"\
  "mov    ecx, edx"\
  "shr    ecx, 2"\
  "rep    stosd"\
  "mov    ecx, edx"\
  "and    ecx, 3"\
  "rep    stosb"\
  "Bye:  pop  ebx"\
  "pop    edi"\
  parm[EAX] [EDX] modify[EAX ECX EDX];
//
void      MEMZERO4(void *blk, int length_by_4);
#pragma   aux MEMZERO4=\
  "xor    eax, eax"\
  "rep    stosd"\
  parm[EDI] [ECX] modify[EAX ECX EDI];
//        Копирование блока памяти
void      MEMCOPY(void *dst, void *src, int length);
#pragma   aux MEMCOPY=\
  "push   edi"\
  "push   esi"\
  "push   ebx"\
  "mov    edi, eax"\
  "mov    esi, edx"\
  "or     edi, edi"\
  "je     Bye"\
  "or     esi, esi"\
  "je     Bye"\
  "or     ecx, ecx"\
  "jle    Bye"\
  "mov    ebx, ecx"\
  "shr    ecx, 2"\
  "rep    movsd"\
  "mov    ecx, ebx"\
  "and    ecx, 3"\
  "rep    movsb"\
  "Bye:   pop ebx"\
  "pop    esi"\
  "pop    edi"\
  parm[EAX] [EDX] [ECX] modify[EAX ECX EDX];
//
void      MEMCOPY4(void *dst, void *src, int length_by_4);
#pragma   aux MEMCOPY4=\
  "rep    movsd"\
  parm[EDI] [ESI] [ECX] modify[ECX ESI EDI];
//        Сравнение блоков памяти. 0 - если не равны, иначе != 0.
int       MEMIDENT(void *blk1, void *blk2, int length);
#pragma   aux MEMIDENT=\
  "push   edi"\
  "push   esi"\
  "push   ebx"\
  "mov    esi, eax"\
  "xor    eax, eax"\
  "mov    edi, edx"\
  "or     edi, edi"\
  "je     Bye"\
  "or     esi, esi"\
  "je     Bye"\
  "or     ecx, ecx"\
  "jle    Bye"\
  "mov    ebx, ecx"\
  "shr    ecx, 2"\
  "repe   cmpsd"\
  "jne    Bye"\
  "mov    ecx, ebx"\
  "and    ecx, 3"\
  "repe   cmpsb"\
  "jne    Bye"\
  "inc    eax"\
  "Bye:   pop  ebx"\
  "pop    esi"\
  "pop    edi"\
  parm[EAX] [EDX] [ECX] modify[ECX EDX] value[EAX];

#else
//        Если используется другой компилятор, то макросы подставляют
//        функции. Иначе (WATCOM) функции могут использовать макросы.
#define   MEMFILL(b,v,l)                        memset(b,v,l)
#define   MEMZERO(b,l)                          memset(b,0,l)
#define   MEMCOPY(d,s,l)                        memcpy(d,s,l)
#define   MEMIDENT(b1,b2,l)                     (memcmp(b1,b2,l)==0)

#define   memFill(b,v,l)                        memset(b,v,l)
#define   memZero(b,l)                          memset(b,0,l)
#define   memCopy(d,s,l)                        memcpy(d,s,l)
#define   memIdent(b1,b2,l)                     (memcmp(b1,b2,l)==0)

#endif    // ASM_PRAGMAS
//        ================================================================
//        Прототипы функций
//        ================================================================
//        Работа с памятью
#ifdef    ASM_PRAGMAS
DECLSPEC  memFill(void *blk, int value, int length);
DECLSPEC  memZero(void *blk, int length);
DECLSPEC  memCopy(void *dst, void *src, int length);
DECLSPEC_INT    memIdent(void *blk1, void *blk2, int length);
#endif
//        ================================================================
//        Векторные операции
//        ================================================================
DECLSPEC  vtSet(vector_t *pv,u3dval x,u3dval y,u3dval z);
DECLSPEC  vthSet(hvector_t *phv,u3dval x,u3dval y,u3dval z,u3dval w);
DECLSPEC  vtZero(vector_t *pv);
DECLSPEC  vthZero(hvector_t *pv);
DECLSPEC  vtCopy(vector_t *pdst,vector_t *psrc);
DECLSPEC  vthCopy(hvector_t *pdst,hvector_t *psrc);
DECLSPEC  vtAdd(vector_t *pdst,vector_t *pv1,vector_t *pv2);
DECLSPEC  vthAdd(hvector_t *pdst,hvector_t *pv1,hvector_t *pv2);
DECLSPEC  vtSub(vector_t *pdst,vector_t *pv1,vector_t *pv2);
DECLSPEC  vthSub(hvector_t *pdst,hvector_t *pv1,hvector_t *pv2);
DECLSPEC  vtNegate(vector_t *dst, vector_t *src);
DECLSPEC  vthNegate(hvector_t *dst, hvector_t *src);
DECLSPEC  vtMul(vector_t *pdst,vector_t *pv,u3dval ml);
DECLSPEC  vthMul(hvector_t *pdst,hvector_t *pv,u3dval ml);
DECLSPEC  vtDot(vector_t *pv1,vector_t *pv2,u3dval *pres);
DECLSPEC  vthDot(hvector_t *pv1,hvector_t *pv2,u3dval *pres);
DECLSPEC  vtAbs(vector_t *pv,u3dval *pres);
DECLSPEC  vtNormalize(vector_t *pv);
DECLSPEC  vthNormalize(hvector_t *pv);
DECLSPEC  vtHomogenize(hvector_t *pv);
DECLSPEC  vtCross(vector_t *pdst,vector_t *pv1,vector_t *pv2);
DECLSPEC  vtMin(vector_t *pvec,u3dval *pres, int *pind);
DECLSPEC  vtMax(vector_t *pvec,u3dval *pres, int *pind);
DECLSPEC_INT vtIsZero(vector_t *pvec);
DECLSPEC_INT vthIsZero(hvector_t *pvec);
DECLSPEC_INT vtIsEqual(vector_t *pv1,vector_t *pv2);
DECLSPEC_INT vthIsEqual(hvector_t *pv1,hvector_t *pv2);
DECLSPEC  vtScaleBy(vector_t *pdst,vector_t *pv1,vector_t *pv2);
DECLSPEC  vthScaleBy(hvector_t *pdst,hvector_t *pv1,hvector_t *pv2);
DECLSPEC  vtZoomIF(vector_t *zoom,vector_t *initial,vector_t *final);
DECLSPEC  vthZoomIF(hvector_t *zoom,hvector_t *initial,hvector_t *final);
DECLSPEC  vtRadToDeg(vector_t *dst,vector_t *src);
DECLSPEC  vtDegToRad(vector_t *dst,vector_t *src);
//        Проекция точки на плоскость
DECLSPEC  vtProjectOnPlane(vector_t *dst,vector_t *p,vector_t *normal);
DECLSPEC  vtPerpendicular(vector_t *dst,vector_t *src);
//        Поворот точки "point" вокруг вектора "dir"
DECLSPEC  vtRotateAroundVector(vector_t *dst,vector_t *dir,
                               vector_t *point,u3dval radians);
//        ================================================================
//        Матричные операции
//        ================================================================
DECLSPEC  mtZero(matrix_t mat);
DECLSPEC  mthZero(hmatrix_t mat);
DECLSPEC  mttZero(transform_t mat);
DECLSPEC  mtCopy(matrix_t dst,matrix_t src);
DECLSPEC  mthCopy(hmatrix_t dst,hmatrix_t src);
DECLSPEC  mttCopy(transform_t dst,transform_t src);
DECLSPEC  mtIdentity(matrix_t mat);
DECLSPEC  mthIdentity(hmatrix_t mat);
DECLSPEC  mttIdentity(transform_t mat);
//        В качетве dst можно передавать hmatrix_t или matrix_t
DECLSPEC  mtSetLU(u3dval *dst,matrix_t src);
//        В качетве src можно передавать hmatrix_t или matrix_t
DECLSPEC  mtGetLU(matrix_t dst,u3dval *src);
DECLSPEC  mtVectorows(matrix_t mat,vector_t *r1,vector_t *r2,
                      vector_t *r3);
DECLSPEC  mtVectorowsv(matrix_t mat,vector_t *r123);
DECLSPEC  mthVectorows(hmatrix_t mat,hvector_t *r1,hvector_t *r2,
                       hvector_t *r3);
DECLSPEC  mthVectorowsv(hmatrix_t mat,hvector_t *r123);
DECLSPEC  mtVectocols(matrix_t mat,vector_t *c1,vector_t *c2,
                      vector_t *c3);
//        Аналогично транспонированию матрицы
DECLSPEC  mtVectocolsv(matrix_t mat,vector_t *c123);
DECLSPEC  mthVectocols(hmatrix_t mat,hvector_t *c1,hvector_t *c2,
                       hvector_t *c3);
//        Аналогично транспонированию матрицы
DECLSPEC  mthVectocolsv(hmatrix_t mat,hvector_t *c123);
DECLSPEC  mtTranspose(matrix_t dst,matrix_t src);
DECLSPEC  mthTranspose(hmatrix_t dst,hmatrix_t src);
DECLSPEC  mtSelftranspose(matrix_t mat);
DECLSPEC  mthSelftranspose(hmatrix_t mat);
DECLSPEC  mtVecmul(vector_t *dst,matrix_t mat,vector_t *v);
DECLSPEC  mthVecmul(hvector_t *dst,hmatrix_t mat,hvector_t *v);
DECLSPEC  mthVectransform(vector_t *dst,transform_t mat,vector_t *v);
DECLSPEC  mtMul(matrix_t dst,matrix_t m1,matrix_t m2);
DECLSPEC  mthMul(hmatrix_t dst,hmatrix_t m1,hmatrix_t m2);
DECLSPEC  mthMulTransforms(transform_t dst,transform_t m1,transform_t m2);
DECLSPEC  mthConcatTransform(transform_t dst,transform_t tr);
DECLSPEC  mtXRotation(matrix_t mat,u3dval around_x);
DECLSPEC  mtYRotation(matrix_t mat,u3dval around_y);
DECLSPEC  mtZRotation(matrix_t mat,u3dval around_z);
//        ================================================================
//        Действия с цветами
//        ================================================================
DECLSPEC  rgbByteToU3D(rgb_t *rgb, bytergb_t *brgb);
DECLSPEC  rgbaByteToU3D(rgba_t *rgba, bytergba_t *brgba);
DECLSPEC  rgbU3DToByte(bytergb_t *brgb, rgb_t *rgb);
DECLSPEC  rgbaU3DToByte(bytergba_t *brgba, rgba_t *rgba);
//        ================================================================
//        Действия с текстурами
//        ================================================================
//        Это не работает или не проверено. Не используйте !!!
DECLSPEC  texEnvironMap(transform_t mat,vector_t *normal, texcoord_t *uv);
//        ================================================================
//        Это заглушки. Не используйте !!!
DECLSPEC  u3dWarning(char *fmt,...);
DECLSPEC  u3dError(char *fmt,...);
DECLSPEC  u3dFatal(char *fmt,...);
//        ================================================================

#ifdef  OLD_DECLSPEC
#define DECLSPEC      OLD_DECLSPEC
#undef  OLD_DECLSPEC
#endif

#ifdef  OLD_DECLSPEC_INT
#define DECLSPEC_INT  OLD_DECLSPEC_INT
#undef  OLD_DECLSPEC_INT
#endif

#ifdef  OLD_DECLSPEC_PTR
#define DECLSPEC_PTR  OLD_DECLSPEC_PTR
#undef  OLD_DECLSPEC_PTR
#endif

#include  "3dsurf.h"

#endif          // U3D_H_INCLUDED

