libtthimage/Lib/pov_hf15a.c
2022-06-27 00:48:18 +02:00

439 lines
9.6 KiB
C

/*
pov_hf15.c
==========
Un 'height_field' de POVray est une image au format TGA
qui stocke des altitudes sur 15 bits, avec les poids
forts dans la composante rouge et les poids faibles dans
la composante verte. Pour le bleu, je ne sais pas ce
qu'il en est, donc on va le forcer a 0.
2 oct 2001: adding a function for writing a PGM 15 bits file.
16 oct 2001: the 'read pgm hf' func of Povray seems bogus, so we have
to wait for POV 3.5 for testing my func :(
23 oct 2001: all references to 16 bits are supersedes by reference
to 15 bits. after all, it's better ?
-------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include "../tthimage.h"
/*::------------------------------------------------------------------::*/
/*
* que faire si l'altitude est negative ? on clampe !-)
* ... et rappelons qu'il faut sauver en TGA pour que Pov
* retrouve ses 2^15 valeurs d'altitude.
*/
int Image_hf15_plot(Image_Desc *im, int x, int y, int h)
{
int r, g;
if (h < 0) h = 0; /* On clampe ... */
if (h > 32767) h = 32767;
if ((x<0) || (y<0) || (x>=im->width) || (y>im->height))
{
#if DEBUG_LEVEL
fprintf(stderr, "%s : %d,%d out of image\n", __func__, x, y);
#endif
return OUT_OF_IMAGE;
}
r = (h >> 8) & 0xff; /* les poids forts */
g = h & 0xff; /* les poids faibles */
(im->Rpix[y])[x] = r;
(im->Gpix[y])[x] = g;
(im->Bpix[y])[x] = 0; /* valeur 'secure', on pourrait y mettre */
/* autre chose. voir les sources de pov ? */
return OLL_KORRECT;
}
/*::------------------------------------------------------------------::*/
/*
* recuperer la hauteur stockée dans une image 'hf15'
* en cas de dépassement, la valeur est silencieusement limitée.
*/
int Image_hf15_height(Image_Desc *img, int x, int y)
{
register int a, b;
int h;
if ((x<0) || (y<0) || (x>=img->width) || (y>img->height))
{
#if DEBUG_LEVEL
fprintf(stderr, "%s : %d,%d out of image\n", __func__, x, y);
#endif
/* VERY BAD BUG HERE */
return OUT_OF_IMAGE;
}
/* 28 mars 2007 : optimization for speed -> use direct access
h = (Image_R_pixel(img, x, y) << 8) + Image_G_pixel(img, x, y);
*/
a = (img->Rpix[y])[x];
b = (img->Gpix[y])[x];
h = ( a << 8) + b;
return h & 0x7fff;
}
/*::------------------------------------------------------------------::*/
/*
* parameter 'mode' is not used. set it to 0, please.
*/
int Image_hf15_hf2gray(Image_Desc *src, Image_Desc *dst, int mode)
{
int x, y, h;
for (y=0; y<src->height; y++)
{
for (x=0; x<src->width; x++)
{
h = Image_hf15_height(src, x, y) >> 7;
Image_plotRGB(dst, x, y, h, h, h);
}
}
return FUNC_IS_BETA;
}
/*::------------------------------------------------------------------::*/
/* il y a peut-etre une maniere plus astucieuse de choisr ces
* coeeficients que de prendre des valeurs arbitraires... */
#define K_R 65
#define K_G 42 /* il faut bien le caser, le 42 */
#define K_B 19
#define K_TOT (K_R+K_G+K_B)
/* parameter 'mode' is not used at this time. please use 0 ! */
int Image_hf15_rgb2hf(Image_Desc *src, Image_Desc *dst, int mode)
{
int x, y, h, hmax, hmin;
#if DEBUG_LEVEL > 1
fprintf(stderr, "RGB -> HF: k_tot = %d\n", K_TOT);
fprintf(stderr, " max_v = %d\n", K_R*255+K_G*255+K_B*255);
#endif
if (0 != mode)
{
fprintf(stderr, "when calling %s, mode must be 0\n", __func__);
#if FORCE_ABORT
abort();
#endif
}
hmax = -9999; hmin = 424242;
for (y=0; y<src->height; y++)
{
for (x=0; x<src->width; x++)
{
h = Image_R_pixel(src, x, y) * K_R +
Image_G_pixel(src, x, y) * K_G +
Image_B_pixel(src, x, y) * K_B ;
#if DEBUG_LEVEL
if (h > hmax) hmax = h;
if (h < hmin) hmin = h;
#endif
Image_hf15_plot(dst, x, y, h);
}
}
#if DEBUG_LEVEL
fprintf(stderr, " h min = %d, h max = %d\n", hmin, hmax);
#endif
return OLL_KORRECT;
}
/*::------------------------------------------------------------------::*/
/*
* Warning: this 15 bit (valid?) pgm file can't be loaded
* by POVray. I've send a bug report, but get no answer
* from the POV team....
* May be we have to wait for the release of v3.5 ?
*/
#define VERSION_STRING "PGM hf15 / Janv 2010"
#define TAILLE_BUFFER 65536
int Image_hf15_save_PGM(char *nom, Image_Desc *img, char *comment)
{
FILE *fp;
int x, y, h, foo;
int par_ligne, nbr_overshoot;
char buffer[TAILLE_BUFFER];
#if DEBUG_LEVEL
fprintf(stderr, "%s: saving %p as file '%s'\n", __func__, img, nom);
#endif
if ((fp=fopen(nom, "w")) == NULL)
{
fprintf(stderr, "ecriture PGM hf15 %s err fopen\n", nom);
return FILE_CREATE_ERR;
}
foo = setvbuf(fp, buffer, _IOFBF, TAILLE_BUFFER);
#if DEBUG_LEVEL
fprintf(stderr, "%s: setvbuf -> %d\n", __func__, foo);
#endif
fprintf(fp, "P2\n%d %d\n32767\n", img->width, img->height);
fprintf(fp, "#\n# written by libimage v %s, %s\n",
IMAGE_VERSION_STRING, VERSION_STRING);
if (comment != NULL)
fprintf(fp, "# %s\n", comment);
fputs("#\n", fp);
nbr_overshoot = 0;
par_ligne = 0;
for (y=0; y<img->height; y++)
{
for (x=0; x<img->width; x++)
{
h = Image_R_pixel(img, x, y) * 256 +
Image_G_pixel(img, x, y);
if (h > 32767)
{
fprintf(stderr, "overshoot at %d,%d -> %d\n",
x, y, h);
if (nbr_overshoot > 42)
{
#if FORCE_ABORT
abort();
#endif
}
nbr_overshoot++;
h = 32767;
}
foo = fprintf(fp, "%d ", h);
par_ligne += foo;
if (par_ligne > 65) /* magic value ? */
{
fputs("\n", fp);
par_ligne = 0;
}
}
#if DEBUG_LEVEL > 1
fprintf(fp, "\n# end of src pixline %d\n", y);
#endif
}
fputs("\n", fp);
#if DEBUG_LEVEL > 1
fprintf(stderr, "Pov hf15 save PGM: %p %s: a re-tester...\n", img, nom);
#endif
fclose(fp);
if (nbr_overshoot)
fprintf(stderr, "in %s, on a eu %d overshoots\n",
__func__, nbr_overshoot);
return FUNC_IS_BETA;
}
/*::------------------------------------------------------------------::*/
static struct
{
int x, y;
} deltas[] =
{ { -1, -1, },
{ 0, -1, },
{ 1, -1, },
{ -1, 0, },
{ 0, 0, },
{ 1, 0, },
{ -1, 1, },
{ 0, 1, },
{ 1, 1 }
};
#define PRECISION 42 /* à quoi ça sert ? */
int
Image_hf15_lissage(Image_Desc *s, Image_Desc *d, int coef, int flag)
{
int x, y, h, cumul, foo;
int r, g;
long temps, nbpix=0L;
#if DEBUG_LEVEL
double ttp;
int under, over;
#endif
if (flag)
{
fprintf(stderr, "Warning! Lissage hf15: flag (%d) must be 0\n", flag);
#if FORCE_ABORT
abort();
#endif
}
#if DEBUG_LEVEL
fprintf(stderr, ">>> Lissage hf15 : %p -> %p : coef %d, flag 0x%04x\n",
s, d, coef, flag);
#endif
#if DEBUG_LEVEL > 1
Image_start_chrono("lissage hf15", 15);
#endif
/* BIG FIX at night, the 7 january 2010 */
/* we _must_ clean the border of the target image buffer */
Image_raz_sides(d);
#if DEBUG_LEVEL
under = over = 0;
#endif
for (y=1; y<s->height-1; y++)
{
for (x=1; x<s->width-1; x++)
{
cumul = 0;
for (foo=0; foo<9; foo++)
{
/* XXX attention optimisation dangeureuse.
h = Image_R_pixel(s, x+deltas[foo].x, y+deltas[foo].y) * 256 +
Image_G_pixel(s, x+deltas[foo].x, y+deltas[foo].y);
XXX car on utilise un acces 'insecure' a la memoire image */
h = (s->Rpix[y+deltas[foo].y])[x+deltas[foo].x] * 256;
h += (s->Gpix[y+deltas[foo].y])[x+deltas[foo].x];
h &= 0x7fff;
h *= PRECISION;
if (foo==4) cumul += (h*coef);
else cumul += h;
}
cumul /= ((8+coef)*PRECISION);
if (cumul > 32767)
{
cumul = 32767;
#if DEBUG_LEVEL
over++;
#endif
}
if (cumul < 0)
{
cumul = 0;
#if DEBUG_LEVEL
under++;
#endif
}
r = (cumul >> 8) & 0x7f;
g = cumul & 0xff;
(d->Rpix[y])[x] = r;
(d->Gpix[y])[x] = g;
(d->Bpix[y])[x] = 0;
nbpix++;
}
}
#if DEBUG_LEVEL
if (under || over)
fprintf(stderr, "%s : under=%d over=%d\n", __func__, under, over);
#endif
#if DEBUG_LEVEL > 1
temps = Image_stop_chrono(NULL, 15);
ttp = ((double)temps / (double)nbpix)*1000000.0;
fprintf(stderr, "Lissage hf15: %.4f µs/pixel\n", ttp);
#endif
d->modified = 1;
return FUNC_IS_BETA;
}
/*::------------------------------------------------------------------::*/
/*
* WARNING! experimental: prototype may change!
*/
int
Image_hf15_calc_minmax(Image_Desc *img, char *txt, int *pmin, int *pmax)
{
int x, y, h, minH, maxH;
#if DEBUG_LEVEL
fprintf(stderr, "%s ( %p, '%s', %p, %p )\n", __func__, img, txt, pmin, pmax);
#endif
minH = 99999999; maxH = -99999999;
for (y=1; y<img->height-1; y++)
{
for (x=1; x<img->width-1; x++)
{
h = (Image_R_pixel(img, x, y) << 8) +
Image_G_pixel(img, x, y);
if (h > maxH) maxH = h;
if (h < minH) minH = h;
}
}
if (txt != NULL)
{
fprintf(stderr, "* hf15 @ %p * %s : min=%d max=%d\n",
img, txt, minH, maxH);
}
if (pmin != NULL) *pmin = minH;
if (pmax != NULL) *pmax = maxH;
return FUNC_IS_BETA;
}
/*::------------------------------------------------------------------::*/
/* new 6 Nov 2001 */
/*
* Need more doc !
*/
int
Image_hf15_mul_add(Image_Desc *src, Image_Desc *dst, int mul, int add)
{
int x, y, h;
fprintf(stderr, "Pov hf15: mul %d & add %d\n", mul, add);
for (y=0; y<src->height; y++)
{
for (x=0; x<src->width; x++)
{
h = Image_hf15_height(src, x, y);
h = (h * mul) + add;
Image_hf15_plot(dst, x, y, h);
}
}
return FUNC_IS_BETA;
}
/*::------------------------------------------------------------------::*/
/* new 6 Nov 2001 */
int
Image_hf15_invert(Image_Desc *src, Image_Desc *dst)
{
int x, y, h;
#if DEBUG_LEVEL
fprintf(stderr, "%s : %p --> %p\n", __func__, src, dst);
#endif
for (y=0; y<src->height; y++)
{
for (x=0; x<src->width; x++)
{
h = 32768 - Image_hf15_height(src, x, y);
Image_hf15_plot(dst, x, y, h);
}
}
return FUNC_IS_BETA;
}
/*::------------------------------------------------------------------::*/