我正在创建一个struct
来保存有关我的项目需要的纹理的数据。该结构有五个成员:
纹理图集宽度(一行中的纹理量),
纹理图集高度(一列中的纹理量),
纹理单位宽度(图谱宽度的倒数),
纹理单位高度(图集高度的倒数)
和一个无符号的GLint
存储纹理ID。
但是,即使在构造函数中初始化了这些成员之后,由于Atlas宽度和高度都设置为0,因此我在程序后面还会收到ArithmeticException
。
我已经尝试重新排列代码并尝试其他看似随机的更改,但是没有一个起作用。
设置项目(或至少相关部分)的方式是,我拥有TextureData
结构的标头和源文件。我在名为“ GeneralData.h”的标头中创建此类型的常量对象。我没有与此标头关联的源文件,因此所有实现也都包含在其中。
这是TextureData代码:
// TextureData.h
struct TextureData
{
const int ATLAS_WIDTH;
const int ATLAS_HEIGHT;
const float TEXTURE_UNIT_WIDTH;
const float TEXTURE_UNIT_HEIGHT;
GLuint TEXTURE_ID;
TextureData(int, int);
virtual ~TextureData() {}
};
// TextureData.cpp
#ifndef STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#include <../stb_image.h>
#endif // STB_IMAGE_IMPLEMENTATION
TextureData::TextureData(int atlas_width, int atlas_height):
ATLAS_WIDTH(atlas_width),
ATLAS_HEIGHT(atlas_height),
TEXTURE_UNIT_WIDTH(1.0f / ATLAS_WIDTH),
TEXTURE_UNIT_HEIGHT(1.0f / ATLAS_HEIGHT)
{
glGenTextures(1, &TEXTURE_ID);
glBindTexture(GL_TEXTURE_2D, TEXTURE_ID);
int width;
int height;
unsigned char* pixels = stbi_load("res/block_textures.png", &width, &height, nullptr, 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
这是GeneralData标头的相关部分:
const TextureData BLOCK_TEXTURE(8, 8);
// These functions are called at some point with index = 0.
// Their behaviour should not be undefined
inline float tex_coord_x(int index)
{
return index % BLOCK_TEXTURE.ATLAS_WIDTH * BLOCK_TEXTURE.TEXTURE_UNIT_WIDTH;
}
inline float tex_coord_y(int index)
{
return index / BLOCK_TEXTURE.ATLAS_HEIGHT * BLOCK_TEXTURE.TEXTURE_UNIT_HEIGHT;
}
如上所述,我得到一个运行时异常(算术),因为我被零除。在这种情况下,我应除以(或模数)八(在TEXTURE_UNIT_WIDTH情况下,应除以0.125f)。
这是调用函数的地方。这是在函数定义和BLOCK_TEXTURE定义之下。
//编辑:
template <typename T, size_t SIZE, typename FUNCTION>
inline std::array<T, SIZE> make_array (FUNCTION func)
{
std::array<T, SIZE> arr;
unsigned int index = 0;
std::for_each(arr.begin(), arr.end(), [&func, &index, &arr](const T& val){ arr[index] = func(index); index++; });
return arr;
}
const std::array<float, B_LAST * 6> TEXTURE_COORDS = make_array<float, B_LAST * 6>([](unsigned int index){ return index%2 == 0? tex_coord_x(TEXTURE_INDICES[index / 2]) : tex_coord_y(TEXTURE_INDICES[index / 2 + 1]); });
答案 0 :(得分:2)
嗯。
此代码在清理并将其放入单个文件后可以正常工作。问题的主要提示是您自己的语句“这是GeneralData标头的相关部分”。您将const值放入标头中,并多次包含它。 const值默认情况下具有内部链接(为什么?不知道...),这意味着您可以获得BLOCK_TEXTURE变量的多个版本。您的代码可能使用了错误的代码,而调试器却捕获了另一种代码。在BLOCK_TEXTURE的构造函数中比较指向此对象的指针,并在当前引发异常以确保确定。作为解决方案,添加extern关键字将BLOCK_TEXTURE的定义转换为声明:
extern const TextureData BLOCK_TEXTURE;
并将其定义在单个文件中的某个位置:
const TextureData BLOCK_TEXTURE(8, 8);
请注意,这可能会在某些时候为您带来静态初始化失败。因此,我建议改用静态函数(在标题中):
static inline GET_BLOCK_TEXTURE() {
static const TextureData BLOCK_TEXTURE(8, 8);
return BLOCK_TEXTURE;
}
这将确保您首次使用时已初始化BLOCK_TEXTURE。
答案 1 :(得分:1)
我相信您的代码中有静态init惨败(但是我不确定100%,这是C ++的某些非常奇怪的部分,并且是UBs)
您可以在头文件中定义全局变量。您在注释中提到不能删除 <DataGridTemplateColumn Width="Auto" Header="Is Locked">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<materialDesign:PackIcon x:Name="LockIcon" Kind="LockOpenOutline" Foreground="Green"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding isLocked}" Value="True">
<Setter Property="Kind" Value="Lock" TargetName="LockIcon"/>
<Setter Property="Foreground" Value="Red" TargetName="LockIcon"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
关键字,因为您会遇到多个定义错误,这是事实。 但是您在每个翻译单元中也有多个全局变量定义。
每个包含inline
的文件都有其自己的GeneralData.h
定义,因此一个文件可能会访问另一个文件中的变量。并且可能尚未初始化。
通过检查在BLOCK_TEXTURE
开始之前还是之后发生异常,可以“确认”(与确认UB一样多)静态初始化失败。使用调试器并检查回溯发生的时间,或者仅在main
的第一行中打印一些内容。
解决方案非常简单:您只应在一个文件中定义全局变量。
在main
中:
GeneralData.h
在extern const TextureData BLOCK_TEXTURE;
extern const std::array<float, B_LAST * 6> TEXTURE_COORDS ;
中:
GeneralData.cpp