Create LUT float buffer From LUT file


ifstream::pos_type size;
char * memblock;

ifstream file (“MRI_Brain_shade.bin”, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
}
DWORD dwSizeRes = size;
int nMin; // For Minimum value
int nMax; // For Maximum value
// Set the first element as min
memcpy( &nMin, memblock, 4 );
memblock += 4;
// Set the second element as max
memcpy( &nMax, memblock, 4 );
memblock += 4;
// Remaining values in color table
int nSizeWithoutHeader = dwSizeRes – 8;
unsigned char* pucLUT = new unsigned char[nSizeWithoutHeader];
// ( 5120 + 1024 ) * 4 = 24576
float* pfRGBALut = new float[24576];// RGBA * (-1024 : 5119).
memcpy( pucLUT, memblock, nSizeWithoutHeader );
unsigned char ucRGB[3];
float fAlpha = 0;
// Copy each element from the color table and convert to float value
for( int i = 0, j = 0; i < nSizeWithoutHeader; )
{
memcpy( &ucRGB, &pucLUT[i], ( 3 * sizeof(unsigned char)));
i += 3;
memcpy( &fAlpha, &pucLUT[i], sizeof( float ));
i += 4;
pfRGBALut[j++] = ucRGB[0] / 255.0f;
pfRGBALut[j++] = ucRGB[1] / 255.0f;
pfRGBALut[j++] = ucRGB[2] / 255.0f;
pfRGBALut[j++] = fAlpha;
}

3D volume using 2D textures in openGL


#include <windows.h>
#include “gl\glew.h”
#include “gl\gl.h”
#include “gl\glu.h”
#include “glut.h”
#include <stdio.h>
#include <sys/stat.h>
#include <math.h>

#define TOTAL_SHADERS 3
#define TEXTURE_COUNT 6

enum TEXTURE_ID_e
{
TEMP_TEX_ID = 0,
DIR_TEX_ID,
VOL_TEX_ID,
FRAME_COLOR_TEX_ID_1,
FRAME_COLOR_TEX_ID_2,
LUT_TEX_ID
};

enum DATA_TYPE_e
{
UNSIGNED_ONE_BYTE = 0,
SIGNED_ONE_BYTE,
UNSIGNED_TWO_BYTE,
SIGNED_TWO_BYTE
};

enum PROGRAM_TYPE_e {
DIRECTION_PROGRAM = 0,
MAIN_RENDER_PROGRAM,
FINAL_DISPLAY_PROGRAM
};

struct HURANGE_COLOR_t
{
public:
int m_nHURangeMin; // Holds the the minimum value of the Hounsfield unit range.
int m_nHURangeMax; // Holds the the maximum value of the Hounsfield unit range.
int m_nHURangeColor[4]; // Holds the Color value.
};

struct SHADER_ATTRIBUTE_LOC
{
int nFrontFace;
int nFrontFaceTex;
int nColorMap;
int nVolumeTexture;
int nDepth;
int nStepSize;
int nTemporarytexture;
int nDirectiontexture;
int nDataRange;
int nWc;
int nWr;
int nRender;
int nSlope;
int nIntercept;
int nRangeMin;
};

struct VOLUME_t
{

// Members
public:

void* m_pPixels; // Pixel data
int m_nWidth; // Width of the volume
int m_nHeight; // Height of the volume
int m_nDepth; // Depth of the volume
int m_nBytesPerPixel; // Bytes per pixel
int m_nMin; // Minimum value in the volume
int m_nMax; // Maximum value in the volume
int m_nDataType; // Pixel data type
float m_fX; // X coordinate value
float m_fY; // Y coordinate value
float m_fZ; // Z coordinate value

public:

// Construct the structure
VOLUME_t()
{
// Initialize all the volume dimensions
m_pPixels = 0; // Null
m_nWidth = 0;
m_nHeight = 0;
m_nDepth = 0;
m_nBytesPerPixel = 1;
m_nMin = 0;
m_nMax = 0;
m_nDataType = 0;
m_fX = 1.0f;
m_fY = 1.0f;
m_fZ = 1.0f;
}
};

VOLUME_t m_stLookUp;
SHADER_ATTRIBUTE_LOC stAttribLoc;

GLuint progObj[ TOTAL_SHADERS ];
GLuint TextureId[ TEXTURE_COUNT ];

///////////////////
DATA_TYPE_e eDataType = UNSIGNED_ONE_BYTE;
const int DCM_WIDTH = 256;
const int DCM_HEIGHT = 256;
const int DCM_DEPTH = 96;
const char* szFile = “F:\\head256x256x109″;

///////////////////
const int DEFAULT_WINDOW_WIDTH = 775;
const int DEFAULT_WINDOW_CENTER = 453;
// Image minimum & maximum HU range.
const int HURANGE_MIN = -1024;
const int HURANGE_MAX = 5119;
// HURangeColor array size
const int HURANGE_COLOR_ARRAY_SIZE = 5;
// Sharpness value array size
const int SHARPNESS_ARRAY_SIZE = 4;
const int RED = 0;
const int GREEN = 1;
const int BLUE = 2;
const int ALPHA = 3;

int m_nMinValue = 0;
int m_nMaxValue = 255;
int m_lLUTWidth = 0;
int nImgWidth;
int nImgHeight;
int m_nWinHeight;
int m_nWinWidth;
int m_nMainHURangeMin = 0;
int m_nSharpness[ SHARPNESS_ARRAY_SIZE ];
float* m_pRGBALUT = 0;
HURANGE_COLOR_t m_stHURangeColor[ HURANGE_COLOR_ARRAY_SIZE ];
GLuint m_fbo;
GLuint m_renderDepthBuffer;
GLuint m_nRenderingGeometry;
GLuint m_vbo; // vertex buffer for Rendering Geometry
GLuint m_nBBoxvbo; // vertex buffer for Bounding Box
GLfloat m_fVertices[72]; // vertex array of VBO
GLfloat m_fColors[72]; // color array of VBO
GLfloat m_fBoundingBoXcolors[72];

int GetSizeof( DATA_TYPE_e eType_i )
{
switch( eType_i )
{
case UNSIGNED_ONE_BYTE:
return sizeof( unsigned char );
case SIGNED_ONE_BYTE:
return sizeof( char );
case UNSIGNED_TWO_BYTE:
return sizeof( unsigned short );
case SIGNED_TWO_BYTE:
return sizeof( short );
}
return 1;
}

int GetMaxValue()
{
return m_nMaxValue;
}
int GetMinValue()
{
return m_nMinValue;
}

GLuint GetTextureId( TEXTURE_ID_e eTexId_i )
{
return TextureId[ static_cast<int>( eTexId_i ) ];
}

void SetTextureId( TEXTURE_ID_e eTexId_i, GLuint uTextureId_i )
{
TextureId[ static_cast<int>( eTexId_i ) ] = uTextureId_i;
}

void SetProgramId( PROGRAM_TYPE_e eProgramId_i, GLuint nProgId_i )
{
progObj[ static_cast<int>( eProgramId_i ) ] = nProgId_i;
}

GLuint GetProgramId( PROGRAM_TYPE_e eProgramId_i )
{
return progObj[ static_cast<int>( eProgramId_i ) ];
}

void SetAspectedOrtho( int nOriginX_i, int nOriginY_i, int nWidth_i, int nHeight_i, float fRange_i )
{
GLfloat fAspectRatio = (GLfloat)nWidth_i / (GLfloat)nHeight_i;

glViewport( nOriginX_i, nOriginY_i, nWidth_i, nHeight_i );

// Reset projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

float fZRange = 12.0 + fRange_i;
if( nWidth_i <= nHeight_i )
{
float fWindowHeight = fRange_i / fAspectRatio;
glOrtho( -fRange_i, fRange_i, -fWindowHeight, fWindowHeight, -fZRange, fZRange );
}
else
{
float fWindowWidth = fRange_i * fAspectRatio;
glOrtho( -fWindowWidth, fWindowWidth, -fRange_i, fRange_i, -fZRange, fZRange );
}
// Reset modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

}

void Reshape(int nWidth_i, int nHeight_i)
{

m_nWinHeight = nHeight_i;
m_nWinWidth = nWidth_i;
if( 0 == nHeight_i )
{
nHeight_i = 1;
}
//SetAspectedOrtho( 0, 0, nWidth_i, nHeight_i, 0.75f );
}

