std::unique_ptr<float[]> loadStbiHdr(const Path &path, TexelConversion request, int &w, int &h) { InputStreamHandle in = FileUtils::openInputStream(path); if (!in) return nullptr; int channels; std::unique_ptr<float[], void(*)(void *)> img(stbi_loadf_from_callbacks(&istreamCallback, in.get(), &w, &h, &channels, 0), stbi_image_free); // We only expect Radiance HDR for now, which only has RGB support. if (!img || channels != 3) return nullptr; int targetChannels = (request == TexelConversion::REQUEST_RGB) ? 3 : 1; std::unique_ptr<float[]> texels(new float[w*h*targetChannels]); if (targetChannels == 3) { std::memcpy(texels.get(), img.get(), w*h*targetChannels*sizeof(float)); } else { for (int i = 0; i < w*h; ++i) texels[i] = convertToScalar(request, img[i*3], img[i*3 + 1], img[i*3 + 2], 1.0f, false); } return std::move(texels); }
sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(GrResourceProvider* resourceProvider, int sampleCnt, bool needsStencil, GrSurfaceDescFlags descFlags, GrMipMapped mipMapped) const { SkASSERT(GrSurfaceProxy::LazyState::kNot == this->lazyInstantiationState()); SkASSERT(!fTarget); GrSurfaceDesc desc; desc.fFlags = descFlags; if (fNeedsClear) { desc.fFlags |= kPerformInitialClear_GrSurfaceFlag; } desc.fWidth = fWidth; desc.fHeight = fHeight; desc.fConfig = fConfig; desc.fSampleCnt = sampleCnt; // The explicit resource allocator requires that any resources it pulls out of the // cache have no pending IO. GrResourceProvider::Flags resourceProviderFlags = GrResourceProvider::Flags::kNoPendingIO; sk_sp<GrSurface> surface; if (GrMipMapped::kYes == mipMapped) { SkASSERT(SkBackingFit::kExact == fFit); // SkMipMap doesn't include the base level in the level count so we have to add 1 int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1; // We should have caught the case where mipCount == 1 when making the proxy and instead // created a non-mipmapped proxy. SkASSERT(mipCount > 1); std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]); // We don't want to upload any texel data for (int i = 0; i < mipCount; i++) { texels[i].fPixels = nullptr; texels[i].fRowBytes = 0; } surface = resourceProvider->createTexture(desc, fBudgeted, texels.get(), mipCount); if (surface) { SkASSERT(surface->asTexture()); SkASSERT(GrMipMapped::kYes == surface->asTexture()->texturePriv().mipMapped()); } } else { if (SkBackingFit::kApprox == fFit) { surface = resourceProvider->createApproxTexture(desc, resourceProviderFlags); } else { surface = resourceProvider->createTexture(desc, fBudgeted, resourceProviderFlags); } } if (!surface) { return nullptr; } if (!GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, surface.get(), needsStencil)) { return nullptr; } return surface; }
sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data, SkBudgeted budgeted) { if (!data) { return nullptr; } const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data); if (!context || context->uniqueID() != dti->fContextUniqueID) { return nullptr; } int mipLevelCount = dti->fMipMapLevelCount; SkASSERT(mipLevelCount >= 1); sk_sp<SkColorSpace> colorSpace; if (dti->fColorSpaceSize) { colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize); } SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight, dti->fColorType, dti->fAlphaType, colorSpace); if (mipLevelCount == 1) { SkPixmap pixmap; pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes); // Use the NoCheck version because we have already validated the SkImage. The |data| // used to be an SkImage before calling getDeferredTextureImageData(). In legacy mode, // getDeferredTextureImageData() will allow parametric transfer functions for images // generated from codecs - which is slightly more lenient than typical SkImage // constructors. sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxyNoCheck( context->resourceProvider(), pixmap, budgeted)); if (!proxy) { return nullptr; } return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(), std::move(proxy), std::move(colorSpace), budgeted); } else { std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]); for (int i = 0; i < mipLevelCount; i++) { texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData; texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes; } return SkImage::MakeTextureFromMipMap(context, info, texels.get(), mipLevelCount, SkBudgeted::kYes, dti->fColorMode); } }
// InfiniteAreaLight Method Definitions InfiniteAreaLight::InfiniteAreaLight(const Transform &LightToWorld, const Spectrum &L, int nSamples, const std::string &texmap) : Light((int)LightFlags::Infinite, LightToWorld, MediumInterface(), nSamples) { // Read texel data from _texmap_ and initialize _Lmap_ Point2i resolution; std::unique_ptr<RGBSpectrum[]> texels(nullptr); if (texmap != "") { texels = ReadImage(texmap, &resolution); if (texels) for (int i = 0; i < resolution.x * resolution.y; ++i) texels[i] *= L.ToRGBSpectrum(); } if (!texels) { resolution.x = resolution.y = 1; texels = std::unique_ptr<RGBSpectrum[]>(new RGBSpectrum[1]); texels[0] = L.ToRGBSpectrum(); } Lmap.reset(new MIPMap<RGBSpectrum>(resolution, texels.get())); // Initialize sampling PDFs for infinite area light // Compute scalar-valued image _img_ from environment map int width = 2 * Lmap->Width(), height = 2 * Lmap->Height(); std::unique_ptr<Float[]> img(new Float[width * height]); float fwidth = 0.5f / std::min(width, height); ParallelFor( [&](int64_t v) { Float vp = (v + .5f) / (Float)height; Float sinTheta = std::sin(Pi * (v + .5f) / height); for (int u = 0; u < width; ++u) { Float up = (u + .5f) / (Float)width; img[u + v * width] = Lmap->Lookup(Point2f(up, vp), fwidth).y(); img[u + v * width] *= sinTheta; } }, height, 32); // Compute sampling distributions for rows and columns of image distribution.reset(new Distribution2D(img.get(), width, height)); }
static std::unique_ptr<float[]> loadPfm(const Path &path, TexelConversion request, int &w, int &h) { InputStreamHandle in = FileUtils::openInputStream(path); if (!in) return nullptr; std::string ident; *in >> ident; int channels; if (ident == "Pf") channels = 1; else if (ident == "PF") channels = 3; else return nullptr; int targetChannels = (request == TexelConversion::REQUEST_RGB) ? 3 : 1; *in >> w >> h; double s; *in >> s; std::string tmp; std::getline(*in, tmp); std::unique_ptr<float[]> img(new float[w*h*channels]); for (int y = 0; y < h; ++y) in->read(reinterpret_cast<char *>(img.get() + (h - y - 1)*w*channels), w*channels*sizeof(float)); if (channels == targetChannels) return std::move(img); std::unique_ptr<float[]> texels(new float[w*h*targetChannels]); if (targetChannels == 3) for (int i = 0; i < w*h; ++i) texels[i*3] = texels[i*3 + 1] = texels[i*3 + 2] = img[i]; else for (int i = 0; i < w*h; ++i) texels[i] = convertToScalar(request, img[i*3], img[i*3 + 1], img[i*3 + 2], 1.0f, false); return std::move(texels); }
boo::GraphicsDataToken InitializeIcons(specter::ViewResources& viewRes) { athena::io::MemoryReader r(URDE_ICONS, URDE_ICONS_SZ); size_t fmt = r.readUint32Big(); if (fmt != 16) Log.report(logvisor::Fatal, "incorrect icon texture format"); size_t width = r.readUint16Big(); size_t height = r.readUint16Big(); size_t mips = r.readUint32Big(); size_t decompSz = r.readUint32Big(); std::unique_ptr<uint8_t[]> texels(new uint8_t[decompSz]); uLongf destSz = decompSz; size_t pos = r.position(); if (uncompress(texels.get(), &destSz, URDE_ICONS + pos, URDE_ICONS_SZ - pos) != Z_OK) Log.report(logvisor::Fatal, "unable to decompress icons"); g_IconAtlas.initializeAtlas(viewRes.m_factory->newStaticTexture(width, height, mips, boo::TextureFormat::RGBA8, texels.get(), destSz)); return viewRes.m_factory->commit(); }
sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data, SkBudgeted budgeted) { if (!data) { return nullptr; } const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data); if (!context || context->uniqueID() != dti->fContextUniqueID) { return nullptr; } SkAutoTUnref<SkColorTable> colorTable; if (dti->fColorTableCnt) { SkASSERT(dti->fColorTableData); colorTable.reset(new SkColorTable(dti->fColorTableData, dti->fColorTableCnt)); } int mipLevelCount = dti->fMipMapLevelCount; SkASSERT(mipLevelCount >= 1); sk_sp<SkColorSpace> colorSpace; if (dti->fColorSpaceSize) { colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize); } SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight, dti->fColorType, dti->fAlphaType, colorSpace); if (mipLevelCount == 1) { SkPixmap pixmap; pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes, colorTable.get()); return SkImage::MakeTextureFromPixmap(context, pixmap, budgeted); } else { SkAutoTDeleteArray<GrMipLevel> texels(new GrMipLevel[mipLevelCount]); for (int i = 0; i < mipLevelCount; i++) { texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData; texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes; } return SkImage::MakeTextureFromMipMap(context, info, texels.get(), mipLevelCount, SkBudgeted::kYes, dti->fGammaTreatment); } }
// InfiniteAreaLight Method Definitions InfiniteAreaLight::InfiniteAreaLight(const Transform &LightToWorld, const Spectrum &L, int nSamples, const std::string &texmap) : Light(LightFlags::Infinite, LightToWorld, nullptr, nSamples) { // Read texel data from _texmap_ and initialize _Lmap_ Point2i resolution; std::unique_ptr<RGBSpectrum[]> texels(nullptr); if (texmap != "") { texels = ReadImage(texmap, &resolution); if (texels) for (int i = 0; i < resolution.x * resolution.y; ++i) texels[i] *= L.ToRGBSpectrum(); } if (!texels) { resolution.x = resolution.y = 1; texels = std::unique_ptr<RGBSpectrum[]>(new RGBSpectrum[1]); texels[0] = L.ToRGBSpectrum(); } Lmap.reset(new MIPMap<RGBSpectrum>(resolution, texels.get())); // Initialize sampling PDFs for infinite area light // Compute scalar-valued image _img_ from environment map int width = resolution.x, height = resolution.y; Float filter = (Float)1. / std::max(width, height); std::unique_ptr<Float[]> img(new Float[width * height]); for (int v = 0; v < height; ++v) { Float vp = (Float)v / (Float)height; Float sinTheta = std::sin(Pi * Float(v + .5f) / Float(height)); for (int u = 0; u < width; ++u) { Float up = (Float)u / (Float)width; img[u + v * width] = Lmap->Lookup(Point2f(up, vp), filter).y(); img[u + v * width] *= sinTheta; } } // Compute sampling distributions for rows and columns of image distribution.reset(new Distribution2D(img.get(), width, height)); }
static std::unique_ptr<float[]> loadExr(const Path &path, TexelConversion request, int &w, int &h) { InputStreamHandle inputStream = FileUtils::openInputStream(path); if (!inputStream) return nullptr; try { ExrIStream in(std::move(inputStream)); Imf::InputFile file(in); Imath::Box2i dataWindow = file.header().dataWindow(); w = dataWindow.max.x - dataWindow.min.x + 1; h = dataWindow.max.y - dataWindow.min.y + 1; int dx = dataWindow.min.x; int dy = dataWindow.min.y; const Imf::ChannelList &channels = file.header().channels(); const Imf::Channel *rChannel = channels.findChannel("R"); const Imf::Channel *gChannel = channels.findChannel("G"); const Imf::Channel *bChannel = channels.findChannel("B"); const Imf::Channel *aChannel = channels.findChannel("A"); const Imf::Channel *yChannel = channels.findChannel("Y"); Imf::FrameBuffer frameBuffer; bool isScalar = request != TexelConversion::REQUEST_RGB; bool acceptsAlpha = request == TexelConversion::REQUEST_ALPHA || request == TexelConversion::REQUEST_AUTO; int targetChannels = isScalar ? 1 : 3; int sourceChannels = (rChannel ? 1 : 0) + (gChannel ? 1 : 0) + (bChannel ? 1 : 0); std::unique_ptr<float[]> texels(new float[w*h*targetChannels]); std::unique_ptr<float[]> img; size_t texelSize = sizeof(float)*targetChannels; char *base = reinterpret_cast<char *>(texels.get() - (dx + dy*w)*targetChannels); if (isScalar && (yChannel != nullptr || (acceptsAlpha && aChannel != nullptr))) { // The user requested a scalar texture and the file either contains an alpha channel or a luminance channel // The alpha channel is only allowed if it was explicitly requested or an auto conversion was requested // RGB -> Scalar falls through and is handled later const char *channelName = (acceptsAlpha && aChannel != nullptr) ? "A" : "Y"; frameBuffer.insert(channelName, Imf::Slice(Imf::FLOAT, base, texelSize, texelSize*w)); } else if (!isScalar && (rChannel || gChannel || bChannel)) { // The user wants RGB and we have (some) RGB channels if (rChannel) frameBuffer.insert("R", Imf::Slice(Imf::FLOAT, base + 0*sizeof(float), texelSize, texelSize*w)); if (gChannel) frameBuffer.insert("G", Imf::Slice(Imf::FLOAT, base + 1*sizeof(float), texelSize, texelSize*w)); if (bChannel) frameBuffer.insert("B", Imf::Slice(Imf::FLOAT, base + 2*sizeof(float), texelSize, texelSize*w)); // If some channels are missing, replace them with black if (!rChannel || !gChannel || !bChannel) std::memset(texels.get(), 0, texelSize*w*h); } else if (!isScalar && yChannel) { // The user wants RGB and we have just luminance -> duplicate luminance across all three channels // This is not the best solution, but we don't want to deal with chroma subsampled images frameBuffer.insert("Y", Imf::Slice(Imf::FLOAT, base, texelSize, texelSize*w)); } else if (isScalar) { // The user wants a scalar texture and we have (some) RGB channels // We can't read directly into the destination, but have to read to a temporary // and do a conversion to scalar later img.reset(new float[sourceChannels*w*h]); char *imgBase = reinterpret_cast<char *>(img.get() - (dx + dy*w)*sourceChannels); const Imf::Channel *channels[] = {rChannel, gChannel, bChannel}; const char *channelNames[] = {"R", "G", "B"}; int texel = 0; for (int i = 0; i < 3; ++i) { if (channels[i]) { frameBuffer.insert(channelNames[i], Imf::Slice(Imf::FLOAT, imgBase + texel*sizeof(float), sourceChannels*sizeof(float), sourceChannels*sizeof(float)*w)); texel++; } } } else { return false; } file.setFrameBuffer(frameBuffer); file.readPixels(dataWindow.min.y, dataWindow.max.y); if (img) { // We only get here if we need to make a scalar texture from an RGB input int texel = 0; int rLocation = -1, gLocation = -1, bLocation = -1; if (rChannel) rLocation = texel++; if (gChannel) gLocation = texel++; if (bChannel) bLocation = texel++; for (int i = 0; i < w*h; ++i) { float r = rChannel ? img[i*sourceChannels + rLocation] : 0.0f; float g = gChannel ? img[i*sourceChannels + gLocation] : 0.0f; float b = bChannel ? img[i*sourceChannels + bLocation] : 0.0f; texels[i] = convertToScalar(request, r, g, b, 0.0f, false); } } else if (!isScalar && yChannel) { // Here we need to duplicate the Y channel stored in R across G and B for (int i = 0; i < w*h; ++i) texels[i*3 + 1] = texels[i*3 + 2] = texels[i*3]; } return std::move(texels); } catch(const std::exception &e) { std::cout << "OpenEXR loader failed: " << e.what() << std::endl; return nullptr; } }