16位浮点数和GL_HALF_FLOAT [英] 16-bit floats and GL_HALF_FLOAT

查看:2335
本文介绍了16位浮点数和GL_HALF_FLOAT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找/编写一个16位浮点数的C ++实现,用于OpenGL顶点缓冲区(纹理坐标,法线等)。以下是我到目前为止的要求:




  • 必须是16位(显然)。

  • 能够使用GL_HALF_FLOAT上传到OpenGL顶点缓冲区。

  • 必须能够表示超过-1.0 - +1.0的数字(否则,我将只使用GL_SHORT归一化)。

  • 必须能够转换为正常的32位浮点数。

  • 算术运算无关紧要 - 我只关心存储。

  • 速度不是主要关注点,但正确性是。



这里是我到目前为止的一个接口:

  class half 
{
public:
half(void):data {}
half(const half& h):data(h.data){}
half(const unsigned short& s):data {s} {b $ b half f)

inline operator const float(){return toFloat() (数据); }
inline operator const double(){return toDouble(data); }

inline const half operator =(const float& rhs){data = fromFloat(rhs); return * this; }
inline const half operator =(const double& rhs){data = fromDouble(rhs); return * this; }

private:
无符号短数据;

static unsigned short fromFloat(float f);
static float toFloat(short h);

inline static unsigned short fromDouble(double d){return fromFloat((float)d); }
inline static double toDouble(short h){return(double)toFloat(h); }
};

std :: ostream&运算符<<(std :: ostream& os,half h){os< (float)h; }
std :: istream& operator>>(std :: istream& is,half& h){float f;是> F; h = f; }

最终,类的真正体现在 toFloat fromFloat()函数,这是我需要帮助。我已经能够找到几个16位float实现的例子,但没有人提到它们是否可以上传到OpenGL。



在将16位浮点上传到OpenGL时,我应该注意哪些问题?有没有专门解决这些问题的半浮点实现?



编辑:根据受欢迎的需求,这里是我的顶点数据如何生成,上传和渲染。 p>

这里是如何在WireCubeEntity类中定义数据:

  VertexHalf vertices [8] = {
vec3(-1.0f,-1.0f,-1.0f),
vec3(1.0f,-1.0f,-1.0f),
vec3 f,1.0f,-1.0f),
vec3(-1.0f,1.0f,-1.0f),
vec3(-1.0f,-1.0f,1.0f),
vec3(1.0f,-1.0f,1.0f),
vec3(1.0f,1.0f,1.0f),
vec3(-1.0f,1.0f,1.0f)
} ;

unsigned char indices [24] = {
0,1,
1,2,
2,3,
3,0,
4,5,
5,6,
6,7,
7,4,
0,4,
1,5,
2,6,
3,7
};

va.load(GL_LINES,VF_BASICHALF,8,vertices,GL_UNSIGNED_BYTE,24,indices);

其中 va 是VertexArray的一个实例。 va.load 定义为:

  MappedBuffers VertexArray :: load GLenum原语,VertexFormat vertexFormat,unsigned int vertexCount,void * vertices,
GLenum indexFormat,unsigned int indexCount,void * indices)
{
MappedBuffers ret;

/ *检查无效的原始类型* /
if(primitive> GL_TRIANGLE_FAN)
{
错误(VertexFormat :: load n);
errormore(Invalid enum'%i'passed to'primitive'.\\\
,primitive);
return ret;
}

/ *清除现有数据* /
clean();

/ *设置顶点数组对象* /
glGenVertexArrays(1,& vao);
bindArray();

/ *创建顶点缓冲区对象* /
glGenBuffers(1,& vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER,vertexSize(vertexFormat)* vertexCount,vertices,GL_STATIC_DRAW);
if(!vertices)ret.vmap = glMapBuffer(GL_ARRAY_BUFFER,GL_WRITE_ONLY);

/ *保存变量供以后使用* /
prim = primitive;
vformat = vertexFormat;
vcount = vertexCount;

/ *如果我们已经得到索引数据,处理它* /
if(indexSize(indexFormat)!= 0)
{
glGenBuffers(1, & ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,indexSize(indexFormat)* indexCount,indices,GL_STATIC_DRAW);
if(!indices)ret.imap = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER,GL_WRITE_ONLY);

iformat = indexFormat;
icount = indexCount;
}