GLuint CreateProgram( char* szVertexShader_i, char* szFragmentShader_i )
{
GLuint nProgram = 0; // Hold the program id
GLuint nVertex = 0; // Vertex shader id
GLuint nFragment = 0; // Fragment shader id
// Generate the program
nProgram = glCreateProgram();
if( NULL != szVertexShader_i )
{
// Create the vertex shader
nVertex = glCreateShader( GL_VERTEX_SHADER );
const char * pcVV = szVertexShader_i;
glShaderSource( nVertex, 1, &pcVV, NULL );
// Compile the vertex shader
glCompileShader( nVertex );
// Attach the shader to the program
glAttachShader( nProgram, nVertex );
}
if( NULL != szFragmentShader_i )
{
// Create the fragment shader
nFragment = glCreateShader( GL_FRAGMENT_SHADER );
const char * pcff = szFragmentShader_i;
glShaderSource( nFragment, 1, &pcff, NULL );
// Compile the fragment shader
glCompileShader( nFragment );
GLenum error = glGetError();
char log[2048];
int acLen = 0;
glGetProgramInfoLog( nProgram, 2048, &acLen, log );
// Attach the shader to the program
glAttachShader( nProgram, nFragment );
}
// Link the program
glLinkProgram( nProgram );

if( nVertex > 0 )
{
glDetachShader( nProgram, nVertex );
glDeleteShader( nVertex );
}
if( nFragment > 0)
{
glDetachShader( nProgram, nFragment );
glDeleteShader( nFragment );
}

GLenum error = glGetError();
char log[2048];
int acLen = 0;
glGetProgramInfoLog( nProgram, 2048, &acLen, log );
// Return the program id
return nProgram;
}

char szVertexShader[] =
“\r\n varying vec4 texcordinate;”
“\r\n varying vec4 position;”
“\r\n”
“\r\n void main()”
“\r\n {“
“\r\n gl_FrontColor = gl_Color;”
“\r\n gl_BackColor = gl_Color;”
“\r\n gl_Position = ftransform();”
“\r\n texcordinate = gl_Position;”
“\r\n texcordinate = texcordinate/texcordinate.w;”
“\r\n texcordinate.x = texcordinate.x/2.0f+ 0.5f;”
“\r\n texcordinate.y = texcordinate.y/2.0f + 0.5f;”
“\r\n }”;

char szFragmentShaderFront[] =
“\r\n uniform sampler2D frontface;”
“\r\n varying vec4 texcordinate;”
“\r\n varying vec4 position;”
“\r\n”
“\r\n void main()”
“\r\n {“
“\r\n gl_FragColor = texture2D(frontface, texcordinate.xy);”
“\r\n }”;

char szFragmentShaderDirection[] =
“\r\n uniform sampler2D frontfacetex;”
“\r\n varying vec4 texcordinate;”
“\r\n uniform vec2 texCoord;”
“\r\n”
“\r\n void main()”
“\r\n {“
“\r\n gl_FragColor = gl_Color – texture2D( frontfacetex, texcordinate.xy );”
“\r\n }”;

//render = 0;
//slope = 1.0;
//intercept = 0.0;
//wc = 500;
//we =

char szFragmentShaderMain[] =
“\r\n varying vec4 texcordinate;”
“\r\n uniform sampler2D temporarytexture;”
“\r\n uniform sampler2D ColorMap;”
“\r\n uniform sampler2D VolumeTexture;”
“\r\n uniform sampler2D Directiontexture;”
“\r\n uniform float depth ;”
“\r\n uniform float StepSize;”
“\r\n uniform float dataRange;”
“\r\n uniform float wc;”
“\r\n uniform float wr;”
“\r\n uniform float render;”
“\r\n varying vec4 position;”
“\r\n uniform float slope;”
“\r\n uniform float intercept;”
“\r\n uniform float rangeMin;”
“\r\n”
“\r\n”
“\r\n vec4 Blend(vec4 src, vec4 dst)”
“\r\n {“
“\r\n vec4 result = dst;”
“\r\n”
“\r\n result.rgb += src.rgb * (1 – dst.a) * src.a ;”
“\r\n”
“\r\n result.a += (1 – dst.a) * src.a;”
“\r\n”
“\r\n return result;”
“\r\n }”
“\r\n void main() “
“\r\n { “
“\r\n “
“\r\n vec4 flResultVal = texture2D(temporarytexture, texcordinate.xy); “
“\r\n vec4 flRsultValtemp = flResultVal; “
“\r\n vec4 flDirection = normalize(texture2D(Directiontexture, texcordinate.xy)); “
“\r\n vec4 flFrontVal = gl_Color; “
“\r\n flFrontVal.xyz = flFrontVal.xyz + StepSize * flDirection.xyz; “
“\r\n vec3 flVolCoord = flFrontVal.xyz + depth * flDirection.xyz; “
“\r\n vec4 temp = 0; “
“\r\n vec4 Alpha = 0; “
“\r\n vec4 temp1 = 0; “
“\r\n vec4 color = 0; “
“\r\n vec2 map; “
“\r\n float value; “
“\r\n float data; “
“\r\n vec3 fDist = 0; “
“\r\n vec4 prevcolor=0; “
“\r\n float dist = 0.0; “
“\r\n “
“\r\n float intialValue = StepSize; “
“\r\n “
“\r\n while( dist <= (0.85 )) “
“\r\n { “
“\r\n //temp.a = texture3D(VolumeTexture, flVolCoord.xyz).r; “
“\r\n “
“\r\n int zVal = (int)( flVolCoord.z * 96.0 ); “
“\r\n int xVal = (int)( flVolCoord.x * 256.0 ); “
“\r\n int yVal = (int)( flVolCoord.y * 256.0 ); “
“\r\n “
“\r\n int zX = zVal % 8; “
“\r\n int zY = zVal / 8; “
“\r\n “
“\r\n float nOnePixelSize = 1.0 / 2048.0; “
“\r\n float nOnePixelSizeYAxis = 1.0 / 3072.0; “
“\r\n float fFinalXVal = ( 256.0 * zX * nOnePixelSize ) + ( xVal * nOnePixelSize ); “
“\r\n float fFinalYVal = ( 256.0 * zY * nOnePixelSizeYAxis ) + ( yVal * nOnePixelSizeYAxis ); “
“\r\n “
“\r\n temp.a = texture2D(VolumeTexture, float2(fFinalXVal,fFinalYVal)).r; “
“\r\n if( temp.a == 0) “
“\r\n { “
“\r\n break; “
“\r\n } “
“\r\n data = temp.a * dataRange – 1; “
“\r\n data = data * slope + intercept; “
“\r\n “
“\r\n value = data + rangeMin; “
“\r\n map.y = floor( (value / 256.0f) ); “
“\r\n map.x = value – ( 256.0f * map.y ); “
“\r\n “
“\r\n float min = wc – wr/2.0;”
“\r\n float max =wc + wr/2.0;”
“\r\n”
“\r\n if(data >= max)”
“\r\n {“
“\r\n temp.a = 1;”
“\r\n Alpha.a = 1;”
“\r\n }”
“\r\n else if(data <= min)”
“\r\n {“
“\r\n temp.a = 0;”
“\r\n Alpha.a = 0;”
“\r\n }”
“\r\n else”
“\r\n {“
“\r\n map.x = map.x / 256.0f;”
“\r\n map.y = map.y / 32.0f;”
“\r\n temp.a = texture2D(ColorMap,map.xy).a;”
“\r\n Alpha.a = ((data – min)/wr); “
“\r\n }”
“\r\n “
“\r\n if(Alpha.a == 0) //Alpha is data “
“\r\n { “
“\r\n flVolCoord += StepSize *flDirection.xyz; “
“\r\n dist = dist + StepSize; “
“\r\n //StepSize = intialValue; “
“\r\n continue; “
“\r\n } “
“\r\n “
“\r\n color.rgb = texture2D(ColorMap,map.xy).rgb;”
“\r\n color.rgb = color.rgb;”
“\r\n color.a = temp.a;”
“\r\n “
“\r\n if((flVolCoord.x >= 0.0f) && (flVolCoord.y >= 0.0f) && (flVolCoord.z >= 0.0f) && “
“\r\n (flVolCoord.x <= 1.0f) && (flVolCoord.y <= 1.0f) && (flVolCoord.z <= 1.0f)) “
“\r\n { “
“\r\n {“
“\r\n if(render == 0) “
“\r\n { “
“\r\n “
“\r\n flResultVal = Blend(color , flResultVal); “
“\r\n } “
“\r\n }”
“\r\n } “
“\r\n flVolCoord += StepSize* flDirection.xyz; “
“\r\n dist = dist + StepSize; “
“\r\n “
“\r\n if(flResultVal.a > 0.9) “
“\r\n { “
“\r\n break; “
“\r\n } “
“\r\n } // end of ray casting loop “
“\r\n //float t = (texture2D(ColorMap,float2( 0.8,0.5)).a);”
“\r\n gl_FragColor = flResultVal;//float4( 0,0,1,1 );”
“\r\n”
“\r\n }”;

