static void tonemap(NodeTonemap* ntm, CompBuf* dst, CompBuf* src) { int x, y; float dr, dg, db, al, igm = (ntm->gamma==0.f) ? 1 : (1.f / ntm->gamma); float auto_key, Lav, Cav[3] = {0, 0, 0}; al = avgLogLum(src, &auto_key, &Lav, Cav); al = (al == 0.f) ? 0.f : (ntm->key / al); if (ntm->type == 1) { // Reinhard/Devlin photoreceptor const float f = exp((double)-ntm->f); const float m = (ntm->m > 0.f) ? ntm->m : (0.3f + 0.7f*pow((double)auto_key, 1.4)); const float ic = 1.f - ntm->c, ia = 1.f - ntm->a; if (ntm->m == 0.f) printf("tonemap node, M: %g\n", m); for (y=0; y<src->y; ++y) { fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type]; fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type]; for (x=0; x<src->x; ++x) { const float L = 0.212671f*sp[x][0] + 0.71516f*sp[x][1] + 0.072169f*sp[x][2]; float I_l = sp[x][0] + ic*(L - sp[x][0]); float I_g = Cav[0] + ic*(Lav - Cav[0]); float I_a = I_l + ia*(I_g - I_l); dp[x][0] /= (dp[x][0] + pow((double)f*I_a, (double)m)); I_l = sp[x][1] + ic*(L - sp[x][1]); I_g = Cav[1] + ic*(Lav - Cav[1]); I_a = I_l + ia*(I_g - I_l); dp[x][1] /= (dp[x][1] + pow((double)f*I_a,(double)m)); I_l = sp[x][2] + ic*(L - sp[x][2]); I_g = Cav[2] + ic*(Lav - Cav[2]); I_a = I_l + ia*(I_g - I_l); dp[x][2] /= (dp[x][2] + pow((double)f*I_a, (double)m)); } } return; } // Reinhard simple photographic tm (simplest, not using whitepoint var) for (y=0; y<src->y; y++) { fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type]; fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type]; for (x=0; x<src->x; x++) { fRGB_copy(dp[x], sp[x]); fRGB_mult(dp[x], al); dr = dp[x][0] + ntm->offset; dg = dp[x][1] + ntm->offset; db = dp[x][2] + ntm->offset; dp[x][0] /= ((dr == 0.f) ? 1.f : dr); dp[x][1] /= ((dg == 0.f) ? 1.f : dg); dp[x][2] /= ((db == 0.f) ? 1.f : db); if (igm != 0.f) { dp[x][0] = pow((double)MAX2(dp[x][0], 0.), igm); dp[x][1] = pow((double)MAX2(dp[x][1], 0.), igm); dp[x][2] = pow((double)MAX2(dp[x][2], 0.), igm); } } } }
// mix two images, src buffer does not have to be same size, static void mixImages(CompBuf *dst, CompBuf *src, float mix) { int x, y; fRGB c1, c2, *dcolp, *scolp; const float mf = 2.f - 2.f*fabsf(mix - 0.5f); if ((dst->x == src->x) && (dst->y == src->y)) { for (y=0; y<dst->y; y++) { dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type]; scolp = (fRGB*)&src->rect[y*dst->x*dst->type]; for (x=0; x<dst->x; x++) { fRGB_copy(c1, dcolp[x]); fRGB_copy(c2, scolp[x]); c1[0] += mix*(c2[0] - c1[0]); c1[1] += mix*(c2[1] - c1[1]); c1[2] += mix*(c2[2] - c1[2]); if (c1[0] < 0.f) c1[0] = 0.f; if (c1[1] < 0.f) c1[1] = 0.f; if (c1[2] < 0.f) c1[2] = 0.f; fRGB_mult(c1, mf); fRGB_copy(dcolp[x], c1); } } } else { float xr = src->x / (float)dst->x; float yr = src->y / (float)dst->y; for (y=0; y<dst->y; y++) { dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type]; for (x=0; x<dst->x; x++) { fRGB_copy(c1, dcolp[x]); qd_getPixelLerp(src, (x + 0.5f)*xr - 0.5f, (y + 0.5f)*yr - 0.5f, c2); c1[0] += mix*(c2[0] - c1[0]); c1[1] += mix*(c2[1] - c1[1]); c1[2] += mix*(c2[2] - c1[2]); if (c1[0] < 0.f) c1[0] = 0.f; if (c1[1] < 0.f) c1[1] = 0.f; if (c1[2] < 0.f) c1[2] = 0.f; fRGB_mult(c1, mf); fRGB_copy(dcolp[x], c1); } } } }