Professional Documents
Culture Documents
Getting X-Plane Real-Time FLIR
Getting X-Plane Real-Time FLIR
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
#define xdob double
#define xflt float
typedef int xint; // always 32-bits. must do it this way since apple has a type xint in
xpc.h!
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
class flir_class
{
public:
flir_class(){memset(this,0,sizeof(*this));} // THIS is a POINTER. so the
first arg is just "this" (the pointer) the third arg is the thing the pointer points to,
thus the '*'
~flir_class(){}
void dis_flir (xflt x1,xflt y1,xflt x2,xflt y2);
void flir_grab_from_net (GLubyte* data_read,xint len_rcvd);
};
extern flir_class flir;
#endif
flir_class flir;
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
void tman_class::load_scratch( enum_tex t ,
string path ,
GLenum tex_type ,
xint dx_vis ,
xint dy_vis ,
xint dx_tot ,
xint dy_tot ,GLubyte*
rgb_data,xint is_pvr)
{
if(!
intrange(tex_type,GL_RGB,GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
))IPAD_alert("Bad minify arg.");
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
// SET THE PARAMETERS
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
xint reduc =0;
xint mini =0; // ALL 2 ND 4 BIT PVRS HAVE MINIFICATION BUILT
IN. SO THIS IS AVAIL FOR ALL PVRS. PROBLEM IS: IT LOOKS LIKE
DONKEY-ASS. SO, LEAVE IT OFF!
// WE STILL GET A 15% RAM SAVINGS AND 10%
FR BOOST FROM SWITCHING TO PVR!
tex_dx_vis[t]=dx_vis;
tex_dy_vis[t]=dy_vis;
tex_dx_tot[t]=dx_tot;
tex_dy_tot[t]=dy_tot;
glBindTexture (GL_TEXTURE_2D,t);
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_S
,GL_REPEAT ); // wrapping is faster.
glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_T
,GL_REPEAT ); // wrapping is faster.
glTexParameteri
(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR );
glTexParameteri
(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR );
glTexParameterf
(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,1.0); //
THIS IS FASTEST, AND WE ONLY NEED ANISO IF MIP-MAPPED, SINCE
MIP-MAPPING IS THE ONLY THING THAT TAKES US DOWN TO A LOW-
RES TEX THAT NEEDS ANISO!
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&max_iso);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EX
T,max_iso ); // aniso makes mini suck a little less, with no change
in ram, and no change in fr that i can measure in the ipad mini
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEA
R_MIPMAP_LINEAR ); // THEORETICAL BEST MIPMAP QUALITY
COMES FROM: GL_LINEAR_MIPMAP_LINEAR
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
GL_LINEAR ); // MAYBE YOU GET FASTER RESULTS WITH:
GL_LINEAR_MIPMAP_NEAREST
}
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
// LOAD THE TEXTURE
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
for(;;)
{
OGL_error_check("glTexImage2D-1");
xint tex_size=0;
if(is_pvr)
{
tex_size=vram_for_texture_any(tex_type,0,dx_tot,dy_tot,xfals);
// packing is never used by compressed texes
OGL_error_check("glTexImage2D-2");
if(is_pvr) // i do not mini the pvr.. that was done by the grinder! all 2
and 4 bit pvr's are minified... there is no way around it!
{
pvr_buffer+=tex_size;
}
else // for non-pvr's, i have to minify the tex here if i want it
done
{
if(!intrange(dx_vis,1,TEX_DIMi))IPAD_alert("Trying to create a
NON-PVR either less than 1 or greater than 1024!",path); // PVRs do not have
these limits! runway is 2048x2048 PVR!
if(!intrange(dy_vis,1,TEX_DIMj))IPAD_alert("Trying to create a
NON-PVR either less than 1 or greater than 1024!",path); // PVRs do not have
these limits! runway is 2048x2048 PVR!
if(!intrange(dx_tot,1,TEX_DIMi))IPAD_alert("Trying to create a
NON-PVR either less than 1 or greater than 1024!",path); // PVRs do not have
these limits! runway is 2048x2048 PVR!
if(!intrange(dy_tot,1,TEX_DIMj))IPAD_alert("Trying to create a
NON-PVR either less than 1 or greater than 1024!",path); // PVRs do not have
these limits! runway is 2048x2048 PVR!
xint step=(tex_type==GL_RGB)?3:4;
for(xint c=0;c<step;c++)
rgb_data[addy_lo+c]=( rgb_data[addy_hi1+c]+
rgb_data[addy_hi2+c]+
rgb_data[addy_hi3+c]+
rgb_data[addy_hi4+c])/4;
}
}
}
}
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
structTEX_image_desc{
GLenum format ; // OpenGL texture format like GL_RGBA.
Defines the number of channels, total storage size, ordering, and encoding.
GLenum packing ;
xint width; // Width of image in pixels.
xint height ; // Height of image in pixels.
xint padding ; // Number of dead bytes between each row.
xint has_mips;}; // If true, eaech image is followed by quarter-size
mip-reduction.
inline void decomp_col( xbyt* rgba, void const* block, bool isDxt1 )
{
xbyt const* bytes = reinterpret_cast< xbyt const* >( block );
xbyt codes[16];
xint a = unpack_565( bytes, codes );
xint b = unpack_565( bytes + 2, codes + 4 );
for( xint i = 0; i < 3; ++i )
{
xint c = codes[i];
xint d = codes[4 + i];
if( isDxt1 && a <= b )
{
codes[8 + i] = ( xbyt )( ( c + d )/2 );
codes[12 + i] = 0;
}
else
{
codes[8 + i] = ( xbyt )( ( 2*c + d )/3 );
codes[12 + i] = ( xbyt )( ( c + 2*d )/3 );
}
}
codes[8 + 3] = 255;
codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255;
xbyt indices[16];
for( xint i = 0; i < 4; ++i )
{
xbyt* ind = indices + 4*i;
xbyt packed = bytes[4 + i];
ind[0] = packed & 0x3;
ind[1] = ( packed >> 2 ) & 0x3;
ind[2] = ( packed >> 4 ) & 0x3;
ind[3] = ( packed >> 6 ) & 0x3;
}
for( xint i = 0; i < 16; ++i )
{
xbyt offset = 4*indices[i];
for( xint j = 0; j < 4; ++j )
rgba[4*i + j] = codes[offset + j];
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
// MAKE IT GRAY TO SIM AN IR IMAGE
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
// if(1)
// {
// rgba[4*i+0]=
// rgba[4*i+1]=
// rgba[4*i+2]=(rgba[4*i+0]+
// rgba[4*i+1]+
// rgba[4*i+2])/3;
// }
}
}
void decomp_image(xbyt* rgba, xint width, xint height, void const* blocks, xint
flags )
{
xbyt const* sourceBlock = reinterpret_cast< xbyt const* >( blocks );
xint bytesPerBlock = ( ( flags & kDxt1 ) != 0 ) ? 8 : 16;
for( xint y = 0; y < height; y += 4 )
{
for( xint x = 0; x < width; x += 4 )
{
xbyt targetRgba[4*16];
decomp( targetRgba, sourceBlock, flags );
xbyt const* sourcePixel = targetRgba;
for( xint py = 0; py < 4; ++py )
{
for( xint px = 0; px < 4; ++px )
{
xint sx = x + px;
xint sy = y + py;
if( sx < width && sy < height )
{
xbyt* targetPixel = rgba + 4*( width*sy + sx );
for( xint i = 0; i < 4; ++i )*targetPixel++ =
*sourcePixel++;
}
else
{
sourcePixel += 4;
}
}
}
sourceBlock += bytesPerBlock;
}
}
}
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
void flir_class::flir_grab_from_net(GLubyte* data_read,xint len_rcvd)
{
borg.set_input(recv_FLIR,enum_nite_vision);
xint rx=data_read[0]+data_read[1]*256;
xint ry=data_read[2]+data_read[3]*256; if(rx!=ry)IPAD_alert("wrong-
size flir image!");
xint flir_tex_dim_recv=rx;
xint this_pack=data_read[4];
xint num_packs=data_read[5];
TEX_image_desc src,dst;
src.format
=GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
dst.format =GL_RGBA
;
src.width =dst.width =flir_tex_dim_recv ;
src.height =dst.height=flir_tex_dim_recv ;
xint flir_len=FLIR_bytes_needed_for_image(src);
static vector<GLubyte> comp_data_buf;
// compressed buffer to hold incoming S3TC image
until it is built up.
if( comp_data_buf.size()<flir_len)
comp_data_buf.resize(flir_len);
static xint pack_len=0
; // ok we could send in several packs to form 1
image. the pack len is however much we sent in in the first packet. offset that much
for the NEXT packet!
if(this_pack==0) pack_len=len_rcvd -6
; // we simply copy each packet into the compressed data buffer
here, with an offset based on which packet this is in the sequence, and the size of
each packet.
memcpy(&*comp_data_buf.begin()
+this_pack*pack_len,data_read+6,len_rcvd-6); // copy this packet into
the buffer.
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
//IF THIS IS THE LAST PACKET OF HOWEVER MANY MAKE UP THE
TEXTURE, THEN UNCOMPRESS IT AND LOAD IT INTO THE TMAN
TEXTURE!
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if(this_pack==num_packs-1)
// ok we have the last packet! get to work
uncompressing!
{
decomp_s3tc(src,dst,&*comp_data_buf.begin(),apps.scratch_array);
// decompress the image to RGB. (someday we can avoid this, but tman
doesn't speak s3tc yet.)
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
// DO NOT UNLOAD THE TEX BEFORE LOADING IT... THERE IS NO
NEED! IT JUST THRASHES RAM LIKE CRAZY FOR NOTHING! JUST
LOAD FROM SCRATCH IS ALL WE WANT TO DO HERE!
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
tman.load_scratch(t_flir_texture,"FLIR",GL_RGBA,flir_tex_dim_recv,flir_tex_di
m_recv,
flir_tex_dim_recv,flir_tex_dim_recv);
}
}