void LoadShaders()
{
// Direction program
SetProgramId( DIRECTION_PROGRAM, CreateProgram( szVertexShader, szFragmentShaderDirection ));
stAttribLoc.nFrontFaceTex = glGetUniformLocation( GetProgramId( DIRECTION_PROGRAM ), “frontfacetex” );

// Main program
SetProgramId( MAIN_RENDER_PROGRAM, CreateProgram( szVertexShader, szFragmentShaderMain ));
stAttribLoc.nColorMap = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “ColorMap” );
stAttribLoc.nVolumeTexture = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “VolumeTexture” );
stAttribLoc.nDepth = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “depth” );
stAttribLoc.nStepSize = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “StepSize” );
stAttribLoc.nTemporarytexture = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “temporarytexture” );
stAttribLoc.nDirectiontexture = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “Directiontexture” );
stAttribLoc.nDataRange = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “dataRange” );
stAttribLoc.nWc = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “wc” );
stAttribLoc.nWr = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “wr” );
stAttribLoc.nRender = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “render” );
stAttribLoc.nSlope = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “slope” );
stAttribLoc.nIntercept = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “intercept” );
stAttribLoc.nRangeMin = glGetUniformLocation( GetProgramId( MAIN_RENDER_PROGRAM ), “rangeMin” );

glUseProgram( GetProgramId( MAIN_RENDER_PROGRAM ));

glUniform1i( stAttribLoc.nTemporarytexture, 0 );
glUniform1i( stAttribLoc.nColorMap,1 );
glUniform1i( stAttribLoc.nVolumeTexture, 2 );
glUniform1i( stAttribLoc.nDirectiontexture, 3 );

// Final render program
SetProgramId( FINAL_DISPLAY_PROGRAM, CreateProgram( szVertexShader, szFragmentShaderFront ));
stAttribLoc.nFrontFace = glGetUniformLocation( GetProgramId( FINAL_DISPLAY_PROGRAM ), “frontface” );

glUseProgram( GetProgramId( FINAL_DISPLAY_PROGRAM ));
glUniform1i( stAttribLoc.nFrontFace, 0 );

glUseProgram( 0 );
}

void CreateFrameBuffer()
{

glGenFramebuffersEXT( 1, &m_fbo );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_fbo );

glGenRenderbuffersEXT( 1, &m_renderDepthBuffer );
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_renderDepthBuffer );

glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, m_nWinWidth, m_nWinHeight );

// Attach the depth render buffer to the FBO as it’s depth attachment
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_renderDepthBuffer);

glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );

}

GLuint Create2dTexture( int nWidth_i, int nHeight_i, bool bOffscreen_i )
{
GLuint nImg;

glGenTextures( 1, &nImg );
glBindTexture( GL_TEXTURE_2D, nImg );
glPixelStoref( GL_UNPACK_ALIGNMENT, 1 );
glPixelStoref( GL_PACK_ALIGNMENT, 1 );
glPixelStoref( GL_UNPACK_ROW_LENGTH, nWidth_i );
glPixelStoref( GL_PACK_ROW_LENGTH, nWidth_i );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

if( bOffscreen_i )
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth_i, nHeight_i, 0, GL_RGBA, GL_FLOAT, NULL );
}
else
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth_i, nHeight_i, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
}
return nImg;
}

void CreateTexturesForRayCasting( int nWidth_i , int nHeight_i )
{

SetTextureId( TEMP_TEX_ID, Create2dTexture( nWidth_i, nHeight_i, true ));
SetTextureId( DIR_TEX_ID, Create2dTexture( nWidth_i, nHeight_i, true ));
SetTextureId( FRAME_COLOR_TEX_ID_1, Create2dTexture( nWidth_i, nHeight_i, false ));
SetTextureId( FRAME_COLOR_TEX_ID_2, Create2dTexture( nWidth_i, nHeight_i, false ));
}

void CreateVBO(float fWidth_i, float fHeight_i, float fDepth_i )
{
// cube
// v6—– v5
// /| /|
// v1——v0|
// | | | |
// | |v7—|-|v4
// |/ |/
// v2——v3

float fDimx,fDimy,fDimz;

fDimx = fWidth_i / 2.0;
fDimy = fHeight_i / 2.0;
fDimz = fDepth_i / 2.0;

for( int i = 0 ; i < 72 ; i++ )
{
m_fBoundingBoXcolors[i] = 1;
}

// Front Face
m_fColors[0] = 1; m_fColors[1] = 1; m_fColors[2] = 0; //v0
m_fVertices[0] = fDimx; m_fVertices[1] = fDimy; m_fVertices[2] = fDimz;

m_fColors[3] = 0; m_fColors[4] = 1; m_fColors[5] = 0; //v1
m_fVertices[3] = -fDimx; m_fVertices[4] = fDimy; m_fVertices[5] = fDimz;

m_fColors[6] = 0; m_fColors[7] = 0; m_fColors[8] = 0; //v2
m_fVertices[6] = -fDimx; m_fVertices[7] = -fDimy; m_fVertices[8] = fDimz;

m_fColors[9] = 1; m_fColors[10] = 0; m_fColors[11] = 0; //v3
m_fVertices[9] = fDimx; m_fVertices[10] = -fDimy; m_fVertices[11] = fDimz;

// Right Face
m_fColors[12] = 1; m_fColors[13] = 1; m_fColors[14] = 0; //vo
m_fVertices[12] = fDimx; m_fVertices[13] = fDimy; m_fVertices[14] = fDimz;

m_fColors[15] = 1; m_fColors[16] = 0; m_fColors[17] = 0; //v3
m_fVertices[15] = fDimx; m_fVertices[16] = -fDimy; m_fVertices[17] = fDimz;

m_fColors[18] = 1; m_fColors[19] = 0; m_fColors[20] = 1; //v4
m_fVertices[18] = fDimx; m_fVertices[19] = -fDimy; m_fVertices[20] = -fDimz;

m_fColors[21] = 1; m_fColors[22] = 1; m_fColors[23] = 1; //v5
m_fVertices[21] = fDimx; m_fVertices[22] = fDimy; m_fVertices[23] = -fDimz;

// Top Face
m_fColors[24] = 1; m_fColors[25] = 1; m_fColors[26] = 0; //v0
m_fVertices[24] = fDimx; m_fVertices[25] = fDimy; m_fVertices[26] = fDimz;

m_fColors[27] = 1; m_fColors[28] = 1; m_fColors[29] = 1; // v5
m_fVertices[27] = fDimx; m_fVertices[28] = fDimy; m_fVertices[29] = -fDimz;

m_fColors[30] = 0; m_fColors[31] = 1; m_fColors[32] = 1; //v6
m_fVertices[30] = -fDimx; m_fVertices[31] = fDimy; m_fVertices[32] = -fDimz;

m_fColors[33] = 0; m_fColors[34] = 1; m_fColors[35] = 0; // v1
m_fVertices[33] = -fDimx; m_fVertices[34] = fDimy; m_fVertices[35] = fDimz;

// Left Face
m_fColors[36] = 0; m_fColors[37] = 1; m_fColors[38] = 0; // v1
m_fVertices[36] = -fDimx; m_fVertices[37] = fDimy; m_fVertices[38] = fDimz;

m_fColors[39] = 0; m_fColors[40] = 1; m_fColors[41] = 1; //v6
m_fVertices[39] = -fDimx; m_fVertices[40] = fDimy; m_fVertices[41] = -fDimz;

m_fColors[42] = 0; m_fColors[43] = 0; m_fColors[44] = 1; // v7
m_fVertices[42] = -fDimx; m_fVertices[43] = -fDimy; m_fVertices[44] = -fDimz;

m_fColors[45] = 0; m_fColors[46] = 0; m_fColors[47] = 0; // v2
m_fVertices[45] = -fDimx; m_fVertices[46] = -fDimy; m_fVertices[47] = fDimz;

// Bottom Face
m_fColors[48] = 0; m_fColors[49] = 0; m_fColors[50] = 1; // v7
m_fVertices[48] = -fDimx; m_fVertices[49] = -fDimy; m_fVertices[50] = -fDimz;

m_fColors[51] = 1; m_fColors[52] = 0; m_fColors[53] = 1; // v4
m_fVertices[51] = fDimx; m_fVertices[52] = -fDimy; m_fVertices[53] = -fDimz;

m_fColors[54] = 1; m_fColors[55] = 0; m_fColors[56] = 0; // v3
m_fVertices[54] = fDimx; m_fVertices[55] = -fDimy; m_fVertices[56] = fDimz;

m_fColors[57] = 0; m_fColors[58] = 0; m_fColors[59] = 0; // v2
m_fVertices[57] = -fDimx; m_fVertices[58] = -fDimy; m_fVertices[59] = fDimz;

// Back Face
m_fVertices[60] = fDimx; m_fVertices[61] = -fDimy; m_fVertices[62] = -fDimz;
m_fColors[60] = 1; m_fColors[61] = 0; m_fColors[62] = 1; //v4

m_fColors[63] = 0; m_fColors[64] = 0; m_fColors[65] = 1; //v7
m_fVertices[63] = -fDimx; m_fVertices[64] = -fDimy; m_fVertices[65] = -fDimz;

m_fColors[66] = 0; m_fColors[67] = 1; m_fColors[68] = 1; // v6
m_fVertices[66] = -fDimx; m_fVertices[67] = fDimy; m_fVertices[68] = -fDimz;

m_fColors[69] = 1; m_fColors[70] = 1; m_fColors[71] = 1; //v5
m_fVertices[69] = fDimx; m_fVertices[70] = fDimy; m_fVertices[71] = -fDimz;

glGenBuffersARB( 1, &m_vbo );
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_vbo );
glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( m_fVertices ) + sizeof( m_fColors ), 0, GL_STATIC_DRAW_ARB );
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof( m_fVertices ), m_fVertices );
// copy vertices starting from 0 offest
glBufferSubDataARB( GL_ARRAY_BUFFER_ARB, sizeof( m_fVertices ), sizeof( m_fColors ), m_fColors );
// copy colours after normals