/ *处理顶点格式* /
switch(vformat)
{
case VF_BASIC:
/ * VF_BASIC一个位置 - 一个3分量浮点矢量* /
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void *)0);
break;
case VF_32:
/ * VF_32有3个组件用于位置,2个用于纹理坐标,3个用于正常。
位置在偏移0,TextureCoordinate在偏移12,正常在偏移20 * /
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,vertexSize(VF_32),(void *)0);
glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,vertexSize(VF_32),(void *)12);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,vertexSize(VF_32),(void *)20);
break;
case VF_BASICHALF:
/ * VF_BASICHALF与VF_BASIC非常相似,除了使用半浮点而不是浮点数。 * /
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,3,GL_HALF_FLOAT,GL_FALSE,0,(void *)0);
break;
case VF_WITHTANGENTS:
/ * VF_WITHTANGENTS类似于VF_32,但有一个切线的附加组件。 * /
/ * Tangent在偏移32 * /
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,vertexSize(VF_WITHTANGENTS),(void *)0);
glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,vertexSize(VF_WITHTANGENTS),(void *)12);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,vertexSize(VF_WITHTANGENTS),(void *)20);
glVertexAttribPointer(3,3,GL_FLOAT,GL_FALSE,vertexSize(VF_WITHTANGENTS),(void *)32);
break;
默认值:
错误(在VertexFormat :: load():\\\
);
errormore(Invalid enum'%i'passed to vertexFormat.\\\
,(int)vformat);
clean();
return MappedBuffers();
}

/ *解除顶点数组* /
unbindArray();

if(vertices)ready = true;

return ret;
}

我知道一个很重的函数。 MappedBuffers 只是一个包含2个指针的结构,所以如果我将 NULL 数据传递到 :: load(),我可以使用指针直接从文件加载数据到缓冲区(可能从另一个线程)。 vertexSize 是一个函数,返回任何顶点格式的传递的 sizeof(),或无效格式的0 。



VertexHalf结构是:

  struct VertexHalf 
{
VertexHalf(void){}
VertexHalf(vec3 _pos):x(_pos.x),y(_pos.y),z(_pos.z){}
VertexHalf float _x,float _y,float _z):x(_x),y(_y),z(_z){}

half x,y,z,padding;
};

最后,使用 VertexArray 我们之前加载的:

  void VertexArray :: draw(void)
{
if = false)
return;

/ *绑定我们的顶点数组* /
bindArray();

/ *绘制它的内容* /
if(ibo == 0)
glDrawArrays(prim,0,vcount);
else
glDrawElements(prim,icount,iformat,NULL);

unbindArray();
}


解决方案

编辑 :最明显的错误显示在您的VertexHalf结构中。你有一个padding的元素。但是当你指定你的glVertexAttribPointer时,你在stride中指定一个0,表示它是紧密包装的。因此,您可以更改VertexHalf以删除填充或更改您的glVertexAttribPointer具有8个字节的步幅。



我使用下面的类与DirectX的float16支持,完美。



Float16.h:

  #ifndef THE__FLOAT_16_H_ 
#define THE__FLOAT_16_H_

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + * /

extern short FloatToFloat16(float value);
extern float Float16ToFloat(short value);

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + * /

class Float16
{
protected:
short mValue;
public:
Float16();
Float16(float value);
Float16(const Float16& value);

operator float();
operator float()const;

friend Float16 operator +(const Float16& val1,const Float16& val2);
friend Float16 operator - (const Float16& val1,const Float16& val2);
friend Float16 operator *(const Float16& val1,const Float16& val2);
friend Float16 operator /(const Float16& val1,const Float16& val2);

Float16& operator =(const Float16& val);
Float16& operator + =(const Float16& val);
Float16& operator - =(const Float16& val);
Float16& operator * =(const Float16& val);
Float16& operator / =(const Float16& val);
Float16&运算符 - ();
};

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + * /

inline Float16 :: Float16()
{
}

/ * + ---- + ---- + --- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + - --- + ---- + ---- + ---- + ---- + ---- + * /

