diff options
Diffstat (limited to 'test/gl2_mac/ocean_surface.cpp')
| -rw-r--r-- | test/gl2_mac/ocean_surface.cpp | 874 |
1 files changed, 874 insertions, 0 deletions
diff --git a/test/gl2_mac/ocean_surface.cpp b/test/gl2_mac/ocean_surface.cpp new file mode 100644 index 0000000..4ad52c7 --- /dev/null +++ b/test/gl2_mac/ocean_surface.cpp @@ -0,0 +1,874 @@ +// Copyright (c) 2011 NVIDIA Corporation. All rights reserved. +// +// TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED +// *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS +// OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA +// OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR +// CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS +// OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY +// OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, +// EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +// +// Please direct any bugs or questions to [email protected] + +#define _HAS_EXCEPTIONS 0 +#include "ocean_surface.h" +#include "math_code.h" +#include <stdio.h> +#include <vector> + +#ifndef PI +#define PI 3.14159265358979323846f +#endif + +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } } +#endif + +enum OceanSurfaceTextureUnits +{ + FoamDiffuseTextureUnit = 0, + FoamIntensityTextureUnit, + Num_OceanSurfaceTextureUnits +}; + +bool file_exists(const char * filename) +{ + FILE *file; + file = fopen(filename, "r"); + if (file) + { + fclose(file); + return true; + } + return false; +} + +void search_file(char* found_filename, size_t numberOfElements, char* filename) +{ + char* search_paths[12] = { + "", + "test/gl2_mac/", + "../", + "../test/gl2_mac/", + "../../", + "../../test/gl2_mac/", + "../../../", + "../../../test/gl2_mac/", + "../../../../", + "../../../../test/gl2_mac/", + "../../../../../", + "../../../../../test/gl2_mac/"}; + + char trial_filename[1024]; + for(int i=0; i<12; i++) + { + snprintf(trial_filename, sizeof(trial_filename)/sizeof(trial_filename[0]), "%s%s", search_paths[i], filename); + if(file_exists(trial_filename)) + { + strncpy(found_filename, trial_filename, numberOfElements); + return; + } + } + strncpy(found_filename, filename, numberOfElements); +} + +gfsdk_waveworks_result OceanSurface::InitQuadTree(const GFSDK_WaveWorks_Quadtree_Params& params) +{ + if(NULL == m_hOceanQuadTree) + { + return GFSDK_WaveWorks_Quadtree_CreateGL2(params, (unsigned int) WaterProgram, &m_hOceanQuadTree); + } + else + { + return GFSDK_WaveWorks_Quadtree_UpdateParams(m_hOceanQuadTree, params); + } +} + +void OceanSurface::CreateTextures(void) +{ + LoadTexture("foam.dds",&FoamDiffuseTextureID); + LoadTexture("foam_intensity_perlin2_rgb.dds",&FoamIntensityTextureID); +} + +OceanSurface::OceanSurface(bool use_texture_arrays) +{ + + // creating and binding global VAO + glGenVertexArrays(1,&GlobalVAO); + glBindVertexArray(GlobalVAO); + + // loading & compiling water shader + WaterProgram = LoadProgram("water.glsl"); + + // initializing quadtree + m_hOceanQuadTree = NULL; + + // get the attribute count, so that we can search for any attrib shader inputs needed by waveworks + GLint numAttrs = 0; + glGetProgramiv(WaterProgram,GL_ACTIVE_ATTRIBUTES,&numAttrs); + + // initializing quadtree shader input mappings + UINT NumQuadtreeShaderInputs = GFSDK_WaveWorks_Quadtree_GetShaderInputCountGL2(); + m_pQuadTreeShaderInputMappings = new gfsdk_U32 [NumQuadtreeShaderInputs]; + GFSDK_WaveWorks_ShaderInput_Desc* quadtree_descs = new GFSDK_WaveWorks_ShaderInput_Desc[NumQuadtreeShaderInputs]; + for(unsigned int i = 0; i < NumQuadtreeShaderInputs; i++) + { + GFSDK_WaveWorks_Quadtree_GetShaderInputDescGL2(i, &(quadtree_descs[i])); + switch(quadtree_descs[i].Type) + { + case GFSDK_WaveWorks_ShaderInput_Desc::GL_FragmentShader_UniformLocation: + case GFSDK_WaveWorks_ShaderInput_Desc::GL_VertexShader_UniformLocation: + case GFSDK_WaveWorks_ShaderInput_Desc::GL_TessEvalShader_UniformLocation: + m_pQuadTreeShaderInputMappings[i] = glGetUniformLocation(WaterProgram, quadtree_descs[i].Name); + break; + case GFSDK_WaveWorks_ShaderInput_Desc::GL_AttribLocation: + m_pQuadTreeShaderInputMappings[i] = (UINT)GFSDK_WaveWorks_UnusedShaderInputRegisterMapping; + for(GLint attrIndex = 0; attrIndex != numAttrs; ++attrIndex) + { + char attribName[256]; + GLint size; + GLenum type; + GLsizei nameLen; + glGetActiveAttrib(WaterProgram,attrIndex,sizeof(attribName),&nameLen,&size,&type,attribName); + if(GFSDK_WaveWorks_GLAttribIsShaderInput(attribName,quadtree_descs[i])) + { + m_pQuadTreeShaderInputMappings[i] = glGetAttribLocation(WaterProgram, attribName); + } + } + + break; + } + } + + // initializing simulation shader input mappings + UINT NumSimulationShaderInputs = GFSDK_WaveWorks_Simulation_GetShaderInputCountGL2(); + m_pSimulationShaderInputMappings = new gfsdk_U32 [NumSimulationShaderInputs]; + GFSDK_WaveWorks_ShaderInput_Desc* simulation_descs = new GFSDK_WaveWorks_ShaderInput_Desc[NumSimulationShaderInputs]; + + for(unsigned int i = 0; i < NumSimulationShaderInputs; i++) + { + GFSDK_WaveWorks_Simulation_GetShaderInputDescGL2(i, &(simulation_descs[i])); + m_pSimulationShaderInputMappings[i] = glGetUniformLocation(WaterProgram, simulation_descs[i].Name); + } + + // reserve texture units for WaveWorks for use during ocean surface rendering + for(unsigned int i = 0; i != GFSDK_WaveWorks_Simulation_GetTextureUnitCountGL2(use_texture_arrays); ++i) + { + glPool.Reserved_Texture_Units[i] = (Num_OceanSurfaceTextureUnits + i) %8; + } + + // creating textures + CreateTextures(); + + // binding textures to shader + FoamDiffuseTextureBindLocation = glGetUniformLocation(WaterProgram, "g_texFoamDiffuseMap"); + FoamIntensityTextureBindLocation = glGetUniformLocation(WaterProgram, "g_texFoamIntensityMap"); + + // initializing the rest of variables + CameraPosition[0] = -20.0f; + CameraPosition[1] = 100.0f; + CameraPosition[2] = 20.0f; + LookAtPosition[0] = 0.0f; + LookAtPosition[1] = 0.0f; + LookAtPosition[2] = 0.0f; + + Alpha = 0; + Beta = 0; + + ScreenWidth = 1280; + ScreenHeight = 720; + total_time = 0; + frame_number = 0; + + // cleanup + SAFE_DELETE_ARRAY(quadtree_descs); + SAFE_DELETE_ARRAY(simulation_descs); +} + + + +OceanSurface::~OceanSurface() +{ + if(m_hOceanQuadTree) + { + GFSDK_WaveWorks_Quadtree_Destroy(m_hOceanQuadTree); + } + + SAFE_DELETE_ARRAY(m_pQuadTreeShaderInputMappings); + SAFE_DELETE_ARRAY(m_pSimulationShaderInputMappings); +} + +void checkError(const char *functionName) +{ + GLenum error; + while (( error = glGetError() ) != GL_NO_ERROR) { + fprintf (stderr, "\nGL error 0x%X detected in %s", error, functionName); + } +} + +void OceanSurface::Render(GFSDK_WaveWorks_SimulationHandle hSim, GFSDK_WaveWorks_Simulation_Settings settings) +{ + // rendering to main buffer + SetupNormalView(); + + // setting up main buffer & GL state + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClearColor(0.38f, 0.45f, 0.56f, 0.0f); + glClearDepthf(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0,0,ScreenWidth,ScreenHeight); + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + // rendering water to main buffer + // setting up program + glUseProgram(WaterProgram); + + glUniformMatrix4fv(glGetUniformLocation(WaterProgram, "u_ViewProjMatrix"), 1, GL_FALSE, (const GLfloat *) NormalViewProjMatrix); + + //fprintf (stderr, "\n\nGFSDK_WaveWorks_Quadtree_GetShaderInputCountGL2: %i",nm); + gfsdk_float4x4 ViewMatrix; + gfsdk_float4x4 ProjMatrix; + ViewMatrix._11 = NormalViewMatrix[0][0]; + ViewMatrix._12 = NormalViewMatrix[0][1]; + ViewMatrix._13 = NormalViewMatrix[0][2]; + ViewMatrix._14 = NormalViewMatrix[0][3]; + ViewMatrix._21 = NormalViewMatrix[1][0]; + ViewMatrix._22 = NormalViewMatrix[1][1]; + ViewMatrix._23 = NormalViewMatrix[1][2]; + ViewMatrix._24 = NormalViewMatrix[1][3]; + ViewMatrix._31 = NormalViewMatrix[2][0]; + ViewMatrix._32 = NormalViewMatrix[2][1]; + ViewMatrix._33 = NormalViewMatrix[2][2]; + ViewMatrix._34 = NormalViewMatrix[2][3]; + ViewMatrix._41 = NormalViewMatrix[3][0]; + ViewMatrix._42 = NormalViewMatrix[3][1]; + ViewMatrix._43 = NormalViewMatrix[3][2]; + ViewMatrix._44 = NormalViewMatrix[3][3]; + + ProjMatrix._11 = NormalProjMatrix[0][0]; + ProjMatrix._12 = NormalProjMatrix[0][1]; + ProjMatrix._13 = NormalProjMatrix[0][2]; + ProjMatrix._14 = NormalProjMatrix[0][3]; + ProjMatrix._21 = NormalProjMatrix[1][0]; + ProjMatrix._22 = NormalProjMatrix[1][1]; + ProjMatrix._23 = NormalProjMatrix[1][2]; + ProjMatrix._24 = NormalProjMatrix[1][3]; + ProjMatrix._31 = NormalProjMatrix[2][0]; + ProjMatrix._32 = NormalProjMatrix[2][1]; + ProjMatrix._33 = NormalProjMatrix[2][2]; + ProjMatrix._34 = NormalProjMatrix[2][3]; + ProjMatrix._41 = NormalProjMatrix[3][0]; + ProjMatrix._42 = NormalProjMatrix[3][1]; + ProjMatrix._43 = NormalProjMatrix[3][2]; + ProjMatrix._44 = NormalProjMatrix[3][3]; + + // binding user textures + glActiveTexture(GL_TEXTURE0 + FoamDiffuseTextureUnit); + glBindTexture(GL_TEXTURE_2D, FoamDiffuseTextureID); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, settings.aniso_level); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + glUniform1i(FoamDiffuseTextureBindLocation, FoamDiffuseTextureUnit); + + glActiveTexture(GL_TEXTURE0 + FoamIntensityTextureUnit); + glBindTexture(GL_TEXTURE_2D, FoamIntensityTextureID); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, settings.aniso_level); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + glUniform1i(FoamIntensityTextureBindLocation, FoamIntensityTextureUnit); + + GFSDK_WaveWorks_Simulation_SetRenderStateGL2(hSim, ViewMatrix, m_pSimulationShaderInputMappings, glPool); + GFSDK_WaveWorks_Quadtree_DrawGL2(m_hOceanQuadTree, ViewMatrix, ProjMatrix, m_pQuadTreeShaderInputMappings); +} + +void OceanSurface::SetupNormalView() +{ + float scene_z_near = 1.0f; + float scene_z_far = 10000.0f; + float camera_fov = 3.14f*0.5f; + mat4CreateView(NormalViewMatrix, CameraPosition, LookAtPosition); + mat4CreateProjection(NormalProjMatrix,scene_z_near,scene_z_near/tan(camera_fov*0.5f)*(float)ScreenHeight/(float)ScreenWidth,scene_z_near/tan(camera_fov*0.5f),scene_z_far); + mat4Mat4Mul(NormalViewProjMatrix,NormalProjMatrix,NormalViewMatrix); +} + + +GLuint OceanSurface::CompileShader(char *text, GLenum type) //returns shader handle or 0 if error +{ + GLint length, compiled; + + GLuint shader; + GLsizei maxlength=65535; + char infolog[65535]; + shader = glCreateShader(type); + glShaderSource(shader, 1, (const GLchar **)&text, NULL); + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + fprintf(stderr,"\nshader [%i] compilation error",type); + fprintf(stderr,"\n...\n%s\n...\n",text); + glGetShaderInfoLog(shader, maxlength, &length, infolog); + fprintf(stderr,"\ninfolog: %s",infolog); + glDeleteShader(shader); + return 0; + } + return shader; +} + +const char* GetIncludeFilename(char* line) +{ + char* curr = line; + + // Simple little state machine to parse a #include line... + + // Leading wspace + while(*curr && isspace(*curr)) + ++curr; + + // Check for #include... + const char* includeTag = "#include"; + if(curr != strstr(curr,includeTag)) + return NULL; + curr += strlen(includeTag); + + // Consume more wspace + while(*curr && isspace(*curr)) + ++curr; + + // Check for leading quote + if(*curr != '\"') + return NULL; + curr ++; + const char* pResult = curr; + + // Advance to closing quote + while(*curr && *curr != '\"') + ++curr; + + if(*curr != '\"') + return NULL; + + // Replace with NULL term + *curr = '\0'; + + return pResult; +} +void splitToDirAndFile(const char* filename, char* dir, char* name) +{ + char* pforward_slash = strrchr(filename, '/'); + char* pback_slash = strrchr(filename, '\\'); + char* pslash = pforward_slash > pback_slash ? pforward_slash : pback_slash; + if (pslash == NULL) + { + dir[0]= '\0'; + strcpy(name, filename); + } + else + { + strncpy(dir, filename, (pslash - filename)/sizeof(filename[0])); + strcat(dir, "/"); + strcpy(name, &pslash[1]); + } +} +int LoadProgramSource(const char* filename, std::vector<char>& loadedSrc) +{ + FILE *f = fopen(filename,"rt"); + if(f==NULL) + { + fprintf(stderr,"\ncould not open [%s]\n",filename); + return -1; + } + + char lineBuffer[1024]; + while(!feof(f)) + { + char* currLine = fgets(lineBuffer,sizeof(lineBuffer),f); + if(currLine) + { + // GLSL does not support #include + // We process #includes here for simplicity, but most real-world apps will want to do this pre-process step offline + const char* includeFileName = GetIncludeFilename(currLine); + if(includeFileName) + { + // Assume relative to curr file + char dir[65536]; + char name[65536]; + splitToDirAndFile(filename, dir, name); + char includePath[65536]; + const size_t includePathSize = sizeof(includePath)/sizeof(includePath[0]); + char* includePathCurr = includePath; + strncpy(includePathCurr, dir, includePathSize); + includePathCurr += strlen(dir); + strncpy(includePathCurr, includeFileName, includePathSize); + includePathCurr += strlen(includeFileName); + if(LoadProgramSource(includePath,loadedSrc)) + return -1; + } + else + { + loadedSrc.insert(loadedSrc.end(),currLine,currLine+strlen(currLine)); + } + } + } + fclose(f); + return 0; +} + +GLuint OceanSurface::LoadProgram(char* filename) //returns program object handle or 0 if error +{ + char tmp_text[65535]; + const char *tmp_pos_start; + const char *tmp_pos_end; + + GLuint result = 0; + GLenum program; + + GLint compiled; + + char trial_filename[1024]; + search_file(trial_filename, sizeof(trial_filename)/sizeof(trial_filename[0]), filename); + + fprintf(stderr,"\nLoading & compiling shader [%s]: ",trial_filename); + + std::vector<char> loadedSrc; + if(LoadProgramSource(trial_filename,loadedSrc)) + { + return 0; + } + loadedSrc.push_back('\0'); + const char* programSrc = &loadedSrc[0]; + GLint length = (GLint)loadedSrc.size(); + + program = glCreateProgram(); + + // looking for vertex shader + tmp_pos_start = strstr(programSrc,"<<<VSTEXT>>>"); + if(tmp_pos_start!=NULL) + { + tmp_pos_start+=12; + tmp_pos_end = strstr(tmp_pos_start,"<<<"); + if (tmp_pos_end==NULL) tmp_pos_end = programSrc + length; + strncpy(tmp_text,tmp_pos_start,tmp_pos_end-tmp_pos_start); + tmp_text[tmp_pos_end-tmp_pos_start]=0; + result = CompileShader(tmp_text,GL_VERTEX_SHADER); + if(result) + { + glAttachShader(program,result); + glDeleteShader(result); + } + } + + // looking for tessellation control shader + tmp_pos_start = strstr(programSrc,"<<<TCTEXT>>>"); + if(tmp_pos_start!=NULL) + { + tmp_pos_start+=12; + tmp_pos_end = strstr(tmp_pos_start,"<<<"); + if (tmp_pos_end==NULL) tmp_pos_end = programSrc + length; + strncpy(tmp_text,tmp_pos_start,tmp_pos_end-tmp_pos_start); + tmp_text[tmp_pos_end-tmp_pos_start]=0; + result = CompileShader(tmp_text,GL_TESS_CONTROL_SHADER); + if(result) + { + glAttachShader(program,result); + glDeleteShader(result); + } + } + + // looking for tessellation evaluation shader + tmp_pos_start = strstr(programSrc,"<<<TETEXT>>>"); + if(tmp_pos_start!=NULL) + { + tmp_pos_start+=12; + tmp_pos_end = strstr(tmp_pos_start,"<<<"); + if (tmp_pos_end==NULL) tmp_pos_end = programSrc + length; + strncpy(tmp_text,tmp_pos_start,tmp_pos_end-tmp_pos_start); + tmp_text[tmp_pos_end-tmp_pos_start]=0; + result = CompileShader(tmp_text,GL_TESS_EVALUATION_SHADER); + if(result) + { + glAttachShader(program,result); + glDeleteShader(result); + } + } + + // looking for geometry shader + tmp_pos_start = strstr(programSrc,"<<<GSTEXT>>>"); + if(tmp_pos_start!=NULL) + { + tmp_pos_start+=12; + tmp_pos_end = strstr(tmp_pos_start,"<<<"); + if (tmp_pos_end==NULL) tmp_pos_end = programSrc + length; + strncpy(tmp_text,tmp_pos_start,tmp_pos_end-tmp_pos_start); + tmp_text[tmp_pos_end-tmp_pos_start]=0; + result = CompileShader(tmp_text,GL_GEOMETRY_SHADER); + if(result) + { + glAttachShader(program,result); + glDeleteShader(result); + } + } + + // looking for fragment shader + tmp_pos_start = strstr(programSrc,"<<<FSTEXT>>>"); + if(tmp_pos_start!=NULL) + { + tmp_pos_start+=12; + tmp_pos_end = strstr(tmp_pos_start,"<<<"); + if (tmp_pos_end==NULL) tmp_pos_end = programSrc + length; + strncpy(tmp_text,tmp_pos_start,tmp_pos_end-tmp_pos_start); + tmp_text[tmp_pos_end-tmp_pos_start]=0; + result = CompileShader(tmp_text,GL_FRAGMENT_SHADER); + if(result) + { + glAttachShader(program,result); + glDeleteShader(result); + } + } + + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &compiled); + if (!compiled) { + const GLsizei maxlength=65535; + char infolog[maxlength]; + fprintf(stderr,"program link error\n"); + glGetProgramInfoLog(program, maxlength, &length, infolog); + fprintf(stderr,"\ninfolog: %s\n",infolog); + return 0; + } + return program; +} + +gliGenericImage* ReadDDSFile(const char *filename, int *bufsize, int *numMipmaps) +{ + gliGenericImage *genericImage; + DDSURFACEDESC2 ddsd; + char filecode[4]; + long factor,uncompressed_components,format_found; + /* try to open the file */ + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) + { + fprintf(stderr,"\nUnable to load texture file [%s]",filename); + return NULL; + } + /* verify the type of file */ + fread(filecode, 1, 4, fp); + if (strncmp(filecode, "DDS ", 4) != 0) + { + fprintf(stderr,"\nThe file [%s] is not a dds file",filename); + fclose(fp); + return NULL; + } + /* get the surface desc */ + fread(&ddsd, sizeof(ddsd), 1, fp); + if((ddsd.dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) + { + fprintf(stderr,"\nDDS header pixelformat field contains no valid data,\nunable to load texture."); + return 0; + } + if(((ddsd.dwFlags & DDSD_WIDTH) != DDSD_WIDTH) || ((ddsd.dwFlags & DDSD_HEIGHT) != DDSD_HEIGHT)) + { + fprintf(stderr,"\nDDS header width/height fields contains no valid data,\nunable to load texture."); + return 0; + } + if((ddsd.dwFlags & DDSD_MIPMAPCOUNT) != DDSD_MIPMAPCOUNT) + { + fprintf(stderr,"\nDDS header mipmapcount field contains no valid data,\nassuming 0 mipmaps."); + //return 0; + } + if(((ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC) != DDPF_FOURCC) && ((ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)) + { + fprintf(stderr,"\nDDS header pixelformat field contains no valid FOURCC and RGB data,\nunable to load texture."); + return 0; + } + if(((ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC) == DDPF_FOURCC) && (ddsd.dwMipMapCount<=1) && ((ddsd.ddpfPixelFormat.dwFourCC==FOURCC_DXT1)||(ddsd.ddpfPixelFormat.dwFourCC==FOURCC_DXT3)||(ddsd.ddpfPixelFormat.dwFourCC==FOURCC_DXT5)) ) + { + fprintf(stderr,"\nDDS header contains DXTx FOURCC code and no mipmaps,\nprogram does not support loading DXTx textures without mipmaps,\nunable to load texture."); + return 0; + } + genericImage = (gliGenericImage*) malloc(sizeof(gliGenericImage)); + memset(genericImage,0,sizeof(gliGenericImage)); + factor=0; + uncompressed_components=0; + format_found=0; + genericImage->width = ddsd.dwWidth; + genericImage->height = ddsd.dwHeight; + if((ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC) == DDPF_FOURCC) // if FOURCC code is valid + { + switch(ddsd.ddpfPixelFormat.dwFourCC) + { + case FOURCC_DXT1: + if(ddsd.dwAlphaBitDepth!=0) + { + genericImage->format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + genericImage->components = 4; + } + else + { + genericImage->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + genericImage->components = 3; + } + factor = 2; + format_found=1; + break; + case FOURCC_DXT3: + genericImage->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + genericImage->components = 4; + factor = 4; + format_found=1; + break; + case FOURCC_DXT5: + genericImage->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + genericImage->components = 4; + factor = 4; + format_found=1; + break; + default: + break; + } + } + if(format_found==0) + { + switch (ddsd.ddpfPixelFormat.dwRGBBitCount) + { + case 24: + genericImage->format = GL_RGB; + genericImage->components = 3; + format_found=2; + break; + case 32: + genericImage->format = GL_RGBA; + genericImage->components = 4; + format_found=2; + default: + break; + } + } + if(format_found==1) // found compressed format + { + *bufsize = ddsd.dwMipMapCount > 1 ? ddsd.dwLinearSize * factor : ddsd.dwLinearSize; + } + if(format_found==2) + { + *bufsize = ddsd.dwMipMapCount > 1 ? ddsd.dwWidth*ddsd.dwHeight*genericImage->components+(ddsd.dwWidth*ddsd.dwHeight*genericImage->components)/2 : ddsd.dwWidth*ddsd.dwHeight*genericImage->components; + } + if(format_found==0) + { + fprintf(stderr,"\nUnsupported DDS format,\nthe program only supports DXTx and RGB/RGBA formats containing 8 bits per component"); + free(genericImage); + return 0; + } + genericImage->pixels = (unsigned char*)malloc(*bufsize); + fread(genericImage->pixels, 1, *bufsize, fp); + fclose(fp); + *numMipmaps = ddsd.dwMipMapCount; + genericImage->numMipmaps=ddsd.dwMipMapCount; + return genericImage; +} + + +int OceanSurface::LoadTexture(char * filename, GLuint * texID) +{ + gliGenericImage *ggi = NULL; + int bufsize,numMipmaps,blocksize,i; + long offset; + GLint size,width,height; + unsigned char c1,c2,c3,c4; + long n; + + char trial_filename[1024]; + search_file(trial_filename, sizeof(trial_filename)/sizeof(trial_filename[0]), filename); + + fprintf(stderr,"\nLoading %s: ", trial_filename); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ggi = ReadDDSFile(trial_filename, &bufsize, &numMipmaps); + if(ggi==NULL) + { + fprintf(stderr,"The file [%s] hasn't been loaded successfully.",trial_filename); + return 0; + } + height = ggi->height; + width = ggi->width; + switch (ggi->format) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + glGenTextures(1,texID); + glBindTexture(GL_TEXTURE_2D, *texID); + blocksize=8; + offset = 0; + height = ggi->height; + width = ggi->width; + for (i = 0; i < numMipmaps && (width || height); ++i) + { + if (width == 0) + width = 1; + if (height == 0) + height = 1; + size = ((width+3)/4)*((height+3)/4)*blocksize; + glCompressedTexImage2D(GL_TEXTURE_2D, i, ggi->format, width, height, 0, size, ggi->pixels+offset); + offset += size; + width >>= 1; + height >>= 1; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + glGenTextures(1,texID); + glBindTexture(GL_TEXTURE_2D, *texID); + blocksize=8; + offset = 0; + height = ggi->height; + width = ggi->width; + for (i = 0; i < numMipmaps && (width || height); ++i) + { + if (width == 0) + width = 1; + if (height == 0) + height = 1; + size = ((width+3)/4)*((height+3)/4)*blocksize; + glCompressedTexImage2D(GL_TEXTURE_2D, i, ggi->format, width, height, 0, size, ggi->pixels + offset); + offset += size; + width >>= 1; + height >>= 1; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + glGenTextures(1,texID); + glBindTexture(GL_TEXTURE_2D, *texID); + blocksize=16; + offset = 0; + height = ggi->height; + width = ggi->width; + for (i = 0; i < numMipmaps && (width || height); ++i) + { + if (width == 0) + width = 1; + if (height == 0) + height = 1; + size = ((width+3)/4)*((height+3)/4)*blocksize; + glCompressedTexImage2D(GL_TEXTURE_2D, i, ggi->format, width, height, 0, size, ggi->pixels + offset); + offset += size; + width >>= 1; + height >>= 1; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + glGenTextures(1,texID); + glBindTexture(GL_TEXTURE_2D, *texID); + blocksize=16; + offset = 0; + height = ggi->height; + width = ggi->width; + for (i = 0; i < numMipmaps && (width || height); ++i) + { + if (width == 0) + width = 1; + if (height == 0) + height = 1; + size = ((width+3)/4)*((height+3)/4)*blocksize; + glCompressedTexImage2D(GL_TEXTURE_2D, i, ggi->format, width, height, + 0, size, ggi->pixels + offset); + offset += size; + width >>= 1; + height >>= 1; + } + break; + case GL_RGB: + glGenTextures(1,texID); + glBindTexture(GL_TEXTURE_2D, *texID); + offset = 0; + height = ggi->height; + width = ggi->width; + if(numMipmaps<=1) + { + for(n=0;n<width*height*3;n+=3) + { + c1=*(ggi->pixels+n); // switching R and B + c3=*(ggi->pixels+n+2); + *(ggi->pixels+n)=c3; + *(ggi->pixels+n+2)=c1; + } + glTexImage2D(GL_TEXTURE_2D, 0, ggi->format, width, height,0, ggi->format, GL_UNSIGNED_BYTE, ggi->pixels); + glGenerateMipmap(GL_TEXTURE_2D); + }else + for (i = 0; i < numMipmaps && (width || height); ++i) + { + if (width == 0) + width = 1; + if (height == 0) + height = 1; + size = width*height*3; + for(n=0;n<size;n+=3) + { + c1=*(ggi->pixels+offset+n); // switching R and B + c3=*(ggi->pixels+offset+n+2); + *(ggi->pixels+offset+n)=c3; + *(ggi->pixels+offset+n+2)=c1; + } + glTexImage2D(GL_TEXTURE_2D, i, ggi->format, width, height,0, ggi->format, GL_UNSIGNED_BYTE, ggi->pixels + offset); + offset += size; + width >>= 1; + height >>= 1; + } + break; + case GL_RGBA: + glGenTextures(1,texID); + glBindTexture(GL_TEXTURE_2D, *texID); + offset = 0; + height = ggi->height; + width = ggi->width; + if(numMipmaps<=1) + { + for(n=0;n<width*height*4;n+=4) + { + c1=*(ggi->pixels+n); // switching BGRA to RGBA + c2=*(ggi->pixels+n+1); + c3=*(ggi->pixels+n+2); + c4=*(ggi->pixels+n+3); + *(ggi->pixels+n)=c3; + *(ggi->pixels+n+1)=c2; + *(ggi->pixels+n+2)=c1; + *(ggi->pixels+n+3)=c4; + } + glTexImage2D(GL_TEXTURE_2D, 0, ggi->format, width, height,0, ggi->format, GL_UNSIGNED_BYTE, ggi->pixels); + glGenerateMipmap(GL_TEXTURE_2D); + }else + for (i = 0; i < numMipmaps && (width || height); ++i) + { + if (width == 0) + width = 1; + if (height == 0) + height = 1; + size = width*height*4; + for(n=0;n<size;n+=4) + { + c1=*(ggi->pixels+offset+n); // switching BGRA to RGBA + c2=*(ggi->pixels+offset+n+1); + c3=*(ggi->pixels+offset+n+2); + c4=*(ggi->pixels+offset+n+3); + *(ggi->pixels+offset+n)=c3; + *(ggi->pixels+offset+n+1)=c2; + *(ggi->pixels+offset+n+2)=c1; + *(ggi->pixels+offset+n+3)=c4; + } + glTexImage2D(GL_TEXTURE_2D, i, ggi->format, width, height,0, ggi->format, GL_UNSIGNED_BYTE, ggi->pixels + offset); + offset += size; + width >>= 1; + height >>= 1; + } + break; + } + free(ggi->pixels); + free(ggi); + fprintf(stderr," Loaded\n"); + return 1; +} |