glGenBuffersARB( 1, &m_nBBoxvbo );
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nBBoxvbo );
glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( m_fVertices ) + sizeof( m_fBoundingBoXcolors ), 0, GL_STATIC_DRAW_ARB );
glBufferSubDataARB( GL_ARRAY_BUFFER_ARB, 0, sizeof( m_fVertices ), m_fVertices );
// copy vertices starting from 0 offest
glBufferSubDataARB( GL_ARRAY_BUFFER_ARB, sizeof( m_fVertices ), sizeof( m_fBoundingBoXcolors ), m_fBoundingBoXcolors );
// copy colours after normals
}

void DrawRenderingGeometry()
{
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_vbo );

// Enable vertex arrays
glEnableClientState( GL_COLOR_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );

// before draw, specify vertex and index arrays with their offsets
glColorPointer( 3, GL_FLOAT, 0, ( void* )( sizeof( m_fVertices )));
glVertexPointer( 3, GL_FLOAT, 0, 0 );

glDrawArrays( GL_QUADS, 0, 24 );

glDisableClientState( GL_VERTEX_ARRAY ); // disable vertex arrays
glDisableClientState( GL_COLOR_ARRAY );

// It is good idea to release VBOs with ID 0 after use.
// Once bound with 0, all pointers in gl*Pointer() behave as real
// pointer, so, normal vertex array operations are re-activated
glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );

}

void GenerateRenderingGeometryList()
{
glNewList( m_nRenderingGeometry = glGenLists(1), GL_COMPILE );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
////glRotatef( 135.0f, 0.0f, 1.0f, 0.0f );
//glRotatef( -90.0f, 1.0f, 0.0f, 0.0f );
DrawRenderingGeometry();
glEndList();
}

void AttachFbo( int nTexId_i )
{

// Attach fbo to specified texture id.
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_fbo );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, nTexId_i, 0 );
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
if( status != GL_FRAMEBUFFER_COMPLETE_EXT )
{
//Log Error
}
}

void CreateRayInitiationTexture()
{

glBindTexture( GL_TEXTURE_2D, GetTextureId( TEMP_TEX_ID ));
//attach fbo to specified texture id
AttachFbo( GetTextureId( TEMP_TEX_ID ));
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// render cube
glCallList( m_nRenderingGeometry );
glBindTexture( GL_TEXTURE_2D, 0 );
}

void CreateDirectionTexture()
{

// Bind front texture to TexturingUnit 0 so that it can be made available
// inside shaders
glUniform1i( stAttribLoc.nFrontFaceTex, 0 );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, GetTextureId( TEMP_TEX_ID ) );
AttachFbo( GetTextureId( DIR_TEX_ID ));
//glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glCallList( m_nRenderingGeometry );

}

void* ReadFile( LPCTSTR lpFileName_i, DATA_TYPE_e eType_i )
{
FILE* fp;
errno_t err = fopen_s( &fp, lpFileName_i, “rb” );
if( 0 != err )
{

return false;
}
size_t FileSize = DCM_WIDTH * DCM_HEIGHT * DCM_DEPTH * GetSizeof( eType_i );

char* chBuffer = new char[ FileSize ];
if( !chBuffer)
{
return false;
}

fread_s(( void* )chBuffer, FileSize, GetSizeof( eType_i ), DCM_WIDTH * DCM_HEIGHT * DCM_DEPTH, fp );
fclose( fp );
return (void*)chBuffer;
}

GLuint Create3DTexture( void* Pixels_i, DATA_TYPE_e eDataType_i )
{
GLuint nTextureID = 0;
if( 0 != Pixels_i )
{
// Set the texture parameters

switch( eDataType_i )
{
case UNSIGNED_ONE_BYTE:
{
int nMax2DTexSize = 2048;
unsigned char* tempD = new unsigned char[ 256*256 ];
memset( tempD, 255,256*256 );
//for( int nTempGridLoc = 0; nTempGridLoc < nTotal2Dtex; nTempGridLoc++ )
{
glActiveTextureARB( GL_TEXTURE0_ARB );
glGenTextures( 1, &nTextureID );
glBindTexture( GL_TEXTURE_2D, nTextureID );
glPixelStoref( GL_UNPACK_ALIGNMENT, 1 );
glPixelStoref( GL_PACK_ALIGNMENT, 1 );
glPixelStoref( GL_UNPACK_ROW_LENGTH, (GLfloat)DCM_WIDTH );
glPixelStoref( GL_PACK_ROW_LENGTH, (GLfloat)DCM_WIDTH );

glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, nMax2DTexSize, 3072,
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL );

BYTE* tempVol = (BYTE*)Pixels_i ;

for( int nTempY = 0; nTempY < 12; nTempY++ )
{
for( int nTempX = 0; nTempX < 8; nTempX++ )
{
glBindTexture( GL_TEXTURE_2D, nTextureID );
glTexSubImage2D( GL_TEXTURE_2D, 0,( DCM_WIDTH * nTempX ),( DCM_HEIGHT * nTempY ),
DCM_WIDTH, DCM_HEIGHT, GL_LUMINANCE,GL_UNSIGNED_BYTE, tempVol );
tempVol += ( DCM_WIDTH * DCM_HEIGHT );
}
}
}
delete[] tempD;

break;
}

default:
{

break;
}
}
}
return nTextureID;
}

