2013年9月10日星期二(DEMO8_6矩阵)

2023-11-05

首先设置了2个矩阵

1,把所有的点存储为1*2矩阵

 

         typedef struct MATRIX1X2_TYP

         {

                   float M[2];

         }MATRIX1X2, * MATRIX1X2_PTR;

M     =      |X Y|

,2把所有变换矩阵采用3*2矩阵

typedef struct MATRIX3X2_TYP

         {

                   float M[3][2];

         }MATRIX3X2, * MATRIX3X2_PTR;

分为平移,缩放,旋转3种

(1)        平移

Mt    =       | 1  0  0 |

                   | 0  1  0 |

                   |dx dy  1 |

(2)缩放

                   |sx  0  0 |

MS   =       |0  sy  0 |

                   |0  0   0|

(3)旋转

                   |cosA   sinA    0|

Mr  =       |-sinA   cosA   0|

                   |  0           0       1|

 

平移(矩阵方式)

下面这个函数用来写平移实在是没效率,不过正如作者所说,是个教学目的。不过非常熟悉矩阵了。

int Translate_Polygon2D_Mat( POLYGON2D_PTR poly, int dx, int dy )

{

         if( ! poly )

         {

                   return ( 0 );

         }

         MATRIX3X2 mt;

         Mat_Init_3X2( & mt, 1, 0, 0, 1, dx, dy );

         MATRIX1X2   p0                       = { poly->x0, poly->y0 };

         MATRIX1X2   p1                       = { 0, 0 };

 

         Mat_Mul1X2_3X2( & p0, & mt, & p1 );

 

         poly->x0                              = p1.M[0];

         poly->y0                              = p1.M[1];

         return ( 1 );

}

 

旋转,也是矩阵方式,确实锻炼基础啊。

int Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta)

{

// this function rotates the local coordinates of the polygon

 

// test for valid pointer

if (!poly)

   return(0);

 

// test for negative rotation angle

if (theta < 0)

   theta+=360;

 

MATRIX3X2 mr; // used to hold rotation transform matrix

 

// initialize the matrix with translation values dx dy

Mat_Init_3X2(&mr,cos_look[theta],sin_look[theta],

                 -sin_look[theta],cos_look[theta],

                  0, 0);

 

// loop and rotate each point, very crude, no lookup!!!

for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)

    {

    // create a 1x2 matrix to do the transform

    MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};

    MATRIX1X2 p1 = {0,0}; // this will hold result

 

    // now rotate via a matrix multiply

    Mat_Mul1X2_3X2(&p0, &mr, &p1);

 

    // now copy the result back into vertex

    poly->vlist[curr_vert].x = p1.M[0];

    poly->vlist[curr_vert].y = p1.M[1];

 

    } // end for curr_vert

 

// return success

return(1);

 

} // end Rotate_Polygon2D_Mat

 

放缩

int Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy);

{

         if ( !poly )

         {

                   return ( 0 );

         }

 

         MATRIX3X2 ms;

         Mat_Init_3X2( & ms, sx, 0, 0, sy, 0, 0 );

         for ( int curr_vert = 0; curr_vert < poly->num_verts; curr_vert ++ )

         {

                   MATRIX1X2   p0                       = { poly->vlist[curr_vert].x, poly->vlist[curr_vert].y };

                   MATRIX1X2   p1                       = { 0, 0 };

 

                   Mat_Mul1X2_3X2( & p0, & mr, & p1 );

 

                   poly->vlist[curr_vert].x= p1.M[0];

                   poly->vlist[curr_vert].y= p1.M[1];

         }

 

         return ( 1 );

}

矩阵[1][2] * [3][2]

int Mat_Mul1X2_3X2( MATRIX1X2_PTR ma, MATRIX3X2_PTR mb, MATRIX1X2_PTR mprod )

