2020-07-06 19:18:29 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <string>
|
|
|
|
#include <cassert>
|
2020-07-10 17:49:16 +00:00
|
|
|
#include <cmath>
|
2020-07-06 19:18:29 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <GL/glew.h>
|
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
|
|
|
|
|
|
|
|
GLuint loadBMP_custom(const char * imagepath){
|
|
|
|
|
|
|
|
printf("Reading image %s\n", imagepath);
|
|
|
|
|
|
|
|
// Data read from the header of the BMP file
|
|
|
|
unsigned char header[54];
|
|
|
|
unsigned int dataPos;
|
|
|
|
unsigned int imageSize;
|
|
|
|
unsigned int width, height;
|
|
|
|
// Actual RGB data
|
|
|
|
unsigned char * data;
|
|
|
|
|
|
|
|
// Open the file
|
|
|
|
FILE * file = fopen(imagepath,"rb");
|
|
|
|
if (!file){
|
|
|
|
printf("%s could not be opened.\n", imagepath);
|
|
|
|
getchar();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the header, i.e. the 54 first bytes
|
|
|
|
|
|
|
|
// If less than 54 bytes are read, problem
|
|
|
|
if ( fread(header, 1, 54, file)!=54 ){
|
|
|
|
printf("Not a correct BMP file\n");
|
|
|
|
fclose(file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// A BMP files always begins with "BM"
|
|
|
|
if ( header[0]!='B' || header[1]!='M' ){
|
|
|
|
printf("Not a correct BMP file\n");
|
|
|
|
fclose(file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// Make sure this is a 24bpp file
|
|
|
|
if ( *(int*)&(header[0x1E])!=0 ) {printf("Not a correct BMP file\n"); fclose(file); return 0;}
|
|
|
|
if ( *(int*)&(header[0x1C])!=24 ) {printf("Not a correct BMP file\n"); fclose(file); return 0;}
|
|
|
|
|
|
|
|
// Read the information about the image
|
|
|
|
dataPos = *(int*)&(header[0x0A]);
|
|
|
|
imageSize = *(int*)&(header[0x22]);
|
|
|
|
width = *(int*)&(header[0x12]);
|
|
|
|
height = *(int*)&(header[0x16]);
|
|
|
|
|
|
|
|
// Some BMP files are misformatted, guess missing information
|
|
|
|
if (imageSize==0) imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component
|
|
|
|
if (dataPos==0) dataPos=54; // The BMP header is done that way
|
|
|
|
|
|
|
|
// Create a buffer
|
|
|
|
data = new unsigned char [imageSize];
|
|
|
|
|
|
|
|
// Read the actual data from the file into the buffer
|
|
|
|
fread(data,1,imageSize,file);
|
|
|
|
|
|
|
|
// Everything is in memory now, the file can be closed.
|
|
|
|
fclose (file);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Give the image to OpenGL
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
|
|
|
|
|
|
|
|
// OpenGL has now copied the data. Free our own version
|
|
|
|
delete [] data;
|
|
|
|
|
|
|
|
// Poor filtering, or ...
|
|
|
|
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
|
|
|
|
// ... nice trilinear filtering ...
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
|
// ... which requires mipmaps. Generate them automatically.
|
|
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// Return the ID of the texture we just created
|
|
|
|
return textureID;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since GLFW 3, glfwLoadTexture2D() has been removed. You have to use another texture loading library,
|
|
|
|
// or do it yourself (just like loadBMP_custom and loadDDS)
|
|
|
|
//GLuint loadTGA_glfw(const char * imagepath){
|
|
|
|
//
|
|
|
|
// // 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);
|
|
|
|
//
|
|
|
|
// // Read the file, call glTexImage2D with the right parameters
|
|
|
|
// glfwLoadTexture2D(imagepath, 0);
|
|
|
|
//
|
|
|
|
// // Nice trilinear filtering.
|
|
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
|
// glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
|
//
|
|
|
|
// // Return the ID of the texture we just created
|
|
|
|
// return textureID;
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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){
|
2020-07-10 17:49:16 +00:00
|
|
|
printf("%s could not be opened.\n", imagepath.c_str()); getchar();
|
2020-07-06 19:18:29 +00:00
|
|
|
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_RGBA_S3TC_DXT1_EXT;
|
|
|
|
break;
|
|
|
|
case FOURCC_DXT3:
|
|
|
|
format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
|
|
|
break;
|
|
|
|
case FOURCC_DXT5:
|
|
|
|
format = GL_COMPRESSED_RGBA_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_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
|
|
|
|
unsigned int offset = 0;
|
|
|
|
|
2020-07-10 17:49:16 +00:00
|
|
|
/* load the mipmaps */
|
2020-07-06 19:18:29 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-07-10 17:49:16 +00:00
|
|
|
GLuint loadDDSArray(const std::vector<std::string>& imagepaths, float mipMapLOD) {
|
2020-07-06 19:18:29 +00:00
|
|
|
|
|
|
|
unsigned char header[124];
|
|
|
|
|
|
|
|
auto imagepath = imagepaths.begin();
|
|
|
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
/* try to open the file */
|
|
|
|
fp = fopen(imagepath->c_str(), "rb");
|
|
|
|
if (fp == NULL)
|
|
|
|
{
|
2020-07-10 17:49:16 +00:00
|
|
|
printf("%s could not be opened.\n", imagepath->c_str());
|
2020-07-06 19:18:29 +00:00
|
|
|
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_RGBA_S3TC_DXT1_EXT;
|
|
|
|
break;
|
|
|
|
case FOURCC_DXT3:
|
|
|
|
mainFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
|
|
|
break;
|
|
|
|
case FOURCC_DXT5:
|
|
|
|
mainFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create one OpenGL texture array
|
|
|
|
GLuint textureID;
|
|
|
|
glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &textureID);
|
2020-07-10 17:49:16 +00:00
|
|
|
glTextureStorage3D(textureID, 1 + std::floor(std::log2(std::max(mainWidth, mainHeight))), mainFormat, mainWidth, mainHeight, imagepaths.size());
|
2020-07-06 19:18:29 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-07-10 17:49:16 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
glGenerateTextureMipmap(textureID);
|
|
|
|
|
2020-07-06 19:18:29 +00:00
|
|
|
return textureID;
|
|
|
|
|
|
|
|
}
|