topameng's profileQuake3 启示录PhotosBlogListsMore Tools Help

Blog


    August 22

    tga图像文件格式读取

    根据david mcduffe编写的TGA文件格式资料翻译而成 
    
    本文档是为满足许多对 TGA 图像格式的了解需要而创建的。本文摘录自truevision 
    技术指南的附录 C,如果
    需要更进一步的信息,请致信以下地址:
               at&t
               electronic photography and imaging center
               2002 wellesley ave.
               indianapolis, in 42619
    本文档不求全面,但力求准确。如果你发现了任何拼写错误或内容错误,请告诉我,(
     david mcduffe, 
    75530,2626 ),我将改正这些错误,谢谢。
    
    不全面的原因是 TGA 包含了超过六种图像文件格式,而其中的几种较为常用。 
    我选择了我现在使用的格式并在本文中加以详解。 如果你需要本文中没有包含的格式说明,你可以与你的 
    truevision 代理商联系。
    对所有的 TGA 格式的文件而言,其第三字节(二进制整数)用来区别各种不同的 
    TGA 文件。下面列出了该字节表明的对应文件类型:
        0  -  文件中没有图像数据
        1  -  未压缩的,颜色表图像
        2  -  未压缩的,rgb 图像
        3  -  未压缩的,黑白图像
        9  -  runlength 编码的颜色表图像
        10 -  runlength 编码的 rgb 图像
        11 -  压缩的,黑白图像
        32 -  使用 huffman,delta 和 runlength 编码的颜色表图像
        33 -  使用 huffman,delta 和 runlength 编码的颜色映射图像,4 
    趟四叉树类型处理。
        本文仅仅描述对应 1,2,9 和 10 的文件格式。 代码里则处理了2,3 10的情况
    ----------------------------------------------------------------------------
    |数据类型 1: 颜色表(color-mapped)图像
    |--------|--------|---------------------------------------------------------
    |  偏移   |  长度   |                            描述
    |--------|--------|---------------------------------------------------------
    |    0   |     1  |  图像信息字段(见本子表的后面)的字符数                                                      
    |        |        |  本字段是1字节无符号整型,指出了图像格式区别字段长度     
    |        |        |  其取值范围是 0 到 255 ,当它为 0 时表示没有图像的     
    |        |        |  信息字段。                                
    |--------|--------|---------------------------------------------------------
    |    1   |     1  |  颜色表的类型                                          
    |        |        |  该字段为表示对应格式 1 的图像而包含一个二进制1
    |--------|--------|---------------------------------------------------------
    |    2   |     1  |  图像类型码                                            
    |        |        |  该字段总为 1 , 这也是此类型为格式1的原因               
    |--------|--------|---------------------------------------------------------
    |    3   |     5  |  颜色表规格                                    
    |        |        |                                            
    |    3   |     2  |  颜色标首址
    |        |        |  颜色表首元表项的整型(低位-高位)索引           
    |    5   |     2  |  颜色表的长度                                          
    |        |        |  颜色表的表项总数,整型(低位-高位)   
    |    7   |     1  |  颜色表表项的位(bit)数
    |        |        |  16代表16位TGA ,24代表24位TGA 32代表32位TGA      
    |--------|--------|---------------------------------------------------------
    |    8   |    10  |  图像规格                                              
    |        |        |
    |    8   |     2  |  图像 x 坐标起始位置              
    |        |        |  图像左下角 x 坐标的整型(低位-高位)值            
    |        |        |         
    |   10   |     2  |  图像 y 坐标起始位置      
    |        |        |  图像左下角 y 坐标的整型(低位-高位)值     
    |   12   |     2  |  图像宽度                                 
    |        |        |  以像素为单位,图像宽度的整型(低位-高位)值     
    |   14   |     2  |  图像高度                                  
    |        |        |  以像素为单位,图像高度的整型(低位-高位)值
    |   16   |     1  |  图像每像素存储占用位(bit)数
    |        |        |
    |   17   |     1  |  图像描述符字节                                        
    |        |        |  bits 3-0 - 每像素的属性位(bit)数                
    |        |        |                                                        
    |        |        |  bit 4    - 保留,必须为 0                             
    |        |        |  bit 5    - 屏幕起始位置标志                           
    |        |        |             0 = 原点在左下角                       
    |        |        |             1 = 原点在左上角                       
    |        |        |             truevision 图像必须为 0
    |        |        |  bits 7-6 - 交叉数据存储标志                       
    |        |        |             00 = 无交叉                                
    |        |        |             01 = 两路奇/偶交叉                     
    |        |        |             10 = 四路交叉                              
    |        |        |             11 = 保留                                  
    |        |        |  这一项应该设为 0,不要问我为什么                  
    |--------|--------|---------------------------------------------------------
    |   18   |  可变  |  图像信息字段                                      
    |        |        |  包含一个自由格式的,长度是图像记录块偏移0处的字节中的
    |        |        |  值。它常常被忽略(即偏移 0 处值为 0),注意其最大可以
    |        |        |  含有 255个字符。如果需要存储更多信息,可以放在图像数据
    |        |        |  之后                                                                   
    |--------|--------|---------------------------------------------------------
    |  可变   |  可变   |  颜色表数据    
    |        |        |  起始位置由前一个字段的大小决定;其长度由单项数据大小
    |        |        |  和数据项数目决定(在前面相应的说明字段中给出)
    |        |        |  每项是 2 字节,3 字节或 4字节,字节中没有使用的位(bit)
    |        |        |  被认为是属性位。      
    |        |        |  4 字节表项中,字节 1 表示 BLUE,字节 2 表示 GREEN,
    |        |        |             字节 3 表示 RED,字节 4 表示属性           
    |        |        |  3 字节表项中各字节依次对应 BLUE,GREEN,RED
    |        |        |  2 字节表项中,两个字节分解成如下形式:            
    |        |        |  arrrrrgg gggbbbbb                         
    |        |        | 但是,由于低位在前,高位在后的存储顺序,从文件中读出表项
    |        |        |  时,将先读入 gggbbbbb 而后读入 arrrrrgg ;a 表示属性位
    |--------|--------|---------------------------------------------------------
    |  可变   |  可变   |  图像数据字段                       
    |        |        |  该字段给出了 (高度)x(宽度)个颜色表项索引,每个索引
    |        |        |  以整数个字节的形式存储(典型的例子如 1 或 2 个字节
    |        |        |  所有的数据都没有符号,对于2-字节表项而言,低位字节是
    |        |        |  先存储的。                                                                                  
    ----------------------------------------------------------------------------
    
    ----------------------------------------------------------------------------
    |数据类型 2: 无颜色表 rgb 图像                               
    |--------|--------|---------------------------------------------------------
    |   偏移  |   长度  |       描述                              
    |--------|--------|---------------------------------------------------------
    |    0   |     1  |  图像信息字段( 见本子表的后面 )的字符数                                    
    |        |        |  本字段是 1 字节无符号整型,指出了图像格式区别字段长度
    |        |        |  其取值范围是 0 到 255 ,当它为 0 时表示没有图像的
    |        |        |  信息字段。
    |--------|--------|---------------------------------------------------------
    |    1   |     1  |  颜色表类型                                             
    |        |        |  该字段的内容或者为 0 或者为 1;0 表示没有颜色表,1表示
    |        |        |  颜色表存在。由于本格式是无颜色表的,因此此项通常被忽略
    |        |        |  提示:如果置为 1(targa绘画程序)将把边框颜色设置为映射
    |        |        |        中的第一种颜色
    |--------|--------|---------------------------------------------------------
    |    2   |     1  |  图像类型码
    |        |        |                                                     
    |        |        |  该字段总为 2 , 这也是此类型为格式 2 的原因    
    |--------|--------|---------------------------------------------------------
    |    3   |     5  |  颜色表规格
    |        |        |                              
    |        |        |  如果颜色表类型字段为 0 则被忽略;否则描述如下
    |        |        |  
    |    3   |     2  |  颜色表首址
    |        |        |  颜色表首元入口的整型(低位-高位)索引
    |        |        |                  
    |    5   |     2  |  颜色表的长度
    |        |        |  颜色表的表项总数,整型(低位-高位)     
    |        |        |                                   
    |    7   |     1  |  颜色表表项的位(bit)数
    |        |        |  16代表16位TGA ,24 代表 24 位 TGA ,32 代表 32 位 TGA
    |        |        |                                              
    |--------|--------|---------------------------------------------------------
    |    8   |    10  |  图像规格
    |        |        |                             
    |    8   |     2  |  图像 x 坐标起始位置       
    |        |        |  图像左下角 x 坐标的整型(低位-高位)值
    |   10   |     2  |  图像 y 坐标起始位置
    |        |        |  图像左下角 y 坐标的整型(低位-高位)值
    |   12   |     2  |  图像宽度 
    |        |        |  以像素为单位,图像宽度的整型(低位-高位)值
    |   14   |     2  |  图像高度
    |        |        |  以像素为单位,图像高度的整型(低位-高位)值
    |   16   |     1  |  图像每像素存储占用位(bit)数
    |        |        |  它的值为16,24 或 32 等等决定了该图像是 TGA 16,TGA24
    |        |        |  TGA 32 等等
    |   17   |     1  |  图像描述符字节
    |        |        |  bits 3-0 - 每像素对应的属性位的位数;对于  TGA 16,
    |        |        |             该值为 0 或 1,对于 TGA 24,该值为 0,
    |        |        |             对于 TGA 32,该值为 8       
    |        |        |  bit 4    - 保留,必须为 0
    |        |        |  bit 5    - 屏幕起始位置标志
    |        |        |             0 = 原点在左下角
    |        |        |             1 = 原点在左上角
    |        |        |             对于 truevision 图像必须为 0
    |        |        |  bits 7-6 - 交叉数据存储标志
    |        |        |             00 = 无交叉                                
    |        |        |             01 = 两路奇/偶交叉                     
    |        |        |             10 = 四路交叉                              
    |        |        |             11 = 保留
    |--------|--------|---------------------------------------------------------
    |   18   | 可变    |  图像信息字段                                      
    |        |        |  包含一个自由格式的,长度是图像记录块偏移 0处的字节中的
    |        |        |  值。它常常被忽略(即偏移 0 处值为 0),注意其最大可以
    |        |        |  含有 255个字符。如果需要存储更多信息,可以放在图像数据
    |        |        |  之后                              
    |--------|--------|---------------------------------------------------------
    |  可变   |  可变   |  颜色表数据                                     
    |        |        |                                                
    |        |        |  如果颜色表类型为 0,则该域不存在,否则越过该域直接读取
    |        |        |  图像颜色表规格中描述了每项的字节数,为 2,3,4 之一
    |        |        |  
    |        |        |  
    |        |        |  
    |        |        |  
    |--------|--------|---------------------------------------------------------
    |  可变  |  可变    |  图像数据域                                               
    |        |        |  这里存储了(宽度)x(高度)个像素,每个像素中的 rgb色值
    |        |        |  该色值包含整数个字节                                  
    |        |        |  3 字节表项中各字节依次对应BLUE,GREEN,RED                                 
    |        |        |  2 字节表项中,两个字节分解成如下形式:            
    |        |        |  arrrrrgg gggbbbbb                         
    |        |        | 但是,由于低位在前,高位在后的存储顺序,从文件中读出表项
    |        |        |  时,将先读入 gggbbbbb 而后读入 arrrrrgg ;a 表示属性位                                    
    |        |        |  4 字节表项包含了分别代表 blue,green,red 及属性的四个
    |        |        |  字节;(由于硬件上的原因)有的时候 TGA 24类型的图像也象
    |        |        |  TGA 32 类型的图像那样存储                              
    ----------------------------------------------------------------------------
    
    ----------------------------------------------------------------------------
    |数据类型 9:  runlength 编码,带颜色表的图像
    |--------|--------|---------------------------------------------------------
    |  偏移  |  长度  |                            描述
    |--------|--------|---------------------------------------------------------
    |    0   |     1  |  图像信息字段(见本子表的后面)的字符数                                                  
    |        |        |  本字段是 1 字节无符号整型,指出了图像格式区别字段长度
    |        |        |  其取值范围是 0 到 255 ,当它为 0 时表示没有图像的     
    |        |        |  信息字段。                                         
    |--------|--------|---------------------------------------------------------
    |    1   |     1  |  颜色表的类型                                                                           
    |        |        |  该字段为表示对应带颜色表的图像而总为 1                                   
    |--------|--------|---------------------------------------------------------
    |    2   |     1  |  图像类型码                                    
    |        |        |  本类型该字段为二进制 9                                   
    |--------|--------|---------------------------------------------------------
    |    3   |     5  |  颜色表规格                                   
    |        |        |  如果颜色表类型字段为 0 则被忽略;否则描述如下
    |    3   |     2  |  颜色表首址
    |        |        |  颜色表首元入口的整型(低位-高位)索引    
    |    5   |     2  |  颜色表的长度
    |        |        |  颜色表的表项总数,整型(低位-高位)     
    |    7   |     1  |  颜色表表项的位(bit)数
    |        |        |  16 代表 16 位 TGA ,24 代表24位 TGA 32代表32 位TGA      
    |--------|--------|---------------------------------------------------------
    |    8   |    10  |  图像规格                                                                                 
    |    8   |     2  |  图像 x 坐标起始位置                                 
    |        |        |  图像左下角 x 坐标的整型(低位-高位)值            
    |   10   |     2  |  图像 y坐标起始位置                              
    |        |        |  图像左下角 y 坐标的整型(低位-高位)值                                             
    |   12   |     2  |  图像宽度                                        
    |        |        |  以像素为单位,图像宽度的整型(低位-高位)值                                           
    |   14   |     2  |  图像高度                                        
    |        |        |  以像素为单位,图像高度的整型(低位-高位)值                                    
    |   16   |     1  |  图像每像素存储占用位(bit)数                                  
    |   17   |     1  |  图像描述符字节                                        
    |        |        |  bits 3-0 - 每像素的属性位(bit)数                                                            
    |        |        |  bit 4    - 保留,必须为 0                             
    |        |        |  bit 5    - 屏幕起始位置标志                           
    |        |        |             0 = 原点在左下角                       
    |        |        |             1 = 原点在左上角                       
    |        |        |             truevision 图像必须为 0              
    |        |        |  bits 7-6 - 交叉数据存储标志                       
    |        |        |             00 = 无交叉                                
    |        |        |             01 = 两路奇/偶交叉                     
    |        |        |             10 = 四路交叉                              
    |        |        |             11 = 保留
    |--------|--------|---------------------------------------------------------
    |   18   | 可变   |  图像信息字段                                      
    |        |        |  包含一个自由格式的,长度是图像记录块偏移 0 处的字节中的
    |        |        |  值。它常常被忽略(即偏移 0 处值为 0 ),注意其最大可以
    |        |        |  含有 255 个字符。如果需要存储更多信息,可以放在图像数据
    |        |        |  之后
    |--------|--------|---------------------------------------------------------
    |  可变  |  可变  |  颜色表数据                                      
    |        |        |  起始位置由前一个字段的大小决定;其长度由单项数据大小
    |        |        |  和数据项数目决定(在前面相应的说明字段中给出)
    |        |        |  每项是 2 字节,3 字节或 4字节,字节中没有使用的位(bit)
    |        |        |  被认为是属性位。                          
    |        |        |  4 字节表项中,字节 1 表示 BLUE,字节 2 表示 GREEN,
    |        |        |             字节 3 表示 RED,字节 4 表示属性           
    |        |        |  3 字节表项中各字节依次对应BLUE,GREEN,RED   
    |        |        |  2 字节表项中,两个字节分解成如下形式:            
    |        |        |  arrrrrgg gggbbbbb                         
    |        |        |  但是,由于低位在前,高位在后的存储顺序,从文件中读出表项
    |        |        |  时,将先读入 gggbbbbb 而后读入 arrrrrgg ;a表示属性位
    |--------|--------|---------------------------------------------------------
    | 可变   |  可变  |  图像数据域                                
    |        |        |  本区域给出了(宽度)x(高度)个颜色表索引这些索引存放
    |        |        |  在数据包中;有两中类型的数据包:run-length 数据包,
    |        |        |  以及未加工的数据包,每种类型的数据包含有1-字节的头信息,
    |        |        |  (其中指出了数据包类型和数目),其后是可变长度的数据域
    |        |        |  头信息中最高位为 1 表示 run-length 类型的数据包,当
    |        |        |  它为 0 时,表示未加工的数据包                                    
    |        |        |  对于 run-length 数据包,头信息含义如下
    |        |        |      __________________________________________________
    |        |        |      | 1 bit |   7 位的重复记数减一                   |
    |        |        |      |   id  |   由于 7 位表示的最大值为 127,故最大  |
    |        |        |      |       |   的运行大小为 128,(译注:原文为     |
    |        |        |      |       |   the largest run size)               |
    |        |        |      |-------|----------------------------------------|
    |        |        |      |   1   |  c     c     c     c     c     c    c  |
    |        |        |      --------------------------------------------------                                          
    |        |        |  对于未加工数据包,头信息的含义如下
    |        |        |      __________________________________________________
    |        |        |      | 1 bit |   7 位的像素个数减一                   |
    |        |        |      |   id  |   由于 7 位表示的最大值为 127,故该    |
    |        |        |      |       |   类型的一个数据包中像素个数不能大于   |
    |        |        |      |       |   128                                  |
    |        |        |      |-------|----------------------------------------|
    |        |        |      |   0   |  n     n     n     n     n     n    n  |
    |        |        |      --------------------------------------------------                                          
    |        |        |  对于 run-length 数据包而言,头信息之后是一个简单的
    |        |        |  颜色索引,且假定该索引被重复头信息中低 7 位表示的次数
    |        |        |  run-length 数据包也许会跨越扫描线
    |        |        |  (扫描线起始于某行结束于下一行)
    |        |        |                                                        
    |        |        |  对于未加工的数据包,头信息之后是颜色索引(数值由头信息
    |        |        |  给出)该类型的数据包也可能跨越扫描线
    ----------------------------------------------------------------------------
    
    
    ----------------------------------------------------------------------------
    |数据类型 10:run length 编码,rgb 图像
    |--------|--------|---------------------------------------------------------
    |   偏移 |   长度 |  描述                              
    |--------|--------|---------------------------------------------------------
    |    0   |     1  |  图像信息字段(见本子表的后面)的字符数                                         
    |        |        |  本字段是 1 字节无符号整型,指出了图像格式区别字段长度 
    |        |        |  其取值范围是 0 到 255 ,当它为 0 时表示没有图像的     
    |        |        |  信息字段。 
    |--------|--------|---------------------------------------------------------
    |    1   |     1  |  该字段的内容或者为 0 或者为 1;0 表示没有颜色表,1表示
    |        |        |  颜色表存在。由于本格式是无颜色表的,因此此项通常被忽略
    |        |        |  提示:如果置为 1(targa绘画程序)将把边框颜色设置为映射
    |        |        |        中的第一种颜色                                
    |--------|--------|---------------------------------------------------------
    |    2   |     1  |  图像类型代码
    |        |        |  本类型该字段为二进制 10            
    |--------|--------|---------------------------------------------------------
    |    3   |     5  |  颜色表规格                                
    |        |        |  如果颜色表类型字段为 0 则被忽略;否则描述如下
    |    3   |     2  |  颜色表首址
    |        |        |  颜色表首元入口的整型(低位-高位)索引
    |    5   |     2  |  颜色表的长度
    |        |        |  颜色表的表项总数,整型(低位-高位)     
    |    7   |     1  |  颜色表表项的位(bit)数
    |        |        |  16代表16位 TGA ,24 代表 24 位 TGA ,32 代表 32 位TGA       
    |--------|--------|---------------------------------------------------------
    |    8   |    10  |  图像规格                                                                                         
    |    8   |     2  |  图像 x 坐标起始位置                                
    |        |        |  图像左下角 x 坐标的整型(低位-高位)值            
    |   10   |     2  |  图像 y 坐标起始位置                      
    |        |        |  图像左下角 y 坐标的整型(低位-高位)值            
    |   12   |     2  |  图像宽度                                        
    |        |        |  以像素为单位,图像宽度的整型(低位-高位)值                                                     
    |   14   |     2  |  图像高度                                            
    |        |        |  以像素为单位,图像高度的整型(低位-高位)值                                   
    |   16   |     1  |  图像每像素存储占用位(bit)数                                   
    |   17   |     1  |  图像描述符字节                                        
    |        |        |  bits 3-0 - 每像素的属性位(bit)数                                                 
    |        |        |  bit 4    - 保留,必须为 0                             
    |        |        |  bit 5    - 屏幕起始位置标志                           
    |        |        |             0 = 原点在左下角                       
    |        |        |             1 = 原点在左上角                       
    |        |        |             truevision 图像必须为 0                
    |        |        |  bits 7-6 - 交叉数据存储标志                       
    |        |        |             00 = 无交叉                                
    |        |        |             01 = 两路奇/偶交叉                     
    |        |        |             10 = 四路交叉                              
    |        |        |             11 = 保留                                                            
    |--------|--------|---------------------------------------------------------
    |   18   | 可变   |  图像信息字段                                      
    |        |        |  包含一个自由格式的,长度是图像记录块偏移 0 处的字节中的
    |        |        |  值。它常常被忽略(即偏移 0 处值为 0 ),注意其最大可以
    |        |        |  含有 255个字符。如果需要存储更多信息,可以放在图像数据
    |        |        |  之后                                        
    |--------|--------|---------------------------------------------------------
    |  可变  |  可变  |  颜色表数据                                                                    
    |        |        |  如果颜色表类型为 0,则该域不存在,否则越过该域直接读取
    |        |        |  图像颜色表规格中描述了每项的字节数,为 2,3,4 之一
    |--------|--------|---------------------------------------------------------
    | 可变   |  可变  |  图像数据域                         
    |        |        |  本区域给出了(宽度)x(高度)个颜色表索引这些索引存放
    |        |        |  在数据包中;有两中类型的数据包:run-length 数据包,
    |        |        |  以及未加工的数据包,每种类型的数据包含有1-字节的头信息,
    |        |        |  (其中指出了数据包类型和数目),其后是可变长度的数据域
    |        |        |  头信息中最高位为 1 表示 run-length 类型的数据包,当
    |        |        |  它为 0 时,表示未加工的数据包                             
    |        |        |  对于 run-length 数据包,头信息含义如下
    |        |        |      __________________________________________________
    |        |        |      | 1 bit |   7 位的重复记数减一                   |
    |        |        |      |   id  |   由于 7 位表示的最大值为 127,故最大  |
    |        |        |      |       |   的运行大小为 128,(译注:原文为     |
    |        |        |      |       |   the largest run size)               |  
    |        |        |      |-------|----------------------------------------|
    |        |        |      |   1   |  c     c     c     c     c     c    c  |
    |        |        |      --------------------------------------------------
    |        |        |                                                        
    |        |        |  对于未加工数据包,头信息的含义如下
    |        |        |      __________________________________________________
    |        |        |      | 1 bit |   7 位的像素个数减一                   |
    |        |        |      |   id  |   由于 7 位表示的最大值为 127,故该    |
    |        |        |      |       |   类型的一个数据包中像素个数不能大于   |
    |        |        |      |       |   128                                  |
    |        |        |      |-------|----------------------------------------|
    |        |        |      |   0   |  n     n     n     n     n     n    n  |
    |        |        |      --------------------------------------------------
    |        |        |
    |        |        |  对于 run length 数据包,头信息之后是一个简单颜色值,
    |        |        |  且假定该值重复的次数为头信息中记录的数
    |        |        |  run-length 数据包也许会跨越扫描线
    |        |        |  (扫描线起始于某行结束于下一行)                                      
    |        |        | 对于未加工数据包,头信息之后是颜色值(数目由头信息指出)                                 
    |        |        |  颜色表项自身有 2-字节,3-字节或 4-字节几种大小(分别
    |        |        |  对应 TGA 16,TGA 24 和 TGA 32)形式如下:
    |        |        |  3 字节表项中各字节依次对应BLUE,GREEN,RED           
    |        |        |  2 字节表项中,两个字节分解成如下形式:            
    |        |        |  arrrrrgg gggbbbbb                         
    |        |        |但是,由于低位在前,高位在后的存储顺序,从文件中读出表项  
    |        |        |  时,将先读入 gggbbbbb 而后读入 arrrrrgg ;a 表示属性位
    |        |        |
    |        |        |  4 字节表项包含了分别代表 blue,green,red 及属性的四个
    |        |        |  字节;(由于硬件上的原因)有的时候 TGA 24类型的图像也象
    |        |        |  TGA 32 类型的图像那样存储
    ----------------------------------------------------------------------------
    quake3 中读取 tga 图像代码:
    name 要加载的图片名称. 指向pic 返回的 tga 图片像素数据.width 返回图片宽度.height 返回图片高度
    ri.FS_ReadFile 读取文件,并返回文件内容指针
    ri.FS_FreeFile 释放文件内容缓存
    ri.Malloc 分配内存
    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;

    static void LoadTGA ( const char *name, byte **pic, int *width, int *height)
    {
     int  columns, rows, numPixels;
     byte *pixbuf;
     int  row, column;
     byte *buf_p;
     byte *buffer;
     TargaHeader targa_header;
     byte  *targa_rgba;
     *pic = NULL;
     // load the file
     ri.FS_ReadFile ( ( char * ) name, (void **)&buffer);
     if (!buffer)
     {
      return;
     }
     buf_p = buffer;
     targa_header.id_length = *buf_p++;
     targa_header.colormap_type = *buf_p++;    //如果colormap_type为0从18位开始为图像数据
     targa_header.image_type = *buf_p++;         // 第三个字节为文件类型
     targa_header.colormap_index = LittleShort ( *(short *)buf_p );  //对于 win32 LittleShort 是空的宏
     buf_p += 2;
     targa_header.colormap_length = LittleShort ( *(short *)buf_p );
     buf_p += 2;
     targa_header.colormap_size = *buf_p++;
     targa_header.x_origin = LittleShort ( *(short *)buf_p );   //8  图像 x 坐标起始位置                               
     buf_p += 2;
     targa_header.y_origin = LittleShort ( *(short *)buf_p );   //10 图像 y 坐标起始位置  
     buf_p += 2;
     targa_header.width = LittleShort ( *(short *)buf_p );    //12 图像宽度
     buf_p += 2;
     targa_header.height = LittleShort ( *(short *)buf_p );    //14 图像高度
     buf_p += 2;
     targa_header.pixel_size = *buf_p++;         //16 图像每像素存储占用位(bit)数   
     targa_header.attributes = *buf_p++;         //17 
     //2  -  未压缩的,rgb 图像
     //3  -  未压缩的,黑白图像
     //10 -  runlength 编码的 rgb 图像
     if (targa_header.image_type!=2&& targa_header.image_type!=10&& targa_header.image_type != 3 ) 
     {
      ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
     }
     //该字段的内容或者为 0 或者为 1,0 表示没有颜色表,1 表示颜色表存在.格式 2,3,10 是无颜色表的
     if ( targa_header.colormap_type != 0 )
     {
      ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" );
     }
     //图像每像素存储占用位(bit)数   
     if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
     {
      ri.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 = (byte *)ri.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 || targa_header.image_type == 3 )
     {
      // Uncompressed RGB or gray scale image
      for(row=rows-1; row>=0; row--)
      {
       pixbuf = targa_rgba + row*columns*4;
       for(column=0; column<columns; column++)
       {
        unsigned char red,green,blue,alphabyte;
        switch (targa_header.pixel_size)
        {
        case 8:
         blue = *buf_p++;
         green = blue;
         red = blue;
         *pixbuf++ = red;
         *pixbuf++ = green;
         *pixbuf++ = blue;
         *pixbuf++ = 255;
         break;
        case 24:
         blue = *buf_p++;
         green = *buf_p++;
         red = *buf_p++;
         *pixbuf++ = red;
         *pixbuf++ = green;
         *pixbuf++ = blue;
         *pixbuf++ = 255;
         break;
        case 32:
         blue = *buf_p++;        //tga 存放像素以BGRA 顺序。我们需要转换为 RGBA 顺序
         green = *buf_p++;
         red = *buf_p++;
         alphabyte = *buf_p++;
         *pixbuf++ = red;
         *pixbuf++ = green;
         *pixbuf++ = blue;
         *pixbuf++ = alphabyte;
         break;
        default:
         ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
         break;
        }
       }
      }
     }
     else if (targa_header.image_type==10)
     {   // Runlength encoded RGB images
      unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
      red = 0;
      green = 0;
      blue = 0;
      alphabyte = 0xff;
      for(row=rows-1; row>=0; row--)
      {
       pixbuf = targa_rgba + row*columns*4;
       for(column=0; column<columns; )
       {
        packetHeader= *buf_p++;
        packetSize = 1 + (packetHeader & 0x7f);
        if (packetHeader & 0x80)
        {        // run-length packet
         switch (targa_header.pixel_size)
         {
          case 24:
           blue = *buf_p++;
           green = *buf_p++;
           red = *buf_p++;
           alphabyte = 255;
           break;
          case 32:
           blue = *buf_p++;
           green = *buf_p++;
           red = *buf_p++;
           alphabyte = *buf_p++;
           break;
          default:
           ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
           break;
         }
         for(j=0;j<packetSize;j++)
         {
          *pixbuf++=red;
          *pixbuf++=green;
          *pixbuf++=blue;
          *pixbuf++=alphabyte;
          column++;
          if (column==columns)
          { // run spans across rows
           column=0;
           if (row>0)
            row--;
           else
            goto breakOut;
           pixbuf = targa_rgba + row*columns*4;
          }
         }
        }
        else {                            // non run-length packet
         for(j=0;j<packetSize;j++)
         {
          switch (targa_header.pixel_size)
          {
           case 24:
            blue = *buf_p++;
            green = *buf_p++;
            red = *buf_p++;
            *pixbuf++ = red;
            *pixbuf++ = green;
            *pixbuf++ = blue;
            *pixbuf++ = 255;
            break;
           case 32:
            blue = *buf_p++;
            green = *buf_p++;
            red = *buf_p++;
            alphabyte = *buf_p++;
            *pixbuf++ = red;
            *pixbuf++ = green;
            *pixbuf++ = blue;
            *pixbuf++ = alphabyte;
            break;
           default:
            ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
            break;
          }
          column++;
          if (column==columns)
          { // pixel packet run spans across rows
           column=0;
           if (row>0)
            row--;
           else
            goto breakOut;
           pixbuf = targa_rgba + row*columns*4;
          }      
         }
        }
       }
    breakOut:;
      }
     }

     // instead we just print a warning
     if (targa_header.attributes & 0x20)
     {
      ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
     }
     ri.FS_FreeFile (buffer);
    August 06

    quake3 使用到的 opengl 函数说明

    对于opengl 扩展函数必须在初始化窗口结束后才能使用 wglGetProcAddress 获得

    Opengl 没有重载函数,对于功能相同但参数类型和数量不同的函数加上后缀,最长可达4个,第一个字符指出有几个参数,第4个为v(如果有的话),指出函数接受一个地址做为参数
    //opengl1.1版本扩展函数,用来切换纹理层,参数如下
    #define GL_TEXTURE0_ARB                     0x84C0
    #define GL_TEXTURE1_ARB                     0x84C1
    #define GL_TEXTURE2_ARB                     0x84C2
    #define GL_TEXTURE3_ARB                     0x84C3

    1.void ( APIENTRY * glActiveTextureARB)( GLenum texture );
    调用扩展提供的函数glActiveTextureARB()来指定当前操作的是哪一个纹理单元,在下一次调用glActiveTextureARB之前所有的函数适用于当前选定的纹理单元
    glActiveTextureARB的Active不能理解为激活,使发生作用!!!应理解为选择(Select)某纹理单元(Texture Unit),即表示后续的
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture);
    作用于此所选的纹理单元.而glEnable(GL_TEXTURE_2D)才是真正激活纹理单元的调用. 新函数 qlActiveTexture

        glActiveTextureARB(GL_TEXTURE0_ARB);  // 选择TEXTURE0为设置目标
        glEnable(GL_TEXTURE_2D);                    // 激活TEXTURE0单元
        glBindTexture(GL_TEXTURE_2D, texture); // 为TEXTURE0单元绑定texture纹理图像
        glActiveTextureARB(GL_TEXTURE1_ARB);  // 选择TEXTURE1为设置目标
        glDisable(GL_TEXTURE_2D);                   // 关闭禁用TEXTURE1单元
        glDrawArrays(GL_TRIANGLE_STRIP, 0, NUM_STRIP_VERTICE); // 由于TEXTURE1单元被关闭,执行此Pass渲染时只有TEXTURE0单元发生了作用。

    如果,
    glActiveTextureARB(GL_TEXTURE1_ARB);  // 选择TEXTURE1为设置目标
    glEnable(GL_TEXTURE_2D);                     // 激活TEXTURE1单元
    glBindTexture(GL_TEXTURE_2D, alphaTex); // 为TEXTURE1单元绑定alphaTex纹理图像
    此时由于有2个纹理单元被激活,glDrawArrays调用将Blend两个纹理单元形成最终的画面.

    2.void ( APIENTRY * glClientActiveTextureARB )( GLenum texture );
    要设置纹理单元的纹理顶点数组,不能使用glActiveTextureARB,而应该使用glClientActiveTextureARB,如:
    glClientActiveTextureARB(GL_TEXTURE0_ARB);
    glTexCoordPointer(2, GL_FLOAT, 0, tp0);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    关闭多重纹理:禁用所有非GL_TEXTURE0_ARB层纹理,最后激活GL_TEXTURE0_ARB纹理
    glActiveTextureARB(GL_TEXTURE1_ARB);
    glDisable(GL_TEXTURE_2D);
    glActiveTextureARB(GL_TEXTURE0_ARB);
    glEnable(GL_TEXTURE_2D);
    特别需要小心的是:既不能在glActiveTextureARB状态下使用glTexCoordPointer设置当前纹理单元的纹理坐标数组指针,更不能在glClientActiveTextureARB状态下设置当前纹理单元的非Client属性,即此时调用的glEnable(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D, tex);均为无效操作.
    glEnableClientState必须进入glClientActiveTextureARB状态后设置才对纹理单元有效,在外部所作设置修改不了纹理单元的设置.

     
    对应的头文件 qgl.h : quake 中采用 q+opengl函数名 替代被使用的opengl函数

    extern void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t );
    /*opgl1.0版本扩展函数
    为了方便指定包含多组纹理坐标的顶点数组,opengl提供了命令glClientActiveTexture。应用程序使用glTexCoordPointer()指定纹理坐标数组时,Opengl将这组纹理坐标分配给glClientActiveTexture指定的纹理单元
    /*
    extern void ( APIENTRY * qglActiveTextureARB )( GLenum texture );
    extern void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );
     
    /*
     
    */
    extern void ( APIENTRY * qglLockArraysEXT) (GLint, GLint);
    extern void ( APIENTRY * qglUnlockArraysEXT) (void);

    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);
    /*
    tells OpenGL to bind the named texture texture to a texture target
    将纹理名字texture代表的纹理绑定到纹理目标上。
    target: GL_TEXTURE_1D 或者 GL_TEXTURE_2D,代表纹理的维数
    texture: 一个数字用来绑定并代表一个纹理目标。
    使用它来切换纹理
    */
    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);
    /*
    混合方程:
    c = (src * sfactor) + (dst * dfactor)
    参数 RGB混合因子

    Alpha 混合因子

    GL_ZERO

    (0,0,0)

    0

    GL_ONE

    (1,1,1)

    1

    GL_SRC_COLOR

    (Rs,Gs,Bs)

    As

    GL_ONE_MINUS_SRC_COLOR

    (1,1,1) - (Rs,Gs,Bs)

    1 - As

    GL_DST_COLOR

    (Rd,Gd,Bd)

    Ad

    GL_ONE_MINUS_DST_COLOR

    (1,1,1) - (Rd,Gd,Bd)

    1-Ad

    GL_SRC_ALPHA

    (As,As,As)

    As

    GL_ONE_MINUS_SRC_ALPHA

    (1,1,1) - (As,As,As)

    1-As

    GL_DST_ALPHA

    (Ad,Ad,Ad)

    Ad

    GL_ONE_MINUS_DST_ALPHA

    (1,1,1) - (Ad,Ad,Ad)

    1-Ad

    GL_SRC_ALPHA_SATURATE

    (f,f,f)*

    1

     
    例如:半透明效果
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    设:
    dst = (1.0f,0.0f,0.0f,0.0f)  red
    src = (0.0f,0.0f,1.0f,0.3f)  blue
    sfactor = 源Alpha值 = 0.3f
    dfactor = 1 - 源Alpha值 = 1 - 0.3f
    则最终混合后颜色:
    c = (blue * 0.3f) + (red * 0.7f)
    sfactor 是输入的片元颜色值混合参数。dfactor 是目前帧缓存中的像素颜色值混合参数
    */
    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);
    /*
    清空帧缓存。mask 可以设置为GL_COLOR_BUFFER_BIT 清空颜色缓存 GL_DEPTH_BUFFER_BIT 清空深度缓存 GL_STENCIL_BUFFER_BIT 清空模板缓存
    例如: glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
    */
    extern  void ( APIENTRY * qglClear )(GLbitfield mask);
    extern  void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
    /*
    指定glClear 清空颜色缓存时使用的颜色,取值范围 0.0-1.0
    例如: qglClearColor( 1, 0, 0.5, 1 )
    */
    extern  void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
    /*glClearDepth 指定 glClear 函数清除深度缓存使用的深度值
    当调用glClear(GL_DEPTH_BUFFER_BIT)时清空深度缓存写入深度值depth,如果不通过glClearDepth设置,默认写入最大的深度值
    例如: glClearDepth( 1.0f )
    */
    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);
     
    /*提交颜色数组供OpenGL使用
    size:  数据大小 . 如:4
    type:  数据类型. 如:GL_UNSIGNED_BYTE ,颜色数据针对 GL_UNSIGNED_BYTE  做了优化。
    stride: 如果数据是紧密连接指定其为0,否则为颜色数据之间的跨距
    pointer: 数组的位置
    例如:
    qglColorPointer( 4,GL_UNSIGNED_BYTE,0,colors);
    */
    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);
    /*
    OpenGl 面剔除特性根据填充图元面对的方向决定是否将其丢弃,使用前需要掉用 glEnable(GL_CULL_FACE)
    mode 参数:
    GL_FRONT  剔除正面
    GL_BACK    剔除背面
    */
    extern  void ( APIENTRY * qglCullFace )(GLenum mode);
    extern  void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range);
    extern  void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);
    /*
    深度值比较,默认为 GL_LESS 如果片元窗口空间z值小于存储的在深度缓存中的值,片元将通过深度测试。
    如果参数为GL_LEQUAL, 片元窗口空间z值小于或等于存储的在深度缓存中的值,片元将通过深度测试。
    这在multipass中很有用。
    例如: glDepthFunc( GL_LEQUAL )
    */
    extern  void ( APIENTRY * qglDepthFunc )(GLenum func);

    /*
    调用glDepthMask(GL_FALSE);可将深度缓冲区设置为只读形式。
    调用glDepthMask(GL_TRUE);可将深度缓冲区设置为可读可写形式
    画透明物体时必须将深度缓冲区设置为只读形式.防止深度缓冲起作用,不画透明物体后面的物体
    */
    extern  void ( APIENTRY * qglDepthMask )(GLboolean flag);

    /*
    深度缓冲区所存储的值范围在-1.0-1.0之间。这个函数允许把一个特定的线性深度值映射到一个标准范围的窗口z坐标。窗口z值的缺省范围是0到1,分别对应近和远裁剪平面
    */
    extern  void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);
    extern  void ( APIENTRY * qglDisable )(GLenum cap);
    extern  void ( APIENTRY * qglDisableClientState )(GLenum array);
     
    /*
    只用1个函数的调用就可以替代几个函数调用:glNormal glColor glVertex 等等
    mode: 指定要被渲染的图元
    first: 指定从已启用数组什么位置开始
    count: 表示有多少个数组元素被提取
    */
    extern  void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count);
     
    /*
    指定要写入的缓存,使用双缓存时,通常只绘制后缓存,并在绘制完成后交换缓存。
    还可以指定要将立体图像(电子眼镜)渲染到那个缓存(GL*LEFT 和 GL*RIGHT),以及将图像渲染到辅助缓存(GL_AUXi)中
    使用单缓存时,mode默认为 GL_FRONT,  使用双缓存时,mode 默认为GL_BACK
    */
    extern  void ( APIENTRY * qglDrawBuffer )(GLenum mode);
     
    /*
    绘制单个Opengl图元,mode可以是任何合法的OpenGL图元类型:GL_POINTS  GL_LINES  GL_TRIANGLES
    count: 要渲染的索引个数
    type: 是数组indeces的数据类型
    indices 是一个索引数组
    例如: qglDrawElements( GL_TRIANGLES,numIndexes,GL_UNSIGNED_INT,indexes );
    */
    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);
    /*
    设置Opengl特性的启用状态。
    默认情况大多数OpenGL特性都被禁用,事实上只有两项特性默认被起用,抖动(GL_DITHER) 和多重采样(GL_MULTISMAPLE)
    实际上游戏很多时候不需要抖动
    GL_BLEND 混合
    GL_DEPTH_TEST 深度测试
    GL_LIGHTING 光照
    GL_ALPHA_TEST 启用alpha测试
    GL_CULL_FACE 启用面剔除
    GL_TEXTURE_2D  启用2维纹理映射模式

    例如: glEnable(GL_DEPTH_TEST) 启动深度测试
    */
    extern  void ( APIENTRY * qglEnable )(GLenum cap);
     
    /*
    启用Opengl客户端状态:
    array:
    GL_VERTEX_ARRAY                 启用顶点数组
    GL_NORMAL_ARRAY                启用法线数组
    GL_TEXTURE_COORD_ARRAY  启用纹理坐标数组
    GL_COLOR_ARRAY                   启用颜色数组
    */
    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);
    /*
    The glFinish function does not return until the effects of all previously called OpenGL functions are complete. Such effects include all changes to the OpenGL state, all changes to the connection state, and all changes to the framebuffer contents.
    阻塞直到Opengl 执行命令结束
    */
    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);
    /*
    返回 Opengl 错误信息
    GL_NO_ERROR
    没有错误. 这个常量值为0
    GL_INVALID_ENUM
    向 Opengl 命令传递了无效的枚举值
    GL_INVALID_VALUE
    向 Opengl 传递的值不再允许的范围内
    GL_INVALID_OPERATION
    发出的Opengl 命令非法(就当前状态而言,此函数命令不合适)
    GL_STACK_OVERFLOW
    命令导致Opengl堆栈溢出
    GL_STACK_UNDERFLOW
    命令导致Opengl堆栈下溢
    GL_OUT_OF_MEMORY
    Opengl 无法分配足够的内存来处理命令
    Opengl 错误是应用程序的bug,需要修改代码。在应用程序中,通常在初始化后面以及渲染动画中的每帧后调用glGetError().为了避免影响性能通常在非生产代码中调用它
    如: assert(glGetError() == GL_NO_ERROR);
    */
    extern  GLenum ( APIENTRY * qglGetError )(void);
    extern  void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params);
    /*
    查询特定的阀值
    GL_MAX_TEXTURE_SIZE  查询支持的最大纹理大小
    GL_MAX_TEXTURE_UNITS  查询支持的纹理单元个数 quake3 中重定义为 GL_MAX_ACTIVE_TEXTURES_ARB
    GL_MAX_ELEMENTS_VRTICES  最大支持的顶点数
    GL_MAX_ELEMENTS_INDICES   最大支持的索引数
    GL_MAX_LIGHTS  查询支持的最大灯光数量
    */
    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);
    /*
    查询信息
    根据name的值返回不同的字符串值
    GL_VENDOR: 返回OpenGL 实现的厂商
    GL_VERSION:返回OpenGL 版本
    GL_EXTENSISONS:返回OpenGL实现中可用的扩展
    GL_RENDERER: 返回厂商特定的渲染器信息
    必须具备渲染上下文时才能调用这个函数
    */
    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);
    /*
    修改当前活动矩阵堆栈的栈顶,将栈顶矩阵替换为矩阵m
    */
    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);
    /*
    mode 可以为 GL_PROJECTION GL_MODELVIEW 或 GL_TEXTURE
    选择活动矩阵堆栈:
    GL_PROJECTION 选择投影矩阵堆栈
    GL_MODELVIEW 选择模型视点矩阵堆栈
    */
    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);
    /*
    Opengl可以将填充图元渲染为线段或点。
    mode 可以为 GL_POINT 绘制点 GL_LINE 绘制多边形线框 GL_FILL填充多边形
    face 可以为 GL_FONT GL_BACK GL_FONT_AND_BACK 它指定用于正面图元,背面图元还是两者
    glPloygonMode(GL_FONT_AND_BACK,GL_FILL)
    */
    extern  void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);
    extern  void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);
    extern  void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask);
    //glPopAttrib此函数未使用
    extern  void ( APIENTRY * qglPopAttrib )(void);
    //glPopClientAttrib 此函数未使用
    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);
    /*
    裁剪测试,可以定义窗口中的一个矩形区域,并将作图限制在其中。若片元部分落在该矩形区,则剪取测试通过,否则片元被删除。超出的部分不会画出
    启用裁剪测试 qglEnable(GL_SCISSOR_TEST)
    qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
    */
    extern  void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
    extern  void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer);
    /*
    指定使用平滑着色还是恒定着色。mode  可以是 GL_SMOOTH 或 GL_FLAT。
    默认为平滑着色,Opengl 在渲染时对顶点颜色执行插值计算
    如果用GL_FLAT,一般使用最后一个顶点做为图元的颜色
    qglShadeModel( GL_SMOOTH );
    */
    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);
    /*
    应用程序使用glTexCoorPointer()指定纹理坐标数组时,Opengl将这组纹理坐标分配给glClientActiveTexture指定的纹理单元.
    定义一组纹理坐标数组,用于OpenGL的顶点数组功能
    size 每个数组元素坐标数量。有效值 1-4
    type 数组的数据类型.GL_FLOAT GL_INT GL_SHORT GL_DOUBLE
    stride 数组坐标之间的字节偏移。0 表示数据是紧密相邻的
    pointer 一个指定顶点数组的数据开始位置的指针
    例如:
    qglTexCoordPointer( 2, GL_FLOAT, 0, texcoords[0] );
    */
    extern  void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

    /*
    在进行纹理贴图时,纹理贴图可以直接贴到物体上从而覆盖物体已有的颜色,也可以和物体原有的颜色进行融合。融合是一种重要的图像处理技术,主要用于透明,发光等等效果的处理。
    void glTexEnvf(GLenum target,GLenum pname,GLfloat param);
    target
    的参数必须是GL_TEXTURE_ENV;
    pname的参数可以为GL_TEXTURE_ENV_MODEGL_TEXTURE_ENV_COLOR;
    param可以为GL_MODULATEGL_DECALGL_BLEND 、GL_ADD、GL_REPLACE 等等
    */

    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);

    /*qglTexImage2D 定义一个二维纹理映射。
    参数target必须是常数GL_TEXTURE_2D
    参数level表示多级分辨率的纹理图像的级数(mipmap level),若只有一种分辨率,则level设为0。Level n is the nth mipmap reduction image
    参数internalformat纹理像素中存储那些分量.可以是1到4的整数,指出选择了R、G、B、A中的哪些分量用于调整和混合,1表示选择了R分量,2表示选择了R和A两个分量,3表示选择了R、G、B三个分量,4表示选择了R、G、B、A四个分量. 或者是如下的值:红色为quake3中用到的
    GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_ALPHA12, GL_ALPHA16, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, GL_LUMINANCE12, GL_LUMINANCE16, GL_LUMINANCE_ALPHA, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12, GL_LUMINANCE16_ALPHA16, GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY12, GL_INTENSITY16, GL_R3_G3_B2, GL_RGB, GL_RGB4, GL_RGB5, GL_RGB8(24位), GL_RGB10, GL_RGB12, GL_RGB16, GL_RGBA, GL_RGBA2, GL_RGBA4(16位), GL_RGB5_A1, GL_RGBA8(32位),GL_RGB4_S3TC,GL_RGB10_A2, GL_RGBA12, or GL_RGBA16.
    参数width和height给出了纹理图像的长度和宽度.
    参数border为纹理边界宽度,它通常为 0
    width和height必须是2n + 2(border),这里n是整数,长和宽可以有不同的值,b是border的值。
    纹理映射的最大尺寸依赖于OpenGL,但它至少必须是使用64x64(若带边界为66x66),若width和height设置为0,则纹理映射有效地关闭。

    参数format和type描述了输入图像数据pixels的格式和类型,它们在这里的意义与在函数glDrawPixels()中的意义相同,事实上,纹理数据与glDrawPixels()所用的数据有同样的格式。
    参数format可以是GL_COLOR_INDEX、GL_RGB、GL_RGBA、GL_RED、GL_GREEN、GL_BLUE、GL_ALPHA、GL_LUMINANCE或GL_LUMINANCE_ALPHA(注意:不能用GL_STENCIL_INDEX和GL_DEPTH_COMPONENT)。

    参数type是GL_BYPE、GL_UNSIGNED_BYTE、GL_SHORT、 GL_UNSIGNED_SHORT、GL_INT、GL_UNSIGNED_INT、GL_FLOAT或GL_BITMAP。  0-255RGBA 类型数据 对应GL_UNSIGNED_BYTE 类型
    参数pixels 指向纹理图像数据,A pointer to the image data in memory。
    例子: qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
    如果低于 opengl 1.4 glTexImage2D 不支持自动 mipmap . 且没有手动设置mipmap。既对不同level指定纹理数据
    设置纹理滤波时只能使用 GL_LINEAR.否则没有图像显示
    qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    */
    extern  void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);

    /*滤波
    设置如何将纹理图像的纹理对应到屏幕上的像素;当纹理图像较大或较小时,怎样通过纹理贴图实现纹理缩放和重复。
    void glTexParameterf(GLenum target,GLenum pname,GLfloat param);
    target 的参数可以为GL_TEXTURE_1D(1维纹理)GL_TEXTURE_2D(2维纹理), GL_TEXTURE_3D(3维纹理) 或 GL_TEXTURE_CUBE_MAP
    pname 的参数可以为: GL_TEXTURE_MAG_FILTER (指定放大滤波)或 GL_TEXTURE_MIN_FILTER(指定缩小滤波)

    pname

    含义

    param常用值

    GL_TEXTURE_MIN_FILTER

    一个像素对应多个纹素.
    放大滤波

    GL_NEAREST 使用坐标离像素中心最近的纹理像素,最近点采样
    GL_LINEAR  离像素坐标中心2x2纹理像素,线性插值
    GL_NEAREST_MIPMAP_NEAREST 使用1个mipmap最近点采样
    GL_LINEAR_MIPMAP_NEAREST 使用1个mipmap取线性插值
    GL_NEAREST_MIPMAP_LINEAR 从2个mipmap最近点采样,进行线性插质
    GL_LINEAR_MIPMAP_LINEAR  三线性过滤:从 2个mipmap 线性插值取得2个点后,然后在两个值之间进行线性插值

    GL_TEXTURE_MAG_FILTER

    多个像素对应一个纹素
    缩小滤波

    GL_NEAREST
    GL_LINEAR

    GL_TEXTURE_WRAP_S

    设置纹理在s方向上的被控行为纹理环绕方式

    GL_CLAMP
    GL_REPEAT

    GL_TEXTURE_WRAP_T

    设置纹理在t方向上的被控行为:纹理环绕方式

    GL_CLAMP
    GL_REPEAT

    GL_TEXTURE_BORDER_COLOR

    设置边界颜色

     

    */
    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);

    /*

    提交顶点数组供opengl使用
    size    数据大小,发送3d顶点时指定为: 3.  范围2,3,4
    type   要提交的数据类型,通常为GL_FLOAT
    stride  如果数据是紧密相连的,将stride指定为0。否则指定为顶点间的跨距,单位为字节。
    pointer 指向数据或者缓存对象中的偏移量
    typedef float vec4_t[4];
    vec4_t xyzw[1000];
    例如: glVertexPointer(3,GL_FLOAT,16,xyzw) //只需要3个顶点,但数据是16位包含xyzw

    */
    extern  void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

    /*
    规一化设备坐标到窗口坐标
    qglViewport( 0, 0, 640, 480);
    */
    extern  void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);

    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 * qwglGetDeviceGammaRamp3DFX)( HDC, LPVOID );
    extern BOOL  ( WINAPI * qwglSetDeviceGammaRamp3DFX)( HDC, LPVOID );

    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);
    /*
    开启或关闭垂直同步。关闭垂直同步可以提高FPS
    水平同步信号,显示设备(显示器)接收到这个信号后,就开始画下一行。
    垂直同步信号,显示设备(显示器)接收到这个信号后,就开始画下一帧。

    */
    extern BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval );

     

    没有使用 gluLookAt 函数。相机使用默认位置的方向。默认情况下,相机位于原点,镜头指向z轴负方向,向上向量为(0,1,0)

     
    August 02

    去掉webbrowse控件的滚动条

     // TODO: 在此处添加消息处理程序代码
    对于delphi vb 类很简单:
    IHTMLBodyElementDisp(IHTMLDocument2(WebBrowser1.document).body).scroll:= 'no';
     
    vc 要查询接口才能使用,相应代码如下:
     HRESULT hr = S_OK;
     IDispatch* pDocDisp = m_wndWeb.get_Document();   //m_wndWeb 为 webbrowse控件类对象
     if (pDocDisp)
     {
      IHTMLDocument2* pDoc = NULL;
      IHTMLElement* pElement = NULL;
      IHTMLBodyElement* pBodyElement = NULL;

      hr = pDocDisp->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void **>(&pDoc));
      hr = pDoc->get_body(&pElement);
      hr = pElement->QueryInterface(IID_IHTMLBodyElement, (void**)&pBodyElement);
      pBodyElement->put_scroll(::SysAllocString(L"no"));

      pBodyElement->Release();
      pElement->Release();
      pDoc->Release();
      pDocDisp->Release();
     } 

    网页中也必须有去掉滚动条的格式说明,可以参考baidu,google等网站
    August 01

    二叉空间分割(BSP)

    二叉空间分割(BSP)
    1.什么是BSP树
    BSP树就是用来对N维空间中的元素进行排序和查找的二叉树。BSP树表示整个空间,BSP树中的任意一个接点表示一个凸的子空间。每个接点包含一个“超平面”,将这个接点表示的空间分割成两个子空间。每个接点除了保存其两个子接点的引用以外,还可以保存一个或多个元素。

    对于N维空间,超平面为N-1维的对象。通常,用BSP树来表示二维或者三维空间,这时,空间中的元素分别指的是线段和多边型。

    因其强大的排序和分类功能,BSP树有着非常广泛的应用。从隐藏面剔除、光线追踪到实体建模和机器人动作规划,都能看到BSP树的身影。

    2.举例
    认识BSP树,可以从二维空间的简单例子开始。为了简化问题,我们假定空间中的线段都是与X或者Y轴平行的,并且每次我们把空间分割成相等的两部分。比如,一个处于XY平面的正方形,第一次分割,在X方向将其分割成相等的两部分,以后的分割,按X->Y->X…的顺序进行。除非进行人为的干预,此过程将递归地进行下去。下图描述了次过程和与之对应的BSP树。

    如何建立BSP树
    介绍
    给定三维空间中的一组多边形,我们要建立的BSP树应该包含它们当中的每一个。建立BSP树的算法是非常简单的:
    1.选择分割平面
    如何建立BSP树
    介绍
    给定三维空间中的一组多边形,我们要建立的BSP树应该包含它们当中的每一个。建立BSP树的算法是非常简单的:
    1. 选择分割平面
    分割平面的选择依赖于BSP树将如何被使用,以及空间中多边形的排序条件。某些情况下,使用空间中某个多边形所在的平面进行分割(叫做自动分割)。在另外一些情况下,与坐标轴垂直的平面常被用做分割平面。
    在任何一种情况下,对选择分割平面的策略进行评估都是很重要的。一个很普遍的想法是让BSP树的结构尽量趋近于平衡二叉树,但是这样做是有代价的。要实现一个完全平衡的BSP树,当一个多边形与分割平面相交时,它必须被分割成两部分。一个糟糕的分割平面选择策略会产生很多这样的分割。
    2. 分割多边形集合
    需要根据步骤1中选择的分割平面将多边形集合分解成两个子集。如果一个多边形完全处于分割平面的一侧,只需要把它添加对应的子集中。如果与分割平面相交,先将其分成两部分,再分别添加到两个子集中。
    3. 何时停止分割
    判断建立BSP树的递归过程在什么条件下停止,也是与具体的应用有关的。可以在接点包含的多边形数目小于某个界限时停止,也可以当BSP树的深度超过某个界限时停止。

    伪代码
    struct BSP_tree
    {
    plane     partition;
    list      polygons;
    BSP_tree  *front, *back;
    };

    这个结构体定义在下面的讨论中将被一直使用。它表示BSP树的一个接点,包含有一个分割平面,处于分割平面的多边形列表,以及指向子接点的指针。

    void Buld_BSP_Tree( BSP_tree *tree, list polygons )
    {
        polygon *root = polygons.Get_From_List();
        tree->partition = root->Get_Plane();
        tree->polygons.Add_To_List( root );
        list front_list, back_list;
        polygon  *poly;

        while( ( poly = polygons.Get_From_List() ) != 0 )
        {
    int result = tree->partition.Classify_polygon(poly);

    switch( result )
    {
    case COINCIDENT: // 共面
         tree->polygons.Add_To_List(poly);
         break;
    case IN_BACK_OF:
         back_list.Add_To_List(poly);
         break;
    case IN_FRONT_OF
         front_list.Add_To_List(poly);
         break;
    case SPANNING:
         polygon *front_piece, *back_piece;
       split_Polygon( poly, tree->partition, front_piece, back_piece );
         back_list.Add_To_List( back_piece );
         front_list.Add_To_List( front_piece );
         break;
     }
           }

           if( !front_list.Is->Empty_List() )
           {
    tree->front = new BSP_tree;
    Build_BSP_Tree( tree->front, front_list );
           }
           if( !back_list->Is_Empty_List() )
           {
    tree->back = new BSP_tree;
    Build_BSP_Tree( tree->back, back_list );
           }
    }

    Buld_BSP_Tree函数根据以上说明的步骤递归地建立BSP树。它使用输入的多边形列表中的第一个多边形所在的平面作为分割平面,假定此列表中的每一个多边形都为凸多边形。
    很明显,通过更合理的分割平面选择策略,这个函数可以得到改进,以后将详细为大家阐述
    如何用平面对多边形分类

    用平面对多边形分类也就是判断平面位于多边形的哪一边。这通常被称为前/后测试,是通过测试多边形的每一个顶点与平面的位置关系来完成的。基本的算法就是遍利多边形的每一条边,找出那些两个顶点分别位于多边形两侧的边,交点将成为分割出的两个多边形的新曾顶点。

    关于实现:
    用平面对顶点分类,只需要把顶点的XYZ坐标值代入平面方程,AX+BY+CZ +D = 0,结果的绝对值为顶点到平面的距离,结果的符号与平面法线的方向有关。如果顶点位于平面法线所指的半平面,结果为正,否则为负。

    下面是分割一个凸多边形的C++伪代码。
    #define EPSILON numeric_limits<float>::epsilon( )

    void SplitPolygon(polygon *poly, plane *part, polygon **front, polygon **back)
    {
    size_t verNum = poly->NumVertices();

    point ptA, ptB;
    float distA, distB;
    std::vector<point> verFront, verBack;

    ptA = poly->Vertex[verNum-1];
    distA = poly->ClassifyPoint( ptA ); //求带符号距离

    for( size_t i = EPSILON; ++i < verNum; )
    {
    ptB = poly->Vertex[i];
    distB = poly->ClassifyPoint( ptB );

    if( distB > EPSILON && distA < -EPSILON )
    {
    vector v = ptA - ptB;
    normalize(v);
    float sect = -part->ClassifyPoint(ptA) / Dot(poly->normal(), v );
    verFront.push_back(ptA+(v*sect));
    verBack.push_back(ptA+(v*sect));
    verFront.push_back(ptB);
    }
    else if( distB<-EPSILON && distA>EPSILON )
    {
    vector v = ptB - ptA;
    normalize(v);
    float sect = -part->ClassifyPoint(ptB) / Dot(poly->normal(), v );
    verFront.push_back(ptB+(v*sect));
    verBack.push_back(ptB+(v*sect));
    verBack.push_back(ptB);
    }
    else if( distB>EPSILON && distA>EPSILON )
    {
    verFront.push_back(ptB);
    }
    else if( distB<-EPSILON && distA<-EPSILON )
    {
    verBack.push_back(ptB);
    }
    else if( distB>-EPSILON && distB<EPSILON )
    {
    verFront.push_back(ptB);
    verBack.push_back(ptB);
    }

    ptA = ptB;
    distA = distB;
    }

    if( !verFront.empty() )
    *front = new polygon(verFront);
    if( !verBack.empty() )
    *back = new polygon(verBack);
    }