{

         for( int col = 0; col < 2; col ++ )

         {

                   float sum                    = 0;

 

                   for ( int index = 0; index < 2; index++ )

                   {

                            sum                              += ( ma->M[index] * mb->M[index][col];

                   }

                   sum                                       += mb->M[index][col];

                   mprod->M[col]                   = sum;

         }

         return ( 1 );

}

初始化:

int Mat_Init_3X2( MATRIX3X2_PTR ma, float m00, float m01, float m10, float m11, float m20, float m21 )

{

         ma->M[0][0]              = m00;

         ma->M[0][1]              = m01;

         ma->M[1][0]              = m10;

         ma->M[1][1]              = m11;

         ma->M[2][0]              = m20;

         ma->M[2][1]              = m21;

 

         return ( 1 );

}

在game_main()中,

以前是

// test for scale

         if (KEYDOWN('A')) // scale up

                   Scale_Polygon2D(&asteroid, 1.1, 1.1);

         else

                   if (KEYDOWN('S')) // scale down

                            Scale_Polygon2D(&asteroid, 0.9, 0.9);

现在是矩阵形式

 

         // test for scale

         if (KEYDOWN('A')) // scale up

                   Scale_Polygon2D_Mat(&ship, 1.1, 1.1);

         else

                   if (KEYDOWN('S')) // scale down

                            Scale_Polygon2D_Mat(&ship, 0.9, 0.9);

 

再加上旋转和平移

if ( KEYDOWN( 'Z'))

         {

                   Rotate_Polygon2D_Mat( & ship, -5 );

         }

         else

         if ( KEYDOWN( 'X'))

         {

                   Rotate_Polygon2D_Mat( & ship, 5 );

         }

         if ( KEYDOWN( VK_RIGHT))

         {

                   Translate_Polygon2D_Mat( & ship,5, 0 );

         }

         else

         if ( KEYDOWN( VK_LEFT))

         {

                   Translate_Polygon2D_Mat( & ship,-5, 0 );

         }

         if ( KEYDOWN( VK_UP))

         {

                   Translate_Polygon2D_Mat( & ship,0, -5 );

         }

         else

         if ( KEYDOWN( VK_DOWN))

         {

                   Translate_Polygon2D_Mat( & ship,0, 5 );

         }

 

 

在Game_Init()中,

开始时

srand( GetTickCount())

然后改定

         LPPALETTEENTRY color;

         color->peRed             = 255;

         color->peGreen                   = 0;

         color->peBlue            = 0;

         color->peFlags           =  PC_NOCOLLAPSE;

         ddraw->Set_Palette_Entry( 1, color );

 

         LPPALETTEENTRY color2;

         color2->peRed           = 0;

         color2->peGreen                 = 255;

         color2->peBlue                   = 0;

         color2->peFlags                  =  PC_NOCOLLAPSE;

         ddraw->Set_Palette_Entry( 2, color2 );

 

         LPPALETTEENTRY color3;

         color3->peRed           = 0;

         color3->peGreen                 = 0;

         color3->peBlue                   = 255;

         color3->peFlags                  =  PC_NOCOLLAPSE;

         ddraw->Set_Palette_Entry( 3, color3 );

 

                         

// define points of asteroid

         VERTEX2DF ship_vertices[24] =

         {

                   1, 11,

                   2, 8,

                   1, 7,

                   1, -1,

                   3,-1,

                   3,-2,

                   11,-3,

                   11,-6,

                   3,-7,

                   2,-8,

                   1,-8,

                   1,-7,

                   -1,-7,

                   -1,-8,

                   -2,-8,

                   -3,-7,

                   -11,-6,

                   -11,-3,

                   -3,-2,

                   -3,-1,

                   -1,-1,

                   -1,7,-2,8,-1,11

         };

 

 

         // initialize asteroid

         ship.state       = 1;   // turn it on

         ship.num_verts   = 24; 

         ship.x0          = SCREEN_WIDTH/2; // position it

         ship.y0          = SCREEN_HEIGHT/2;

         ship.xv          = 0;

         ship.yv          = 0;

         ship.color       = 2; // white

         ship.vlist       = new VERTEX2DF [ship.num_verts];

 

         for (int index = 0; index < ship.num_verts; index++)

                   ship.vlist[index] = ship_vertices[index];

 

结果如下图:

封装一下。

成员函数

 

int DDRAW_Interface::Translate_Polygon2D_Mat( POLYGON2D_PTR poly, int dx, int dy )

{

         if( ! poly )

         {

                   return ( 0 );

         }

         MATRIX3X2 mt;

         Mat_Init_3X2( & mt, 1, 0, 0, 1, dx, dy );

         MATRIX1X2   p0                       = { poly->x0, poly->y0 };

         MATRIX1X2   p1                       = { 0, 0 };

 

         Mat_Mul1X2_3X2( & p0, & mt, & p1 );

 

         poly->x0                              = p1.M[0];

         poly->y0                              = p1.M[1];

         return ( 1 );

}

int DDRAW_Interface::Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta)

