bool Image::initWithS3TCData(const unsigned char * data, ssize_t dataLen) { const uint32_t FOURCC_DXT1 = makeFourCC('D', 'X', 'T', '1'); const uint32_t FOURCC_DXT3 = makeFourCC('D', 'X', 'T', '3'); const uint32_t FOURCC_DXT5 = makeFourCC('D', 'X', 'T', '5'); /* load the .dds file */ S3TCTexHeader *header = (S3TCTexHeader *)data; unsigned char *pixelData = static_cast<unsigned char*>(malloc((dataLen - sizeof(S3TCTexHeader)) * sizeof(unsigned char))); memcpy((void *)pixelData, data + sizeof(S3TCTexHeader), dataLen - sizeof(S3TCTexHeader)); _width = header->ddsd.width; _height = header->ddsd.height; _numberOfMipmaps = MAX(1, header->ddsd.DUMMYUNIONNAMEN2.mipMapCount); //if dds header reports 0 mipmaps, set to 1 to force correct software decoding (if needed). _dataLen = 0; int blockSize = (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) ? 8 : 16; /* calculate the dataLen */ int width = _width; int height = _height; if (supportsS3TC) //compressed data length { _dataLen = dataLen - sizeof(S3TCTexHeader); _data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char))); memcpy((void *)_data, (void *)pixelData, _dataLen); } else //decompressed data length { for (int i = 0; i < _numberOfMipmaps && (width || height); ++i) { if (width == 0) width = 1; if (height == 0) height = 1; _dataLen += (height * width * 4); width >>= 1; height >>= 1; } _data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char))); } /* if hardware supports s3tc, set pixelformat before loading mipmaps, to support non-mipmapped textures */ if (supportsS3TC) { //decode texture through hardware if (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) { _renderFormat = Texture2D::PixelFormat::S3TC_DXT1; } else if (FOURCC_DXT3 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) { _renderFormat = Texture2D::PixelFormat::S3TC_DXT3; } else if (FOURCC_DXT5 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) { _renderFormat = Texture2D::PixelFormat::S3TC_DXT5; } } else { //will software decode _renderFormat = Texture2D::PixelFormat::RGBA8888; } /* load the mipmaps */ int encodeOffset = 0; int decodeOffset = 0; width = _width; height = _height; for (int i = 0; i < _numberOfMipmaps && (width || height); ++i) { if (width == 0) width = 1; if (height == 0) height = 1; int size = ((width + 3) / 4)*((height + 3) / 4)*blockSize; if (supportsS3TC) { //decode texture through hardware _mipmaps[i].address = (unsigned char *)_data + encodeOffset; _mipmaps[i].len = size; } else { //if it is not gles or device do not support S3TC, decode texture by software OUTPUT_LOG("cocos2d: Hardware S3TC decoder not present. Using software decoder"); int bytePerPixel = 4; unsigned int stride = width * bytePerPixel; std::vector<unsigned char> decodeImageData(stride * height); if (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) { s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT1); } else if (FOURCC_DXT3 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) { s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT3); } else if (FOURCC_DXT5 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) { s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT5); } _mipmaps[i].address = (unsigned char *)_data + decodeOffset; _mipmaps[i].len = (stride * height); memcpy((void *)_mipmaps[i].address, (void *)&decodeImageData[0], _mipmaps[i].len); decodeOffset += stride * height; } encodeOffset += size; width >>= 1; height >>= 1; } /* end load the mipmaps */ if (pixelData != nullptr) { free(pixelData); }; return true; }
uint32_t ShaderManager::at(const std::string& filename) { /* filename suffix can be one of the followings values, where they are named after shader type. .vert for a vertex shader .tesc for a tessellation control shader .tese for a tessellation evaluation shader .geom for a geometry shader .frag for a fragment shader .comp for a compute shader */ size_t length = filename.length(); if(length < std::string("*.type").length()) return 0; const auto it = shader_id_map.find(filename); if(it != shader_id_map.end()) return it->second; const char* p = filename.c_str() + filename.length(); p -= 5; if(*p != '.') { slog.w(TAG, "filename [%s] suffix doesn't belongs to {'vert', 'tesc', 'tese', 'geom', 'frag', 'comp'}", filename.c_str()); return 0; } int type = *reinterpret_cast<const int*>(p + 1); #if __cplusplus >= 201103L constexpr uint32_t VERT = makeFourCC('v', 'e', 'r', 't'); constexpr uint32_t TESC = makeFourCC('t', 'e', 's', 'c'); constexpr uint32_t TESE = makeFourCC('t', 'e', 's', 'e'); constexpr uint32_t GEOM = makeFourCC('g', 'e', 'o', 'm'); constexpr uint32_t FRAG = makeFourCC('f', 'r', 'a', 'g'); constexpr uint32_t COMP = makeFourCC('c', 'o', 'm', 'p'); #else #define VERT makeFourCC('v', 'e', 'r', 't') #define TESC makeFourCC('t', 'e', 's', 'c') #define TESE makeFourCC('t', 'e', 's', 'e') #define GEOM makeFourCC('g', 'e', 'o', 'm') #define FRAG makeFourCC('f', 'r', 'a', 'g') #define COMP makeFourCC('c', 'o', 'm', 'p') #endif Shader* shader = nullptr; switch(type) { case VERT: shader = new(std::nothrow) VertexShader(); break; case TESC: shader = new(std::nothrow) TessControlShader(); break; case TESE: shader = new(std::nothrow) TessEvaluationShader(); break; case GEOM: shader = new(std::nothrow) GeometryShader(); break; case FRAG: shader = new(std::nothrow) FragmentShader(); break; case COMP: shader = new(std::nothrow) ComputeShader(); break; default: assert(false && "unknown shader type"); break; } shader->loadFromFile(filename); bool flag = shader->compile(); assert(flag); // fast fail uint32_t id = shader->getId(); shader_id_map[filename] = id; delete shader; return id; }