1
0
Fork 0
Univerxel/src/client/render/gl/texture.cpp

261 lines
7.1 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <cassert>
#include <cmath>
#include <vector>
#include <iostream>
#include <array>
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
GLuint loadDDS(const std::string& imagepath, bool linear){
unsigned char header[124];
FILE *fp;
/* try to open the file */
fp = fopen(imagepath.c_str(), "rb");
if (fp == NULL){
printf("%s could not be opened.\n", imagepath.c_str()); getchar();
return 0;
}
/* verify the type of file */
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0) {
fclose(fp);
return 0;
}
/* get the surface desc */
fread(&header, 124, 1, fp);
unsigned int height = *(unsigned int*)&(header[8 ]);
unsigned int width = *(unsigned int*)&(header[12]);
unsigned int linearSize = *(unsigned int*)&(header[16]);
unsigned int mipMapCount = *(unsigned int*)&(header[24]);
unsigned int fourCC = *(unsigned int*)&(header[80]);
unsigned char * buffer;
unsigned int bufsize;
/* how big is it going to be including all mipmaps? */
bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize;
buffer = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
fread(buffer, 1, bufsize, fp);
/* close the file pointer */
fclose(fp);
unsigned int format;
switch(fourCC)
{
case FOURCC_DXT1:
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
default:
free(buffer);
return 0;
}
// Create one OpenGL texture
GLuint textureID;
glGenTextures(1, &textureID);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, textureID);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
unsigned int blockSize = (format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) ? 8 : 16;
unsigned int offset = 0;
/* load the mipmaps */
for (unsigned int level = 0; level < mipMapCount && (width || height); ++level)
{
unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height,
0, size, buffer + offset);
offset += size;
width /= 2;
height /= 2;
// Deal with Non-Power-Of-Two textures. This code is not included in the webpage to reduce clutter.
if(width < 1) width = 1;
if(height < 1) height = 1;
}
free(buffer);
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST);
glGenerateTextureMipmap(textureID);
return textureID;
}
GLuint loadDDSArray(const std::vector<std::string>& imagepaths, float mipMapLOD, float anisotropy) {
unsigned char header[124];
auto imagepath = imagepaths.begin();
FILE *fp;
/* try to open the file */
fp = fopen(imagepath->c_str(), "rb");
if (fp == NULL)
{
printf("%s could not be opened.\n", imagepath->c_str());
getchar();
return 0;
}
/* verify the type of file */
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0)
{
fclose(fp);
return 0;
}
/* get the surface desc */
fread(&header, 124, 1, fp);
unsigned int mainHeight = *(unsigned int *)&(header[8]);
unsigned int mainWidth = *(unsigned int *)&(header[12]);
unsigned int mainFourCC = *(unsigned int *)&(header[80]);
fclose(fp);
unsigned int mainFormat;
switch (mainFourCC)
{
case FOURCC_DXT1:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
default:
return 0;
}
// Create one OpenGL texture array
GLuint textureID;
glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &textureID);
glTextureStorage3D(textureID, 1 + std::floor(std::log2(std::max(mainWidth, mainHeight))), mainFormat, mainWidth, mainHeight, imagepaths.size());
ushort layer = 0;
for (imagepath = imagepaths.begin(); imagepath != imagepaths.end(); ++imagepath, ++layer)
{
GLuint subTextureID = loadDDS(*imagepath, false);
glCopyImageSubData(subTextureID, GL_TEXTURE_2D, 0, 0, 0, 0, textureID, GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer, mainWidth, mainHeight, 1);
glDeleteTextures(1, &subTextureID);
}
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameterf(textureID, GL_TEXTURE_LOD_BIAS, mipMapLOD);
glTextureParameterf(textureID, GL_TEXTURE_MAX_ANISOTROPY, anisotropy);
glGenerateTextureMipmap(textureID);
return textureID;
}
GLuint loadDDSCube(const std::array<std::string, 6>& imagepaths) {
unsigned char header[124];
auto imagepath = imagepaths.begin();
FILE *fp;
/* try to open the file */
fp = fopen(imagepath->c_str(), "rb");
if (fp == NULL)
{
printf("%s could not be opened.\n", imagepath->c_str());
getchar();
return 0;
}
/* verify the type of file */
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0)
{
fclose(fp);
return 0;
}
/* get the surface desc */
fread(&header, 124, 1, fp);
unsigned int mainHeight = *(unsigned int *)&(header[8]);
unsigned int mainWidth = *(unsigned int *)&(header[12]);
unsigned int mainFourCC = *(unsigned int *)&(header[80]);
fclose(fp);
unsigned int mainFormat;
switch (mainFourCC)
{
case FOURCC_DXT1:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
default:
return 0;
}
// Create one OpenGL texture array
GLuint textureID;
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &textureID);
glTextureStorage2D(textureID, 1, mainFormat, mainWidth, mainHeight);
ushort layer = 0;
for (imagepath = imagepaths.begin(); imagepath != imagepaths.end(); ++imagepath, ++layer)
{
GLuint subTextureID = loadDDS(*imagepath, false);
glCopyImageSubData(subTextureID, GL_TEXTURE_2D, 0, 0, 0, 0, textureID, GL_TEXTURE_CUBE_MAP, 0, 0, 0, layer, mainWidth, mainHeight, 1);
glDeleteTextures(1, &subTextureID);
}
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glGenerateTextureMipmap(textureID);
return textureID;
}