{

         // this function rotates the local coordinates of the polygon

 

         // test for valid pointer

         if (!poly)

                   return(0);

 

         // test for negative rotation angle

         if (theta < 0)

                   theta+=360;

 

         MATRIX3X2 mr; // used to hold rotation transform matrix

 

         // initialize the matrix with translation values dx dy

         Mat_Init_3X2(&mr,cos_look[theta],sin_look[theta],

                   -sin_look[theta],cos_look[theta],

                   0, 0);

 

         // loop and rotate each point, very crude, no lookup!!!

         for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)

         {

                   // create a 1x2 matrix to do the transform

                   MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};

                   MATRIX1X2 p1 = {0,0}; // this will hold result

 

                   // now rotate via a matrix multiply

                   Mat_Mul1X2_3X2(&p0, &mr, &p1);

 

                   // now copy the result back into vertex

                   poly->vlist[curr_vert].x = p1.M[0];

                   poly->vlist[curr_vert].y = p1.M[1];

 

         } // end for curr_vert

 

         // return success

         return(1);

 

} // end Rotate_Polygon2D_Mat

int DDRAW_Interface::Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy)

{

         if ( !poly )

         {

                   return ( 0 );

         }

 

         MATRIX3X2 ms;

         Mat_Init_3X2( & ms, sx, 0, 0, sy, 0, 0 );

         for ( int curr_vert = 0; curr_vert < poly->num_verts; curr_vert ++ )

         {

                   MATRIX1X2   p0                       = { poly->vlist[curr_vert].x, poly->vlist[curr_vert].y };

                   MATRIX1X2   p1                       = { 0, 0 };

 

                   Mat_Mul1X2_3X2( & p0, & ms, & p1 );

 

                   poly->vlist[curr_vert].x= p1.M[0];

                   poly->vlist[curr_vert].y= p1.M[1];

         }

 

         return ( 1 );

}

 

int DDRAW_Interface::Mat_Mul1X2_3X2( MATRIX1X2_PTR ma, MATRIX3X2_PTR mb, MATRIX1X2_PTR mprod )