inline Float16 :: Float16(float value)
{
mValue = FloatToFloat16(value);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16 :: Float16(const Float16& value)
{
mValue = value.mValue;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16 :: operator float()
{
return Float16ToFloat(mValue);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16 :: operator float()const
{
return Float16ToFloat(mValue);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16& Float16 :: operator =(const Float16& val)
{
mValue = val.mValue;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16& Float16 :: operator + =(const Float16& val)
{
* this = * this + val;
return * this;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float 16& Float16 :: operator - =(const Float16& val)
{
* this = * this - val;
return * this;

}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + * /

inline Float16& Float16 :: operator * =(const Float16& val)
{
* this = * this * val;
return * this;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16& Float16 :: operator / =(const Float16& val)
{
* this = * this / val;
return * this;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16& Float16 :: operator - ()
{
* this = Float16( - (float)* this);
return * this;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /
/ * + ---- +朋友+ ---- + * /
/ * + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + * /

inline Float16运算符+(const Float16& val1,const Float16& val2 )
{
return Float16((float)val1 +(float)val2);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16运算符 - (const Float16& val1,const Float16& val2)
{
return Float16(float)val1 - )val2);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16运算符*(const Float16& val1,const Float16& val2)
{
return Float16(float)val1 * )val2);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline Float16 operator /(const Float16& val1,const Float16& val2)
{
return Float16(float)val1 / )val2);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /


#endif

Float16.cpp:

  #includeTypes / Float16.h

//#include < d3dx9.h>

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + * /

short FloatToFloat16(float value)
{
short fltInt16;
int fltInt32;
memcpy(& fltInt32,& value,sizeof(float));
fltInt16 =((fltInt32& 0x7fffffff)>>> 13) - (0x38000000>> 13)
fltInt16 | =((fltInt32& 0x80000000)>> 16);

return fltInt16;
}

/ + ---- + ---- + --- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + - --- + ---- + ---- + ---- + ---- + ---- + /

  float Float16ToFloat(short fltInt16)
{
int fltInt32 =((fltInt16& 0x8000)<<
fltInt32 | =((fltInt16& 0x7fff)<< 13)+ 0x38000000;

float fRet;
memcpy(& fRet,& fltInt32,sizeof(float));
return fRet;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /


I'm looking for/writing a C++ implementation of a 16-bit floating point number to use with OpenGL vertex buffers (texture coordinates, normals, etc). Here are my requirements so far:

  • Must be 16-bit (obviously).
  • Must be able to be uploaded to an OpenGL vertex buffer using GL_HALF_FLOAT.
  • Must be able to represent numbers beyond -1.0 - +1.0 (Otherwise I would just use GL_SHORT normalized).
  • Must be able to convert to and from a normal 32-bit float.
  • Arithmetic operations do not matter - I only care about storage.
  • Speed is not a primary concern, but correctness is.

Here's what I have so far for an interface:

class half
{
public:
    half(void) : data(0) {}
    half(const half& h) : data(h.data) {}
    half(const unsigned short& s) : data(s) {}
    half(const float& f) : data(fromFloat(f)) {}
    half(const double& d) : data(fromDouble(d)) {}

    inline operator const float() { return toFloat(data); }
    inline operator const double() { return toDouble(data); }

    inline const half operator=(const float& rhs) { data = fromFloat(rhs); return *this; }
    inline const half operator=(const double& rhs) { data = fromDouble(rhs); return *this; }

private:
    unsigned short data;

    static unsigned short fromFloat(float f);
    static float toFloat(short h);

    inline static unsigned short fromDouble(double d) { return fromFloat((float)d); }
    inline static double toDouble(short h) { return (double)toFloat(h); }
};

std::ostream& operator<<(std::ostream& os, half h) { os << (float)h; }
std::istream& operator>>(std::istream& is, half& h) { float f; is >> f; h = f; }

Ultimately, the real meat of the class lies in the toFloat() and fromFloat() functions, which is what I need help with. I've been able to find quite a few examples of 16-bit float implementations, but none of them mention whether or not they can be uploaded to OpenGL or not.

What are some concerns I should be aware of when uploading a 16-bit float to OpenGL? Is there a half-float implementation that specifically addresses these concerns?

EDIT: By popular demand, here is how my vertex data is generated, uploaded, and rendered.

Here is how the data is defined within the WireCubeEntity class:

VertexHalf vertices[8] = {
        vec3(-1.0f, -1.0f, -1.0f),
        vec3(1.0f, -1.0f, -1.0f),
        vec3(1.0f, 1.0f, -1.0f),
        vec3(-1.0f, 1.0f, -1.0f),
        vec3(-1.0f, -1.0f, 1.0f),
        vec3(1.0f, -1.0f, 1.0f),
        vec3(1.0f, 1.0f, 1.0f),
        vec3(-1.0f, 1.0f, 1.0f)
    };

    unsigned char indices[24] = {
        0, 1,
        1, 2,
        2, 3,
        3, 0,
        4, 5,
        5, 6,
        6, 7,
        7, 4,
        0, 4,
        1, 5,
        2, 6,
        3, 7
    };

    va.load(GL_LINES, VF_BASICHALF, 8, vertices, GL_UNSIGNED_BYTE, 24, indices);

where va is an instance of VertexArray. va.load is defined as:

MappedBuffers VertexArray::load(GLenum primitive, VertexFormat vertexFormat, unsigned int vertexCount, void* vertices,
                                                  GLenum indexFormat, unsigned int indexCount, void* indices)
{
    MappedBuffers ret;

    /* Check for invalid primitive types */
    if (primitive > GL_TRIANGLE_FAN)
    {
        error("in VertexFormat::load():\n");
        errormore("Invalid enum '%i' passed to 'primitive'.\n", primitive);
        return ret;
    }

    /* Clean up existing data */
    clean();

    /* Set up Vertex Array Object */
    glGenVertexArrays(1, &vao);
    bindArray();

    /* Create Vertex Buffer Object */
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, vertexSize(vertexFormat) * vertexCount, vertices, GL_STATIC_DRAW);
    if (!vertices) ret.vmap = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);

    /* Save variables for later usage */
    prim = primitive;
    vformat = vertexFormat;
    vcount = vertexCount;

    /* If we've been given index data, handle it */
    if (indexSize(indexFormat) != 0)
    {
        glGenBuffers(1, &ibo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize(indexFormat) * indexCount, indices, GL_STATIC_DRAW);
        if (!indices) ret.imap = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);

        iformat = indexFormat;
        icount = indexCount;
    }

    /* Handle the vertex format */
    switch (vformat)
    {
    case VF_BASIC:
        /* VF_BASIC only has a position - a 3-component float vector */
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        break;
    case VF_32:
        /* VF_32 has 3 components for position, 2 for texture coordinates, and 3 for a normal.
        Position is at offset 0, TextureCoordinate is at offset 12, and Normal is at offset 20 */
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glEnableVertexAttribArray(2);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertexSize(VF_32), (void*)0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, vertexSize(VF_32), (void*)12);
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, vertexSize(VF_32), (void*)20);
        break;
    case VF_BASICHALF:
        /* VF_BASICHALF is very similar to VF_BASIC, except using half-floats instead of floats. */
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_HALF_FLOAT, GL_FALSE, 0, (void*)0);
        break;
    case VF_WITHTANGENTS:
        /* VF_WITHTANGENTS is similar to VF_32, but with additional components for a Tangent. */
        /* Tangent is at offset 32 */
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glEnableVertexAttribArray(2);
        glEnableVertexAttribArray(3);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertexSize(VF_WITHTANGENTS), (void*)0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, vertexSize(VF_WITHTANGENTS), (void*)12);
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, vertexSize(VF_WITHTANGENTS), (void*)20);
        glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, vertexSize(VF_WITHTANGENTS), (void*)32);
        break;
    default:
        error("In VertexFormat::load():\n");
        errormore("Invalid enum '%i' passed to vertexFormat.\n", (int)vformat);
        clean();
        return MappedBuffers();
    }

    /* Unbind the vertex array */
    unbindArray();

    if (vertices) ready = true;

    return ret;
}

