// Scan through the image from the lower left corner across each row // and then up to the top right. Initially the image is sampled very // coarsely. Increment the static variables that track the progress // through the scans int GLCanvas::DrawPixel() { if (raytracing_x > args->width) { raytracing_x = raytracing_skip/2; raytracing_y += raytracing_skip; } if (raytracing_y > args->height) { if (raytracing_skip == 1) return 0; raytracing_skip = raytracing_skip / 2; if (raytracing_skip % 2 == 0) raytracing_skip++; assert (raytracing_skip >= 1); raytracing_x = raytracing_skip/2; raytracing_y = raytracing_skip/2; glEnd(); glPointSize(raytracing_skip); glBegin(GL_POINTS); } // compute the color and position of intersection Vec3f color= TraceRay(raytracing_x, raytracing_y); double r = linear_to_srgb(color.x()); double g = linear_to_srgb(color.y()); double b = linear_to_srgb(color.z()); glColor3f(r,g,b); // glColor3f(1,0,0); double x = 2 * (raytracing_x/double(args->width)) - 1; double y = 2 * (raytracing_y/double(args->height)) - 1; glVertex3f(x,y,-1); raytracing_x += raytracing_skip; return 1; }
DWORD WINAPI ThreadFunc(void * arg) { tVals* vars = (tVals*)arg; int i=0; while(true) { i++; double rayx,rayy; int tempSkip; WaitForSingleObject(*(vars->rayLock),INFINITE); if ((*vars->raytracing_x) >= vars->args->width) { (*vars->raytracing_x) = (*vars->raytracing_skip)/2; (*vars->raytracing_y) += (*vars->raytracing_skip); } if ((*vars->raytracing_y) >= vars->args->height) { if ((*vars->raytracing_skip) == 1) break; (*vars->raytracing_skip) = *(vars->raytracing_skip) / 2; if (*(vars->raytracing_skip) % 2 == 0) (*vars->raytracing_skip)++; assert (*(vars->raytracing_skip) >= 1); (*vars->raytracing_x) = (*vars->raytracing_skip)/2; (*vars->raytracing_y) = (*vars->raytracing_skip)/2; } rayx=*(vars->raytracing_x); rayy=*(vars->raytracing_y); tempSkip=(*vars->raytracing_skip); (*vars->raytracing_x) += *(vars->raytracing_skip); (*vars->pixels)+=1; ReleaseMutex(*(vars->rayLock)); // compute the color and position of intersection glm::vec3 color= TraceRay(rayx, rayy,vars); double r = linear_to_srgb(color.r); double g = linear_to_srgb(color.g); double b = linear_to_srgb(color.b); WaitForSingleObject(*(vars->glLock),INFINITE); globalR=r;globalG=g;globalB=b; globalX=rayx;globalY=rayy; globalSkip=tempSkip; //if ((*vars->pixels)<10000) globalIsPoint=true; while (globalIsPoint); ReleaseMutex(*(vars->glLock)); } std::cout<<"Thread terminated"<<std::endl; return 0; }
static bool analyze_image(GLuint fbo) { GLfloat *expected_data = malloc(PATTERN_WIDTH * PATTERN_HEIGHT * 4 * sizeof(GLfloat)); unsigned x, y, component; bool pass; for (y = 0; y < PATTERN_HEIGHT; ++y) { for (x = 0; x < PATTERN_WIDTH; ++x) { for (component = 0; component < 4; ++component) { float val = x / 255.0; if (component < 3 && enable_srgb_framebuffer) { if (src_format == GL_SRGB8_ALPHA8) val = srgb_to_linear(val); if (dst_format == GL_SRGB8_ALPHA8) val = linear_to_srgb(val); } expected_data[(y * PATTERN_WIDTH + x) * 4 + component] = val; } } } glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); pass = piglit_probe_image_rgba(0, 0, PATTERN_WIDTH, PATTERN_HEIGHT, expected_data); free(expected_data); return pass; }
bool check_gamma(uint32_t src, uint32_t dst, bool toSRGB, float error, uint32_t* expected) { bool result = true; uint32_t expectedColor = src & 0xff000000; // Alpha should always be exactly preserved. if ((src & 0xff000000) != (dst & 0xff000000)) { result = false; } // need to unpremul before we can perform srgb magic float invScale = 0; float alpha = SkGetPackedA32(src); if (alpha) { invScale = 255.0f / alpha; } for (int c = 0; c < 3; ++c) { float srcComponent = ((src & (0xff << (c * 8))) >> (c * 8)) * invScale; float lower = SkTMax(0.f, srcComponent - error); float upper = SkTMin(255.f, srcComponent + error); if (toSRGB) { lower = linear_to_srgb(lower / 255.f); upper = linear_to_srgb(upper / 255.f); } else { lower = srgb_to_linear(lower / 255.f); upper = srgb_to_linear(upper / 255.f); } lower *= alpha; upper *= alpha; SkASSERT(lower >= 0.f && lower <= 255.f); SkASSERT(upper >= 0.f && upper <= 255.f); uint8_t dstComponent = (dst & (0xff << (c * 8))) >> (c * 8); if (dstComponent < SkScalarFloorToInt(lower) || dstComponent > SkScalarCeilToInt(upper)) { result = false; } uint8_t expectedComponent = SkScalarRoundToInt((lower + upper) * 0.5f); expectedColor |= expectedComponent << (c * 8); } *expected = expectedColor; return result; }
// Scan through the image from the lower left corner across each row // and then up to the top right. Initially the image is sampled very // coarsely. Increment the static variables that track the progress // through the scans void GLCanvas::DrawPixel( int ray_x, int ray_y, std::vector<Triple<double, double, double> > & colors, std::vector<Triple<double, double, double> > & vertices ) { // compute the color and position of intersection Vec3f color= TraceRay(ray_x, ray_y); double r = linear_to_srgb(color.x()); double g = linear_to_srgb(color.y()); double b = linear_to_srgb(color.z()); colors.push_back(make_triple(r,g,b)); //glColor3f(r,g,b); double x = 2 * (ray_x/double(args->width)) - 1; double y = 2 * (ray_y/double(args->height)) - 1; vertices.push_back(make_triple(x,y,(double)(-1))); //glVertex3f(x,y,-1); }
//Write the image to a file void GLCanvas::WriteToFile() { //ORIGINAL CODE COMMENT //PLEASE BE UNIQUE std::cout << "Only in new folder!\n"; //Open file Image newfile(""); newfile.Allocate(args->width, args->height); //Write to file for (int i = 0; i < args->width; i++) { for (int j = 0; j < args->height; j++) { glm::vec3 color = TraceRay((i + 0.5),(j + 0.5)); //std::cout << color.r << "\t" << color.g << "\t" << color.b << "\n"; double r = linear_to_srgb(color.r); double g = linear_to_srgb(color.g); double b = linear_to_srgb(color.b); r *= 255; if (r > 255) r = 255; g *= 255; if (g > 255) g = 255; b *= 255; if (b > 255) b = 255; int ri, gi, bi; Color pixelcolor(r,g,b); //std::cout << r << "\t" << g << "\t" << b << "\n"; newfile.SetPixel(i, j, pixelcolor); } } //Save and close file newfile.Save("Rendering.ppm"); return; }
DEF_TEST(sk_linear_to_srgb, r) { // All bytes should round trip. for (int i = 0; i < 256; i++) { int actual = linear_to_srgb(sk_linear_from_srgb[i]); if (i != actual) { ERRORF(r, "%d -> %d\n", i, actual); } } // Should be monotonic between 0 and 1. uint8_t prev = 0; for (float f = FLT_MIN; f <= 1.0f; ) { // We don't bother checking denorm values. uint8_t srgb = linear_to_srgb(f); REPORTER_ASSERT(r, srgb >= prev); prev = srgb; union { float flt; uint32_t bits; } pun = { f }; pun.bits++; SkDEBUGCODE(pun.bits += 127); f = pun.flt; } }
void resize_image(const QImage &img, QImage &out){ assert(img.format() == QImage::Format_RGB32); assert(out.format() == QImage::Format_RGB32); #pragma omp parallel for for (int i = 0; i < out.width() * out.height(); ++i){ int ox = i % out.width(); int oy = i / out.width(); float fx = img.width() * static_cast<float>(ox) / out.width(); float fy = img.height() * static_cast<float>(oy) / out.height(); int ix = static_cast<int>(fx); int iy = static_cast<int>(fy); fx = fx - ix; fy = fy - iy; uint8_t *out_scanline = out.scanLine(oy); // This is just nearest neighbor filtering with sRGB correction for (int c = 0; c < 4; ++c){ // Convert to linear space to do the filtering int x = ix; int y = iy; const uint8_t *img_scanline = img.scanLine(y); const float v00 = srgb_to_linear(static_cast<float>(img_scanline[x * 4 + c]) / 255.0); x = clamp(ix + 1, 0, img.width() - 1); const float v10 = srgb_to_linear(static_cast<float>(img_scanline[x * 4 + c]) / 255.0); x = ix; y = clamp(iy + 1, 0, img.height() - 1); img_scanline = img.scanLine(y); const float v01 = srgb_to_linear(static_cast<float>(img_scanline[x * 4 + c]) / 255.0); x = clamp(ix + 1, 0, img.width() - 1); const float v11 = srgb_to_linear(static_cast<float>(img_scanline[x * 4 + c]) / 255.0); // Now do the bilinear filtering const float v = v00 * (1.0 - fx) * (1.0 - fy) + v10 * fx * (1.0 - fy) + v01 * (1.0 - fx) * fy + v11 * fx * fy; // Convert back to sRGB to save result out_scanline[ox * 4 + c] = static_cast<unsigned char>(linear_to_srgb(v) * 255.0); } } }
void Radiosity::setupVBOs() { HandleGLError("enter radiosity setupVBOs()"); mesh_tri_verts.clear(); mesh_tri_indices.clear(); mesh_textured_tri_indices.clear(); // initialize the data in each vector int num_faces = mesh->numFaces(); assert (num_faces > 0); for (int i = 0; i < num_faces; i++) { Face *f = mesh->getFace(i); Edge *e = f->getEdge(); glm::vec3 normal = f->computeNormal(); double avg_s = 0; double avg_t = 0; glm::vec3 avg_color(0,0,0); int start = mesh_tri_verts.size(); // wireframe is normally black, except when it's the special // patch, then the wireframe is red glm::vec4 wireframe_color(0,0,0,0.5); if (args->render_mode == RENDER_FORM_FACTORS && i == max_undistributed_patch) { wireframe_color = glm::vec4(1,0,0,1); } // add the 4 corner vertices for (int j = 0; j < 4; j++) { glm::vec3 pos = ((*f)[j])->get(); double s = (*f)[j]->get_s(); double t = (*f)[j]->get_t(); glm::vec3 color = setupHelperForColor(f,i,j); color = glm::vec3(linear_to_srgb(color.r), linear_to_srgb(color.g), linear_to_srgb(color.b)); avg_color += 0.25f * color; mesh_tri_verts.push_back(VBOPosNormalColor(pos,normal, glm::vec4(color.r,color.g,color.b,1.0), wireframe_color, s,t)); avg_s += 0.25 * s; avg_t += 0.25 * t; e = e->getNext(); } // the centroid (for wireframe rendering) glm::vec3 centroid = f->computeCentroid(); mesh_tri_verts.push_back(VBOPosNormalColor(centroid,normal, glm::vec4(avg_color.r,avg_color.g,avg_color.b,1), glm::vec4(1,1,1,1), avg_s,avg_t)); if (f->getMaterial()->hasTextureMap()) { mesh_textured_tri_indices.push_back(VBOIndexedTri(start+0,start+1,start+4)); mesh_textured_tri_indices.push_back(VBOIndexedTri(start+1,start+2,start+4)); mesh_textured_tri_indices.push_back(VBOIndexedTri(start+2,start+3,start+4)); mesh_textured_tri_indices.push_back(VBOIndexedTri(start+3,start+0,start+4)); } else { mesh_tri_indices.push_back(VBOIndexedTri(start+0,start+1,start+4)); mesh_tri_indices.push_back(VBOIndexedTri(start+1,start+2,start+4)); mesh_tri_indices.push_back(VBOIndexedTri(start+2,start+3,start+4)); mesh_tri_indices.push_back(VBOIndexedTri(start+3,start+0,start+4)); } } assert ((int)mesh_tri_verts.size() == num_faces*5); assert ((int)mesh_tri_indices.size() + (int)mesh_textured_tri_indices.size() == num_faces*4); // copy the data to each VBO glBindBuffer(GL_ARRAY_BUFFER,mesh_tri_verts_VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(VBOPosNormalColor) * num_faces * 5, &mesh_tri_verts[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh_tri_indices_VBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(VBOIndexedTri) * mesh_tri_indices.size(), &mesh_tri_indices[0], GL_STATIC_DRAW); if (mesh_textured_tri_indices.size() > 0) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh_textured_tri_indices_VBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(VBOIndexedTri) * mesh_textured_tri_indices.size(), &mesh_textured_tri_indices[0], GL_STATIC_DRAW); } HandleGLError("radiosity setupVBOs() just before texture"); // WARNING: this naive VBO implementation only allows a single texture // FIXME: something still buggy about textures int num_textured_materials = 0; for (unsigned int mat = 0; mat < mesh->materials.size(); mat++) { Material *m = mesh->materials[mat]; if (m->hasTextureMap()) { // FIXME: old gl... //glBindTexture(GL_TEXTURE_2D,m->getTextureID()); num_textured_materials++; } } assert (num_textured_materials <= 1); HandleGLError("leave radiosity setupVBOs()"); }
void Radiosity::insertColor(Vec3f v) { double r = linear_to_srgb(v.x()); double g = linear_to_srgb(v.y()); double b = linear_to_srgb(v.z()); glColor3f(r,g,b); }
// Scan through the image from the lower left corner across each row // and then up to the top right. Initially the image is sampled very // coarsely. Increment the static variables that track the progress // through the scans int GLCanvas::DrawPixel() { if (raytracing_x >= raytracing_divs_x) { // end of row raytracing_x = 0; raytracing_y += 1; } if (raytracing_y >= raytracing_divs_y) { // last row if (raytracing_divs_x >= args->width || raytracing_divs_y >= args->height) { // stop rendering, matches resolution of current camera return 0; } // else decrease pixel size & start over again in the bottom left corner raytracing_divs_x *= 6; raytracing_divs_y *= 6; if (raytracing_divs_x > args->width * 0.51 || raytracing_divs_x > args->height * 0.51) { raytracing_divs_x = args->width; raytracing_divs_y = args->height; } raytracing_x = 0; raytracing_y = 0; if (raytracer->render_to_a) { raytracer->pixels_b.clear(); raytracer->pixels_indices_b.clear(); raytracer->render_to_a = false; } else { raytracer->pixels_a.clear(); raytracer->pixels_indices_a.clear(); raytracer->render_to_a = true; } } double x_spacing = args->width / double (raytracing_divs_x); double y_spacing = args->height / double (raytracing_divs_y); // compute the color and position of intersection glm::vec3 pos1 = GetPos((raytracing_x )*x_spacing, (raytracing_y )*y_spacing); glm::vec3 pos2 = GetPos((raytracing_x+1)*x_spacing, (raytracing_y )*y_spacing); glm::vec3 pos3 = GetPos((raytracing_x+1)*x_spacing, (raytracing_y+1)*y_spacing); glm::vec3 pos4 = GetPos((raytracing_x )*x_spacing, (raytracing_y+1)*y_spacing); glm::vec3 color = TraceRay((raytracing_x+0.5)*x_spacing, (raytracing_y+0.5)*y_spacing); double r = linear_to_srgb(color.r); double g = linear_to_srgb(color.g); double b = linear_to_srgb(color.b); if (raytracer->render_to_a) { int start = raytracer->pixels_a.size(); raytracer->pixels_a.push_back(VBOPosNormalColor(pos1,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_a.push_back(VBOPosNormalColor(pos2,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_a.push_back(VBOPosNormalColor(pos3,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_a.push_back(VBOPosNormalColor(pos4,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_indices_a.push_back(VBOIndexedTri(start+0,start+1,start+2)); raytracer->pixels_indices_a.push_back(VBOIndexedTri(start+0,start+2,start+3)); } else { int start = raytracer->pixels_b.size(); raytracer->pixels_b.push_back(VBOPosNormalColor(pos1,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_b.push_back(VBOPosNormalColor(pos2,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_b.push_back(VBOPosNormalColor(pos3,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_b.push_back(VBOPosNormalColor(pos4,glm::vec3(0,0,0),glm::vec4(r,g,b,1.0))); raytracer->pixels_indices_b.push_back(VBOIndexedTri(start+0,start+1,start+2)); raytracer->pixels_indices_b.push_back(VBOIndexedTri(start+0,start+2,start+3)); } raytracing_x += 1; return 1; }
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SRGBMipMaps, reporter, ctxInfo) { GrContext* context = ctxInfo.grContext(); if (!context->caps()->srgbSupport()) { return; } const int rtS = 16; const int texS = rtS * 2; // Fill texture with a dither of black and 60% sRGB (~ 32.5% linear) gray. Although there is // only one likely failure mode (doing a direct downsample of the sRGB values), this pattern // maximizes the minimum error across all three conceivable failure modes: // 1) Likely incorrect: // (A + B) / 2 // 2) No input decode, decode output: // linear_to_srgb((A + B) / 2) // 3) Decode input, no output encode: // (srgb_to_linear(A) + srgb_to_linear(B)) / 2 const U8CPU srgb60 = sk_float_round2int(0.6f * 255.0f); static const SkPMColor colors[2] = { SkPackARGB32(0xFF, srgb60, srgb60, srgb60), SkPackARGB32(0xFF, 0x00, 0x00, 0x00) }; uint32_t texData[texS * texS]; for (int y = 0; y < texS; ++y) { for (int x = 0; x < texS; ++x) { texData[y * texS + x] = colors[(x + y) % 2]; } } // We can be pretty generous with the error detection, thanks to the choice of input. // The closest likely failure mode is off by > 0.1, so anything that encodes within // 10/255 of optimal is more than good enough for this test. const U8CPU expectedSRGB = sk_float_round2int( linear_to_srgb(srgb_to_linear(srgb60 / 255.0f) / 2.0f) * 255.0f); const U8CPU expectedLinear = srgb60 / 2; const U8CPU error = 10; // Create our test texture GrSurfaceDesc desc; desc.fFlags = kNone_GrSurfaceFlags; desc.fConfig = kSRGBA_8888_GrPixelConfig; desc.fWidth = texS; desc.fHeight = texS; GrTextureProvider* texProvider = context->textureProvider(); SkAutoTUnref<GrTexture> texture(texProvider->createTexture(desc, SkBudgeted::kNo, texData, 0)); // Create two render target contexts (L32 and S32) sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); sk_sp<GrRenderTargetContext> l32RenderTargetContext = context->makeRenderTargetContext( SkBackingFit::kExact, rtS, rtS, kRGBA_8888_GrPixelConfig, nullptr); sk_sp<GrRenderTargetContext> s32RenderTargetContext = context->makeRenderTargetContext( SkBackingFit::kExact, rtS, rtS, kSRGBA_8888_GrPixelConfig, std::move(srgbColorSpace)); SkRect rect = SkRect::MakeWH(SkIntToScalar(rtS), SkIntToScalar(rtS)); GrNoClip noClip; GrPaint paint; paint.setPorterDuffXPFactory(SkBlendMode::kSrc); GrTextureParams mipMapParams(SkShader::kRepeat_TileMode, GrTextureParams::kMipMap_FilterMode); paint.addColorTextureProcessor(texture, nullptr, SkMatrix::MakeScale(0.5f), mipMapParams); // 1) Draw texture to S32 surface (should generate/use sRGB mips) paint.setGammaCorrect(true); s32RenderTargetContext->drawRect(noClip, paint, SkMatrix::I(), rect); read_and_check_pixels(reporter, s32RenderTargetContext->asTexture().get(), expectedSRGB, error, "first render of sRGB"); // 2) Draw texture to L32 surface (should generate/use linear mips) paint.setGammaCorrect(false); l32RenderTargetContext->drawRect(noClip, paint, SkMatrix::I(), rect); read_and_check_pixels(reporter, l32RenderTargetContext->asTexture().get(), expectedLinear, error, "re-render as linear"); // 3) Go back to sRGB paint.setGammaCorrect(true); s32RenderTargetContext->drawRect(noClip, paint, SkMatrix::I(), rect); read_and_check_pixels(reporter, s32RenderTargetContext->asTexture().get(), expectedSRGB, error, "re-render as sRGB"); }
static Sk4f linear_unit_to_srgb_255f(const Sk4f& l4) { return linear_to_srgb(l4) * Sk4f(255) + Sk4f(0.5f); }