{

         int index;

         for( int col = 0; col < 2; col ++ )

         {

                   float sum                    = 0;

 

                   for (  index = 0; index < 2; index++ )

                   {

                            sum                              += ( ma->M[index] * mb->M[index][col];

                   }

                   sum                                       += mb->M[index][col];

                   mprod->M[col]                   = sum;

         }

         return ( 1 );

}

int DDRAW_Interface::Mat_Init_3X2( MATRIX3X2_PTR ma, float m00, float m01, float m10, float m11, float m20, float m21 )

{

         ma->M[0][0]              = m00;

         ma->M[0][1]              = m01;

         ma->M[1][0]              = m10;

         ma->M[1][1]              = m11;

         ma->M[2][0]              = m20;

         ma->M[2][1]              = m21;

 

         return ( 1 );

}

 

Game_init()不变

Game_main()改为

 

         ddraw->Draw_Polygon2D(&ship, ddraw->getbackbuffer(), ddraw->getbacklpitch());

 

        

         // test for scale

         if (KEYDOWN('A')) // scale up

                   ddraw->Scale_Polygon2D_Mat(&ship, 1.1, 1.1);

         else

                   if (KEYDOWN('S')) // scale down

                            ddraw->Scale_Polygon2D_Mat(&ship, 0.9, 0.9);

 

        

                   if ( KEYDOWN( 'Z'))

                   {

                            ddraw->Rotate_Polygon2D_Mat( & ship, -5 );

                   }

                   else

                            if ( KEYDOWN( 'X'))

                            {

                                     ddraw->Rotate_Polygon2D_Mat( & ship, 5 );

                            }

                            if ( KEYDOWN( VK_RIGHT))

                            {

                                      ddraw->Translate_Polygon2D_Mat( & ship,5, 0 );

                            }

                            else

                                     if ( KEYDOWN( VK_LEFT))

                                     {

                                               ddraw->Translate_Polygon2D_Mat( & ship,-5, 0 );

                                     }

                                     if ( KEYDOWN( VK_UP))

                                     {

                                               ddraw->Translate_Polygon2D_Mat( & ship,0, -5 );

                                     }

                                     else

                                               if ( KEYDOWN( VK_DOWN))

                                               {

                                                        ddraw->Translate_Polygon2D_Mat( & ship,0, 5 );

                                               }

 

         // rotate the polygon by 5 degrees

         ddraw->Rotate_Polygon2D(&ship, 5);

 

结果OK

 

,根据T3DLIB进行,将矩阵为数组和结构体的联合体

 

typedef struct MATRIX3X2_TYP

{

         union

         {

                   float M[3][2];

                   struct

                   {

                            float M00, M01;

                            float M10, M11;

                            float M20, M21;

 

                   };

 

         };

 

}MATRIX3X2, * MATRIX3X2_PTR;

 

 

 

typedef struct MATRIX1X2_TYP

{

         union

         {

                   float M[2];

                   struct

                   {

                            float M00, float M01;

                   };

         };

        

}MATRIX1X2, * MATRIX1X2_PTR;

 

补充个

int DDRAW_Interface::Draw_Polygon2D16( POLYGON2D_PTR poly, UCHAR * vbuffer, int lpitch )

{

         int index = 0;

         if( poly->state )

         {

                   for(index = 0; index < poly->num_verts - 1; index ++ )

                   {

                            Draw_Clip_Line16( poly->vlist[index].x + poly->x0,

                                     poly->vlist[index].y + poly->y0,

                                     poly->vlist[index+1].x + poly->x0,

                                     poly->vlist[index+1].y + poly->y0,

 

                                     poly->color,

                                     vbuffer, lpitch );

                   }

                   Draw_Clip_Line16( poly->vlist[0].x + poly->x0,

                            poly->vlist[0].y + poly->y0,

                            poly->vlist[index].x + poly->x0,

                            poly->vlist[index].y + poly->y0,

                            poly->color,

                            vbuffer, lpitch );

 

                   return ( 1 );

         }

         else

                   return ( 0 );

}

在构造函数中,

         m_dwWidth                                  = SCREEN_WIDTH;

         m_dwHeight                                 = SCREEN_HEIGHT;

         m_dwBPP                                              = SCREEN_BPP;

而不是以前的0.

 

我的思路这里有个问题,就是切换区域实际上应该在成员变量里,因为每个窗口未必一样,应该是个变量,

所以设置成员变量。

         int                                                             m_min_clip_x;

         int                                                             m_min_clip_y;

         int                                                             m_max_clip_x;

         int                                                             m_max_clip_y;

构造函数上初始化

 

         m_max_clip_x                            = SCREEN_WIDTH - 1;

         m_max_clip_y                            = SCREEN_HEIGHT - 1;

         m_min_clip_x                    = 0;

         m_min_clip_y                    = 0;

 

相应地,在ddraw_init()中改为

 

         m_min_clip_x                              = 0;

         m_max_clip_x                                      = width - 1;

         m_min_clip_y                              = 0;

         m_max_clip_y                                      = height - 1;

 

         RECT       screen_rect                          = { 0, 0, width, height };

         m_lpddclipper                              = DDraw_Attach_Clipper( m_lpddsback, 1, & screen_rect );

 

以前遗漏了一个

 

int DDRAW_Interface::Set_Palette( LPPALETTEENTRY set_palette )

{

         memcpy( palette, set_palette, MAX_COLORS_PALETTE * sizeof( PALETTEENTRY ) );

         m_lpddpal->SetEntries( 0, 0, MAX_COLORS_PALETTE, palette );

         return ( 1 );

 

}

再一运行发现有问题,改为以前的。

         m_min_clip_x                              = 0;

         m_max_clip_x                                      = width - 1;

         m_min_clip_y                              = 0;

         m_max_clip_y                                      = height - 1;

 

         RECT       screen_rect                          = { 0, 0, width -1, height - 1 };

         m_lpddclipper                              = DDraw_Attach_Clipper( m_lpddsback, 1, & screen_rect );

恢复正常,看来尽信书不如无书。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2013年9月10日星期二(DEMO8_6矩阵) 的相关文章

  • Requests入门

    前言 爬虫三大库 Requests Lxml BeautifulSoup Requests库的官方文档指出 让HTTP服务于人类 Requests库的作用就是请求网站获取网页数据的 今天我们来了解一下Requests库 如果感觉博主的文章还
  • 最新最全GPT-3模型网络结构详细解析

    最近 GPT3很火 现在有很多讲GPT 3的文章 比如讲解它可以做什么 思考它的带来的影响 可视化其工作方式 看了这些文章并不足以详细了解GPT 3模型 仍然需要认真研究相关论文和博客 因此 本文主要目标 帮助其他人对GPT 3体系结构有一
  • 放炮罚计算器软件

    放炮罚计算器软件 放炮罚 又称为百胡 红胡 告胡子 跑胡子 煨胡子 是湖南人喜欢的一种字牌娱乐活动 据说起源于双峰 又称为双峰跑胡子 放炮罚由于其灵活多变 惊险刺激 而广受湖南人民的喜爱 街头巷尾随处可见在玩放炮罚的广大兄弟姐妹 这种字牌游
  • Linux进程之调度器

    1 Linux调度器的原理 Linux调度器 Linux Scheduler 负责管理这一进程在CPU上运行时的资源分配 它根据选定策略和所估算的进程行为 考量各种因素的权重 对等待在运行队列的进程按优先级排列 从而决定哪个进程能够接下来获
  • base64加密解密

    String random UUID randomUUID toString replaceAll substring 0 8 随机八位数字字母结合字符串 System out println random 2458ec59 String
  • 期货开户收费政策非常合理

    需要大家支付的费用由两部分组成 一部分是保证金 另一部分是费率 保证金和费率都由交易所收取 收取的费用是固定的 因为后期大家投资的项目是不一样的 所以需要大家准备的费用肯定也不一样 除了交易所所收取的费用以外 还包括了开户公司所收取的费用
  • 51单片机原理图

    51单片机 TOC

随机推荐

  • ANDROID APP的页面布局(Part I)

    做一个好的APP自然是不能缺少一个好的漂亮的且合理的页面布局了 ANDORID里面支持的布局大致上有下列即种 根据界面的需要使用不同的布局可达到事半功倍的效果 这个跟做HMTL的页面的原理是一样 好的页面看起来就是舒服 而且容易维护 1 L
  • Lambda表达式与函数式编程

    文章目录 函数式编程 Stream流 概述 为什么学 函数式编程思想 Lambda表达式 概述 Lambda表达式的前身 省略规则 Stream流 概述 案例数据准备 创建流 中间操作 终结操作 reduce归并 注意事项 Optional
  • C语言运算符优先级(超详细)

    转自 http blog csdn net huangblog article details 8271791 每当想找哪个运算符优先级高时 很多时候总是想找的就没有 真让人气愤 现在 终于有个我个人觉得非常全的 分享给大家 欢迎拍砖 C语
  • 前端开发面试题及答案整理(合集)

    前端开发面试题及答案 1 对Web标准以及W3C的理解与认识 答 标签闭合 标签小写 不乱嵌套 提高搜索机器人搜索几率 使用外链CSS和JS脚本 结构行为表现的分离 文件下载与页面速度更快 内容能被更多的用户所访问 内容能被更广泛的设备所访
  • Qt 助手 assistant 单独运行 及 字体设置

    曾经在 Qt creator上 不知道点击了哪里 Qt 助手也是可以单独运行的 这样就可以不需要安装字体了 但是 一直没有找到这个重现的规则 或者快捷键 1 运行Qt 助手 assistant linux 所在目录 xxxxxx Qt5 1
  • java调用 Myeclipse用jax-ws创建的webservice具体方法(三)

    首先需要下载所需的jar包 webservices所需全部jar包下载 点击打开链接 直接上代码 import java net MalformedURLException import java net URL import java r
  • 基于亚奈奎斯特采样和SOMP算法的平板脉冲响应空间插值matlab仿真

    目录 1 算法运行效果图预览 2 算法运行软件版本 3 部分核心程序 4 算法理论概述 5 算法完整程序工程 1 算法运行效果图预览 2 算法运行软件版本 matlab2022a 3 部分核心程序 fine regular grid NSa
  • Could not resolve placeholder 'jdbc.driverClassName' in string value "${jdbc.driverClassName}

    org springframework beans factory BeanDefinitionStoreException Invalid bean definition with name dataSource defined in f
  • $.ajaxFileUpload上传文件出现错误...问题总结

    1 加载报错 ajaxfileupload js 1 Uncaught ReferenceError jQuery is not defined 上传报错 Uncaught TypeError ajaxFileUpload is not a
  • C++ Pat甲级1003 Emergency (25 分)图+dfs

    1003 Emergency 25 分 As an emergency rescue team leader of a city you are given a special map of your country The map sho
  • FPGA实现电机转速PID控制

    通过纯RTL实现电机转速PID控制 包括电机编码器值读取 电机速度 正反转控制 PID算法 卡尔曼滤波 最终实现对电机速度进行控制 使其能够渐近设定的编码器目标值 一 设计思路 前面通过SOPC之NIOS 实现电机转速PID控制 调用中断函
  • Android数据库升级解决方案

    方案一 第三方库ActiveAndroid数据库 在对应继承model的实体类中添加的字段 并且对应的数据库版本升级 1 在assert资源文件添加一个migrations文件夹 里面创建文件 版本号 sql 文件中添加数据库脚本 即 AL
  • 最容易理解的JavaScript解决约瑟夫环问题的方式之一

    这种方式虽然效率不是最高的 但绝对是最容易理解的思路之一 function ysf flag stayNum allNum let arr let start 1 for let i 1 i lt allNum i arr push i 当
  • 做爱做的事,做有快感的事

    还是不发首页了 最近没规划 需要缓一缓 因为发首页还是要符合几点要求的 所以就先停停 不过文章还是得写 本来十一点多就写好了 没想到洗个澡就过了十二点 今天就更像聊天了 上一篇说到拖延症 最后留下了一个尾巴 就是怎么找到不会发生拖延症的事去
  • 【Git】(四)子模块

    1 增加子模块 进入准备添加子模块所在的目录 例如library git submodule add b 1 0 0 0 git gitee com sunriver2000 SubModule git 参数 b用于指定子模块分支 2 更新
  • 刷脸支付每个人的脸都具有唯一性无法复制

    移动支付时代 手机成为承载资金的介质 人人手机里有支付宝或者微信支付 但如果手机一旦丢失 不法分子破解了用户密码 那么资金安全也面临威胁 而刷脸支付的第一大优势就在于保证用户资金安全 因为在整个支付过程中 用户完全不用打开手机和自己的资金账
  • [游戏开发][Shader]GLSLSandBox转Unity-CG语言

    官网 GLSL Sandbox Galleryhttps glslsandbox com 屏幕坐标计算 fragCoord与 ScreenParams mat2矩阵转换 vec2向量 在GLSL里mat2 a b c d 函数返回vec2
  • yolov3之数据集预处理

    目录 txt标签文件的说明 将jpg与txt文件分开 txt生成xml标签文件 xml标签详解 xml标签生成txt txt标签文件的说明 获取到的数据集是这样的 需要转换为VOC格式 其实就是将txt转换为xml文件 打开txt文件可以看
  • 在线代码编辑器:Monaco Editor

    monaco editor是微软开源的一款web版代码编辑器 它支持智能提示 代码高亮 代码格式化 Monaco Editor是为VS Code提供支持的代码编辑器 运行在浏览器环境中 编辑器提供代码提示 智能建议等功能 供开发人员远程更方
  • 2013年9月10日星期二(DEMO8_6矩阵)

    首先设置了2个矩阵 1 把所有的点存储为1 2矩阵 typedef struct MATRIX1X2 TYP float M 2 MATRIX1X2 MATRIX1X2 PTR M X Y 2把所有变换矩阵采用3 2矩阵 typedef s