I'ts a pretty heavy function, I know. MappedBuffers is simply a struct that contains 2 pointers so that if I pass NULL data into VertexArray::load(), I can use the pointers to load the data directly from file into buffers (possibly from another thread). vertexSize is a function that returns the sizeof() of whichever vertex format I pass in, or 0 for an invalid format.

The VertexHalf struct is:

struct VertexHalf
{
    VertexHalf(void) {}
    VertexHalf(vec3 _pos) :x(_pos.x), y(_pos.y), z(_pos.z) {}
    VertexHalf(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}

    half x, y, z, padding;
};

And finally the data is rendered using the VertexArray we loaded earlier:

void VertexArray::draw(void)
{
    if (ready == false)
        return;

    /* Bind our vertex array */
    bindArray();

    /* Draw it's contents */
    if (ibo == 0)
        glDrawArrays(prim, 0, vcount);
    else
        glDrawElements(prim, icount, iformat, NULL);

    unbindArray();
}

解决方案

Edit: The most obvious error appears in your VertexHalf structure. You have an element of padding. Yet when you specify your glVertexAttribPointer you specify a 0 in the stride which indicates it is tightly packed. So you can either change VertexHalf to remove the padding or change your glVertexAttribPointer to have a stride of 8 bytes.

I use the following class with DirectX for float16 support and it works perfectly.

