| /* |
| * Copyright © 2008 Ben Smith |
| * Copyright © 2010-2011 Linaro Limited |
| * |
| * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark. |
| * |
| * glmark2 is free software: you can redistribute it and/or modify it under the |
| * terms of the GNU General Public License as published by the Free Software |
| * Foundation, either version 3 of the License, or (at your option) any later |
| * version. |
| * |
| * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along with |
| * glmark2. If not, see <http://www.gnu.org/licenses/>. |
| * |
| * Authors: |
| * Ben Smith (original glmark benchmark) |
| * Alexandros Frantzis (glmark2) |
| */ |
| #include "texture.h" |
| #include "log.h" |
| #include "util.h" |
| #include "image-reader.h" |
| |
| #include <cstdarg> |
| #include <vector> |
| |
| class ImageData { |
| void resize(unsigned int w, unsigned int h, unsigned int b) |
| { |
| width = w; |
| height = h; |
| bpp = b; |
| delete [] pixels; |
| pixels = new unsigned char[bpp * width * height]; |
| } |
| |
| public: |
| ImageData() : pixels(0), width(0), height(0), bpp(0) {} |
| ~ImageData() { delete [] pixels; } |
| bool load(ImageReader &reader); |
| |
| unsigned char *pixels; |
| unsigned int width; |
| unsigned int height; |
| unsigned int bpp; |
| }; |
| |
| bool |
| ImageData::load(ImageReader &reader) |
| { |
| if (reader.error()) |
| return false; |
| |
| resize(reader.width(), reader.height(), reader.pixelBytes()); |
| |
| Log::debug(" Height: %d Width: %d Bpp: %d\n", width, height, bpp); |
| |
| /* |
| * Copy the row data to the image buffer in reverse Y order, suitable |
| * for texture upload. |
| */ |
| unsigned char *ptr = &pixels[bpp * width * (height - 1)]; |
| |
| while (reader.nextRow(ptr)) |
| ptr -= bpp * width; |
| |
| return !reader.error(); |
| } |
| |
| static void |
| setup_texture(GLuint *tex, ImageData &image, GLint min_filter, GLint mag_filter) |
| { |
| GLenum format = image.bpp == 3 ? GL_RGB : GL_RGBA; |
| |
| glGenTextures(1, tex); |
| glBindTexture(GL_TEXTURE_2D, *tex); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, image.width, image.height, 0, |
| format, GL_UNSIGNED_BYTE, image.pixels); |
| |
| if ((min_filter != GL_NEAREST && min_filter != GL_LINEAR) || |
| (mag_filter != GL_NEAREST && mag_filter != GL_LINEAR)) |
| { |
| glGenerateMipmap(GL_TEXTURE_2D); |
| } |
| } |
| |
| namespace TexturePrivate |
| { |
| TextureMap textureMap; |
| } |
| |
| bool |
| Texture::load(const std::string &textureName, GLuint *pTexture, ...) |
| { |
| // Make sure the named texture is in the map. |
| TextureMap::const_iterator textureIt = TexturePrivate::textureMap.find(textureName); |
| if (textureIt == TexturePrivate::textureMap.end()) |
| { |
| return false; |
| } |
| |
| // Pull the pathname out of the descriptor and use it for the PNG load. |
| TextureDescriptor* desc = textureIt->second; |
| const std::string& filename = desc->pathname(); |
| ImageData image; |
| |
| if (desc->filetype() == TextureDescriptor::FileTypePNG) { |
| PNGReader reader(filename); |
| if (!image.load(reader)) |
| return false; |
| } |
| else if (desc->filetype() == TextureDescriptor::FileTypeJPEG) { |
| JPEGReader reader(filename); |
| if (!image.load(reader)) |
| return false; |
| } |
| |
| va_list ap; |
| va_start(ap, pTexture); |
| GLint arg; |
| |
| while ((arg = va_arg(ap, GLint)) != 0) { |
| GLint arg2 = va_arg(ap, GLint); |
| setup_texture(pTexture, image, arg, arg2); |
| pTexture++; |
| } |
| |
| va_end(ap); |
| |
| return true; |
| } |
| |
| const TextureMap& |
| Texture::find_textures() |
| { |
| using std::vector; |
| using std::string; |
| if (!TexturePrivate::textureMap.empty()) |
| { |
| return TexturePrivate::textureMap; |
| } |
| vector<string> pathVec; |
| string dataDir(GLMARK_DATA_PATH"/textures"); |
| Util::list_files(dataDir, pathVec); |
| // Now that we have a list of all of the image files available to us, |
| // let's go through and pull out the names and what format they're in |
| // so the scene can decide which ones to use. |
| for(vector<string>::const_iterator pathIt = pathVec.begin(); |
| pathIt != pathVec.end(); |
| pathIt++) |
| { |
| const string& curPath = *pathIt; |
| string::size_type namePos(0); |
| string::size_type slashPos = curPath.rfind("/"); |
| if (slashPos != string::npos) |
| { |
| // Advance to the first character after the last slash |
| namePos = slashPos + 1; |
| } |
| |
| // Find the position of the extension |
| string::size_type pngExtPos = curPath.rfind(".png"); |
| string::size_type jpgExtPos = curPath.rfind(".jpg"); |
| string::size_type extPos(string::npos); |
| |
| // Select the extension that's closer to the end of the file name |
| if (pngExtPos == string::npos) |
| { |
| extPos = jpgExtPos; |
| } |
| else if (jpgExtPos == string::npos) |
| { |
| extPos = pngExtPos; |
| } |
| else |
| { |
| extPos = std::max(pngExtPos, jpgExtPos); |
| } |
| |
| if (extPos == string::npos) |
| { |
| // We can't trivially determine it's an image file so skip it... |
| continue; |
| } |
| |
| // Set the file type based on the extension |
| TextureDescriptor::FileType type(TextureDescriptor::FileTypeUnknown); |
| if (extPos == pngExtPos) |
| { |
| type = TextureDescriptor::FileTypePNG; |
| } |
| else if (extPos == jpgExtPos) |
| { |
| type = TextureDescriptor::FileTypeJPEG; |
| } |
| |
| string name(curPath, namePos, extPos - namePos); |
| TextureDescriptor* desc = new TextureDescriptor(name, curPath, type); |
| TexturePrivate::textureMap.insert(std::make_pair(name, desc)); |
| } |
| |
| return TexturePrivate::textureMap; |
| } |