2025-01-26 18:33:45 +01:00

388 lines
9.6 KiB
C

/*
Raydium - CQFD Corp.
http://raydium.org/
License: GPL - GNU General Public License, see "gpl.txt" file.
*/
#ifndef DONT_INCLUDE_HEADERS
#include "index.h"
#else
#include "headers/hdr.h"
#endif
void raydium_hdr_settings_color_local(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
raydium_hdr_color_local[0]=r;
raydium_hdr_color_local[1]=g;
raydium_hdr_color_local[2]=b;
raydium_hdr_color_local[3]=a;
}
void raydium_hdr_settings_color_ambient(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
raydium_hdr_color_ambient[0]=r;
raydium_hdr_color_ambient[1]=g;
raydium_hdr_color_ambient[2]=b;
raydium_hdr_color_ambient[3]=a;
}
void raydium_hdr_settings_eye(float speed, float alpha_max)
{
raydium_hdr_alpha_max=alpha_max;
raydium_hdr_eye_speed=speed;
}
void raydium_hdr_settings(GLfloat *color_local, GLfloat *color_ambient, float eye_speed, float alpha_max)
{
GLfloat r,g,b,a;
r=color_ambient[0];
g=color_ambient[1];
b=color_ambient[2];
a=color_ambient[3];
raydium_hdr_settings_color_ambient(r,g,b,a);
r=color_local[0];
g=color_local[1];
b=color_local[2];
a=color_local[3];
raydium_hdr_settings_color_local(r,g,b,a);
raydium_hdr_settings_eye(eye_speed,alpha_max);
}
void raydium_hdr_init(void)
{
glClearStencil(0); // default stencil "color"
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
glEnable(GL_STENCIL_TEST);
raydium_hdr_eye=0;
raydium_hdr_state=0;
raydium_hdr_texture_id=-1;
raydium_hdr_generated=0;
raydium_hdr_settings_color_local(1,1,1,1);
raydium_hdr_settings_color_ambient(0.45,0.45,0.45,0.45);
raydium_hdr_settings_eye(RAYDIUM_HDR_EYE_SPEED_DEFAULT,1);
raydium_log("HDR: OK");
}
void raydium_hdr_internal_window_malloc(void)
{
if(!raydium_hdr_state)
return;
if(raydium_hdr_mem)
free(raydium_hdr_mem);
raydium_hdr_mem=malloc(raydium_window_tx*raydium_window_ty);
}
void raydium_hdr_enable(void)
{
raydium_hdr_state=1;
if(raydium_hdr_texture_id<0)
{
raydium_hdr_texture_id=raydium_texture_load_internal("","hdrmap",1,RAYDIUM_HDR_SIZE,RAYDIUM_HDR_SIZE,3,-1);
raydium_hdr_mem=NULL;
raydium_hdr_internal_window_malloc();
raydium_hdr_mem_hdr=malloc(RAYDIUM_HDR_SIZE*RAYDIUM_HDR_SIZE);
raydium_hdr_mem_hdr2=malloc(RAYDIUM_HDR_SIZE*RAYDIUM_HDR_SIZE);
raydium_hdr_mem_hdr3=malloc(RAYDIUM_HDR_SIZE*RAYDIUM_HDR_SIZE*3);
}
}
void raydium_hdr_disable(void)
{
raydium_hdr_state=0;
}
void raydium_hdr_block(signed char blocking)
{
if(blocking)
glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
else
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
}
void raydium_hdr_blur(unsigned char *in, unsigned char *out)
{
int x,y;
float p;
// 1st row and last row
for(x=1;x<RAYDIUM_HDR_SIZE-1;x++)
{
p=0;
p+=in[ (x-1) + (RAYDIUM_HDR_SIZE*0) ];
p+=in[ (x+1) + (RAYDIUM_HDR_SIZE*0) ];
p+=in[ (x-1) + (RAYDIUM_HDR_SIZE*1) ];
p+=in[ (x+0) + (RAYDIUM_HDR_SIZE*1) ];
p+=in[ (x+1) + (RAYDIUM_HDR_SIZE*1) ];
out[x]=p/5;
p=0;
p+=in[ (x-1) + (RAYDIUM_HDR_SIZE*(RAYDIUM_HDR_SIZE-2)) ];
p+=in[ (x+0) + (RAYDIUM_HDR_SIZE*(RAYDIUM_HDR_SIZE-2)) ];
p+=in[ (x+1) + (RAYDIUM_HDR_SIZE*(RAYDIUM_HDR_SIZE-2)) ];
p+=in[ (x-1) + (RAYDIUM_HDR_SIZE*(RAYDIUM_HDR_SIZE-1)) ];
p+=in[ (x+1) + (RAYDIUM_HDR_SIZE*(RAYDIUM_HDR_SIZE-1)) ];
out[x+(RAYDIUM_HDR_SIZE*(RAYDIUM_HDR_SIZE-1))]=p/5;
}
// 1st col and last col
for(y=1;y<RAYDIUM_HDR_SIZE-1;y++)
{
p=0;
p+=in[ 1 + ((y-1)*RAYDIUM_HDR_SIZE) ];
p+=in[ 1 + ((y+0)*RAYDIUM_HDR_SIZE) ];
p+=in[ 1 + ((y+1)*RAYDIUM_HDR_SIZE) ];
p+=in[ 0 + ((y-1)*RAYDIUM_HDR_SIZE) ];
p+=in[ 0 + ((y+1)*RAYDIUM_HDR_SIZE) ];
out[y*RAYDIUM_HDR_SIZE]=p/5;
p=0;
p+=in[ (RAYDIUM_HDR_SIZE-2) + ((y-1)*RAYDIUM_HDR_SIZE) ];
p+=in[ (RAYDIUM_HDR_SIZE-2) + ((y+0)*RAYDIUM_HDR_SIZE) ];
p+=in[ (RAYDIUM_HDR_SIZE-2) + ((y+1)*RAYDIUM_HDR_SIZE) ];
p+=in[ (RAYDIUM_HDR_SIZE-1) + ((y-1)*RAYDIUM_HDR_SIZE) ];
p+=in[ (RAYDIUM_HDR_SIZE-1) + ((y+1)*RAYDIUM_HDR_SIZE) ];
out[(y*RAYDIUM_HDR_SIZE) + (RAYDIUM_HDR_SIZE-1) ]=p/5;
}
// body
for(x=1;x<RAYDIUM_HDR_SIZE-1;x++)
for(y=1;y<RAYDIUM_HDR_SIZE-1;y++)
{
p=0;
p+=in[(x+0)+((y+0)*RAYDIUM_HDR_SIZE)];
p+=in[(x-1)+((y-1)*RAYDIUM_HDR_SIZE)];
p+=in[(x+0)+((y-1)*RAYDIUM_HDR_SIZE)];
p+=in[(x+1)+((y-1)*RAYDIUM_HDR_SIZE)];
p+=in[(x-1)+((y+0)*RAYDIUM_HDR_SIZE)];
p+=in[(x+1)+((y+0)*RAYDIUM_HDR_SIZE)];
p+=in[(x-1)+((y+1)*RAYDIUM_HDR_SIZE)];
p+=in[(x+0)+((y+1)*RAYDIUM_HDR_SIZE)];
p+=in[(x+1)+((y+1)*RAYDIUM_HDR_SIZE)];
out[x+(y*RAYDIUM_HDR_SIZE)]=p/9;
}
// upper left pixel
p=0;
p+=in[1+(0*RAYDIUM_HDR_SIZE)];
p+=in[1+(1*RAYDIUM_HDR_SIZE)];
p+=in[0+(1*RAYDIUM_HDR_SIZE)];
out[0]=p/3;
// upper right pixel
p=0;
p+=in[(RAYDIUM_HDR_SIZE-2)+(0*RAYDIUM_HDR_SIZE)];
p+=in[(RAYDIUM_HDR_SIZE-2)+(1*RAYDIUM_HDR_SIZE)];
p+=in[(RAYDIUM_HDR_SIZE-1)+(1*RAYDIUM_HDR_SIZE)];
out[RAYDIUM_HDR_SIZE-1]=p/3;
// bottom left pixel
p=0;
p+=in[ ((RAYDIUM_HDR_SIZE-1)*RAYDIUM_HDR_SIZE) + 1 ];
p+=in[ ((RAYDIUM_HDR_SIZE-2)*RAYDIUM_HDR_SIZE) + 1 ];
p+=in[ ((RAYDIUM_HDR_SIZE-2)*RAYDIUM_HDR_SIZE) + 0 ];
out[(RAYDIUM_HDR_SIZE-1)*RAYDIUM_HDR_SIZE]=p/3;
// bottom right pixel
p=0;
p+=in[ ((RAYDIUM_HDR_SIZE-1)*RAYDIUM_HDR_SIZE) + (RAYDIUM_HDR_SIZE-2) ];
p+=in[ ((RAYDIUM_HDR_SIZE-2)*RAYDIUM_HDR_SIZE) + (RAYDIUM_HDR_SIZE-1) ];
p+=in[ ((RAYDIUM_HDR_SIZE-2)*RAYDIUM_HDR_SIZE) + (RAYDIUM_HDR_SIZE-2) ];
out[((RAYDIUM_HDR_SIZE-1)*RAYDIUM_HDR_SIZE) + (RAYDIUM_HDR_SIZE-1) ]=p/3;
}
void raydium_hdr_map(void)
{
int x,y,i;
float fx,fy;
float incx,incy;
int offset;
unsigned char pixel;
int total;
float hdr_exposure;
if(!raydium_hdr_state || raydium_hdr_generated)
return;
glDisable(GL_STENCIL_TEST);
// download stencil to RAM ...
glReadPixels (0,0,raydium_window_tx,raydium_window_ty,GL_STENCIL_INDEX,GL_UNSIGNED_BYTE,raydium_hdr_mem);
incx=raydium_window_tx/(RAYDIUM_HDR_SIZE*1.f);
incy=raydium_window_ty/(RAYDIUM_HDR_SIZE*1.f);
fx=0;
fy=0;
total=0;
// ... downscaling ...
for(y=0;y<RAYDIUM_HDR_SIZE;y++)
{
for(x=0;x<RAYDIUM_HDR_SIZE;x++)
{
offset=(x+(RAYDIUM_HDR_SIZE*y));
pixel=raydium_hdr_mem[raydium_trigo_round(fx)+(raydium_window_tx*(raydium_trigo_round(fy)))];
//slooooooooooooow ! (?!)
//glReadPixels(raydium_trigo_round(fx),raydium_trigo_round(fy),1,1,GL_STENCIL_INDEX,GL_UNSIGNED_BYTE,&pixel);
raydium_hdr_mem_hdr2[offset]=(pixel?255:0);
total+=pixel;
fx+=incx;
}
fx=0;
fy+=incy;
}
hdr_exposure=(float)total/(RAYDIUM_HDR_SIZE*RAYDIUM_HDR_SIZE);
// dec intensity using exposure factor
if(raydium_hdr_eye>0)
{
raydium_hdr_eye-=(hdr_exposure*(raydium_hdr_eye_speed*raydium_frame_time));
if(raydium_hdr_eye<=0)
raydium_hdr_eye=-9999; // the eye is now ok
}
// we're in "total" drak
if(hdr_exposure==0)
raydium_hdr_eye=0; // be ready for another "flash"
if(hdr_exposure>0 && raydium_hdr_eye==0)
raydium_hdr_eye=raydium_hdr_alpha_max;
//printf("%i/%i (%f)\n",total,RAYDIUM_HDR_SIZE*RAYDIUM_HDR_SIZE,hdr_exposure*100);
if(raydium_hdr_eye>0)
// if(!raydium_key[GLUT_KEY_F11])
for(x=0;x<RAYDIUM_HDR_PASS;x++)
{
raydium_hdr_blur(raydium_hdr_mem_hdr2,raydium_hdr_mem_hdr);
raydium_hdr_blur(raydium_hdr_mem_hdr,raydium_hdr_mem_hdr2);
}
hdr_exposure=(raydium_hdr_eye>0?raydium_hdr_eye:0); // clamp
for(i=0;i<RAYDIUM_HDR_SIZE*RAYDIUM_HDR_SIZE;i++)
{
raydium_hdr_mem_hdr3[0 + i*3] = raydium_hdr_mem_hdr2[i] * hdr_exposure;
raydium_hdr_mem_hdr3[1 + i*3] = raydium_hdr_mem_hdr2[i] * hdr_exposure;
raydium_hdr_mem_hdr3[2 + i*3] = raydium_hdr_mem_hdr2[i] * hdr_exposure;
}
// ... and we upload to hdr_texture
glBindTexture(GL_TEXTURE_2D,raydium_hdr_texture_id);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,RAYDIUM_HDR_SIZE,RAYDIUM_HDR_SIZE,0,GL_RGB,GL_UNSIGNED_BYTE,raydium_hdr_mem_hdr3);
raydium_hdr_generated=1;
}
void raydium_hdr_map_apply(void)
{
if(!raydium_hdr_state)
return;
if(!raydium_hdr_generated)
raydium_hdr_map();
raydium_hdr_generated=0;
#ifdef DEBUG_HDR_STENCIL
if(raydium_key[GLUT_KEY_F10])
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
raydium_osd_start();
glStencilFunc(GL_EQUAL, 1, 0xffffffff);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glEnable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_2D);
glColor4f(1,1,1,1);
glBegin(GL_QUADS);
glVertex3f(0,0,0);
glVertex3f(100,0,0);
glVertex3f(100,100,0);
glVertex3f(0,100,0);
glEnd();
raydium_osd_stop();
glEnable(GL_TEXTURE_2D);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
glDisable(GL_STENCIL_TEST);
}
else
{
#endif
raydium_osd_start();
glBindTexture(GL_TEXTURE_2D,raydium_hdr_texture_id);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_ONE,GL_ONE);
//localized hdr "glow" effect
glColor4fv(raydium_hdr_color_local);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(0,0,0);
glTexCoord2f(1,0);
glVertex3f(100,0,0);
glTexCoord2f(1,1);
glVertex3f(100,100,0);
glTexCoord2f(0,1);
glVertex3f(0,100,0);
glEnd();
//ambiental hdr "glow" effect
glColor4fv(raydium_hdr_color_ambient);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(-50,-50,0);
glTexCoord2f(1,0);
glVertex3f(150,-50,0);
glTexCoord2f(1,1);
glVertex3f(150,150,0);
glTexCoord2f(0,1);
glVertex3f(-50,150,0);
glEnd();
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
raydium_rendering_internal_restore_render_state();
raydium_osd_stop();
#ifdef DEBUG_HDR_STENCIL
}
#endif
}
signed char raydium_hdr_texture(int texture, signed char hdr)
{
if(texture>=0 && texture<raydium_texture_index)
{
raydium_texture_hdr[texture]=hdr;
return 1;
}
raydium_log("HDR: cannot set HDR attribute on texture: invalid name or index");
return 0;
}
signed char raydium_hdr_texture_name(char *name, signed char hdr)
{
return raydium_hdr_texture(raydium_texture_find_by_name(name),hdr);
}
void raydium_hdr_texture_reset(void)
{
int i;
for(i=0;i<RAYDIUM_MAX_TEXTURES;i++)
raydium_texture_hdr[i]=0;
}