Float16.h:

#ifndef THE__FLOAT_16_H_
#define THE__FLOAT_16_H_

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

extern short FloatToFloat16( float value );
extern float Float16ToFloat( short value );

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

class Float16
{
protected:
    short mValue;
public:
    Float16();
    Float16( float value );
    Float16( const Float16& value );

    operator float();
    operator float() const;

    friend Float16 operator + ( const Float16& val1, const Float16& val2 );
    friend Float16 operator - ( const Float16& val1, const Float16& val2 );
    friend Float16 operator * ( const Float16& val1, const Float16& val2 );
    friend Float16 operator / ( const Float16& val1, const Float16& val2 );

    Float16& operator =( const Float16& val );
    Float16& operator +=( const Float16& val );
    Float16& operator -=( const Float16& val );
    Float16& operator *=( const Float16& val );
    Float16& operator /=( const Float16& val );
    Float16& operator -();
};

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16::Float16()
{
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16::Float16( float value )
{
    mValue  = FloatToFloat16( value );
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16::Float16( const Float16 &value )
{
    mValue  = value.mValue;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16::operator float()
{
    return Float16ToFloat( mValue );
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16::operator float() const
{
    return Float16ToFloat( mValue );
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16& Float16::operator =( const Float16& val )
{
    mValue  = val.mValue;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16& Float16::operator +=( const Float16& val )
{
    *this   = *this + val;
    return *this;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16& Float16::operator -=( const Float16& val )
{
    *this   = *this - val;
    return *this;

}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16& Float16::operator *=( const Float16& val )
{
    *this   = *this * val;
    return *this;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16& Float16::operator /=( const Float16& val )
{
    *this   = *this / val;
    return *this;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16& Float16::operator -()
{
    *this   = Float16( -(float)*this );
    return *this;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/
/*+----+                                 Friends                                       +----+*/
/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16 operator + ( const Float16& val1, const Float16& val2 )
{
    return Float16( (float)val1 + (float)val2 );
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16 operator - ( const Float16& val1, const Float16& val2 )
{
    return Float16( (float)val1 - (float)val2 );
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16 operator * ( const Float16& val1, const Float16& val2 )
{
    return Float16( (float)val1 * (float)val2 );
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline Float16 operator / ( const Float16& val1, const Float16& val2 )
{
    return Float16( (float)val1 / (float)val2 );
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/


#endif

Float16.cpp:

#include "Types/Float16.h"

//#include <d3dx9.h>

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

short FloatToFloat16( float value )
{
    short   fltInt16;
    int     fltInt32;
    memcpy( &fltInt32, &value, sizeof( float ) );
    fltInt16    =  ((fltInt32 & 0x7fffffff) >> 13) - (0x38000000 >> 13);
    fltInt16    |= ((fltInt32 & 0x80000000) >> 16);

    return fltInt16;
}

/+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+/

float Float16ToFloat( short fltInt16 )
{
    int fltInt32    =  ((fltInt16 & 0x8000) << 16);
    fltInt32        |= ((fltInt16 & 0x7fff) << 13) + 0x38000000;

    float fRet;
    memcpy( &fRet, &fltInt32, sizeof( float ) );
    return fRet;
 }

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

这篇关于16位浮点数和GL_HALF_FLOAT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