bool Renderoffscreen()
{

float fMaxTextureDimension = static_cast<float>( max( max( DCM_WIDTH, DCM_HEIGHT ), DCM_DEPTH ));

int nSwapLogic[2];
nSwapLogic[0] = GetTextureId( FRAME_COLOR_TEX_ID_1 );
nSwapLogic[1] = GetTextureId( FRAME_COLOR_TEX_ID_2 );

int nCurrentSurface = 0;
float flDepth = 0.0f;
float fDiagonal = 1.732f * fMaxTextureDimension;
glClearColor( 0.0, 0.0, 0.0, 0.0 );
glClearDepth( 0 );
glDepthFunc( GL_GREATER | GL_EQUAL );

// Clear Offscreen Textures
AttachFbo( nSwapLogic[0] );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
AttachFbo( nSwapLogic[1] );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

float m_fStepSize = fDiagonal;

//float fStepSize = m_fStepSize / ( 9.0f * fMaxTextureDimension );
//float fStepSize = 1.0f/512;
float fStepSize = 1.0f / ( fMaxTextureDimension );

glUseProgram( GetProgramId( MAIN_RENDER_PROGRAM ));
glUniform1f( stAttribLoc.nStepSize, fStepSize );

// Pass data range value to shaders
if( UNSIGNED_ONE_BYTE == eDataType )
{
// Pass data range of unsigned byte to shaders.
glUniform1f( stAttribLoc.nDataRange, 255 );
}
if( SIGNED_ONE_BYTE == eDataType )
{
// Pass data range of signed byte to shaders.
glUniform1f( stAttribLoc.nDataRange, 127 );
}
else if( UNSIGNED_TWO_BYTE == eDataType )
{
// Pass data range of unsigned short to shaders.
glUniform1f( stAttribLoc.nDataRange, 65535 );
}
else if( SIGNED_TWO_BYTE == eDataType)
{
// Pass data range of signed short to shaders.
glUniform1f( stAttribLoc.nDataRange, 32767 );
}

// Pass windowing values to shaders.
glUniform1f( stAttribLoc.nWc, DEFAULT_WINDOW_CENTER );
glUniform1f( stAttribLoc.nWr, DEFAULT_WINDOW_WIDTH );

// Pass rendering mode to shaders.
glUniform1f( stAttribLoc.nRender, 0 );

// Pass slope & intercepts to shaders.
glUniform1f( stAttribLoc.nSlope, 1 );
glUniform1f( stAttribLoc.nIntercept, 0 );

glUniform1f( stAttribLoc.nRangeMin, m_nMainHURangeMin );

// Bind textures to texturing units so that they can be made available inside shaders.
glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, GetTextureId( LUT_TEX_ID ));
glActiveTexture( GL_TEXTURE3 );
glBindTexture( GL_TEXTURE_2D, GetTextureId( DIR_TEX_ID ));

// Ray is casted in volume with a default step size of 9.0f (can be changed)
// Inside shader, volume is sampled at 9 locations along the direction of ray.
// Intensity values obtained at differenet locations are blended for all
// sampling points.
// int flag = 0;

// for( float fSlices = 0; fSlices < fDiagonal; fSlices += m_fStepSize )

flDepth = 0;
for( int iter = 0;iter < 2;iter++ )
{

glUseProgram( GetProgramId( MAIN_RENDER_PROGRAM ));

// Bind textures to texturing units so that they can be made avilable
// inside shaders
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, nSwapLogic[1 - nCurrentSurface] );

glActiveTexture( GL_TEXTURE2 );
glBindTexture( GL_TEXTURE_2D, GetTextureId( VOL_TEX_ID ));

AttachFbo( nSwapLogic[nCurrentSurface] );
glUniform1f( stAttribLoc.nDepth, flDepth );

glCallList( m_nRenderingGeometry );

nCurrentSurface = 1 – nCurrentSurface;

// Increment depth.
flDepth += 0.85; // root(3) / 2
// flDepth += ( float )( m_fStepSize / fMaxTextureDimension );
glDepthFunc( GL_GREATER | GL_EQUAL );

}
return true;
}

bool LoadLUT()
{

// Fill the look up dimensions
m_stLookUp.m_pPixels = m_pRGBALUT;
m_stLookUp.m_nBytesPerPixel = 4;
m_stLookUp.m_nHeight = 1;
m_stLookUp.m_nDepth = 1;
m_stLookUp.m_nMin = HURANGE_MIN;
m_stLookUp.m_nMax = HURANGE_MAX;
m_stLookUp.m_nWidth = m_lLUTWidth;
return true;
}
//

GLuint CreateLUT()
{
GLuint nTexId = 0;
if( 0 != m_stLookUp.m_pPixels )
{
glGenTextures( 1, &nTexId );
glBindTexture( GL_TEXTURE_2D, nTexId );
glPixelStoref( GL_UNPACK_ALIGNMENT, 1 );
glPixelStoref( GL_PACK_ALIGNMENT, 1 );
glPixelStoref( GL_UNPACK_ROW_LENGTH, 256 );
glPixelStoref( GL_PACK_ROW_LENGTH, 32 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );

float* fTempData = new float[ 256 * 32 * 4];
memset( fTempData, 0 , 256 * 32 * 4 );
for( int nTemp = 0; nTemp < 32; nTemp++ )
for( int nTemp1 = 0; nTemp1 < 256*4; nTemp1+=4 )
{
fTempData[ 256 * 4 * nTemp + nTemp1 ] = m_pRGBALUT[ nTemp1 ];//(float)(nTemp1/1024.0);
fTempData[ 256 * 4 * nTemp + nTemp1 + 1] = m_pRGBALUT[ nTemp1 + 1 ];
fTempData[ 256 * 4 * nTemp + nTemp1 + 2] = m_pRGBALUT[ nTemp1 + 2 ];
fTempData[ 256 * 4 * nTemp + nTemp1 + 3] = m_pRGBALUT[ nTemp1 + 3 ];
}

//m_stLookUp.m_pPixels
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 32, 0, GL_RGBA, GL_FLOAT, fTempData );
delete[] fTempData;

return nTexId;

// Create the texture
/*glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256,
32, 0, GL_RGBA, GL_FLOAT, fTempData );*/
}
return -1;
}

void SetColorLUT( HURANGE_COLOR_t* pColorLUT_i, int* pSharpnessValues_i )
{

float fRColor = 0.0f;
float fGColor = 0.0f;
float fBColor = 0.0f;
long lLUTCount = 0;
long lLUTSize = 0;

int nHURangeMin = 0;
int nHURangeMax = 0;
float fSharpness = 0;

int nRedMax = 0;
int nGreenMax = 0;
int nBlueMax = 0;
int nRedMin = 0;
int nGreenMin = 0;
int nBlueMin = 0;

int nCurrentHU = 0;

float fAlpha = 0.0f;
int nAlphaMax = 0;
int nAlphaMin = 0;

HURANGE_COLOR_t m_pHURangeColor[ HURANGE_COLOR_ARRAY_SIZE ];
HURANGE_COLOR_t m_pHURangeColor1[ HURANGE_COLOR_ARRAY_SIZE ];

// Calculate the difference in WC & WW from default for color band.
int nWCDelta = 0;//m_nWindowCenter – m_nDefaultWindowCenter;

int nVolMin = GetMinValue();
int nVolMax = GetMaxValue();

pColorLUT_i[0].m_nHURangeMin = 0;
if( pColorLUT_i[0].m_nHURangeMin < nVolMin )
{
pColorLUT_i[0].m_nHURangeMin = nVolMin;
}
if( pColorLUT_i[HURANGE_COLOR_ARRAY_SIZE - 1].m_nHURangeMax > nVolMax )
{
pColorLUT_i[HURANGE_COLOR_ARRAY_SIZE - 1].m_nHURangeMax = nVolMax;
}

for( int nIndex = 0; nIndex < HURANGE_COLOR_ARRAY_SIZE; nIndex++ )
{
m_pHURangeColor[nIndex].m_nHURangeMin = pColorLUT_i[nIndex].m_nHURangeMin + nWCDelta;
m_pHURangeColor[nIndex].m_nHURangeMax = pColorLUT_i[nIndex].m_nHURangeMax + nWCDelta;

m_pHURangeColor[nIndex].m_nHURangeColor[0] = pColorLUT_i[nIndex].m_nHURangeColor[0];
m_pHURangeColor[nIndex].m_nHURangeColor[1] = pColorLUT_i[nIndex].m_nHURangeColor[1];
m_pHURangeColor[nIndex].m_nHURangeColor[2] = pColorLUT_i[nIndex].m_nHURangeColor[2];
m_pHURangeColor[nIndex].m_nHURangeColor[3] = pColorLUT_i[nIndex].m_nHURangeColor[3];

m_pHURangeColor1[nIndex].m_nHURangeMin = pColorLUT_i[nIndex].m_nHURangeMin;
m_pHURangeColor1[nIndex].m_nHURangeMax = pColorLUT_i[nIndex].m_nHURangeMax;

m_pHURangeColor1[nIndex].m_nHURangeColor[0] = pColorLUT_i[nIndex].m_nHURangeColor[0];
m_pHURangeColor1[nIndex].m_nHURangeColor[1] = pColorLUT_i[nIndex].m_nHURangeColor[1];
m_pHURangeColor1[nIndex].m_nHURangeColor[2] = pColorLUT_i[nIndex].m_nHURangeColor[2];
m_pHURangeColor1[nIndex].m_nHURangeColor[3] = pColorLUT_i[nIndex].m_nHURangeColor[3];
}

m_nMainHURangeMin = nVolMin * ( -1 );
m_lLUTWidth = ( -nVolMin ) + nVolMax + 1;

int nDivisor = m_lLUTWidth / 256;
int nReminder = m_lLUTWidth % 256;
if( nReminder != 0 )
{
m_lLUTWidth = m_lLUTWidth + ( ( 256 * ( nDivisor + 1 )) – m_lLUTWidth );
}
lLUTSize = m_lLUTWidth * 4;

m_pRGBALUT = new float[lLUTSize];

for( int nIndex = 0; nIndex <= HURANGE_COLOR_ARRAY_SIZE; nIndex++ )
{
if ( lLUTCount >= lLUTSize )
{
break;
}

fSharpness = ( 0 == nIndex || 1 == nIndex ) ? ( float ) pSharpnessValues_i[0] :
( float )pSharpnessValues_i[nIndex - 1];

nRedMin = m_pHURangeColor[nIndex].m_nHURangeColor[0];
nGreenMin = m_pHURangeColor[nIndex].m_nHURangeColor[1];
nBlueMin = m_pHURangeColor[nIndex].m_nHURangeColor[2];

if( nIndex == 0 && nVolMin < m_pHURangeColor[nIndex].m_nHURangeMin )
{
nVolMin = GetMinValue();
nHURangeMin = GetMinValue();
nHURangeMax = ( nVolMin + m_pHURangeColor[nIndex].m_nHURangeMin ) / 2;

nRedMin = 255;
nGreenMin = 255;
nBlueMin = 255;
nAlphaMin = m_pHURangeColor[nIndex].m_nHURangeColor[3];

nRedMax = m_pHURangeColor[nIndex].m_nHURangeColor[0];
nGreenMax = m_pHURangeColor[nIndex].m_nHURangeColor[1];
nBlueMax = m_pHURangeColor[nIndex].m_nHURangeColor[2];
nAlphaMax = m_pHURangeColor[nIndex].m_nHURangeColor[3];

while( nVolMin <= ( nVolMin + m_pHURangeColor[nIndex].m_nHURangeMin ) / 2 )
{
nCurrentHU = nVolMin;
if( fSharpness > 0 )
{
int nHUCenter = m_pHURangeColor[nIndex-1].m_nHURangeMin;
float fFirstVal = 1 / ( 1 + exp( ( 2 * fSharpness / 10 *
( nHURangeMin – nHUCenter )) /
( nHURangeMax – nHURangeMin )));
float fLastVal = 1 / ( 1 + exp( ( 2 * fSharpness / 10 *
( nHURangeMax – nHUCenter )) /
(nHURangeMax – nHURangeMin )));

fRColor = ( float ) nRedMin +
( ( float ) ( nRedMax – nRedMin ) / ( nHURangeMax – nHURangeMin ) *
( nCurrentHU – nHURangeMin )) * exp( 1 – ( fSharpness/100 ));

// Calculate and Store G value.
fGColor = ( float ) nGreenMin +
( ( float )( nGreenMax – nGreenMin ) / ( nHURangeMax – nHURangeMin ) *
( nCurrentHU – nHURangeMin )) * exp( 1 – ( fSharpness/100 ));

// Calculate and store B value.
fBColor = ( float ) nBlueMin +
( ( float )( nBlueMax – nBlueMin ) / ( nHURangeMax – nHURangeMin ) *
( nCurrentHU – nHURangeMin )) * exp( 1 – ( fSharpness / 100 ));

// Calculate and store A value.
fAlpha = ( float ) nAlphaMin +
( ( float )( nAlphaMax – nAlphaMin ) / ( nHURangeMax – nHURangeMin ) *
( nCurrentHU – nHURangeMin ));

fAlpha = ( float ) nAlphaMin +
( ( float )( nAlphaMax – nAlphaMin ) *
( exp( ( fSharpness / 10 * ( nCurrentHU -nHURangeMin ) ) /
( nHURangeMax – nHURangeMin )) – fFirstVal )) / ( fLastVal – fFirstVal );
fAlpha = ( float ) nAlphaMin +
( ( float )( nAlphaMax – nAlphaMin ) *
( 1 / ( 1 + exp( ( 2 * fSharpness / 10 * ( nCurrentHU – nHUCenter )) /
( nHURangeMax – nHURangeMin ))) – fFirstVal )) / ( fLastVal – fFirstVal );
}
else
{
// Calculate and store R value.
fRColor = ( float )nRedMin
+ ((float)( nRedMax – nRedMin )
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

//Calculate and Store G value
fGColor = (float)nGreenMin
+ ((float)(nGreenMax – nGreenMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

//Calculate and Store B value
fBColor = (float) nBlueMin
+ ((float)(nBlueMax – nBlueMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

//Calculate and Store A value
fAlpha = (float)nAlphaMin
+ ((float)(nAlphaMax – nAlphaMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

}

m_pRGBALUT[lLUTCount++] = fRColor / 255.0f;
m_pRGBALUT[lLUTCount++] = fGColor / 255.0f;
m_pRGBALUT[lLUTCount++] = fBColor / 255.0f;
m_pRGBALUT[lLUTCount++] = (fAlpha) / 100.0f;

if(lLUTCount >= lLUTSize)
{
break;
}

nVolMin++;
}
}
else if( nIndex == HURANGE_COLOR_ARRAY_SIZE)
{
nVolMax = GetMaxValue();
nVolMin = (m_pHURangeColor[nIndex - 1].m_nHURangeMax + nVolMax) / 2;

nRedMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[0];
nGreenMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[1];
nBlueMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[2];
nAlphaMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[3];

nRedMax = m_pHURangeColor[nIndex - 1].m_nHURangeColor[0];
nGreenMax = m_pHURangeColor[nIndex - 1].m_nHURangeColor[1];
nBlueMax = m_pHURangeColor[nIndex - 1].m_nHURangeColor[2];
nAlphaMax = m_pHURangeColor[nIndex - 1].m_nHURangeColor[3];

while(nVolMin <= nVolMax)
{
if( fSharpness > 0 )
{
int nHUCenter = m_pHURangeColor[nIndex-1].m_nHURangeMin;
float fFirstVal = 1 /
(1 + exp((2*fSharpness/10 * (nHURangeMin – nHUCenter))
/(nHURangeMax – nHURangeMin)));
float fLastVal =1 /
(1 + exp((2*fSharpness/10 * (nHURangeMax – nHUCenter))
/(nHURangeMax – nHURangeMin)));

fRColor = (float) nRedMin
+ ((float)( nRedMax – nRedMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ))* exp(1 – (fSharpness/100));

//Calculate and Store G value
fGColor = (float)nGreenMin
+ ((float)( nGreenMax – nGreenMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ))* exp(1 – (fSharpness/100));

//Calculate and Store B value
fBColor = (float)nBlueMin
+ ((float)(nBlueMax – nBlueMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ))* exp(1 – (fSharpness/100));

//Calculate and Store A value
fAlpha = (float)nAlphaMin
+ ((float)(nAlphaMax – nAlphaMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

fAlpha=(float)nAlphaMin
+ ((float)(nAlphaMax – nAlphaMin)
* (exp((fSharpness/10* (nCurrentHU -nHURangeMin))/(nHURangeMax – nHURangeMin)) -
fFirstVal))/(fLastVal – fFirstVal);
fAlpha = (float)nAlphaMin
+ ((float)(nAlphaMax – nAlphaMin)
* (1/(1 + exp((2*fSharpness/10 * (nCurrentHU – nHUCenter))
/ (nHURangeMax – nHURangeMin))) – fFirstVal))
/ (fLastVal – fFirstVal);

}
else
{
//Calculate and Store R value
fRColor = (float)nRedMin
+ ((float)(nRedMax – nRedMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));
//Calculate and Store G value
fGColor = (float)nGreenMin
+ ((float)(nGreenMax – nGreenMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

//Calculate and Store B value
fBColor = (float)nBlueMin
+ ((float)(nBlueMax – nBlueMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

//Calculate and Store A value

fAlpha = (float)nAlphaMin
+ ((float)(nAlphaMax – nAlphaMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));
}

m_pRGBALUT[lLUTCount++] = fRColor / 255.0f;
m_pRGBALUT[lLUTCount++] = fGColor / 255.0f;
m_pRGBALUT[lLUTCount++] = fBColor / 255.0f;
m_pRGBALUT[lLUTCount++] = (fAlpha) / 100.0f;
if( lLUTCount >= lLUTSize)
{
break;
}

nVolMin++;
}
}
else
{
nRedMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[0];
nGreenMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[1];
nBlueMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[2];
nAlphaMin = m_pHURangeColor[nIndex - 1].m_nHURangeColor[3];

nRedMax = m_pHURangeColor[nIndex].m_nHURangeColor[0];
nGreenMax = m_pHURangeColor[nIndex].m_nHURangeColor[1];
nBlueMax = m_pHURangeColor[nIndex].m_nHURangeColor[2];
nAlphaMax = m_pHURangeColor[nIndex].m_nHURangeColor[3];

if( nIndex – 1 == 0)
{
nVolMin = GetMinValue();
nHURangeMin = (nVolMin + m_pHURangeColor[nIndex].m_nHURangeMin)/2;
nHURangeMax = (m_pHURangeColor[nIndex].m_nHURangeMin +
m_pHURangeColor[nIndex+1].m_nHURangeMin) / 2;
}
else if( nIndex == HURANGE_COLOR_ARRAY_SIZE – 1)
{
nHURangeMin = (m_pHURangeColor[nIndex - 1].m_nHURangeMin +
m_pHURangeColor[nIndex].m_nHURangeMin) / 2;
nHURangeMax = m_pHURangeColor[nIndex].m_nHURangeMax ;
}
else
{
nHURangeMin = (m_pHURangeColor[nIndex - 1].m_nHURangeMin +
m_pHURangeColor[nIndex].m_nHURangeMin) / 2;
nHURangeMax = (m_pHURangeColor[nIndex].m_nHURangeMin +
m_pHURangeColor[nIndex + 1].m_nHURangeMin) / 2;
}

for(nCurrentHU = nHURangeMin; nCurrentHU <= nHURangeMax; nCurrentHU++ )
{
if( fSharpness > 0 )
{
int nHUCenter = m_pHURangeColor[nIndex-1].m_nHURangeMin;
float fFirstVal = 1 /
(1 + exp((2*fSharpness/10 * (nHURangeMin – nHUCenter))
/(nHURangeMax – nHURangeMin)));
float fLastVal =1 /
(1 + exp((2*fSharpness/10 * (nHURangeMax – nHUCenter))
/(nHURangeMax – nHURangeMin)));

fRColor = (float)nRedMin
+ ((float)(nRedMax – nRedMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ))* exp(1 – (fSharpness/100));

// Calculate and store G value
fGColor = (float)nGreenMin
+ ((float)(nGreenMax – nGreenMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ))* exp(1 – (fSharpness/100));

// Calculate and store B value
fBColor = (float)nBlueMin
+ ((float)(nBlueMax – nBlueMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ))* exp(1 – (fSharpness/100));

// Calculate and store A value
fAlpha = (float)nAlphaMin
+ ((float)(nAlphaMax – nAlphaMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

fAlpha=(float)nAlphaMin
+ ((float)(nAlphaMax – nAlphaMin)
* (exp((fSharpness/10* (nCurrentHU -nHURangeMin))/
(nHURangeMax – nHURangeMin)) – fFirstVal))/(fLastVal – fFirstVal);
fAlpha = (float)nAlphaMin
+ ((float)( nAlphaMax – nAlphaMin)
* (1/(1 + exp((2*fSharpness/10 * (nCurrentHU – nHUCenter))
/ (nHURangeMax – nHURangeMin))) – fFirstVal))
/ (fLastVal – fFirstVal);

}
else
{
// Calculate and store R value
fRColor = (float)nRedMin
+ ((float)(nRedMax – nRedMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));//* exp(1 – (fSharpness/100));

// Calculate and store G value
fGColor = (float) nGreenMin
+ ((float)( nGreenMax – nGreenMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));//* exp(1 – (fSharpness/100));

//Calculate and store B value
fBColor = (float)nBlueMin
+ ((float)(nBlueMax – nBlueMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));//* exp(1 – (fSharpness/100));

//Calculate and Store A value

fAlpha = (float) nAlphaMin
+ ((float)( nAlphaMax – nAlphaMin)
/ (nHURangeMax – nHURangeMin)
* ( nCurrentHU – nHURangeMin ));

}

m_pRGBALUT[lLUTCount++] = fRColor / 255.0f;
m_pRGBALUT[lLUTCount++] = fGColor / 255.0f;
m_pRGBALUT[lLUTCount++] = fBColor / 255.0f;
m_pRGBALUT[lLUTCount++] = (fAlpha) / 100.0f;

if(lLUTCount >= lLUTSize)
{
break;
}
}
}
}
// Load the LUT from the resource.
LoadLUT();
// Create the LUT texture.
SetTextureId( LUT_TEX_ID, CreateLUT());

}

void InitializeLUT()
{
int nIndex = 0;
m_stHURangeColor[ nIndex ].m_nHURangeMax = 119;
m_stHURangeColor[ nIndex ].m_nHURangeMin = 118;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ RED ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ GREEN ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ BLUE ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ ALPHA ] = 0;

nIndex++;

m_stHURangeColor[ nIndex ].m_nHURangeMax = 120;
m_stHURangeColor[ nIndex ].m_nHURangeMin = 119;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ RED ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ GREEN ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ BLUE ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ ALPHA ] = 0;

nIndex++;

m_stHURangeColor[ nIndex ].m_nHURangeMax = 198;
m_stHURangeColor[ nIndex ].m_nHURangeMin = 120;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ RED ] = 128;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ GREEN ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ BLUE ] = 0;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ ALPHA ] = 3;

nIndex++;

m_stHURangeColor[ nIndex ].m_nHURangeMax = 667;
m_stHURangeColor[ nIndex ].m_nHURangeMin = 198;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ RED ] = 255;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ GREEN ] = 255;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ BLUE ] = 128;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ ALPHA ] = 93;

nIndex++;

m_stHURangeColor[ nIndex ].m_nHURangeMax = 668;
m_stHURangeColor[ nIndex ].m_nHURangeMin = 667;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ RED ] = 255;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ GREEN ] = 255;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ BLUE ] = 255;
m_stHURangeColor[ nIndex ].m_nHURangeColor[ ALPHA ] = 100;

nIndex = -1;

m_nSharpness[ ++nIndex ] = 5;
m_nSharpness[ ++nIndex ] = 5;
m_nSharpness[ ++nIndex ] = 5;
m_nSharpness[ ++nIndex ] = 5;

SetColorLUT( m_stHURangeColor, m_nSharpness );

}

void MapToScreen()
{

glMatrixMode( GL_MODELVIEW );
// Save state of model view matrix.
glPushMatrix();
// Reset
glLoadIdentity();

// Save state of projection matrix.
glMatrixMode( GL_PROJECTION );
glPushMatrix();
// Reset
glLoadIdentity();
glPushAttrib( GL_VIEWPORT_BIT );
//glOrtho( 0 , 1, 0, 1, 0, 10 );

glColor3f( 0, 0, 0 );
glBegin( GL_QUADS );
glVertex2f( 0.0f, 0.0f );
glVertex2f( 1.0f, 0.0f );
glVertex2f( 1.0f, 1.0f );
glVertex2f( 0.0f, 1.0f );
glEnd();

// Return back
glPopAttrib();
// Back to original projection.
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
// Back to original modelview.
glPopMatrix();

}

void ClearOff()
{
// Delete offscreen textures
GLuint uTexId = GetTextureId( TEMP_TEX_ID );
glDeleteTextures( 1, &uTexId );
uTexId = GetTextureId( DIR_TEX_ID );
glDeleteTextures( 1, &uTexId );
uTexId = GetTextureId( FRAME_COLOR_TEX_ID_1 );
glDeleteTextures( 1, &uTexId );
uTexId = GetTextureId( FRAME_COLOR_TEX_ID_2 );
glDeleteTextures( 1, &uTexId );

// Delete frameBuffer object
glDeleteFramebuffersEXT( 1,&m_fbo );
glDeleteRenderbuffersEXT( 1, &m_renderDepthBuffer );

}

void Initialize3D()
{
float fSizex, fSizey, fSizez;
fSizex = DCM_WIDTH;
fSizey = DCM_HEIGHT;
fSizez = DCM_DEPTH;

float maxdim = max( max( fSizex, fSizey ), fSizez );

fSizex = fSizex / maxdim;
fSizey = fSizey / maxdim;
fSizez = fSizez / maxdim;
void* pPixels = ReadFile( szFile, eDataType );
SetTextureId( VOL_TEX_ID, Create3DTexture( pPixels, eDataType ));
delete [] pPixels;
pPixels = 0;
CreateVBO( fSizex, fSizey, fSizez );
GenerateRenderingGeometryList();
LoadShaders();
InitializeLUT();
}

void SetupRC()
{
glewInit();
Initialize3D();
}

void RenderScene()
{

glEnable( GL_DEPTH_TEST );
glEnable( GL_CULL_FACE );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

CreateFrameBuffer();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( -0.5, 0.5, -0.5, 0.5, -2, 2 );

// Reset modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//glTranslatef( 0,0,-1.0 );

CreateTexturesForRayCasting( m_nWinWidth, m_nWinHeight );
CreateRayInitiationTexture();

glCullFace( GL_FRONT );
glUseProgram( GetProgramId( DIRECTION_PROGRAM ));
CreateDirectionTexture();
glCullFace( GL_BACK );

Renderoffscreen();

// Map offscreen texture To screen
glViewport( 0, 0, m_nWinWidth, m_nWinHeight );

/*glUseProgram( GetProgramId( FINAL_DISPLAY_PROGRAM ));*/
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, GetTextureId( FRAME_COLOR_TEX_ID_2 ));

glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // unbind Frame buffer
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//SetAspectedOrtho( 0, 0, m_nWinWidth, m_nWinHeight, 0.75f );
//MapToScreen();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glOrtho( -1, 1, -1, 1, -2, 2 );

// Reset modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//glUseProgram(0);
glDisable( GL_CULL_FACE );

glColor3f( 0, 1, 0 );
glBegin( GL_QUADS );

glTexCoord2f( 0,0 );
glVertex2f( -1.0f, -1.0f );

glTexCoord2f( 1,0 );
glVertex2f( 1.0f, -1.0f );

glTexCoord2f( 1,1 );
glVertex2f( 1.0f, 1.0f );

glTexCoord2f( 0,1 );
glVertex2f( -1.0f, 1.0f );
glEnd();

glutSwapBuffers();
ClearOff();
}

int main( int argc, char* argv[])
{
glutInit( &argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA );
glutInitWindowSize( 900, 900 );
glutCreateWindow(“Shader”);
glutDisplayFunc(RenderScene);
glutReshapeFunc(Reshape);
SetupRC();
glutMainLoop();
return 0;
}

YARN and MRv2: The New Incarnations In The Cloud!


As you all know, MapReduce has undergone a complete overhaul in hadoop-0.23 (or from CDH4 onwards, for the Cloudera fans like me)  and we now have, what we call, MapReduce 2.0 (MRv2 or simply MR2) or YARN. You might have read a lot about the same and I’m not going to explain it all over again here. But I feel a little recapitulation will be useful for all of us.

Aging MapReduce Continue reading

Upgrade Upgrade Upgrade…


Like Apache Hadoop MapReduce got a large overhaul and upgrade, there is been a local upgrade here too. Just got in to the lions den last week.

Apache Hadoop

Yep, you heard it correct, Asia’s one of the best Apache Hadoop facility, with all the industry standard amenities for the cloud and a huge number of certified Hadoop developers as colleagues; sure, you can expect industry standard cloud technology write-ups from now on.

To Experience Certainty, Stay tuned…

Flip an One dimensional image array verticaly


Flip Vertically

This function is used for flipping a one dimensional pixel array vertically

/**
* Function to Flip PixelData
*
* @param pPixelData_io – Original Pixel Data
* @param nSize_i – Buffer Size
* @return Nil
* @exception Nil
* @see Nil
* @since 1.0
*/
void FlipPixelData( void* pPixelData_io, int nSize_i )
{
int nRow, nStride;
GLubyte* pSwapline;
 nStride = m_Size->cx * 2; // length of a line in bytes
pSwapline = (GLubyte *) malloc(nStride);
    // vertical flip
for(nRow = 0; nRow < m_Size->cy/2; nRow++)
{
memcpy(pSwapline, (byte*)pPixelData_io + nRow * nStride, nStride);
memcpy((byte*)pPixelData_io + nRow * nStride, (byte*)pPixelData_io + (m_Size->cy – nRow – 1) *       nStride, nStride);
memcpy((byte*)pPixelData_io + (m_Size->cy – nRow -1) * nStride, pSwapline, nStride);
}
free(pSwapline);
}

Windows 8: Public Release and General Availability on 26 Oct 2012.


Windows 8, the new shiny OS is now available for the general public to download from Microsoft Stores.Windows 8 Upgrade Offer

Microsoft is offering an upgrade offer if you are currently using Windows 7, for $39.99. Windows8 Upgrade OfferFor more details please visit http://windows.microsoft.com/en-US/windows/buy?ocid=GA8_O_WOL_DIS_Compare_FPP_Null

UPDATE: As of now, the upgrade links are not working. Trying to do an upgrade will get you to the screen as shown below! Yup, we are waiting…
Windows8 Upgrade Offer Failed.

UPDATE: Everything is up and running fine. Great work MS :)Windows 8 Upgrade Assistant.

At the same time, Microsoft is offering another upgrade offer if you recently bought your Windows 7 PC and wish to upgrade to Windows 8. The offer price is just $14.99. The is cool if you still want to try the new beast.
Windows8 Upgrade.

For more details visit the Windows upgrade page, https://www.windowsupgradeoffer.com/en-US/

UPDATE: As of now the upgrade assistant is not working. See the error message the upgrade assistant throwing out while connecting to upgrade offer server.
Windows8 upgrade assistant failed.

UPDATE: Everything working fine as of now, the upgrade assistant went like a breeze and the upgrade process was very quick, got the Windows 8 Pro key within a minute, yup, you guessed it correct, for $14.99. The upgrade assistant is a mini downloader too, after completing the Windows 8 upgrade offer, the upgrade assistant started downloading the OS! That was very nice, but I dismissed the download because the just bought key worked flawlessly with the MSDN image too, so why download the same thing over and again?

For those who are looking for the MSDN image, there are torrents out there, which will get you an untouched virgin image of Windows 8 Pro, from MSDN. Use the same with the key and enjoy the new OS.

As of now there is no confirmed reports that Microsoft is verifying your purchase of PC, so you can register with some seemingly genuine data on https://www.windowsupgradeoffer.com/en-US/ and grab your copy of Windows 8. So what are you waiting for, grab your copy of genuine Windows 8, without wasting time searching for illegal KMS servers. Be genuine, at least for the product key. :)