Commit 7a4ea895 authored by unknown's avatar unknown Committed by jean-pierre charras

3D viewer enhancements (better render + better vrml reader) from Mario Luzeiro

parent 15403684
......@@ -57,13 +57,31 @@ void S3D_MASTER::ObjectCoordsTo3DUnits( std::vector< S3D_VERTEX >& aVertices )
// adjust rotation
if( m_MatRotation.x )
RotatePoint( &aVertices[ii].y, &aVertices[ii].z, m_MatRotation.x * 10 );
{
double a = aVertices[ii].y;
double b = aVertices[ii].z;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].y = (float)a;
aVertices[ii].z = (float)b;
}
if( m_MatRotation.y )
RotatePoint( &aVertices[ii].z, &aVertices[ii].x, m_MatRotation.y * 10 );
{
double a = aVertices[ii].z;
double b = aVertices[ii].x;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].z = (float)a;
aVertices[ii].x = (float)b;
}
if( m_MatRotation.z )
RotatePoint( &aVertices[ii].x, &aVertices[ii].y, m_MatRotation.z * 10 );
{
double a = aVertices[ii].x;
double b = aVertices[ii].y;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].x = (float)a;
aVertices[ii].y = (float)b;
}
/* adjust offset position (offset is given in UNIT 3D (0.1 inch) */
#define SCALE_3D_CONV ((IU_PER_MILS * 1000) / UNITS3D_TO_UNITSPCB)
......@@ -138,9 +156,9 @@ VERTEX_VALUE_CTRL::VERTEX_VALUE_CTRL( wxWindow* aParent, wxBoxSizer* aBoxSizer )
wxString text;
wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
gridSizer->AddGrowableCol( 1 );
gridSizer->SetFlexibleDirection( wxHORIZONTAL );
gridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
gridSizer->AddGrowableCol( 1 );
gridSizer->SetFlexibleDirection( wxHORIZONTAL );
gridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
aBoxSizer->Add( gridSizer, 0, wxEXPAND, 5 );
......
......@@ -16,17 +16,21 @@
#include <gestfich.h>
#include <gl/glew.h> // must be included before gl.h
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <3d_viewer_id.h>
#include <textures/text_silk.c>
#include <textures/text_pcb.c>
// -----------------
// helper function (from wxWidgets, opengl/cube.cpp sample
// -----------------
void CheckGLError()
void CheckGLError(const char *aFileName, int aLineNumber)
{
GLenum errLast = GL_NO_ERROR;
......@@ -47,7 +51,7 @@ void CheckGLError()
errLast = err;
wxLogError(wxT("OpenGL error %d"), err);
wxLogError( wxT( "OpenGL error %d\nAt: %s, line: %d" ), err, aFileName, aLineNumber );
}
}
......@@ -78,6 +82,7 @@ EDA_3D_CANVAS::EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList ) :
wxFULL_REPAINT_ON_RESIZE )
{
m_init = false;
m_shadow_init = false;
// Clear all gl list identifiers:
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
......@@ -490,15 +495,46 @@ void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent& event )
// Do nothing, to avoid flashing.
}
typedef struct s_sImage
{
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[64 * 64 * 4 + 1];
}tsImage;
GLuint load_and_generate_texture( tsImage *image )
{
GLuint texture;
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, image->width, image->height, GL_RGBA, GL_UNSIGNED_BYTE, image->pixel_data );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
return texture;
}
/* Initialize broad parameters for OpenGL */
void EDA_3D_CANVAS::InitGL()
{
wxSize size = GetClientSize();
if( !m_init )
{
m_init = true;
m_text_pcb = load_and_generate_texture( (tsImage *)&text_pcb );
m_text_silk = load_and_generate_texture( (tsImage *)&text_silk );
g_Parm_3D_Visu.m_Zoom = 1.0;
m_ZBottom = 1.0;
m_ZTop = 10.0;
......@@ -513,7 +549,7 @@ void EDA_3D_CANVAS::InitGL()
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
// speedups
glEnable( GL_DITHER );
//glEnable( GL_DITHER );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE );
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
......@@ -521,52 +557,7 @@ void EDA_3D_CANVAS::InitGL()
// Initialize alpha blending function.
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
// set viewing projection
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
#define MAX_VIEW_ANGLE 160.0 / 45.0
if( g_Parm_3D_Visu.m_Zoom > MAX_VIEW_ANGLE )
g_Parm_3D_Visu.m_Zoom = MAX_VIEW_ANGLE;
if( Parent()->ModeIsOrtho() )
{
// OrthoReductionFactor is chosen so as to provide roughly the same size as
// Perspective View
const double orthoReductionFactor = 400 / g_Parm_3D_Visu.m_Zoom;
// Initialize Projection Matrix for Ortographic View
glOrtho( -size.x / orthoReductionFactor, size.x / orthoReductionFactor,
-size.y / orthoReductionFactor, size.y / orthoReductionFactor, 1, 10 );
}
else
{
// Ratio width / height of the window display
double ratio_HV = (double) size.x / size.y;
// Initialize Projection Matrix for Perspective View
gluPerspective( 45.0 * g_Parm_3D_Visu.m_Zoom, ratio_HV, 1, 10 );
}
// position viewer
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0.0F, 0.0F, -( m_ZBottom + m_ZTop) / 2 );
// clear color and depth buffers
glClearColor( g_Parm_3D_Visu.m_BgColor.m_Red,
g_Parm_3D_Visu.m_BgColor.m_Green,
g_Parm_3D_Visu.m_BgColor.m_Blue, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Setup light sources:
SetLights();
CheckGLError();
}
}
......@@ -578,16 +569,19 @@ void EDA_3D_CANVAS::SetLights()
/* set viewing projection */
light_color[3] = 1.0;
GLfloat Z_axis_pos[4] = { 0.0, 0.0, 3.0, 0.0 };
GLfloat lowZ_axis_pos[4] = { 0.0, 0.0, -3.0, 0.5 };
GLfloat Z_axis_pos[4] = { 0.0, 0.0, 30.0, 0.0 };
GLfloat lowZ_axis_pos[4] = { 0.0, 0.0, -30.0, 0.5 };
/* activate light */
light = 1.0;
light_color[0] = light_color[1] = light_color[2] = light;
glLightfv( GL_LIGHT0, GL_POSITION, Z_axis_pos );
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_color );
light = 0.3;
light_color[0] = light_color[1] = light_color[2] = light;
light_color[0] = 0.3;
light_color[1] = 0.3;
light_color[2] = 0.4;
glLightfv( GL_LIGHT1, GL_POSITION, lowZ_axis_pos );
glLightfv( GL_LIGHT1, GL_DIFFUSE, light_color );
glEnable( GL_LIGHT0 ); // White spot on Z axis
......@@ -654,7 +648,6 @@ void EDA_3D_CANVAS::TakeScreenshot( wxCommandEvent& event )
viewport.x, viewport.y,
GL_ALPHA, GL_UNSIGNED_BYTE, alphabuffer );
image.SetData( pixelbuffer );
image.SetAlpha( alphabuffer );
image = image.Mirror( false );
......
......@@ -43,10 +43,11 @@
#endif
#include <3d_struct.h>
#include <convert_basic_shapes_to_polygon.h>
class BOARD_DESIGN_SETTINGS;
class EDA_3D_FRAME;
class S3D_VERTEX;
class VIA;
class D_PAD;
......@@ -61,8 +62,14 @@ enum GL_LIST_ID
GL_ID_BOARD, // List id for copper layers
GL_ID_TECH_LAYERS, // List id for non copper layers (masks...)
GL_ID_AUX_LAYERS, // List id for user layers (draw, eco, comment)
GL_ID_3DSHAPES_SOLID, // List id for 3D shapes, non transparent entities
GL_ID_3DSHAPES_TRANSP, // List id for 3D shapes, transparent entities
GL_ID_3DSHAPES_SOLID_FRONT, // List id for 3D shapes, non transparent entities
GL_ID_3DSHAPES_TRANSP_FRONT,// List id for 3D shapes, transparent entities
GL_ID_3DSHAPES_SOLID_BACK, // List id for 3D shapes, non transparent entities
GL_ID_3DSHAPES_TRANSP_BACK,// List id for 3D shapes, transparent entities
GL_ID_SHADOW_FRONT,
GL_ID_SHADOW_BACK,
GL_ID_SHADOW_BOARD,
GL_ID_BODY, // Body only list
GL_ID_END
};
......@@ -76,6 +83,16 @@ private:
double m_ZBottom; // position of the back layer
double m_ZTop; // position of the front layer
GLuint m_text_pcb;
GLuint m_text_silk;
bool m_shadow_init;
GLuint m_text_fake_shadow_front;
GLuint m_text_fake_shadow_back;
GLuint m_text_fake_shadow_board;
void Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture, GLuint aTexture_size, bool aDraw_body, int aBlurPasses );
public:
EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList = 0 );
~EDA_3D_CANVAS();
......@@ -122,6 +139,9 @@ public:
m_draw3dOffset.x = aPosX;
m_draw3dOffset.y = aPosY;
}
void SetGLTechLayersColor( LAYER_NUM aLayer );
void SetGLCopperColor();
void SetGLEpoxyColor( double aTransparency = 1.0 );
/**
* Function BuildBoard3DView
......@@ -129,7 +149,7 @@ public:
* Populates the OpenGL GL_ID_BOARD draw list with board items only on copper layers.
* 3D footprint shapes, tech layers and aux layers are not on this list
*/
void BuildBoard3DView();
void BuildBoard3DView(GLuint aBoardList, GLuint aBodyOnlyList);
/**
* Function BuildTechLayers3DView
......@@ -138,6 +158,12 @@ public:
*/
void BuildTechLayers3DView();
/**
* Function BuildShadowList
* Called by CreateDrawGL_List()
*/
void BuildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList );
/**
* Function BuildFootprintShape3DList
* Called by CreateDrawGL_List()
......@@ -148,7 +174,8 @@ public:
* which need to be drawn after all other items
*/
void BuildFootprintShape3DList( GLuint aOpaqueList,
GLuint aTransparentList);
GLuint aTransparentList,
bool aSideToLoad );
/**
* Function BuildBoard3DAuxLayers
* Called by CreateDrawGL_List()
......@@ -163,7 +190,11 @@ public:
void Draw3DViaHole( const VIA * aVia );
void Draw3DPadHole( const D_PAD * aPad );
void GenerateFakeShadowsTextures();
DECLARE_EVENT_TABLE()
};
void CheckGLError(const char *aFileName, int aLineNumber);
#endif /* _3D_CANVAS_H_ */
......@@ -30,36 +30,6 @@
#include <3d_viewer.h>
S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) :
EDA_ITEM( father, NOT_USED )
{
m_DiffuseColor.x = m_DiffuseColor.y = m_DiffuseColor.z = 1.0;
m_SpecularColor.x = m_SpecularColor.y = m_SpecularColor.z = 1.0;
m_AmbientIntensity = 1.0;
m_Transparency = 0.0;
m_Shininess = 1.0;
m_Name = name;
}
void S3D_MATERIAL::SetMaterial()
{
S3D_MASTER * s3dParent = (S3D_MASTER *) GetParent();
s3dParent->SetLastTransparency( m_Transparency );
if( ! s3dParent->IsOpenGlAllowed() )
return;
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
glColor4f( m_DiffuseColor.x * m_AmbientIntensity,
m_DiffuseColor.y * m_AmbientIntensity,
m_DiffuseColor.z * m_AmbientIntensity,
1.0 - m_Transparency );
#if 0
glColorMaterial( GL_FRONT_AND_BACK, GL_SPECULAR );
glColor3f( m_SpecularColor.x, m_SpecularColor.y, m_SpecularColor.z );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
#endif
}
bool S3D_MASTER::IsOpenGlAllowed()
{
......@@ -68,9 +38,12 @@ bool S3D_MASTER::IsOpenGlAllowed()
if( m_lastTransparency == 0.0 )
return true;
}
if( m_loadTransparentObjects ) // return true for transparent objects only
if( m_loadTransparentObjects ) // return true for transparent objects only
{
if( m_lastTransparency != 0.0 )
return true;
}
return false;
}
......@@ -102,6 +75,13 @@ S3D_MASTER::S3D_MASTER( EDA_ITEM* aParent ) :
m_3D_Drawings = NULL;
m_Materials = NULL;
m_ShapeType = FILE3D_NONE;
m_use_modelfile_diffuseColor = true;
m_use_modelfile_emissiveColor = false;
m_use_modelfile_specularColor = false;
m_use_modelfile_ambientIntensity = false;
m_use_modelfile_transparency = true;
m_use_modelfile_shininess = false;
}
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -43,15 +43,14 @@
#include <colors_selection.h>
#include <convert_basic_shapes_to_polygon.h>
#include <gl/glew.h> // must be included before gl.h
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <3d_draw_basic_functions.h>
// Imported function:
extern void CheckGLError();
/* Helper function
* returns true if aLayer should be displayed, false otherwise
*/
......@@ -99,6 +98,252 @@ static void BuildPadShapeThickOutlineAsPolygon( D_PAD* aPad,
}
// Based on the tutorial by http://www.ulrichmierendorff.com/software/opengl_blur.html
/* It will blur a openGL texture
*
*/
static void blur_tex( GLuint aTex, int aPasses, GLuint aTexture_size )
{
int i, x, y;
glFlush();
glFinish();
glPushAttrib( GL_ALL_ATTRIB_BITS );
glDisable( GL_LIGHTING );
glDisable( GL_CULL_FACE );
glDisable( GL_DEPTH_TEST );
glDisable( GL_ALPHA_TEST );
glDisable( GL_COLOR_MATERIAL );
glReadBuffer( GL_BACK_LEFT );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glViewport( 0, 0, aTexture_size, aTexture_size );
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glOrtho( 0.0f, aTexture_size, aTexture_size, 0.0f, -1.0f, 1.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, aTex );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
while (aPasses > 0)
{
i = 0;
for (x = 0; x < 2; x++)
{
for (y = 0; y < 2; y++, i++)
{
glColor4f (1.0f,1.0f,1.0f,1.0 / (i + 1.0));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f( 0 + (x - 0.5)/aTexture_size, 1 + (y-0.5)/aTexture_size );
glVertex2f( 0, 0 );
glTexCoord2f( 0 + (x - 0.5)/aTexture_size, 0 + (y-0.5)/aTexture_size );
glVertex2f( 0, aTexture_size );
glTexCoord2f( 1 + (x - 0.5)/aTexture_size, 1 + (y-0.5)/aTexture_size );
glVertex2f( aTexture_size, 0 );
glTexCoord2f( 1 + (x - 0.5)/aTexture_size, 0 + (y-0.5)/aTexture_size );
glVertex2f( aTexture_size, aTexture_size );
glEnd ();
}
}
glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, aTexture_size, aTexture_size, 0 );
aPasses--;
}
glFlush();
glFinish();
glDisable( GL_BLEND );
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glPopAttrib();
glEnable(GL_DEPTH_TEST);
}
void EDA_3D_CANVAS::Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture,
GLuint aTexture_size, bool aDraw_body, int aBlurPasses )
{
float *depthbufferFloat = (float*) malloc( aTexture_size * aTexture_size * sizeof(float) );
unsigned char *depthbufferRGBA = (unsigned char*) malloc( aTexture_size * aTexture_size * 4 );
glDisable( GL_TEXTURE_2D );
glViewport( 0, 0, aTexture_size, aTexture_size );
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// move the board in order to draw it with its center at 0,0 3D coordinates
glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits,
0.0F );
if( aDraw_body )
{
if( m_glLists[GL_ID_BODY] )
{
glCallList( m_glLists[GL_ID_BOARD] );
}
}
// Call model list
glCallList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] );
if( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] )
{
glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] );
}
glPixelStorei( GL_PACK_ALIGNMENT, 4 );
glReadBuffer( GL_BACK_LEFT );
glFinish();
glReadPixels( 0, 0,
aTexture_size, aTexture_size,
GL_DEPTH_COMPONENT, GL_FLOAT, depthbufferFloat );
glFinish();
for( unsigned int i = 0; i< (aTexture_size * aTexture_size); i++ )
{
unsigned char v = depthbufferFloat[i] * 255;
depthbufferRGBA[i * 4 + 0] = v;
depthbufferRGBA[i * 4 + 1] = v;
depthbufferRGBA[i * 4 + 2] = v;
depthbufferRGBA[i * 4 + 3] = 255;
}
glFinish();
glEnable( GL_TEXTURE_2D );
glGenTextures( 1, aDst_gl_texture );
glBindTexture( GL_TEXTURE_2D, *aDst_gl_texture );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
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_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, aTexture_size, aTexture_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, depthbufferRGBA );
glFlush();
glFinish();
CheckGLError( __FILE__, __LINE__ );
blur_tex( *aDst_gl_texture, aBlurPasses, aTexture_size );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, *aDst_gl_texture );
glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, depthbufferRGBA );
for(unsigned int i = 0; i< (aTexture_size * aTexture_size); i++)
{
float v = (float)depthbufferRGBA[i * 4] / 255.0f;
v = v * v;
depthbufferRGBA[i * 4 + 0] = 0;
depthbufferRGBA[i * 4 + 1] = 0;
depthbufferRGBA[i * 4 + 2] = 0;
depthbufferRGBA[i * 4 + 3] = 255 - (unsigned char)(v * 255);
}
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_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, aTexture_size, aTexture_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, depthbufferRGBA );
free( depthbufferRGBA );
free( depthbufferFloat );
}
#define SHADOW_BOARD_SCALE 1.5f
void EDA_3D_CANVAS::GenerateFakeShadowsTextures()
{
if( m_shadow_init == true )
{
return;
}
m_shadow_init = true;
CreateDrawGL_List();
glClearColor( 0, 0, 0, 1 );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( -g_Parm_3D_Visu.m_BoardSize.x * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
g_Parm_3D_Visu.m_BoardSize.x * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
-g_Parm_3D_Visu.m_BoardSize.y * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
g_Parm_3D_Visu.m_BoardSize.y * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
0.0, 3500000 * g_Parm_3D_Visu.m_BiuTo3Dunits );
// Render FRONT shadow
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, 0.03 );
glRotatef( 180, 0.0, 1.0, 0.0 );
Create_and_Render_Shadow_Buffer( &m_text_fake_shadow_front, 512, false, 5 );
// Render BACK shadow
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, 0.03 );
///glRotatef( 0.0, 0.0, 1.0, 0.0 );
Create_and_Render_Shadow_Buffer( &m_text_fake_shadow_back, 512, false, 5 );
// Render ALL BOARD shadow
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( -g_Parm_3D_Visu.m_BoardSize.x * SHADOW_BOARD_SCALE * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
g_Parm_3D_Visu.m_BoardSize.x * SHADOW_BOARD_SCALE * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
-g_Parm_3D_Visu.m_BoardSize.y * SHADOW_BOARD_SCALE * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
g_Parm_3D_Visu.m_BoardSize.y * SHADOW_BOARD_SCALE * g_Parm_3D_Visu.m_BiuTo3Dunits / 2.0f,
0.0, 6.0f * 3500000 * g_Parm_3D_Visu.m_BiuTo3Dunits );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, -0.4f );
glRotatef( 180.0, 0.0, 1.0, 0.0 );
Create_and_Render_Shadow_Buffer( &m_text_fake_shadow_board, 512, true, 10 );
}
void EDA_3D_CANVAS::Redraw()
{
// SwapBuffer requires the window to be shown before calling
......@@ -113,12 +358,89 @@ void EDA_3D_CANVAS::Redraw()
// multiple canvases: If we updated the viewport in the wxSizeEvent
// handler, changing the size of one canvas causes a viewport setting that
// is wrong when next another canvas is repainted.
const wxSize ClientSize = GetClientSize();
wxSize size = GetClientSize();
InitGL();
if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) && g_Parm_3D_Visu.IsRealisticMode() && g_Parm_3D_Visu.HightQualityMode() )
{
GenerateFakeShadowsTextures ();
}
// *MUST* be called *after* SetCurrent( ):
glViewport( 0, 0, ClientSize.x, ClientSize.y );
glViewport( 0, 0, size.x, size.y );
InitGL();
// clear color and depth buffers
glClearColor( 0.95, 0.95, 1.0, 1.0 );
glClearStencil( 0 );
glClearDepth( 1.0 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
// Draw background
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glDisable( GL_LIGHTING );
glDisable( GL_COLOR_MATERIAL );
glDisable( GL_DEPTH_TEST );
glDisable( GL_TEXTURE_2D );
glBegin( GL_QUADS );
glColor4f( 0.95, 0.95, 1.0, 1.0 );
glVertex2f( -1.0, 0.85 );
glColor4f( g_Parm_3D_Visu.m_BgColor.m_Red,
g_Parm_3D_Visu.m_BgColor.m_Green,
g_Parm_3D_Visu.m_BgColor.m_Blue, 1.0 );
glVertex2f( -1.0,-1.0 );
glVertex2f( 1.0,-1.0 );
glColor4f( 0.95, 0.95, 1.0, 1.0 );
glVertex2f( 1.0, 0.85 );
glEnd();
glEnable( GL_DEPTH_TEST );
// set viewing projection
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
#define MAX_VIEW_ANGLE 160.0 / 45.0
if( g_Parm_3D_Visu.m_Zoom > MAX_VIEW_ANGLE )
g_Parm_3D_Visu.m_Zoom = MAX_VIEW_ANGLE;
if( Parent()->ModeIsOrtho() )
{
// OrthoReductionFactor is chosen to provide roughly the same size as
// Perspective View
const double orthoReductionFactor = 400 / g_Parm_3D_Visu.m_Zoom;
// Initialize Projection Matrix for Ortographic View
glOrtho( -size.x / orthoReductionFactor, size.x / orthoReductionFactor,
-size.y / orthoReductionFactor, size.y / orthoReductionFactor, 1, 100 );
}
else
{
// Ratio width / height of the window display
double ratio_HV = (double) size.x / size.y;
// Initialize Projection Matrix for Perspective View
gluPerspective( 45.0 * g_Parm_3D_Visu.m_Zoom, ratio_HV, 1, 100 );
}
// position viewer
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0.0F, 0.0F, -( m_ZBottom + m_ZTop) / 2 );
// Setup light sources:
SetLights();
CheckGLError( __FILE__, __LINE__ );
glMatrixMode( GL_MODELVIEW ); // position viewer
// transformations
......@@ -134,6 +456,7 @@ void EDA_3D_CANVAS::Redraw()
glRotatef( g_Parm_3D_Visu.m_Rot[1], 0.0, 1.0, 0.0 );
glRotatef( g_Parm_3D_Visu.m_Rot[2], 0.0, 0.0, 1.0 );
if( ! m_glLists[GL_ID_BOARD] || ! m_glLists[GL_ID_TECH_LAYERS] )
CreateDrawGL_List();
......@@ -147,8 +470,28 @@ void EDA_3D_CANVAS::Redraw()
// draw all objects in lists
// transparent objects should be drawn after opaque objects
glCallList( m_glLists[GL_ID_BOARD] );
glCallList( m_glLists[GL_ID_TECH_LAYERS] );
if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) )
{
if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] )
CreateDrawGL_List();
}
glDisable( GL_TEXTURE_2D );
glEnable( GL_COLOR_MATERIAL );
SetOpenGlDefaultMaterial();
glColor4f( 1.0, 1.0, 1.0, 1.0 );
if( m_glLists[GL_ID_BOARD] )
{
glCallList( m_glLists[GL_ID_BOARD] );
}
if( m_glLists[GL_ID_TECH_LAYERS] )
{
glCallList( m_glLists[GL_ID_TECH_LAYERS] );
}
if( g_Parm_3D_Visu.GetFlag( FL_COMMENTS ) || g_Parm_3D_Visu.GetFlag( FL_COMMENTS ) )
{
......@@ -158,12 +501,56 @@ void EDA_3D_CANVAS::Redraw()
glCallList( m_glLists[GL_ID_AUX_LAYERS] );
}
// Draw Component Shadow
if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) && g_Parm_3D_Visu.IsRealisticMode() && g_Parm_3D_Visu.HightQualityMode() )
{
glEnable( GL_CULL_FACE );
glDisable( GL_DEPTH_TEST );
glEnable( GL_COLOR_MATERIAL ) ;
SetOpenGlDefaultMaterial();
glColor4f( 1.0, 1.0, 1.0, 1.0 );
glEnable( GL_TEXTURE_2D );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
if( m_glLists[GL_ID_SHADOW_FRONT] )
{
glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_front );
glCallList( m_glLists[GL_ID_SHADOW_FRONT] );
}
if( m_glLists[GL_ID_SHADOW_BACK] )
{
glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_back );
glCallList( m_glLists[GL_ID_SHADOW_BACK] );
}
glColor4f( 1.0, 1.0, 1.0, 1.0 );
glEnable( GL_DEPTH_TEST );
glDisable( GL_TEXTURE_2D );
glDisable( GL_CULL_FACE );
}
glEnable(GL_COLOR_MATERIAL);
SetOpenGlDefaultMaterial();
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glColor4f( 1.0, 1.0, 1.0, 1.0 );
// Draw Solid Shapes
if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) )
{
if( ! m_glLists[GL_ID_3DSHAPES_SOLID] )
if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] )
CreateDrawGL_List();
glCallList( m_glLists[GL_ID_3DSHAPES_SOLID] );
glCallList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] );
}
// Grid uses transparency: draw it after all objects
......@@ -173,16 +560,31 @@ void EDA_3D_CANVAS::Redraw()
// This list must be drawn last, because it contains the
// transparent gl objects, which should be drawn after all
// non transparent objects
if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) && m_glLists[GL_ID_3DSHAPES_TRANSP] )
glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP] );
if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) && m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] )
glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] );
// Draw Board Shadow
if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) && g_Parm_3D_Visu.IsRealisticMode() && g_Parm_3D_Visu.HightQualityMode() )
{
if( m_glLists[GL_ID_SHADOW_BOARD] )
{
glEnable( GL_CULL_FACE );
glDisable( GL_COLOR_MATERIAL );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_board );
glCallList( m_glLists[GL_ID_SHADOW_BOARD] );
glDisable( GL_CULL_FACE );
}
}
SwapBuffers();
}
// Helper function: initialize the copper color to draw the board
// in realistic mode.
static inline void SetGLCopperColor()
void EDA_3D_CANVAS::SetGLCopperColor()
{
glDisable( GL_TEXTURE_2D );
// Generates a golden yellow color, near board "copper" color
const double lum = 0.7/255.0;
glColor4f( 255.0*lum, 223.0*lum, 0.0*lum, 1.0 );
......@@ -190,7 +592,7 @@ static inline void SetGLCopperColor()
// Helper function: initialize the color to draw the epoxy
// body board in realistic mode.
static inline void SetGLEpoxyColor( double aTransparency = 1.0 )
void EDA_3D_CANVAS::SetGLEpoxyColor( double aTransparency )
{
// Generates an epoxy color, near board color
const double lum = 0.2/255.0;
......@@ -208,8 +610,10 @@ static inline void SetGLSolderMaskColor( double aTransparency = 1.0 )
// Helper function: initialize the color to draw the non copper layers
// in realistic mode and normal mode.
static inline void SetGLTechLayersColor( LAYER_NUM aLayer )
void EDA_3D_CANVAS::SetGLTechLayersColor( LAYER_NUM aLayer )
{
EDA_COLOR_T color;
if( g_Parm_3D_Visu.IsRealisticMode() )
{
switch( aLayer )
......@@ -222,28 +626,112 @@ static inline void SetGLTechLayersColor( LAYER_NUM aLayer )
case B_SilkS:
case F_SilkS:
SetGLColor( LIGHTGRAY, 0.9 );
if( g_Parm_3D_Visu.HightQualityMode() )
{
SetGLTexture( m_text_silk, 50.0f );
}
break;
case B_Mask:
case F_Mask:
SetGLSolderMaskColor( 0.7 );
if( g_Parm_3D_Visu.HightQualityMode() )
{
SetGLTexture( m_text_pcb, 35.0f );
}
break;
default:
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( aLayer );
color = g_ColorsSettings.GetLayerColor( aLayer );
SetGLColor( color, 0.7 );
break;
}
}
else
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( aLayer );
color = g_ColorsSettings.GetLayerColor( aLayer );
SetGLColor( color, 0.7 );
}
}
void EDA_3D_CANVAS::BuildBoard3DView()
void EDA_3D_CANVAS::BuildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList )
{
// Use similar calculation as Grid limits, in 3D units
wxSize brd_size = g_Parm_3D_Visu.m_BoardSize;
wxPoint brd_center_pos = g_Parm_3D_Visu.m_BoardPos;
float xsize = brd_size.x;
float ysize = brd_size.y;
float scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
float xmin = (brd_center_pos.x - xsize / 2.0) * scale;
float xmax = (brd_center_pos.x + xsize / 2.0) * scale;
float ymin = (brd_center_pos.y - ysize / 2.0) * scale;
float ymax = (brd_center_pos.y + ysize / 2.0) * scale;
float zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( F_Paste );
zpos *= g_Parm_3D_Visu.m_BiuTo3Dunits;
// Shadow FRONT
glNewList( aFrontList, GL_COMPILE );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );
glBegin (GL_QUADS);
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
glEnd();
glEndList();
// Shadow BACK
zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( B_Paste );
zpos *= g_Parm_3D_Visu.m_BiuTo3Dunits;
glNewList( aBacklist, GL_COMPILE );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( B_Paste ) );
glBegin (GL_QUADS);
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
glEnd();
glEndList();
// Shadow BOARD
xsize = brd_size.x * SHADOW_BOARD_SCALE;
ysize = brd_size.y * SHADOW_BOARD_SCALE;
scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
xmin = (brd_center_pos.x - xsize / 2.0) * scale;
xmax = (brd_center_pos.x + xsize / 2.0) * scale;
ymin = (brd_center_pos.y - ysize / 2.0) * scale;
ymax = (brd_center_pos.y + ysize / 2.0) * scale;
glNewList( aBoardList, GL_COMPILE );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );
glBegin (GL_QUADS);
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, zpos * 30.0);
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, zpos * 30.0);
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, zpos * 30.0);
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, zpos * 30.0);
glEnd();
glEndList();
}
void EDA_3D_CANVAS::BuildBoard3DView(GLuint aBoardList, GLuint aBodyOnlyList)
{
BOARD* pcb = GetBoard();
......@@ -298,6 +786,8 @@ void EDA_3D_CANVAS::BuildBoard3DView()
LAYER_ID cu_seq[MAX_CU_LAYERS]; // preferred sequence, could have called CuStack()
// but I assume that's backwards
glNewList( aBoardList, GL_COMPILE );
for( unsigned i=0; i<DIM(cu_seq); ++i )
cu_seq[i] = ToLAYER_ID( B_Cu - i );
......@@ -438,7 +928,9 @@ void EDA_3D_CANVAS::BuildBoard3DView()
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
if( realistic_mode )
{
SetGLCopperColor();
}
else
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
......@@ -457,75 +949,98 @@ void EDA_3D_CANVAS::BuildBoard3DView()
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos,
thickness,
g_Parm_3D_Visu.m_BiuTo3Dunits );
throughHolesListBuilt = true;
}
// Draw vias holes (vertical cylinders)
for( const TRACK* track = pcb->m_Track; track; track = track->Next() )
if ( !g_Parm_3D_Visu.GetFlag( FL_SHOW_BOARD_BODY ) )
{
const VIA *via = dynamic_cast<const VIA*>(track);
SetGLCopperColor();
if( via )
Draw3DViaHole( via );
}
// Draw vias holes (vertical cylinders)
for( const TRACK* track = pcb->m_Track; track; track = track->Next() )
{
const VIA *via = dynamic_cast<const VIA*>(track);
// Draw pads holes (vertical cylinders)
for( const MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
Draw3DPadHole( pad );
if( via )
Draw3DViaHole( via );
}
// Draw pads holes (vertical cylinders)
for( const MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
Draw3DPadHole( pad );
}
}
// Draw board substrate:
if( bufferPcbOutlines.GetCornersCount() &&
( realistic_mode || g_Parm_3D_Visu.GetFlag( FL_SHOW_BOARD_BODY ) ) )
if( g_Parm_3D_Visu.IsRealisticMode() )
{
int copper_thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
// a small offset between substrate and external copper layer to avoid artifacts
// when drawing copper items on board
int epsilon = Millimeter2iu( 0.01 );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( B_Cu );
int board_thickness = g_Parm_3D_Visu.GetLayerZcoordBIU( F_Cu )
- g_Parm_3D_Visu.GetLayerZcoordBIU( B_Cu );
// items on copper layers and having a thickness = copper_thickness
// are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
// therefore substrate position is copper_thickness/2 to
// substrate_height - copper_thickness/2
zpos += (copper_thickness + epsilon) / 2;
board_thickness -= copper_thickness + epsilon;
if( realistic_mode )
SetGLEpoxyColor();
else
SetGLEpoxyColor( 0.9 );
if( g_Parm_3D_Visu.HightQualityMode() )
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
SetGLColor( color, 0.7 );
SetGLTexture( m_text_pcb, 35.0f );
}
}
else
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
SetGLColor( color, 0.7 );
}
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Cu ) );
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polysetHoles;
float copper_thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
// Add polygons, without holes
bufferPcbOutlines.ExportTo( currLayerPolyset );
// a small offset between substrate and external copper layer to avoid artifacts
// when drawing copper items on board
float epsilon = Millimeter2iu( 0.01 );
float zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( B_Cu );
float board_thickness = g_Parm_3D_Visu.GetLayerZcoordBIU( F_Cu )
- g_Parm_3D_Visu.GetLayerZcoordBIU( B_Cu );
// Build holes list
allLayerHoles.ExportTo( polysetHoles );
// items on copper layers and having a thickness = copper_thickness
// are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
// therefore substrate position is copper_thickness/2 to
// substrate_height - copper_thickness/2
zpos += (copper_thickness + epsilon) / 2.0;
board_thickness -= copper_thickness + epsilon;
// remove holes
currLayerPolyset -= polysetHoles;
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Cu ) );
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polysetHoles;
// Add polygons, without holes
bufferPcbOutlines.ExportTo( currLayerPolyset );
bufferPcbOutlines.RemoveAllContours();
bufferPcbOutlines.ImportFrom( currLayerPolyset );
// Build holes list
allLayerHoles.ExportTo( polysetHoles );
// remove holes
currLayerPolyset -= polysetHoles;
bufferPcbOutlines.RemoveAllContours();
bufferPcbOutlines.ImportFrom( currLayerPolyset );
// Draw board substrate:
if( bufferPcbOutlines.GetCornersCount() &&
( g_Parm_3D_Visu.GetFlag( FL_SHOW_BOARD_BODY ) ) )
{
// for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
// sides
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness/2,
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness/2.0,
board_thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
glEndList();
glNewList( aBodyOnlyList, GL_COMPILE );
if( bufferPcbOutlines.GetCornersCount() )
{
glColor4f( 1.0, 1.0, 1.0, 1.0 );
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness/2.0,
board_thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
glEndList();
}
......@@ -879,9 +1394,9 @@ void EDA_3D_CANVAS::CreateDrawGL_List()
if( ! m_glLists[GL_ID_BOARD] )
{
m_glLists[GL_ID_BOARD] = glGenLists( 1 );
glNewList( m_glLists[GL_ID_BOARD], GL_COMPILE );
BuildBoard3DView();
glEndList();
m_glLists[GL_ID_BODY] = glGenLists( 1 );
BuildBoard3DView(m_glLists[GL_ID_BOARD], m_glLists[GL_ID_BODY]);
}
if( ! m_glLists[GL_ID_TECH_LAYERS] )
......@@ -902,22 +1417,27 @@ void EDA_3D_CANVAS::CreateDrawGL_List()
// draw modules 3D shapes
if( ! m_glLists[GL_ID_3DSHAPES_SOLID] && g_Parm_3D_Visu.GetFlag( FL_MODULE ) )
if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] && g_Parm_3D_Visu.GetFlag( FL_MODULE ) )
{
m_glLists[GL_ID_3DSHAPES_SOLID] = glGenLists( 1 );
m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] = glGenLists( 1 );
// GL_ID_3DSHAPES_TRANSP is an auxiliary list for 3D shapes;
// GL_ID_3DSHAPES_TRANSP_FRONT is an auxiliary list for 3D shapes;
// Ensure it is cleared before rebuilding it
if( m_glLists[GL_ID_3DSHAPES_TRANSP] )
glDeleteLists( m_glLists[GL_ID_3DSHAPES_TRANSP], 1 );
if( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] )
glDeleteLists( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT], 1 );
m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] = glGenLists( 1 );
BuildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT],
m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT], false );
m_glLists[GL_ID_3DSHAPES_TRANSP] = glGenLists( 1 );
BuildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID],
m_glLists[GL_ID_3DSHAPES_TRANSP] );
m_glLists[GL_ID_SHADOW_FRONT] = glGenLists( 1 );
m_glLists[GL_ID_SHADOW_BACK] = glGenLists( 1 );
m_glLists[GL_ID_SHADOW_BOARD] = glGenLists( 1 );
BuildShadowList(m_glLists[GL_ID_SHADOW_FRONT], m_glLists[GL_ID_SHADOW_BACK], m_glLists[GL_ID_SHADOW_BOARD]);
}
// Test for errors
CheckGLError();
CheckGLError( __FILE__, __LINE__ );
#ifdef PRINT_CALCULATION_TIME
unsigned endtime = GetRunningMicroSecs();
......@@ -929,7 +1449,7 @@ void EDA_3D_CANVAS::CreateDrawGL_List()
void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList,
GLuint aTransparentList)
GLuint aTransparentList, bool aSideToLoad)
{
// aOpaqueList is the gl list for non transparent items
// aTransparentList is the gl list for non transparent items,
......@@ -941,7 +1461,7 @@ void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList,
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
module->ReadAndInsert3DComponentShape( this, !loadTransparentObjects,
loadTransparentObjects );
loadTransparentObjects, aSideToLoad );
glEndList();
......@@ -950,7 +1470,7 @@ void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList,
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
module->ReadAndInsert3DComponentShape( this, !loadTransparentObjects,
loadTransparentObjects );
loadTransparentObjects, aSideToLoad );
glEndList();
}
......@@ -1144,7 +1664,8 @@ void EDA_3D_CANVAS::Draw3DViaHole( const VIA* aVia )
void MODULE::ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas,
bool aAllowNonTransparentObjects,
bool aAllowTransparentObjects )
bool aAllowTransparentObjects,
bool aSideToLoad )
{
// Read from disk and draws the footprint 3D shapes if exists
......
......@@ -33,10 +33,7 @@
#include <3d_viewer.h>
#include <info3d_visu.h>
#include <3d_draw_basic_functions.h>
// Imported function:
extern void TransfertToGLlist( std::vector<S3D_VERTEX>& aVertices, double aBiuTo3DUnits );
extern void CheckGLError();
#include <modelparsers.h>
// Number of segments to approximate a circle by segments
#define SEGM_PER_CIRCLE 16
......@@ -62,6 +59,7 @@ static inline void SetNormalZneg()
glNormal3f( 0.0, 0.0, -1.0 );
}
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
/* Draw3D_VerticalPolygonalCylinder is a helper function.
*
......@@ -132,6 +130,15 @@ void SetGLColor( EDA_COLOR_T color, double alpha )
glColor4f( red, green, blue, alpha );
}
static float m_texture_scale;
void SetGLTexture( GLuint text_id, float scale )
{
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, text_id );
m_texture_scale = scale;
}
/* draw all solid polygons found in aPolysList
* aZpos = z position in board internal units
......@@ -152,9 +159,9 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tessCPolyPt2Vertex );
GLdouble v_data[3];
double zpos = ( aZpos + (aThickness / 2) ) * aBiuTo3DUnits;
double zpos = ( aZpos + (aThickness / 2.0) ) * aBiuTo3DUnits;
g_Parm_3D_Visu.m_CurrentZpos = zpos;
v_data[2] = aZpos + (aThickness / 2);
v_data[2] = aZpos + (aThickness / 2.0);
// Set normal to toward positive Z axis, for a solid object only (to draw the top side)
if( aThickness )
......@@ -198,7 +205,7 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
break;
// Prepare the bottom side of solid areas
zpos = ( aZpos - (aThickness / 2) ) * aBiuTo3DUnits;
zpos = ( aZpos - (aThickness / 2.0) ) * aBiuTo3DUnits;
g_Parm_3D_Visu.m_CurrentZpos = zpos;
v_data[2] = zpos;
// Now;, set normal to toward negative Z axis, for the solid object bottom side
......@@ -211,7 +218,7 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
return;
// Build the 3D data : vertical side
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2), false, aBiuTo3DUnits );
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2.0), false, aBiuTo3DUnits );
}
......@@ -400,6 +407,12 @@ void CALLBACK tessCPolyPt2Vertex( const GLvoid* data )
// cast back to double type
const CPolyPt* ptr = (const CPolyPt*) data;
if( g_Parm_3D_Visu.IsRealisticMode() && g_Parm_3D_Visu.HightQualityMode() )
{
glTexCoord2f( ptr->x* g_Parm_3D_Visu.m_BiuTo3Dunits * m_texture_scale,
-ptr->y * g_Parm_3D_Visu.m_BiuTo3Dunits * m_texture_scale);
}
glVertex3d( ptr->x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-ptr->y * g_Parm_3D_Visu.m_BiuTo3Dunits,
g_Parm_3D_Visu.m_CurrentZpos );
......
......@@ -126,4 +126,12 @@ void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
void SetGLColor( EDA_COLOR_T aColor, double aTransparency = 1.0 );
/**
* Set a texture id and a scale to apply when rendering the polygons
* @param text_id = texture ID created by glGenTextures
* @param scale = scale to apply to texture coords
*/
void SetGLTexture( GLuint text_id, float scale );
#endif // _3D_DRAW_BASIC_FUNCTIONS_H_
......@@ -107,7 +107,8 @@ EDA_3D_FRAME::EDA_3D_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent,
ReCreateMainToolbar();
// Make a EDA_3D_CANVAS
int attrs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0 };
int attrs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16,
WX_GL_STENCIL_SIZE, 1, 0 };
m_canvas = new EDA_3D_CANVAS( this, attrs );
m_auimgr.SetManagedWindow( this );
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_class.cpp
*/
#include <fctsys.h>
#include <3d_struct.h>
#include <3d_material.h>
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) :
EDA_ITEM( father, NOT_USED )
{
m_Name = name;
m_AmbientColor.clear();
m_DiffuseColor.clear();
m_EmissiveColor.clear();
m_SpecularColor.clear();
m_Shininess.clear();
m_Transparency.clear();
}
void SetOpenGlDefaultMaterial()
{
glm::vec4 ambient( 0.2, 0.2, 0.2, 1.0 );
glm::vec4 specular( 0.1, 0.1, 0.1, 1.0 );
glm::vec4 emissive( 0.1, 0.1, 0.1, 1.0 );
GLint shininess_value = 100;
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
//glColor4f( 1.0, 1.0, 1.0, 1.0 );
glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
}
void S3D_MATERIAL::SetOpenGLMaterial( unsigned int materialIndex )
{
S3D_MASTER * s3dParent = (S3D_MASTER *) GetParent();
if( ! s3dParent->IsOpenGlAllowed() )
return;
float transparency_value = 0.0f;
if( m_Transparency.size() > materialIndex )
{
transparency_value = m_Transparency[materialIndex];
s3dParent->SetLastTransparency( transparency_value );
}
if( m_DiffuseColor.size() > materialIndex )
{
glm::vec3 color = m_DiffuseColor[materialIndex];
if( m_AmbientColor.size() == 0 )
{
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
}
glColor4f( color.x, color.y, color.z, 1.0 - transparency_value );
}
if( m_Shininess.size() > materialIndex )
{
glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, m_Shininess[materialIndex] );
}
// emissive
if( m_EmissiveColor.size() > materialIndex )
{
glm::vec4 emissive;
emissive[0] = m_EmissiveColor[materialIndex].x;
emissive[1] = m_EmissiveColor[materialIndex].y;
emissive[2] = m_EmissiveColor[materialIndex].z;
emissive[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
}
// specular
if( m_SpecularColor.size() > materialIndex )
{
glm::vec4 specular;
specular[0] = m_SpecularColor[materialIndex].x;
specular[1] = m_SpecularColor[materialIndex].y;
specular[2] = m_SpecularColor[materialIndex].z;
specular[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
}
// ambient
if( m_AmbientColor.size() > materialIndex )
{
glm::vec4 ambient;
ambient[0] = m_AmbientColor[materialIndex].x;
ambient[1] = m_AmbientColor[materialIndex].y;
ambient[2] = m_AmbientColor[materialIndex].z;
ambient[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
}
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_material.h
*/
#ifndef STRUCT_3D_MATERIAL_H
#define STRUCT_3D_MATERIAL_H
#include <common.h>
#include <base_struct.h>
#include <gal/opengl/glm/glm.hpp>
class S3D_MASTER;
class S3D_MATERIAL : public EDA_ITEM /* openGL "material" data*/
{
public:
wxString m_Name;
// Material list
std::vector< glm::vec3 > m_AmbientColor;
std::vector< glm::vec3 > m_DiffuseColor;
std::vector< glm::vec3 > m_EmissiveColor;
std::vector< glm::vec3 > m_SpecularColor;
std::vector< float > m_Shininess;
std::vector< float > m_Transparency;
public:
S3D_MATERIAL( S3D_MASTER* father, const wxString& name );
S3D_MATERIAL* Next() const { return (S3D_MATERIAL*) Pnext; }
S3D_MATERIAL* Back() const { return (S3D_MATERIAL*) Pback; }
void SetOpenGLMaterial(unsigned int materialIndex);
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override
#endif
};
void SetOpenGlDefaultMaterial();
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_mesh_model.cpp
* @brief
*/
#include <3d_mesh_model.h>
#include <boost/geometry/algorithms/area.hpp>
S3D_MESH::S3D_MESH()
{
isPerFaceNormalsComputed = false;
isPointNormalizedComputed = false;
isPerPointNormalsComputed = false;
m_Materials = NULL;
childs.clear();
m_translation = glm::vec3( 0.0f, 0.0f, 0.0f );
m_rotation = glm::vec4( 0.0f, 0.0f, 0.0f, 0.0f );
m_scale = glm::vec3( 1.0f, 1.0f, 1.0f );
m_scaleOrientation = glm::vec4( 0.0f, 0.0f, 1.0f, 0.0f ); // not used
m_center = glm::vec3( 0.0f, 0.0f, 0.0f ); // not used
}
S3D_MESH::~S3D_MESH()
{
for( unsigned int idx = 0; idx < childs.size(); idx++ )
{
delete childs[idx];
}
}
void S3D_MESH::openGL_RenderAllChilds()
{
glPushMatrix();
glTranslatef( m_translation.x, m_translation.y, m_translation.z );
glRotatef( m_rotation[3], m_rotation[0], m_rotation[1], m_rotation[2] );
glScalef( m_scale.x, m_scale.y, m_scale.z );
SetOpenGlDefaultMaterial();
// Render your self
openGL_Render();
// Render childs
for( unsigned int idx = 0; idx < childs.size(); idx++ )
{
childs[idx]->openGL_Render();
}
SetOpenGlDefaultMaterial();
glPopMatrix();
}
void S3D_MESH::openGL_Render()
{
//DBG( printf( " render\n" ) );
if( m_Materials )
{
m_Materials->SetOpenGLMaterial( 0 );
}
if( m_CoordIndex.size() == 0)
{
return;
}
glPushMatrix();
glTranslatef( m_translation.x, m_translation.y, m_translation.z );
glRotatef( m_rotation[3], m_rotation[0], m_rotation[1], m_rotation[2] );
glScalef( m_scale.x, m_scale.y, m_scale.z );
std::vector< glm::vec3 > normals;
calcPointNormalized();
calcPerFaceNormals();
if( m_PerVertexNormalsNormalized.size() == 0 )
{
if( g_Parm_3D_Visu.IsRealisticMode() && g_Parm_3D_Visu.HightQualityMode() )
{
calcPerPointNormals();
}
}
for( unsigned int idx = 0; idx < m_CoordIndex.size(); idx++ )
{
if( m_MaterialIndex.size() > 1 )
{
if( m_Materials )
{
m_Materials->SetOpenGLMaterial(m_MaterialIndex[idx]);
}
}
switch( m_CoordIndex[idx].size() )
{
case 3: glBegin( GL_TRIANGLES );break;
case 4: glBegin( GL_QUADS ); break;
default: glBegin( GL_POLYGON ); break;
}
if( m_PerVertexNormalsNormalized.size() > 0 )
{
for(unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ )
{
glm::vec3 normal = m_PerVertexNormalsNormalized[m_CoordIndex[idx][ii]];
glNormal3fv( &normal.x );
glm::vec3 point = m_Point[m_CoordIndex[idx][ii]];
glVertex3fv( &point.x );
}
} else if( g_Parm_3D_Visu.IsRealisticMode() && g_Parm_3D_Visu.HightQualityMode() )
{
std::vector< glm::vec3 > normals_list;
normals_list = m_PerFaceVertexNormals[idx];
for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ )
{
glm::vec3 normal = normals_list[ii];
glNormal3fv( &normal.x );
glm::vec3 point = m_Point[m_CoordIndex[idx][ii]];
glVertex3fv( &point.x );
}
} else
{
// Flat
glm::vec3 normal = m_PerFaceNormalsNormalized[idx];
for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ )
{
glNormal3fv( &normal.x );
glm::vec3 point = m_Point[m_CoordIndex[idx][ii]];
glVertex3fv( &point.x );
}
}
glEnd();
}
glPopMatrix();
}
void S3D_MESH::calcPointNormalized ()
{
if( isPointNormalizedComputed == true )
{
return;
}
isPointNormalizedComputed = true;
if( m_PerVertexNormalsNormalized.size() > 0 )
{
return;
}
m_PointNormalized.clear();
float biggerPoint = 0.0f;
for( unsigned int i = 0; i< m_Point.size(); i++ )
{
if( fabs( m_Point[i].x ) > biggerPoint) biggerPoint = fabs( m_Point[i].x );
if( fabs( m_Point[i].y ) > biggerPoint) biggerPoint = fabs( m_Point[i].y );
if( fabs( m_Point[i].z ) > biggerPoint) biggerPoint = fabs( m_Point[i].z );
}
biggerPoint = 1.0 / biggerPoint;
for( unsigned int i= 0; i< m_Point.size(); i++ )
{
glm::vec3 p;
p = m_Point[i] * biggerPoint;
m_PointNormalized.push_back( p );
}
}
bool IsClockwise(glm::vec3 v0, glm::vec3 v1, glm::vec3 v2)
{
double sum = 0.0;
sum += (v1.x - v0.x) * (v1.y + v0.y);
sum += (v2.x - v1.x) * (v2.y + v1.y);
sum += (v0.x - v2.x) * (v0.y + v2.y);
return sum > FLT_EPSILON;
}
void S3D_MESH::calcPerFaceNormals ()
{
if( isPerFaceNormalsComputed == true )
{
return;
}
isPerFaceNormalsComputed = true;
if( m_PerVertexNormalsNormalized.size() > 0 )
{
return;
}
bool haveAlreadyNormals_from_model_file = false;
if( m_PerFaceNormalsNormalized.size() > 0 )
{
haveAlreadyNormals_from_model_file = true;
}
m_PerFaceNormalsRaw.clear();
m_PerFaceSquaredArea.clear();
for( unsigned int idx = 0; idx < m_CoordIndex.size(); idx++ )
{
// User normalized and multiply to get better resolution
glm::vec3 v0 = m_PointNormalized[m_CoordIndex[idx][0]];
glm::vec3 v1 = m_PointNormalized[m_CoordIndex[idx][1]];
glm::vec3 v2 = m_PointNormalized[m_CoordIndex[idx][m_CoordIndex[idx].size() - 1]];
/*
// !TODO: improove and check what is best to calc the normal (check what have more resolution)
glm::vec3 v0 = m_Point[m_CoordIndex[idx][0]];
glm::vec3 v1 = m_Point[m_CoordIndex[idx][1]];
glm::vec3 v2 = m_Point[m_CoordIndex[idx][m_CoordIndex[idx].size() - 1]];
*/
glm::vec3 cross_prod;
/*
// This is not working as good as it is expected :/
if( IsClockwise( v0, v1, v2 ) )
{
// CW
cross_prod = glm::cross( v1 - v2, v0 - v2 );
} else
{*/
// CCW
cross_prod = glm::cross( v1 - v0, v2 - v0 );
//}
float area = glm::dot( cross_prod, cross_prod );
if( cross_prod[2] < 0.0 )
{
area = -area;
}
if (area < FLT_EPSILON)
{
area = FLT_EPSILON * 2.0f;
}
m_PerFaceSquaredArea.push_back( area );
m_PerFaceNormalsRaw.push_back( cross_prod );
if( haveAlreadyNormals_from_model_file == false )
{
// normalize vertex normal
float l = glm::length( cross_prod );
if( l > FLT_EPSILON ) // avoid division by zero
{
cross_prod = cross_prod / l;
}
else
{
// Cannot calc normal
if( (cross_prod.x > cross_prod.y) && (cross_prod.x > cross_prod.z))
{
cross_prod.x = 1.0; cross_prod.y = 0.0; cross_prod.z = 0.0;
} else if( (cross_prod.y > cross_prod.x) && (cross_prod.y > cross_prod.z))
{
cross_prod.x = 0.0; cross_prod.y = 1.0; cross_prod.z = 0.0;
} else
{
cross_prod.x = 0.0; cross_prod.y = 1.0; cross_prod.z = 0.0;
}
}
m_PerFaceNormalsNormalized.push_back( cross_prod );
}
}
}
// http://www.bytehazard.com/code/vertnorm.html
// http://www.emeyex.com/site/tuts/VertexNormals.pdf
void S3D_MESH::calcPerPointNormals ()
{
if( isPerPointNormalsComputed == true )
{
return;
}
isPerPointNormalsComputed = true;
if( m_PerVertexNormalsNormalized.size() > 0 )
{
return;
}
m_PerFaceVertexNormals.clear();
// for each face A in mesh
for( unsigned int each_face_A_idx = 0; each_face_A_idx < m_CoordIndex.size(); each_face_A_idx++ )
{
// n = face A facet normal
std::vector< glm::vec3 > face_A_normals;
face_A_normals.clear();
face_A_normals.resize(m_CoordIndex[each_face_A_idx].size());
// loop through all 3 vertices
// for each vert in face A
for( unsigned int each_vert_A_idx = 0; each_vert_A_idx < m_CoordIndex[each_face_A_idx].size(); each_vert_A_idx++ )
{
face_A_normals[each_vert_A_idx] = m_PerFaceNormalsRaw[each_face_A_idx] * (m_PerFaceSquaredArea[each_face_A_idx]);
// for each face A in mesh
for( unsigned int each_face_B_idx = 0; each_face_B_idx < m_CoordIndex.size(); each_face_B_idx++ )
{
//if A != B { // ignore self
if ( each_face_A_idx != each_face_B_idx)
{
if( (m_CoordIndex[each_face_B_idx][0] == (int)(m_CoordIndex[each_face_A_idx][each_vert_A_idx])) ||
(m_CoordIndex[each_face_B_idx][1] == (int)(m_CoordIndex[each_face_A_idx][each_vert_A_idx])) ||
(m_CoordIndex[each_face_B_idx][2] == (int)(m_CoordIndex[each_face_A_idx][each_vert_A_idx])) )
{
glm::vec3 vector_face_A = m_PerFaceNormalsNormalized[each_face_A_idx];
glm::vec3 vector_face_B = m_PerFaceNormalsNormalized[each_face_B_idx];
float dot_prod = glm::dot(vector_face_A, vector_face_B);
if( dot_prod > 0.05f )
{
face_A_normals[each_vert_A_idx] += m_PerFaceNormalsRaw[each_face_B_idx] * (m_PerFaceSquaredArea[each_face_B_idx] * dot_prod);
}
}
}
}
// normalize vertex normal
float l = glm::length( face_A_normals[each_vert_A_idx] );
if( l > FLT_EPSILON ) // avoid division by zero
{
face_A_normals[each_vert_A_idx] /= l;
}
}
m_PerFaceVertexNormals.push_back( face_A_normals );
}
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_mesh_model.h
* @brief
*/
#ifndef __3D_MESH_MODEL_H__
#define __3D_MESH_MODEL_H__
#include <fctsys.h>
#include <common.h>
#include <macros.h>
#include <base_struct.h>
#include <gal/opengl/glm/glm.hpp>
#include <vector>
#include <kicad_string.h>
#include <info3d_visu.h>
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
#include <wx/glcanvas.h>
class S3D_MESH;
class S3D_MESH
{
public:
S3D_MESH();
~S3D_MESH();
void openGL_Render();
void openGL_RenderAllChilds();
S3D_MATERIAL *m_Materials;
// Point and index list
std::vector< glm::vec3 > m_Point;
std::vector< std::vector<int> > m_CoordIndex;
std::vector< glm::vec3 > m_PerFaceNormalsNormalized;
std::vector< glm::vec3 > m_PerVertexNormalsNormalized;
std::vector< int > m_MaterialIndex;
glm::vec3 m_translation;
glm::vec4 m_rotation;
glm::vec3 m_scale;
glm::vec4 m_scaleOrientation; // not used
glm::vec3 m_center; // not used
std::vector<S3D_MESH *> childs;
private:
std::vector< glm::vec3 > m_PerFaceNormalsRaw;
std::vector< std::vector< glm::vec3 > > m_PerFaceVertexNormals;
std::vector< glm::vec3 > m_PointNormalized;
std::vector< float > m_PerFaceSquaredArea;
std::vector< std::vector<int> > m_InvalidCoordIndexes; //!TODO: check for invalid CoordIndex in file and remove the index and the same material index
bool isPerFaceNormalsComputed;
void calcPerFaceNormals ();
bool isPointNormalizedComputed;
void calcPointNormalized();
bool isPerPointNormalsComputed;
void calcPerPointNormals();
};
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
......@@ -32,8 +33,9 @@
#include <common.h>
#include <base_struct.h>
#include <3d_material.h>
#include <gal/opengl/glm/glm.hpp>
/* 3D modeling units -> PCB units conversion scale:
* 1 "3D model unit" wings3d = 1 unit = 2.54 mm = 0.1 inch = 100 mils
*/
......@@ -44,48 +46,7 @@ class S3D_MASTER;
class STRUCT_3D_SHAPE;
/* S3D_VERTEX manages a 3D coordinate (3 float numbers: x,y,z coordinates)*/
class S3D_VERTEX
{
public:
double x, y, z;
public:
S3D_VERTEX()
{
x = y = z = 0.0;
}
S3D_VERTEX( double px, double py, double pz)
{
x = px;
y = py;
z = pz;
}
};
class S3D_MATERIAL : public EDA_ITEM /* openGL "material" data*/
{
public:
wxString m_Name;
S3D_VERTEX m_DiffuseColor;
S3D_VERTEX m_EmissiveColor;
S3D_VERTEX m_SpecularColor;
float m_AmbientIntensity;
float m_Transparency;
float m_Shininess;
public:
S3D_MATERIAL( S3D_MASTER* father, const wxString& name );
S3D_MATERIAL* Next() const { return (S3D_MATERIAL*) Pnext; }
S3D_MATERIAL* Back() const { return (S3D_MATERIAL*) Pback; }
void SetMaterial();
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override
#endif
};
#define S3D_VERTEX glm::vec3
/* Master structure for a 3D item description */
......@@ -106,6 +67,14 @@ public:
FILE3D_UNKNOWN
};
// Check defaults in S3D_MASTER
bool m_use_modelfile_diffuseColor;
bool m_use_modelfile_emissiveColor;
bool m_use_modelfile_specularColor;
bool m_use_modelfile_ambientIntensity;
bool m_use_modelfile_transparency;
bool m_use_modelfile_shininess;
private:
wxString m_Shape3DName; /* 3D shape name in 3D library */
FILE3D_TYPE m_ShapeType;
......@@ -114,6 +83,8 @@ private:
bool m_loadTransparentObjects;
bool m_loadNonTransparentObjects;
public:
S3D_MASTER( EDA_ITEM* aParent );
~S3D_MASTER();
......
......@@ -2,6 +2,7 @@ add_definitions(-DPCBNEW)
include_directories(BEFORE ${INC_BEFORE})
include_directories(
textures
../pcbnew
../polygon
${INC_AFTER}
......@@ -16,12 +17,17 @@ set(3D-VIEWER_SRCS
3d_draw.cpp
3d_draw_basic_functions.cpp
3d_frame.cpp
3d_material.cpp
3d_mesh_model.cpp
3d_read_mesh.cpp
3d_toolbar.cpp
info3d_visu.cpp
trackball.cpp
x3dmodelparser.cpp
vrmlmodelparser.cpp
vrml_aux.cpp
vrml_v1_modelparser.cpp
vrml_v2_modelparser.cpp
x3dmodelparser.cpp
)
add_library(3d-viewer STATIC ${3D-VIEWER_SRCS})
......@@ -85,7 +85,7 @@ INFO3D_VISU::~INFO3D_VISU()
*/
void INFO3D_VISU::InitSettings( BOARD* aBoard )
{
EDA_RECT bbbox = aBoard->ComputeBoundingBox( false );
EDA_RECT bbbox = aBoard->ComputeBoundingBox( true );
if( bbbox.GetWidth() == 0 && bbbox.GetHeight() == 0 )
{
......@@ -93,6 +93,7 @@ void INFO3D_VISU::InitSettings( BOARD* aBoard )
bbbox.SetHeight( Millimeter2iu( 100 ) );
}
m_BoardSettings = &aBoard->GetDesignSettings();
m_BoardSize = bbbox.GetSize();
......@@ -199,8 +200,8 @@ void INFO3D_VISU::InitSettings( BOARD* aBoard )
double INFO3D_VISU::GetModulesZcoord3DIU( bool aIsFlipped )
{
if( aIsFlipped )
return m_layerZcoord[B_Cu] - ( m_copperThickness / 2 );
return m_layerZcoord[B_Paste] - ( m_copperThickness / 2 ); //B_Cu NOTE: in order to display modules in top of Paste and near the shadow
else
return m_layerZcoord[F_Cu] + ( m_copperThickness / 2 );
return m_layerZcoord[F_Paste] + ( m_copperThickness / 2 ); //F_Cu
}
......@@ -95,6 +95,9 @@ public:
// to scale 3D units between -1.0 and +1.0
double m_CurrentZpos; // temporary storage of current value of Z position,
// used in some calculation
double zpos_offset;
private:
double m_layerZcoord[LAYER_ID_COUNT]; // Z position of each layer (normalized)
double m_copperThickness; // Copper thickness (normalized)
......
......@@ -32,13 +32,9 @@
#include <map>
#include <vector>
#include <wx/string.h>
#include <3d_mesh_model.h>
class S3D_MASTER;
class S3D_VERTEX;
extern void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
class S3D_MODEL_PARSER;
class X3D_MODEL_PARSER;
......@@ -118,13 +114,17 @@ public:
static void GetNodeProperties( wxXmlNode* aNode, PROPERTY_MAP& aProps );
/**
* Return string representing x3d file in vrml format
* Return string representing x3d file in vrml2 format
* Function Load must be called before this function, otherwise empty
* data set is returned.
*/
wxString VRML_representation();
wxString VRML2_representation();
private:
wxString m_Filename;
S3D_MESH *m_model;
std::vector<S3D_MESH *> childs;
std::vector< wxString > vrml_materials;
std::vector< wxString > vrml_points;
std::vector< wxString > vrml_coord_indexes;
......@@ -137,57 +137,110 @@ private:
void rotate( S3D_VERTEX& aCoordinate, S3D_VERTEX& aRotAxis, double angle );
};
/**
* class WRL_MODEL_PARSER
* class VRML2_MODEL_PARSER
* Parses
*/
class VRML_MODEL_PARSER: public S3D_MODEL_PARSER
class VRML2_MODEL_PARSER: public S3D_MODEL_PARSER
{
public:
VRML_MODEL_PARSER( S3D_MASTER* aMaster );
~VRML_MODEL_PARSER();
VRML2_MODEL_PARSER( S3D_MASTER* aMaster );
~VRML2_MODEL_PARSER();
void Load( const wxString aFilename );
private:
/**
* Function ReadMaterial
* read the description of a 3D material definition in the form:
* DEF yellow material Material (
* DiffuseColor 1.00000 1.00000 0.00000e 0
* EmissiveColor 0.00000e 0 0.00000e 0 0.00000e 0
* SpecularColor 1.00000 1.00000 1.00000
* AmbientIntensity 1.00000
* Transparency 0.00000e 0
* Shininess 1.00000
*)
* Or type:
* USE yellow material
* Return string representing VRML2 file in vrml2 format
* Function Load must be called before this function, otherwise empty
* data set is returned.
*/
int readMaterial( FILE* file, int* LineNum );
int readChildren( FILE* file, int* LineNum );
int readShape( FILE* file, int* LineNum );
int readAppearance( FILE* file, int* LineNum );
int readGeometry( FILE* file, int* LineNum );
wxString VRML2_representation();
private:
int read_Transform();
int read_DEF();
int read_Shape();
int read_Appearance();
int read_material();
int read_Material();
int read_IndexedFaceSet();
int read_Coordinate();
int read_Normal();
int read_Color();
int read_coordIndex();
int read_colorIndex();
bool m_normalPerVertex;
bool colorPerVertex;
S3D_MESH *m_model;
std::vector<S3D_MESH *> childs;
FILE *m_file;
S3D_MATERIAL *m_Materials;
wxString m_Filename;
};
/**
* class VRML1_MODEL_PARSER
* Parses
*/
class VRML1_MODEL_PARSER: public S3D_MODEL_PARSER
{
public:
VRML1_MODEL_PARSER( S3D_MASTER* aMaster );
~VRML1_MODEL_PARSER();
void Load( const wxString aFilename );
/**
* Function ReadCoordList
* reads 3D coordinate lists like:
* coord Coordinate { point [
* -5.24489 6.57640e-3 -9.42129e-2,
* -5.11821 6.57421e-3 0.542654,
* -3.45868 0.256565 1.32000 ] }
* or:
* normal Normal { vector [
* 0.995171 -6.08102e-6 9.81541e-2,
* 0.923880 -4.09802e-6 0.382683,
* 0.707107 -9.38186e-7 0.707107]
* }
*
* text_buffer contains the first line of this node :
* "coord Coordinate { point ["
* Return string representing VRML2 file in vrml2 format
* Function Load must be called before this function, otherwise empty
* data set is returned.
*/
void readCoordsList( FILE* file, char* text_buffer, std::vector< double >& aList,
int* LineNum );
wxString VRML2_representation();
private:
int read_separator();
int readMaterial();
int readCoordinate3();
int readIndexedFaceSet();
int readMaterial_ambientColor();
int readMaterial_diffuseColor();
int readMaterial_emissiveColor();
int readMaterial_specularColor();
int readMaterial_shininess();
int readMaterial_transparency();
int readCoordinate3_point();
int readIndexedFaceSet_coordIndex();
int readIndexedFaceSet_materialIndex();
bool m_normalPerVertex;
bool colorPerVertex;
S3D_MESH *m_model;
std::vector<S3D_MESH *> childs;
S3D_MATERIAL *m_Materials;
FILE *m_file;
wxString m_Filename;
};
/**
* class VRML_MODEL_PARSER
* Parses
*/
class VRML_MODEL_PARSER: public S3D_MODEL_PARSER
{
public:
VRML_MODEL_PARSER( S3D_MASTER* aMaster );
~VRML_MODEL_PARSER();
void Load( const wxString aFilename );
private:
VRML1_MODEL_PARSER *vrml1_parser;
VRML2_MODEL_PARSER *vrml2_parser;
};
#endif // MODELPARSERS_H
/* GIMP RGBA C-Source image dump (text_pcb.c) */
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[64 * 64 * 4 + 1];
} text_pcb = {
64, 64, 4,
"\357\357\357\377\357\357\357\377\355\355\355\377\362\362\362\377\362\362"
"\362\377\366\366\366\377\366\366\366\377\370\370\370\377\370\370\370\377"
"\363\363\363\377\363\363\363\377\357\357\357\377\360\360\360\377\354\354"
"\354\377\354\354\354\377\351\351\351\377\351\351\351\377\357\357\357\377"
"\357\357\357\377\363\363\363\377\357\357\357\377\366\366\366\377\366\366"
"\366\377\366\366\366\377\366\366\366\377\362\362\362\377\363\363\363\377"
"\355\355\355\377\346\346\346\377\340\340\340\377\335\335\335\377\331\331"
"\331\377\331\331\331\377\335\335\335\377\335\335\335\377\343\343\343\377"
"\351\351\351\377\355\355\355\377\355\355\355\377\362\362\362\377\362\362"
"\362\377\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\360\360\360\377\360\360\360\377\354\354\354\377\351\351\351\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\352\352\352\377"
"\352\352\352\377\357\357\357\377\355\355\355\377\360\360\360\377\360\360"
"\360\377\355\355\355\377\355\355\355\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\355\355\355\377\357\357\357\377\355\355\355\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\357\357\357\377\357\357"
"\357\377\354\354\354\377\346\346\346\377\346\346\346\377\351\351\351\377"
"\357\357\357\377\360\360\360\377\363\363\363\377\360\360\360\377\366\366"
"\366\377\366\366\366\377\366\366\366\377\366\366\366\377\363\363\363\377"
"\363\363\363\377\355\355\355\377\346\346\346\377\343\343\343\377\335\335"
"\335\377\331\331\331\377\331\331\331\377\335\335\335\377\340\340\340\377"
"\343\343\343\377\351\351\351\377\355\355\355\377\357\357\357\377\362\362"
"\362\377\362\362\362\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\360\360\360\377\360\360\360\377\354\354\354\377\351\351"
"\351\377\343\343\343\377\343\343\343\377\344\344\344\377\344\344\344\377"
"\352\352\352\377\352\352\352\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\360\360\360\377\355\355\355\377\357\357\357\377"
"\357\357\357\377\354\354\354\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\362\362\362\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\360\360\360\377\357\357"
"\357\377\357\357\357\377\351\351\351\377\351\351\351\377\351\351\351\377"
"\351\351\351\377\355\355\355\377\355\355\355\377\363\363\363\377\363\363"
"\363\377\366\366\366\377\366\366\366\377\366\366\366\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\355\355\355\377\343\343\343\377\340\340"
"\340\377\335\335\335\377\331\331\331\377\331\331\331\377\335\335\335\377"
"\340\340\340\377\346\346\346\377\351\351\351\377\355\355\355\377\357\357"
"\357\377\362\362\362\377\362\362\362\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\360\360\360\377\360\360\360\377\354\354"
"\354\377\354\354\354\377\351\351\351\377\343\343\343\377\344\344\344\377"
"\344\344\344\377\352\352\352\377\352\352\352\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\357\357\357\377\354\354\354\377\352\352\352\377\352\352"
"\352\377\352\352\352\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377\360\360"
"\360\377\354\354\354\377\355\355\355\377\354\354\354\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\355\355\355\377\355\355\355\377\363\363"
"\363\377\363\363\363\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\366\366\366\377\363\363\363\377\363\363\363\377\355\355\355\377\346\346"
"\346\377\340\340\340\377\335\335\335\377\331\331\331\377\331\331\331\377"
"\335\335\335\377\340\340\340\377\346\346\346\377\351\351\351\377\355\355"
"\355\377\360\360\360\377\362\362\362\377\362\362\362\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360"
"\360\377\354\354\354\377\355\355\355\377\351\351\351\377\343\343\343\377"
"\344\344\344\377\344\344\344\377\352\352\352\377\352\352\352\377\357\357"
"\357\377\355\355\355\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\352\352\352\377\351\351\351\377\354\354\354\377\354\354"
"\354\377\354\354\354\377\354\354\354\377\360\360\360\377\360\360\360\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377\363\363"
"\363\377\363\363\363\377\355\355\355\377\355\355\355\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\357\357\357\377\357\357"
"\357\377\363\363\363\377\363\363\363\377\362\362\362\377\362\362\362\377"
"\363\363\363\377\366\366\366\377\363\363\363\377\355\355\355\377\351\351"
"\351\377\346\346\346\377\340\340\340\377\335\335\335\377\332\332\332\377"
"\332\332\332\377\335\335\335\377\335\335\335\377\343\343\343\377\352\352"
"\352\377\355\355\355\377\360\360\360\377\365\365\365\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377\362\362"
"\362\377\362\362\362\377\355\355\355\377\357\357\357\377\352\352\352\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\352\352\352\377\352\352"
"\352\377\357\357\357\377\355\355\355\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\355\355\355\377\351\351\351\377\354\354"
"\354\377\354\354\354\377\357\357\357\377\357\357\357\377\354\354\354\377"
"\354\354\354\377\357\357\357\377\357\357\357\377\357\357\357\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\355\355\355\377\355\355\355\377"
"\351\351\351\377\343\343\343\377\343\343\343\377\352\352\352\377\357\357"
"\357\377\357\357\357\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\363\363\363\377\365\365\365\377\363\363\363\377\355\355"
"\355\377\352\352\352\377\346\346\346\377\342\342\342\377\337\337\337\377"
"\332\332\332\377\327\327\327\377\335\335\335\377\337\337\337\377\343\343"
"\343\377\352\352\352\377\355\355\355\377\360\360\360\377\365\365\365\377"
"\363\363\363\377\362\362\362\377\362\362\362\377\363\363\363\377\363\363"
"\363\377\362\362\362\377\362\362\362\377\355\355\355\377\357\357\357\377"
"\352\352\352\377\344\344\344\377\344\344\344\377\344\344\344\377\352\352"
"\352\377\352\352\352\377\357\357\357\377\357\357\357\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\357\357\357\377\357\357"
"\357\377\362\362\362\377\354\354\354\377\357\357\357\377\357\357\357\377"
"\354\354\354\377\354\354\354\377\357\357\357\377\357\357\357\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\362\362\362\377\355\355\355\377"
"\352\352\352\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\352\352\352\377\355\355\355\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\363\363\363\377\365\365\365\377\365\365\365\377\360\360"
"\360\377\355\355\355\377\352\352\352\377\347\347\347\377\342\342\342\377"
"\335\335\335\377\327\327\327\377\327\327\327\377\335\335\335\377\337\337"
"\337\377\344\344\344\377\346\346\346\377\352\352\352\377\360\360\360\377"
"\365\365\365\377\365\365\365\377\365\365\365\377\363\363\363\377\365\365"
"\365\377\363\363\363\377\362\362\362\377\362\362\362\377\355\355\355\377"
"\357\357\357\377\352\352\352\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\352\352\352\377\352\352\352\377\357\357\357\377\357\357\357\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\357\357"
"\357\377\357\357\357\377\362\362\362\377\354\354\354\377\354\354\354\377"
"\354\354\354\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360"
"\360\377\362\362\362\377\362\362\362\377\362\362\362\377\357\357\357\377"
"\355\355\355\377\352\352\352\377\344\344\344\377\344\344\344\377\337\337"
"\337\377\344\344\344\377\352\352\352\377\355\355\355\377\362\362\362\377"
"\362\362\362\377\363\363\363\377\365\365\365\377\365\365\365\377\365\365"
"\365\377\360\360\360\377\360\360\360\377\354\354\354\377\347\347\347\377"
"\342\342\342\377\335\335\335\377\327\327\327\377\327\327\327\377\335\335"
"\335\377\337\337\337\377\344\344\344\377\347\347\347\377\352\352\352\377"
"\360\360\360\377\365\365\365\377\365\365\365\377\365\365\365\377\363\363"
"\363\377\363\363\363\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\355\355\355\377\355\355\355\377\352\352\352\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\352\352\352\377\352\352\352\377\357\357\357\377"
"\357\357\357\377\352\352\352\377\352\352\352\377\355\355\355\377\355\355"
"\355\377\357\357\357\377\357\357\357\377\357\357\357\377\354\354\354\377"
"\354\354\354\377\354\354\354\377\357\357\357\377\357\357\357\377\360\360"
"\360\377\362\362\362\377\362\362\362\377\362\362\362\377\357\357\357\377"
"\357\357\357\377\352\352\352\377\352\352\352\377\344\344\344\377\344\344"
"\344\377\337\337\337\377\337\337\337\377\344\344\344\377\352\352\352\377"
"\357\357\357\377\362\362\362\377\365\365\365\377\365\365\365\377\363\363"
"\363\377\363\363\363\377\360\360\360\377\352\352\352\377\347\347\347\377"
"\344\344\344\377\337\337\337\377\335\335\335\377\331\331\331\377\331\331"
"\331\377\335\335\335\377\337\337\337\377\344\344\344\377\347\347\347\377"
"\354\354\354\377\360\360\360\377\363\363\363\377\363\363\363\377\365\365"
"\365\377\365\365\365\377\363\363\363\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\355\355\355\377\352\352\352\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\352\352\352\377\352\352\352\377"
"\357\357\357\377\357\357\357\377\352\352\352\377\352\352\352\377\355\355"
"\355\377\355\355\355\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\354\354"
"\354\377\354\354\354\377\355\355\355\377\355\355\355\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\352\352\352\377\352\352\352\377\344\344"
"\344\377\342\342\342\377\337\337\337\377\337\337\337\377\344\344\344\377"
"\354\354\354\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\352\352\352\377"
"\347\347\347\377\344\344\344\377\342\342\342\377\337\337\337\377\331\331"
"\331\377\331\331\331\377\337\337\337\377\342\342\342\377\344\344\344\377"
"\347\347\347\377\354\354\354\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\347\347\347\377\347\347"
"\347\377\347\347\347\377\347\347\347\377\347\347\347\377\354\354\354\377"
"\354\354\354\377\354\354\354\377\362\362\362\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\357\357\357\377\357\357\357\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\355\355\355\377\355\355\355\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\355\355\355\377\352\352\352\377\352\352\352\377\344\344"
"\344\377\342\342\342\377\342\342\342\377\342\342\342\377\342\342\342\377"
"\347\347\347\377\354\354\354\377\355\355\355\377\360\360\360\377\363\363"
"\363\377\363\363\363\377\360\360\360\377\360\360\360\377\352\352\352\377"
"\352\352\352\377\344\344\344\377\344\344\344\377\342\342\342\377\337\337"
"\337\377\331\331\331\377\331\331\331\377\337\337\337\377\342\342\342\377"
"\347\347\347\377\344\344\344\377\352\352\352\377\352\352\352\377\355\355"
"\355\377\360\360\360\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\355\355\355\377\352\352\352\377\347\347\347\377\344\344"
"\344\377\347\347\347\377\347\347\347\377\351\351\351\377\351\351\351\377"
"\351\351\351\377\354\354\354\377\355\355\355\377\354\354\354\377\357\357"
"\357\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\351\351\351\377\351\351\351\377\351\351"
"\351\377\351\351\351\377\351\351\351\377\352\352\352\377\352\352\352\377"
"\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377\344\344"
"\344\377\344\344\344\377\342\342\342\377\342\342\342\377\342\342\342\377"
"\343\343\343\377\343\343\343\377\351\351\351\377\351\351\351\377\355\355"
"\355\377\355\355\355\377\355\355\355\377\360\360\360\377\355\355\355\377"
"\354\354\354\377\352\352\352\377\344\344\344\377\347\347\347\377\342\342"
"\342\377\334\334\334\377\331\331\331\377\331\331\331\377\334\334\334\377"
"\342\342\342\377\347\347\347\377\344\344\344\377\352\352\352\377\354\354"
"\354\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\351\351\351\377\351\351"
"\351\377\344\344\344\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\346\346\346\377\351\351\351\377\351\351\351\377\355\355"
"\355\377\354\354\354\377\352\352\352\377\352\352\352\377\352\352\352\377"
"\352\352\352\377\352\352\352\377\352\352\352\377\351\351\351\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377"
"\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377\347\347"
"\347\377\344\344\344\377\344\344\344\377\342\342\342\377\342\342\342\377"
"\343\343\343\377\343\343\343\377\343\343\343\377\346\346\346\377\346\346"
"\346\377\351\351\351\377\351\351\351\377\352\352\352\377\352\352\352\377"
"\354\354\354\377\352\352\352\377\347\347\347\377\344\344\344\377\342\342"
"\342\377\334\334\334\377\331\331\331\377\331\331\331\377\331\331\331\377"
"\331\331\331\377\334\334\334\377\342\342\342\377\344\344\344\377\347\347"
"\347\377\352\352\352\377\354\354\354\377\352\352\352\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\351\351\351\377\351\351"
"\351\377\346\346\346\377\346\346\346\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\343\343\343\377\346\346\346\377\346\346\346\377\351\351"
"\351\377\351\351\351\377\347\347\347\377\347\347\347\377\344\344\344\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377\347\347"
"\347\377\344\344\344\377\343\343\343\377\343\343\343\377\340\340\340\377"
"\340\340\340\377\335\335\335\377\335\335\335\377\340\340\340\377\340\340"
"\340\377\343\343\343\377\343\343\343\377\343\343\343\377\346\346\346\377"
"\346\346\346\377\347\347\347\377\347\347\347\377\351\351\351\377\344\344"
"\344\377\342\342\342\377\334\334\334\377\331\331\331\377\325\325\325\377"
"\325\325\325\377\331\331\331\377\334\334\334\377\342\342\342\377\344\344"
"\344\377\351\351\351\377\347\347\347\377\347\347\347\377\346\346\346\377"
"\346\346\346\377\343\343\343\377\343\343\343\377\343\343\343\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\340\340\340\377"
"\340\340\340\377\340\340\340\377\340\340\340\377\343\343\343\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\342\342\342\377"
"\337\337\337\377\337\337\337\377\337\337\337\377\337\337\337\377\337\337"
"\337\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\346\346\346\377\343\343\343\377\343\343\343\377"
"\340\340\340\377\335\335\335\377\335\335\335\377\335\335\335\377\340\340"
"\340\377\340\340\340\377\340\340\340\377\343\343\343\377\351\351\351\377"
"\346\346\346\377\346\346\346\377\352\352\352\377\347\347\347\377\347\347"
"\347\377\342\342\342\377\337\337\337\377\331\331\331\377\334\334\334\377"
"\326\326\326\377\326\326\326\377\334\334\334\377\331\331\331\377\337\337"
"\337\377\342\342\342\377\347\347\347\377\347\347\347\377\352\352\352\377"
"\346\346\346\377\346\346\346\377\343\343\343\377\343\343\343\377\343\343"
"\343\377\343\343\343\377\346\346\346\377\343\343\343\377\343\343\343\377"
"\340\340\340\377\335\335\335\377\335\335\335\377\340\340\340\377\343\343"
"\343\377\343\343\343\377\351\351\351\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\337\337\337\377\337\337\337\377\337\337\337\377\337\337"
"\337\377\337\337\337\377\344\344\344\377\344\344\344\377\344\344\344\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\346\346\346\377\343\343\343\377"
"\343\343\343\377\340\340\340\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\340\340\340\377\340\340\340\377\340\340\340\377\346\346\346\377"
"\351\351\351\377\346\346\346\377\352\352\352\377\352\352\352\377\347\347"
"\347\377\347\347\347\377\342\342\342\377\337\337\337\377\334\334\334\377"
"\335\335\335\377\327\327\327\377\327\327\327\377\335\335\335\377\334\334"
"\334\377\337\337\337\377\342\342\342\377\347\347\347\377\344\344\344\377"
"\352\352\352\377\351\351\351\377\346\346\346\377\346\346\346\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\340\340\340\377"
"\340\340\340\377\340\340\340\377\335\335\335\377\335\335\335\377\340\340"
"\340\377\343\343\343\377\343\343\343\377\351\351\351\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\347\347\347\377\346\346\346\377"
"\343\343\343\377\343\343\343\377\340\340\340\377\340\340\340\377\335\335"
"\335\377\335\335\335\377\340\340\340\377\340\340\340\377\343\343\343\377"
"\346\346\346\377\346\346\346\377\346\346\346\377\347\347\347\377\352\352"
"\352\377\347\347\347\377\347\347\347\377\342\342\342\377\337\337\337\377"
"\334\334\334\377\335\335\335\377\327\327\327\377\327\327\327\377\335\335"
"\335\377\334\334\334\377\337\337\337\377\342\342\342\377\347\347\347\377"
"\347\347\347\377\352\352\352\377\346\346\346\377\346\346\346\377\346\346"
"\346\377\346\346\346\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\340\340\340\377\340\340\340\377\340\340\340\377\340\340\340\377\340\340"
"\340\377\340\340\340\377\343\343\343\377\343\343\343\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\347\347\347\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\344\344\344\377\352\352\352\377"
"\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\352\352\352\377\354\354\354\377"
"\351\351\351\377\346\346\346\377\346\346\346\377\343\343\343\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\346\346\346\377"
"\346\346\346\377\352\352\352\377\352\352\352\377\352\352\352\377\354\354"
"\354\377\352\352\352\377\347\347\347\377\347\347\347\377\342\342\342\377"
"\340\340\340\377\334\334\334\377\335\335\335\377\327\327\327\377\327\327"
"\327\377\335\335\335\377\335\335\335\377\340\340\340\377\342\342\342\377"
"\347\347\347\377\347\347\347\377\352\352\352\377\354\354\354\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\351\351\351\377\351\351\351\377"
"\346\346\346\377\346\346\346\377\346\346\346\377\343\343\343\377\343\343"
"\343\377\340\340\340\377\343\343\343\377\346\346\346\377\351\351\351\377"
"\351\351\351\377\355\355\355\377\355\355\355\377\355\355\355\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377"
"\352\352\352\377\352\352\352\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\355\355\355\377\355\355\355\377\355\355\355\377\352\352\352\377"
"\354\354\354\377\351\351\351\377\351\351\351\377\351\351\351\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\351\351\351\377\352\352\352\377\352\352\352\377\352\352\352\377\354\354"
"\354\377\354\354\354\377\354\354\354\377\351\351\351\377\351\351\351\377"
"\344\344\344\377\340\340\340\377\335\335\335\377\335\335\335\377\327\327"
"\327\377\327\327\327\377\335\335\335\377\335\335\335\377\340\340\340\377"
"\344\344\344\377\351\351\351\377\351\351\351\377\352\352\352\377\354\354"
"\354\377\354\354\354\377\352\352\352\377\352\352\352\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\351\351\351\377\343\343"
"\343\377\343\343\343\377\340\340\340\377\343\343\343\377\351\351\351\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377"
"\352\352\352\377\357\357\357\377\357\357\357\377\357\357\357\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\362\362\362\377\357\357\357\377"
"\357\357\357\377\360\360\360\377\355\355\355\377\351\351\351\377\351\351"
"\351\377\343\343\343\377\346\346\346\377\346\346\346\377\343\343\343\377"
"\351\351\351\377\355\355\355\377\360\360\360\377\360\360\360\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\357\357\357\377\354\354\354\377"
"\351\351\351\377\346\346\346\377\343\343\343\377\335\335\335\377\335\335"
"\335\377\327\327\327\377\327\327\327\377\335\335\335\377\335\335\335\377"
"\343\343\343\377\346\346\346\377\351\351\351\377\354\354\354\377\357\357"
"\357\377\362\362\362\377\362\362\362\377\362\362\362\377\360\360\360\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\351\351\351\377\351\351"
"\351\377\343\343\343\377\346\346\346\377\346\346\346\377\346\346\346\377"
"\351\351\351\377\355\355\355\377\363\363\363\377\363\363\363\377\363\363"
"\363\377\363\363\363\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\363\363\363\377\362\362\362\377\363\363\363\377\360\360\360\377\355\355"
"\355\377\351\351\351\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\351\351\351\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\362\362\362\377\362\362\362\377\362\362\362\377\363\363\363\377"
"\357\357\357\377\351\351\351\377\346\346\346\377\343\343\343\377\335\335"
"\335\377\335\335\335\377\327\327\327\377\327\327\327\377\335\335\335\377"
"\335\335\335\377\343\343\343\377\346\346\346\377\351\351\351\377\357\357"
"\357\377\363\363\363\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\360\360\360\377\360\360\360\377\355\355\355\377\355\355\355\377\351\351"
"\351\377\351\351\351\377\343\343\343\377\343\343\343\377\346\346\346\377"
"\351\351\351\377\355\355\355\377\360\360\360\377\363\363\363\377\363\363"
"\363\377\363\363\363\377\363\363\363\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\363\363\363\377\363\363\363\377\363\363\363\377\363\363"
"\363\377\355\355\355\377\351\351\351\377\351\351\351\377\346\346\346\377"
"\346\346\346\377\351\351\351\377\351\351\351\377\360\360\360\377\363\363"
"\363\377\363\363\363\377\365\365\365\377\365\365\365\377\363\363\363\377"
"\363\363\363\377\357\357\357\377\354\354\354\377\347\347\347\377\343\343"
"\343\377\335\335\335\377\335\335\335\377\327\327\327\377\327\327\327\377"
"\335\335\335\377\335\335\335\377\343\343\343\377\347\347\347\377\351\351"
"\351\377\357\357\357\377\363\363\363\377\363\363\363\377\365\365\365\377"
"\365\365\365\377\365\365\365\377\363\363\363\377\360\360\360\377\355\355"
"\355\377\351\351\351\377\351\351\351\377\351\351\351\377\346\346\346\377"
"\351\351\351\377\351\351\351\377\355\355\355\377\360\360\360\377\365\365"
"\365\377\365\365\365\377\365\365\365\377\365\365\365\377\363\363\363\377"
"\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\362\362\362\377\363\363\363\377\363\363\363\377\363\363"
"\363\377\363\363\363\377\355\355\355\377\355\355\355\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\360\360\360\377\360\360"
"\360\377\363\363\363\377\363\363\363\377\365\365\365\377\365\365\365\377"
"\363\363\363\377\363\363\363\377\357\357\357\377\355\355\355\377\347\347"
"\347\377\343\343\343\377\335\335\335\377\335\335\335\377\327\327\327\377"
"\327\327\327\377\335\335\335\377\335\335\335\377\343\343\343\377\347\347"
"\347\377\351\351\351\377\357\357\357\377\363\363\363\377\363\363\363\377"
"\365\365\365\377\365\365\365\377\365\365\365\377\363\363\363\377\363\363"
"\363\377\360\360\360\377\355\355\355\377\355\355\355\377\351\351\351\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\355\355\355\377\360\360"
"\360\377\365\365\365\377\365\365\365\377\365\365\365\377\365\365\365\377"
"\363\363\363\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\363\363\363\377\365\365\365\377\365\365\365\377\365\365"
"\365\377\363\363\363\377\363\363\363\377\355\355\355\377\355\355\355\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\352\352\352\377\360\360"
"\360\377\360\360\360\377\363\363\363\377\365\365\365\377\365\365\365\377"
"\370\370\370\377\363\363\363\377\363\363\363\377\360\360\360\377\355\355"
"\355\377\347\347\347\377\343\343\343\377\335\335\335\377\335\335\335\377"
"\327\327\327\377\327\327\327\377\335\335\335\377\335\335\335\377\343\343"
"\343\377\347\347\347\377\354\354\354\377\357\357\357\377\363\363\363\377"
"\363\363\363\377\362\362\362\377\362\362\362\377\362\362\362\377\363\363"
"\363\377\363\363\363\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\352\352\352\377\351\351\351\377\351\351\351\377\351\351\351\377\355\355"
"\355\377\360\360\360\377\365\365\365\377\365\365\365\377\365\365\365\377"
"\365\365\365\377\365\365\365\377\363\363\363\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\365\365\365\377\365\365\365\377\365\365\365\377\365\365"
"\365\377\365\365\365\377\363\363\363\377\363\363\363\377\355\355\355\377"
"\355\355\355\377\351\351\351\377\352\352\352\377\352\352\352\377\352\352"
"\352\377\360\360\360\377\360\360\360\377\365\365\365\377\365\365\365\377"
"\365\365\365\377\370\370\370\377\363\363\363\377\357\357\357\377\352\352"
"\352\377\355\355\355\377\347\347\347\377\343\343\343\377\335\335\335\377"
"\335\335\335\377\327\327\327\377\327\327\327\377\335\335\335\377\335\335"
"\335\377\343\343\343\377\347\347\347\377\355\355\355\377\354\354\354\377"
"\357\357\357\377\363\363\363\377\363\363\363\377\362\362\362\377\362\362"
"\362\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360\360\377"
"\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377\351\351"
"\351\377\351\351\351\377\355\355\355\377\363\363\363\377\365\365\365\377"
"\365\365\365\377\365\365\365\377\365\365\365\377\365\365\365\377\363\363"
"\363\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\355\355\355\377\355\355\355\377\352\352\352\377\351\351\351\377\351\351"
"\351\377\352\352\352\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377\357\357"
"\357\377\355\355\355\377\355\355\355\377\347\347\347\377\343\343\343\377"
"\335\335\335\377\337\337\337\377\331\331\331\377\331\331\331\377\337\337"
"\337\377\335\335\335\377\343\343\343\377\347\347\347\377\355\355\355\377"
"\352\352\352\377\357\357\357\377\357\357\357\377\357\357\357\377\354\354"
"\354\377\354\354\354\377\362\362\362\377\360\360\360\377\360\360\360\377"
"\352\352\352\377\351\351\351\377\346\346\346\377\346\346\346\377\346\346"
"\346\377\346\346\346\377\351\351\351\377\355\355\355\377\355\355\355\377"
"\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377"
"\355\355\355\377\360\360\360\377\352\352\352\377\351\351\351\377\351\351"
"\351\377\352\352\352\377\354\354\354\377\354\354\354\377\354\354\354\377"
"\354\354\354\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\355\355\355\377\355\355\355\377\352\352\352\377\346\346\346\377"
"\335\335\335\377\332\332\332\377\331\331\331\377\331\331\331\377\331\331"
"\331\377\337\337\337\377\335\335\335\377\343\343\343\377\346\346\346\377"
"\352\352\352\377\352\352\352\377\354\354\354\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\357\357\357\377\354\354\354\377\354\354\354\377"
"\354\354\354\377\354\354\354\377\351\351\351\377\346\346\346\377\346\346"
"\346\377\346\346\346\377\346\346\346\377\351\351\351\377\354\354\354\377"
"\352\352\352\377\360\360\360\377\360\360\360\377\355\355\355\377\355\355"
"\355\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\351\351\351\377\351\351"
"\351\377\351\351\351\377\351\351\351\377\351\351\351\377\351\351\351\377"
"\351\351\351\377\352\352\352\377\352\352\352\377\352\352\352\377\347\347"
"\347\377\344\344\344\377\344\344\344\377\347\347\347\377\347\347\347\377"
"\347\347\347\377\351\351\351\377\351\351\351\377\351\351\351\377\351\351"
"\351\377\351\351\351\377\352\352\352\377\352\352\352\377\347\347\347\377"
"\343\343\343\377\335\335\335\377\327\327\327\377\331\331\331\377\331\331"
"\331\377\331\331\331\377\337\337\337\377\335\335\335\377\343\343\343\377"
"\346\346\346\377\352\352\352\377\351\351\351\377\347\347\347\377\351\351"
"\351\377\351\351\351\377\351\351\351\377\351\351\351\377\347\347\347\377"
"\347\347\347\377\347\347\347\377\347\347\347\377\344\344\344\377\344\344"
"\344\377\342\342\342\377\342\342\342\377\344\344\344\377\344\344\344\377"
"\347\347\347\377\347\347\347\377\354\354\354\377\352\352\352\377\352\352"
"\352\377\351\351\351\377\351\351\351\377\351\351\351\377\351\351\351\377"
"\351\351\351\377\343\343\343\377\343\343\343\377\343\343\343\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\346\346\346\377\346\346\346\377\346\346\346\377\347\347"
"\347\377\347\347\347\377\344\344\344\377\344\344\344\377\344\344\344\377"
"\347\347\347\377\347\347\347\377\347\347\347\377\347\347\347\377\347\347"
"\347\377\347\347\347\377\351\351\351\377\346\346\346\377\346\346\346\377"
"\343\343\343\377\340\340\340\377\335\335\335\377\327\327\327\377\331\331"
"\331\377\331\331\331\377\331\331\331\377\334\334\334\377\335\335\335\377"
"\335\335\335\377\340\340\340\377\346\346\346\377\351\351\351\377\347\347"
"\347\377\347\347\347\377\347\347\347\377\347\347\347\377\347\347\347\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377\337\337"
"\337\377\337\337\337\377\337\337\337\377\337\337\337\377\344\344\344\377"
"\344\344\344\377\344\344\344\377\344\344\344\377\347\347\347\377\347\347"
"\347\377\346\346\346\377\346\346\346\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\343\343\343\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\335\335\335\377\335\335\335\377\335\335\335\377\340\340\340\377"
"\340\340\340\377\340\340\340\377\342\342\342\377\342\342\342\377\342\342"
"\342\377\342\342\342\377\342\342\342\377\337\337\337\377\337\337\337\377"
"\337\337\337\377\342\342\342\377\342\342\342\377\342\342\342\377\342\342"
"\342\377\342\342\342\377\342\342\342\377\346\346\346\377\340\340\340\377"
"\340\340\340\377\335\335\335\377\335\335\335\377\335\335\335\377\327\327"
"\327\377\331\331\331\377\337\337\337\377\337\337\337\377\331\331\331\377"
"\327\327\327\377\335\335\335\377\340\340\340\377\346\346\346\377\343\343"
"\343\377\342\342\342\377\342\342\342\377\342\342\342\377\342\342\342\377"
"\342\342\342\377\337\337\337\377\337\337\337\377\337\337\337\377\337\337"
"\337\377\335\335\335\377\332\332\332\377\332\332\332\377\335\335\335\377"
"\337\337\337\377\337\337\337\377\337\337\337\377\337\337\337\377\342\342"
"\342\377\342\342\342\377\342\342\342\377\340\340\340\377\340\340\340\377"
"\335\335\335\377\335\335\335\377\335\335\335\377\334\334\334\377\334\334"
"\334\377\334\334\334\377\334\334\334\377\335\335\335\377\335\335\335\377"
"\337\337\337\377\337\337\337\377\337\337\337\377\337\337\337\377\337\337"
"\337\377\337\337\337\377\337\337\337\377\337\337\337\377\337\337\337\377"
"\337\337\337\377\342\342\342\377\342\342\342\377\337\337\337\377\337\337"
"\337\377\337\337\337\377\337\337\337\377\337\337\337\377\340\340\340\377"
"\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\327\327\327\377\331\331\331\377\337\337\337\377\335\335\335\377"
"\327\327\327\377\327\327\327\377\335\335\335\377\335\335\335\377\343\343"
"\343\377\337\337\337\377\342\342\342\377\342\342\342\377\342\342\342\377"
"\342\342\342\377\337\337\337\377\337\337\337\377\335\335\335\377\335\335"
"\335\377\335\335\335\377\332\332\332\377\332\332\332\377\332\332\332\377"
"\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377\337\337"
"\337\377\337\337\337\377\337\337\337\377\337\337\337\377\335\335\335\377"
"\335\335\335\377\334\334\334\377\334\334\334\377\334\334\334\377\331\331"
"\331\377\331\331\331\377\331\331\331\377\331\331\331\377\331\331\331\377"
"\331\331\331\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332"
"\332\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332\332\377"
"\332\332\332\377\332\332\332\377\334\334\334\377\334\334\334\377\331\331"
"\331\377\331\331\331\377\331\331\331\377\331\331\331\377\331\331\331\377"
"\335\335\335\377\335\335\335\377\327\327\327\377\327\327\327\377\327\327"
"\327\377\327\327\327\377\327\327\327\377\327\327\327\377\327\327\327\377"
"\327\327\327\377\332\332\332\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\340\340\340\377\334\334\334\377\334\334\334\377\334\334\334\377"
"\334\334\334\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332"
"\332\377\332\332\332\377\327\327\327\377\332\332\332\377\332\332\332\377"
"\327\327\327\377\327\327\327\377\327\327\327\377\332\332\332\377\332\332"
"\332\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332\332\377"
"\331\331\331\377\331\331\331\377\331\331\331\377\326\326\326\377\326\326"
"\326\377\326\326\326\377\326\326\326\377\326\326\326\377\331\331\331\377"
"\331\331\331\377\331\331\331\377\332\332\332\377\332\332\332\377\332\332"
"\332\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332\332\377"
"\332\332\332\377\332\332\332\377\332\332\332\377\334\334\334\377\331\331"
"\331\377\331\331\331\377\331\331\331\377\331\331\331\377\331\331\331\377"
"\331\331\331\377\335\335\335\377\335\335\335\377\327\327\327\377\327\327"
"\327\377\327\327\327\377\327\327\327\377\327\327\327\377\327\327\327\377"
"\327\327\327\377\327\327\327\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\335\335\335\377\334\334\334\377\334\334\334\377\334\334\334\377"
"\334\334\334\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332"
"\332\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332\332\377"
"\332\332\332\377\327\327\327\377\327\327\327\377\332\332\332\377\332\332"
"\332\377\332\332\332\377\332\332\332\377\332\332\332\377\332\332\332\377"
"\332\332\332\377\331\331\331\377\331\331\331\377\326\326\326\377\326\326"
"\326\377\326\326\326\377\334\334\334\377\334\334\334\377\334\334\334\377"
"\334\334\334\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\335\335\335\377\337\337\337\377\337\337\337\377\337\337\337\377"
"\337\337\337\377\337\337\337\377\337\337\337\377\335\335\335\377\332\332"
"\332\377\334\334\334\377\337\337\337\377\337\337\337\377\337\337\337\377"
"\337\337\337\377\337\337\337\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377"
"\332\332\332\377\327\327\327\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\340\340\340\377\342\342\342\377\342\342\342\377\342\342\342\377"
"\342\342\342\377\337\337\337\377\337\337\337\377\337\337\337\377\335\335"
"\335\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377"
"\335\335\335\377\335\335\335\377\332\332\332\377\332\332\332\377\335\335"
"\335\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377"
"\335\335\335\377\335\335\335\377\335\335\335\377\334\334\334\377\334\334"
"\334\377\334\334\334\377\334\334\334\377\335\335\335\377\335\335\335\377"
"\335\335\335\377\335\335\335\377\340\340\340\377\340\340\340\377\340\340"
"\340\377\343\343\343\377\343\343\343\377\343\343\343\377\340\340\340\377"
"\340\340\340\377\337\337\337\377\337\337\337\377\337\337\337\377\337\337"
"\337\377\332\332\332\377\334\334\334\377\342\342\342\377\342\342\342\377"
"\342\342\342\377\342\342\342\377\342\342\342\377\342\342\342\377\335\335"
"\335\377\340\340\340\377\340\340\340\377\340\340\340\377\335\335\335\377"
"\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\334\334\334\377\337\337\337\377\342\342\342\377\342\342\342\377"
"\347\347\347\377\344\344\344\377\344\344\344\377\344\344\344\377\343\343"
"\343\377\340\340\340\377\340\340\340\377\340\340\340\377\335\335\335\377"
"\335\335\335\377\335\335\335\377\335\335\335\377\334\334\334\377\334\334"
"\334\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377"
"\335\335\335\377\335\335\335\377\335\335\335\377\335\335\335\377\335\335"
"\335\377\335\335\335\377\335\335\335\377\335\335\335\377\343\343\343\377"
"\343\343\343\377\343\343\343\377\343\343\343\377\346\346\346\377\346\346"
"\346\377\346\346\346\377\346\346\346\377\346\346\346\377\346\346\346\377"
"\343\343\343\377\346\346\346\377\343\343\343\377\344\344\344\377\344\344"
"\344\377\342\342\342\377\337\337\337\377\337\337\337\377\344\344\344\377"
"\344\344\344\377\347\347\347\377\347\347\347\377\347\347\347\377\347\347"
"\347\377\342\342\342\377\342\342\342\377\342\342\342\377\346\346\346\377"
"\343\343\343\377\335\335\335\377\335\335\335\377\335\335\335\377\331\331"
"\331\377\337\337\337\377\337\337\337\377\342\342\342\377\344\344\344\377"
"\344\344\344\377\352\352\352\377\351\351\351\377\351\351\351\377\351\351"
"\351\377\346\346\346\377\346\346\346\377\346\346\346\377\346\346\346\377"
"\343\343\343\377\343\343\343\377\343\343\343\377\343\343\343\377\340\340"
"\340\377\340\340\340\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\343\343\343\377\343\343\343\377\343\343\343\377\343\343"
"\343\377\343\343\343\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\351\351\351\377\351\351"
"\351\377\351\351\351\377\355\355\355\377\355\355\355\377\355\355\355\377"
"\355\355\355\377\351\351\351\377\352\352\352\377\346\346\346\377\346\346"
"\346\377\343\343\343\377\344\344\344\377\344\344\344\377\344\344\344\377"
"\344\344\344\377\344\344\344\377\347\347\347\377\351\351\351\377\351\351"
"\351\377\351\351\351\377\347\347\347\377\347\347\347\377\344\344\344\377"
"\344\344\344\377\343\343\343\377\335\335\335\377\334\334\334\377\331\331"
"\331\377\334\334\334\377\342\342\342\377\342\342\342\377\344\344\344\377"
"\347\347\347\377\352\352\352\377\355\355\355\377\360\360\360\377\355\355"
"\355\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\355\355\355\377\355\355\355\377\351\351\351\377\351\351"
"\351\377\343\343\343\377\343\343\343\377\351\351\351\377\351\351\351\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\351\351"
"\351\377\351\351\351\377\351\351\351\377\351\351\351\377\343\343\343\377"
"\343\343\343\377\354\354\354\377\354\354\354\377\354\354\354\377\355\355"
"\355\377\355\355\355\377\355\355\355\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\355\355\355\377\355\355\355\377\351\351"
"\351\377\346\346\346\377\346\346\346\377\346\346\346\377\346\346\346\377"
"\351\351\351\377\351\351\351\377\351\351\351\377\352\352\352\377\354\354"
"\354\377\354\354\354\377\357\357\357\377\354\354\354\377\354\354\354\377"
"\351\351\351\377\344\344\344\377\342\342\342\377\337\337\337\377\337\337"
"\337\377\337\337\337\377\334\334\334\377\342\342\342\377\342\342\342\377"
"\344\344\344\377\352\352\352\377\355\355\355\377\362\362\362\377\363\363"
"\363\377\365\365\365\377\365\365\365\377\365\365\365\377\362\362\362\377"
"\362\362\362\377\362\362\362\377\357\357\357\377\357\357\357\377\352\352"
"\352\377\352\352\352\377\344\344\344\377\344\344\344\377\352\352\352\377"
"\354\354\354\377\363\363\363\377\363\363\363\377\363\363\363\377\363\363"
"\363\377\355\355\355\377\355\355\355\377\354\354\354\377\354\354\354\377"
"\347\347\347\377\347\347\347\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\355\355\355\377\360\360\360\377\360\360\360\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377\360\360"
"\360\377\355\355\355\377\351\351\351\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\351\351\351\377\352\352\352\377\352\352\352\377\360\360"
"\360\377\362\362\362\377\362\362\362\377\362\362\362\377\357\357\357\377"
"\354\354\354\377\354\354\354\377\347\347\347\377\347\347\347\377\342\342"
"\342\377\337\337\337\377\334\334\334\377\334\334\334\377\337\337\337\377"
"\344\344\344\377\351\351\351\377\355\355\355\377\360\360\360\377\365\365"
"\365\377\366\366\366\377\371\371\371\377\370\370\370\377\366\366\366\377"
"\366\366\366\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362"
"\362\377\355\355\355\377\355\355\355\377\352\352\352\377\352\352\352\377"
"\355\355\355\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\355\355\355\377\355\355\355\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\363\363\363\377\363\363\363\377\363\363\363\377\363\363"
"\363\377\360\360\360\377\355\355\355\377\351\351\351\377\351\351\351\377"
"\343\343\343\377\343\343\343\377\351\351\351\377\354\354\354\377\355\355"
"\355\377\362\362\362\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\362\362\362\377\357\357\357\377\352\352\352\377\347\347\347\377\344\344"
"\344\377\337\337\337\377\337\337\337\377\332\332\332\377\337\337\337\377"
"\337\337\337\377\343\343\343\377\351\351\351\377\355\355\355\377\363\363"
"\363\377\366\366\366\377\366\366\366\377\371\371\371\377\373\373\373\377"
"\373\373\373\377\371\371\371\377\365\365\365\377\365\365\365\377\365\365"
"\365\377\365\365\365\377\360\360\360\377\360\360\360\377\355\355\355\377"
"\357\357\357\377\357\357\357\377\362\362\362\377\362\362\362\377\363\363"
"\363\377\363\363\363\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\362\362\362\377\363\363\363\377\363\363\363\377\362\362"
"\362\377\362\362\362\377\355\355\355\377\355\355\355\377\351\351\351\377"
"\351\351\351\377\343\343\343\377\343\343\343\377\351\351\351\377\355\355"
"\355\377\360\360\360\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\362\362\362\377\360\360\360\377\355\355\355\377\354\354"
"\354\377\347\347\347\377\342\342\342\377\337\337\337\377\335\335\335\377"
"\337\337\337\377\340\340\340\377\343\343\343\377\346\346\346\377\355\355"
"\355\377\365\365\365\377\370\370\370\377\371\371\371\377\373\373\373\377"
"\373\373\373\377\373\373\373\377\371\371\371\377\366\366\366\377\366\366"
"\366\377\366\366\366\377\365\365\365\377\365\365\365\377\360\360\360\377"
"\360\360\360\377\355\355\355\377\355\355\355\377\360\360\360\377\363\363"
"\363\377\363\363\363\377\363\363\363\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\362\362\362\377\357\357\357\377\362\362\362\377\362\362"
"\362\377\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\355\355\355\377\352\352\352\377"
"\347\347\347\377\347\347\347\377\343\343\343\377\351\351\351\377\351\351"
"\351\377\355\355\355\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360"
"\360\377\352\352\352\377\346\346\346\377\342\342\342\377\337\337\337\377"
"\335\335\335\377\335\335\335\377\340\340\340\377\340\340\340\377\351\351"
"\351\377\360\360\360\377\363\363\363\377\366\366\366\377\373\373\373\377"
"\373\373\373\377\371\371\371\377\371\371\371\377\373\373\373\377\373\373"
"\373\377\370\370\370\377\370\370\370\377\363\363\363\377\363\363\363\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377\363\363"
"\363\377\363\363\363\377\363\363\363\377\363\363\363\377\365\365\365\377"
"\365\365\365\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360"
"\360\377\363\363\363\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\363\363\363\377\362\362\362\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\362\362\362\377\362\362\362\377\355\355\355\377"
"\352\352\352\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\352\352\352\377\354\354\354\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377\360\360"
"\360\377\355\355\355\377\351\351\351\377\346\346\346\377\343\343\343\377"
"\335\335\335\377\335\335\335\377\334\334\334\377\340\340\340\377\343\343"
"\343\377\351\351\351\377\357\357\357\377\362\362\362\377\366\366\366\377"
"\373\373\373\377\371\371\371\377\371\371\371\377\370\370\370\377\373\373"
"\373\377\373\373\373\377\370\370\370\377\370\370\370\377\363\363\363\377"
"\363\363\363\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\360\360\360\377\363\363\363\377\362\362\362\377\362\362\362\377"
"\363\363\363\377\363\363\363\377\360\360\360\377\360\360\360\377\357\357"
"\357\377\357\357\357\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\357\357\357\377\360\360\360\377\363\363\363\377\363\363"
"\363\377\363\363\363\377\363\363\363\377\362\362\362\377\362\362\362\377"
"\355\355\355\377\352\352\352\377\344\344\344\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\352\352\352\377\352\352\352\377\357\357\357\377"
"\355\355\355\377\365\365\365\377\365\365\365\377\365\365\365\377\365\365"
"\365\377\363\363\363\377\355\355\355\377\351\351\351\377\346\346\346\377"
"\340\340\340\377\340\340\340\377\334\334\334\377\334\334\334\377\340\340"
"\340\377\343\343\343\377\347\347\347\377\355\355\355\377\362\362\362\377"
"\366\366\366\377\371\371\371\377\371\371\371\377\366\366\366\377\365\365"
"\365\377\365\365\365\377\365\365\365\377\366\366\366\377\366\366\366\377"
"\362\362\362\377\362\362\362\377\355\355\355\377\357\357\357\377\360\360"
"\360\377\360\360\360\377\357\357\357\377\357\357\357\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360"
"\360\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\360\360\360\377\357\357\357\377\357\357\357\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\355\355\355\377"
"\360\360\360\377\354\354\354\377\352\352\352\377\344\344\344\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\352\352\352\377\355\355\355\377"
"\357\357\357\377\360\360\360\377\362\362\362\377\362\362\362\377\363\363"
"\363\377\365\365\365\377\363\363\363\377\363\363\363\377\355\355\355\377"
"\346\346\346\377\340\340\340\377\340\340\340\377\334\334\334\377\334\334"
"\334\377\340\340\340\377\343\343\343\377\347\347\347\377\355\355\355\377"
"\362\362\362\377\366\366\366\377\371\371\371\377\371\371\371\377\365\365"
"\365\377\365\365\365\377\365\365\365\377\365\365\365\377\366\366\366\377"
"\366\366\366\377\362\362\362\377\362\362\362\377\355\355\355\377\357\357"
"\357\377\357\357\357\377\360\360\360\377\357\357\357\377\357\357\357\377"
"\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377\360\360"
"\360\377\360\360\360\377\357\357\357\377\357\357\357\377\360\360\360\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\354\354\354\377\357\357\357\377\351\351\351\377\351\351\351\377\343\343"
"\343\377\343\343\343\377\344\344\344\377\344\344\344\377\352\352\352\377"
"\355\355\355\377\362\362\362\377\362\362\362\377\357\357\357\377\357\357"
"\357\377\363\363\363\377\363\363\363\377\362\362\362\377\363\363\363\377"
"\355\355\355\377\346\346\346\377\340\340\340\377\340\340\340\377\335\335"
"\335\377\335\335\335\377\340\340\340\377\342\342\342\377\344\344\344\377"
"\355\355\355\377\362\362\362\377\366\366\366\377\363\363\363\377\365\365"
"\365\377\370\370\370\377\370\370\370\377\366\366\366\377\366\366\366\377"
"\363\363\363\377\363\363\363\377\362\362\362\377\362\362\362\377\355\355"
"\355\377\355\355\355\377\352\352\352\377\352\352\352\377\360\360\360\377"
"\360\360\360\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\354\354\354\377\354\354\354\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377\354\354"
"\354\377\357\357\357\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\357\357\357\377\357\357\357\377\351\351\351\377\351\351"
"\351\377\343\343\343\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\351\351\351\377\354\354\354\377\360\360\360\377\362\362\362\377\357\357"
"\357\377\362\362\362\377\363\363\363\377\363\363\363\377\357\357\357\377"
"\357\357\357\377\354\354\354\377\351\351\351\377\343\343\343\377\340\340"
"\340\377\335\335\335\377\335\335\335\377\337\337\337\377\337\337\337\377"
"\344\344\344\377\355\355\355\377\362\362\362\377\363\363\363\377\363\363"
"\363\377\363\363\363\377\370\370\370\377\370\370\370\377\366\366\366\377"
"\366\366\366\377\363\363\363\377\362\362\362\377\357\357\357\377\357\357"
"\357\377\355\355\355\377\355\355\355\377\355\355\355\377\352\352\352\377"
"\357\357\357\377\360\360\360\377\363\363\363\377\363\363\363\377\360\360"
"\360\377\357\357\357\377\357\357\357\377\357\357\357\377\354\354\354\377"
"\354\354\354\377\357\357\357\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\355\355\355\377\357\357\357\377\354\354\354\377\354\354\354\377"
"\354\354\354\377\354\354\354\377\357\357\357\377\357\357\357\377\351\351"
"\351\377\346\346\346\377\343\343\343\377\343\343\343\377\343\343\343\377"
"\343\343\343\377\351\351\351\377\354\354\354\377\355\355\355\377\360\360"
"\360\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\357\357\357\377\357\357\357\377\352\352\352\377\347\347\347\377\343\343"
"\343\377\343\343\343\377\335\335\335\377\335\335\335\377\337\337\337\377"
"\337\337\337\377\344\344\344\377\355\355\355\377\362\362\362\377\360\360"
"\360\377\360\360\360\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\362\362\362\377\362\362\362\377\362\362\362\377\357\357\357\377\355\355"
"\355\377\352\352\352\377\352\352\352\377\352\352\352\377\352\352\352\377"
"\352\352\352\377\355\355\355\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\355\355\355\377\352\352\352\377\352\352\352\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\355\355\355\377\355\355\355\377\355\355\355\377\352\352\352\377"
"\352\352\352\377\352\352\352\377\354\354\354\377\357\357\357\377\357\357"
"\357\377\351\351\351\377\346\346\346\377\340\340\340\377\340\340\340\377"
"\340\340\340\377\343\343\343\377\351\351\351\377\351\351\351\377\355\355"
"\355\377\355\355\355\377\360\360\360\377\360\360\360\377\362\362\362\377"
"\362\362\362\377\357\357\357\377\357\357\357\377\352\352\352\377\344\344"
"\344\377\342\342\342\377\342\342\342\377\334\334\334\377\334\334\334\377"
"\337\337\337\377\337\337\337\377\344\344\344\377\352\352\352\377\357\357"
"\357\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357"
"\357\377\355\355\355\377\352\352\352\377\352\352\352\377\352\352\352\377"
"\352\352\352\377\352\352\352\377\352\352\352\377\357\357\357\377\357\357"
"\357\377\357\357\357\377\355\355\355\377\355\355\355\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\355\355\355\377\344\344"
"\344\377\344\344\344\377\344\344\344\377\344\344\344\377\347\347\347\377"
"\352\352\352\377\347\347\347\377\347\347\347\377\347\347\347\377\347\347"
"\347\377\352\352\352\377\347\347\347\377\346\346\346\377\340\340\340\377"
"\340\340\340\377\340\340\340\377\340\340\340\377\346\346\346\377\346\346"
"\346\377\354\354\354\377\354\354\354\377\355\355\355\377\355\355\355\377"
"\355\355\355\377\355\355\355\377\355\355\355\377\357\357\357\377\352\352"
"\352\377\344\344\344\377\342\342\342\377\342\342\342\377\334\334\334\377"
"\334\334\334\377\337\337\337\377\337\337\337\377\344\344\344\377\352\352"
"\352\377\357\357\357\377\355\355\355\377\360\360\360\377\354\354\354\377"
"\354\354\354\377\354\354\354\377\352\352\352\377\352\352\352\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\344\344\344\377\344\344\344\377"
"\346\346\346\377\346\346\346\377\346\346\346\377\346\346\346\377\351\351"
"\351\377\351\351\351\377\351\351\351\377\347\347\347\377\347\347\347\377"
"\347\347\347\377\347\347\347\377\347\347\347\377\347\347\347\377\347\347"
"\347\377\344\344\344\377\344\344\344\377\344\344\344\377\344\344\344\377"
"\347\347\347\377\352\352\352\377\347\347\347\377\347\347\347\377\347\347"
"\347\377\347\347\347\377\347\347\347\377\344\344\344\377\344\344\344\377"
"\337\337\337\377\332\332\332\377\332\332\332\377\337\337\337\377\346\346"
"\346\377\346\346\346\377\351\351\351\377\351\351\351\377\354\354\354\377"
"\351\351\351\377\354\354\354\377\355\355\355\377\354\354\354\377\357\357"
"\357\377\352\352\352\377\344\344\344\377\342\342\342\377\342\342\342\377"
"\334\334\334\377\334\334\334\377\335\335\335\377\335\335\335\377\342\342"
"\342\377\344\344\344\377\352\352\352\377\354\354\354\377\360\360\360\377"
"\357\357\357\377\354\354\354\377\354\354\354\377\354\354\354\377\355\355"
"\355\377\352\352\352\377\352\352\352\377\347\347\347\377\344\344\344\377"
"\340\340\340\377\340\340\340\377\340\340\340\377\340\340\340\377\346\346"
"\346\377\346\346\346\377\354\354\354\377\354\354\354\377\347\347\347\377"
"\347\347\347\377\347\347\347\377\347\347\347\377\347\347\347\377\347\347"
"\347\377\347\347\347\377\347\347\347\377\347\347\347\377\347\347\347\377"
"\347\347\347\377\347\347\347\377\352\352\352\377\352\352\352\377\355\355"
"\355\377\355\355\355\377\352\352\352\377\352\352\352\377\344\344\344\377"
"\344\344\344\377\342\342\342\377\337\337\337\377\337\337\337\377\342\342"
"\342\377\344\344\344\377\344\344\344\377\352\352\352\377\354\354\354\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360"
"\360\377\355\355\355\377\352\352\352\377\344\344\344\377\342\342\342\377"
"\342\342\342\377\334\334\334\377\332\332\332\377\335\335\335\377\335\335"
"\335\377\342\342\342\377\344\344\344\377\352\352\352\377\354\354\354\377"
"\360\360\360\377\357\357\357\377\354\354\354\377\354\354\354\377\354\354"
"\354\377\355\355\355\377\352\352\352\377\352\352\352\377\344\344\344\377"
"\344\344\344\377\340\340\340\377\340\340\340\377\340\340\340\377\340\340"
"\340\377\346\346\346\377\346\346\346\377\354\354\354\377\351\351\351\377"
"\354\354\354\377\352\352\352\377\352\352\352\377\352\352\352\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\346\346\346\377\346\346\346\377"
"\346\346\346\377\347\347\347\377\347\347\347\377\347\347\347\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\355\355\355\377\352\352\352\377"
"\352\352\352\377\347\347\347\377\347\347\347\377\344\344\344\377\344\344"
"\344\377\347\347\347\377\347\347\347\377\352\352\352\377\352\352\352\377"
"\355\355\355\377\357\357\357\377\357\357\357\377\357\357\357\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\355\355\355\377\344\344\344\377"
"\337\337\337\377\337\337\337\377\332\332\332\377\332\332\332\377\337\337"
"\337\377\337\337\337\377\344\344\344\377\352\352\352\377\357\357\357\377"
"\355\355\355\377\360\360\360\377\354\354\354\377\354\354\354\377\354\354"
"\354\377\354\354\354\377\354\354\354\377\352\352\352\377\352\352\352\377"
"\351\351\351\377\351\351\351\377\346\346\346\377\340\340\340\377\340\340"
"\340\377\340\340\340\377\346\346\346\377\351\351\351\377\351\351\351\377"
"\351\351\351\377\354\354\354\377\352\352\352\377\352\352\352\377\352\352"
"\352\377\352\352\352\377\352\352\352\377\352\352\352\377\354\354\354\377"
"\354\354\354\377\354\354\354\377\354\354\354\377\354\354\354\377\354\354"
"\354\377\357\357\357\377\357\357\357\377\360\360\360\377\362\362\362\377"
"\357\357\357\377\357\357\357\377\355\355\355\377\355\355\355\377\352\352"
"\352\377\352\352\352\377\355\355\355\377\355\355\355\377\357\357\357\377"
"\357\357\357\377\362\362\362\377\362\362\362\377\363\363\363\377\363\363"
"\363\377\365\365\365\377\365\365\365\377\360\360\360\377\354\354\354\377"
"\344\344\344\377\337\337\337\377\337\337\337\377\332\332\332\377\332\332"
"\332\377\337\337\337\377\337\337\337\377\344\344\344\377\352\352\352\377"
"\357\357\357\377\360\360\360\377\363\363\363\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\357\357\357\377"
"\357\357\357\377\354\354\354\377\354\354\354\377\346\346\346\377\346\346"
"\346\377\343\343\343\377\346\346\346\377\346\346\346\377\354\354\354\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\355\355\355\377\357\357"
"\357\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\360\360\360\377\357\357\357\377\357\357\357\377\352\352\352\377\355\355"
"\355\377\352\352\352\377\352\352\352\377\355\355\355\377\362\362\362\377"
"\362\362\362\377\362\362\362\377\363\363\363\377\363\363\363\377\363\363"
"\363\377\365\365\365\377\365\365\365\377\365\365\365\377\363\363\363\377"
"\355\355\355\377\352\352\352\377\344\344\344\377\337\337\337\377\332\332"
"\332\377\332\332\332\377\337\337\337\377\337\337\337\377\344\344\344\377"
"\355\355\355\377\362\362\362\377\360\360\360\377\363\363\363\377\360\360"
"\360\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360\360\377"
"\357\357\357\377\357\357\357\377\354\354\354\377\354\354\354\377\346\346"
"\346\377\346\346\346\377\346\346\346\377\346\346\346\377\354\354\354\377"
"\354\354\354\377\357\357\357\377\357\357\357\377\357\357\357\377\355\355"
"\355\377\357\357\357\377\355\355\355\377\357\357\357\377\362\362\362\377"
"\362\362\362\377\363\363\363\377\363\363\363\377\363\363\363\377\363\363"
"\363\377\365\365\365\377\365\365\365\377\365\365\365\377\365\365\365\377"
"\365\365\365\377\365\365\365\377\363\363\363\377\360\360\360\377\357\357"
"\357\377\354\354\354\377\354\354\354\377\354\354\354\377\351\351\351\377"
"\362\362\362\377\363\363\363\377\366\366\366\377\370\370\370\377\370\370"
"\370\377\370\370\370\377\370\370\370\377\370\370\370\377\365\365\365\377"
"\363\363\363\377\355\355\355\377\352\352\352\377\344\344\344\377\337\337"
"\337\377\332\332\332\377\332\332\332\377\337\337\337\377\337\337\337\377"
"\344\344\344\377\355\355\355\377\362\362\362\377\360\360\360\377\365\365"
"\365\377\363\363\363\377\363\363\363\377\363\363\363\377\362\362\362\377"
"\362\362\362\377\360\360\360\377\360\360\360\377\354\354\354\377\354\354"
"\354\377\346\346\346\377\346\346\346\377\346\346\346\377\346\346\346\377"
"\354\354\354\377\354\354\354\377\360\360\360\377\360\360\360\377\363\363"
"\363\377\357\357\357\377\362\362\362\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\366\366\366\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\363\363\363\377\365\365\365\377\365\365\365\377\365\365\365\377"
"\365\365\365\377\365\365\365\377\365\365\365\377\365\365\365\377\360\360"
"\360\377\360\360\360\377\357\357\357\377\354\354\354\377\351\351\351\377"
"\351\351\351\377\357\357\357\377\362\362\362\377\370\370\370\377\370\370"
"\370\377\370\370\370\377\370\370\370\377\370\370\370\377\370\370\370\377"
"\365\365\365\377\365\365\365\377\360\360\360\377\352\352\352\377\344\344"
"\344\377\337\337\337\377\332\332\332\377\332\332\332\377\337\337\337\377"
"\337\337\337\377\344\344\344\377\355\355\355\377\362\362\362\377\360\360"
"\360\377\365\365\365\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\362\362\362\377\362\362\362\377\360\360\360\377\360\360\360\377\354\354"
"\354\377\354\354\354\377\346\346\346\377\346\346\346\377\346\346\346\377"
"\346\346\346\377\354\354\354\377\354\354\354\377\360\360\360\377\360\360"
"\360\377\362\362\362\377\355\355\355\377\362\362\362\377\362\362\362\377"
"\362\362\362\377\366\366\366\377\366\366\366\377\363\363\363\377\365\365"
"\365\377\365\365\365\377\365\365\365\377\365\365\365\377\371\371\371\377"
"\371\371\371\377\371\371\371\377\371\371\371\377\365\365\365\377\365\365"
"\365\377\360\360\360\377\363\363\363\377\357\357\357\377\357\357\357\377"
"\354\354\354\377\357\357\357\377\357\357\357\377\360\360\360\377\365\365"
"\365\377\370\370\370\377\376\376\376\377\376\376\376\377\370\370\370\377"
"\370\370\370\377\365\365\365\377\363\363\363\377\360\360\360\377\352\352"
"\352\377\344\344\344\377\337\337\337\377\332\332\332\377\332\332\332\377"
"\337\337\337\377\337\337\337\377\344\344\344\377\355\355\355\377\362\362"
"\362\377\362\362\362\377\365\365\365\377\363\363\363\377\363\363\363\377"
"\363\363\363\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360"
"\360\377\354\354\354\377\354\354\354\377\346\346\346\377\346\346\346\377"
"\346\346\346\377\346\346\346\377\354\354\354\377\354\354\354\377\360\360"
"\360\377\360\360\360\377\357\357\357\377\355\355\355\377\362\362\362\377"
"\362\362\362\377\362\362\362\377\362\362\362\377\366\366\366\377\362\362"
"\362\377\363\363\363\377\363\363\363\377\363\363\363\377\370\370\370\377"
"\370\370\370\377\370\370\370\377\370\370\370\377\371\371\371\377\365\365"
"\365\377\365\365\365\377\360\360\360\377\363\363\363\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360"
"\360\377\365\365\365\377\366\366\366\377\376\376\376\377\376\376\376\377"
"\370\370\370\377\370\370\370\377\365\365\365\377\360\360\360\377\355\355"
"\355\377\343\343\343\377\337\337\337\377\337\337\337\377\332\332\332\377"
"\332\332\332\377\337\337\337\377\337\337\337\377\344\344\344\377\355\355"
"\355\377\362\362\362\377\362\362\362\377\365\365\365\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\357\357\357\377\357\357\357\377\360\360"
"\360\377\360\360\360\377\354\354\354\377\354\354\354\377\346\346\346\377"
"\346\346\346\377\346\346\346\377\346\346\346\377\354\354\354\377\354\354"
"\354\377\360\360\360\377\360\360\360\377\357\357\357\377\357\357\357\377"
"\362\362\362\377\362\362\362\377\362\362\362\377\362\362\362\377\366\366"
"\366\377\357\357\357\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\370\370\370\377\370\370\370\377\370\370\370\377\370\370\370\377\370\370"
"\370\377\363\363\363\377\363\363\363\377\360\360\360\377\360\360\360\377"
"\357\357\357\377\354\354\354\377\354\354\354\377\357\357\357\377\360\360"
"\360\377\360\360\360\377\365\365\365\377\365\365\365\377\376\376\376\377"
"\370\370\370\377\370\370\370\377\370\370\370\377\365\365\365\377\360\360"
"\360\377\355\355\355\377\343\343\343\377\337\337\337\377\335\335\335\377"
"\332\332\332\377\332\332\332\377\335\335\335\377\337\337\337\377\344\344"
"\344\377\355\355\355\377\362\362\362\377\362\362\362\377\363\363\363\377"
"\363\363\363\377\363\363\363\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\354\354\354\377\357\357\357\377\354\354\354\377\354\354\354\377"
"\346\346\346\377\346\346\346\377\346\346\346\377\346\346\346\377\354\354"
"\354\377\354\354\354\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\355\355\355\377\355\355\355\377\362\362\362\377\362\362"
"\362\377\366\366\366\377\355\355\355\377\360\360\360\377\362\362\362\377"
"\362\362\362\377\362\362\362\377\366\366\366\377\370\370\370\377\370\370"
"\370\377\370\370\370\377\363\363\363\377\363\363\363\377\360\360\360\377"
"\357\357\357\377\354\354\354\377\354\354\354\377\354\354\354\377\354\354"
"\354\377\357\357\357\377\360\360\360\377\365\365\365\377\365\365\365\377"
"\371\371\371\377\370\370\370\377\370\370\370\377\366\366\366\377\362\362"
"\362\377\360\360\360\377\355\355\355\377\343\343\343\377\337\337\337\377"
"\335\335\335\377\332\332\332\377\332\332\332\377\335\335\335\377\335\335"
"\335\377\342\342\342\377\352\352\352\377\357\357\357\377\362\362\362\377"
"\363\363\363\377\360\360\360\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\354\354\354\377\357\357\357\377\354\354\354\377"
"\354\354\354\377\346\346\346\377\346\346\346\377\346\346\346\377\346\346"
"\346\377\354\354\354\377\354\354\354\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\357\357\357\377\355\355\355\377\355\355\355\377\362\362"
"\362\377\362\362\362\377\363\363\363\377\352\352\352\377\355\355\355\377"
"\355\355\355\377\362\362\362\377\362\362\362\377\362\362\362\377\362\362"
"\362\377\363\363\363\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\357\357\357\377\357\357\357\377\351\351\351\377\351\351\351\377\346\346"
"\346\377\351\351\351\377\357\357\357\377\360\360\360\377\365\365\365\377"
"\365\365\365\377\365\365\365\377\370\370\370\377\363\363\363\377\363\363"
"\363\377\362\362\362\377\360\360\360\377\355\355\355\377\343\343\343\377"
"\337\337\337\377\335\335\335\377\327\327\327\377\327\327\327\377\335\335"
"\335\377\335\335\335\377\342\342\342\377\352\352\352\377\357\357\357\377"
"\357\357\357\377\363\363\363\377\360\360\360\377\360\360\360\377\360\360"
"\360\377\357\357\357\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\351\351\351\377\351\351\351\377\346\346\346\377\340\340\340\377\340\340"
"\340\377\346\346\346\377\351\351\351\377\351\351\351\377\357\357\357\377"
"\354\354\354\377\352\352\352\377\352\352\352\377\355\355\355\377\355\355"
"\355\377\362\362\362\377\362\362\362\377\360\360\360\377\355\355\355\377"
"\352\352\352\377\355\355\355\377\360\360\360\377\362\362\362\377\362\362"
"\362\377\362\362\362\377\363\363\363\377\363\363\363\377\363\363\363\377"
"\362\362\362\377\354\354\354\377\354\354\354\377\351\351\351\377\351\351"
"\351\377\346\346\346\377\346\346\346\377\354\354\354\377\357\357\357\377"
"\363\363\363\377\365\365\365\377\365\365\365\377\363\363\363\377\362\362"
"\362\377\362\362\362\377\355\355\355\377\357\357\357\377\354\354\354\377"
"\343\343\343\377\335\335\335\377\335\335\335\377\327\327\327\377\327\327"
"\327\377\335\335\335\377\335\335\335\377\342\342\342\377\352\352\352\377"
"\357\357\357\377\357\357\357\377\363\363\363\377\360\360\360\377\360\360"
"\360\377\360\360\360\377\357\357\357\377\357\357\357\377\357\357\357\377"
"\357\357\357\377\351\351\351\377\346\346\346\377\340\340\340\377\340\340"
"\340\377\340\340\340\377\340\340\340\377\346\346\346\377\351\351\351\377"
"\357\357\357\377\357\357\357\377\352\352\352\377\352\352\352\377\354\354"
"\354\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360\360\377"
"\352\352\352\377\355\355\355\377\355\355\355\377\355\355\355\377\355\355"
"\355\377\357\357\357\377\355\355\355\377\357\357\357\377\362\362\362\377"
"\357\357\357\377\362\362\362\377\354\354\354\377\354\354\354\377\346\346"
"\346\377\346\346\346\377\344\344\344\377\344\344\344\377\354\354\354\377"
"\357\357\357\377\363\363\363\377\360\360\360\377\360\360\360\377\363\363"
"\363\377\362\362\362\377\362\362\362\377\355\355\355\377\357\357\357\377"
"\354\354\354\377\340\340\340\377\335\335\335\377\335\335\335\377\327\327"
"\327\377\327\327\327\377\335\335\335\377\335\335\335\377\342\342\342\377"
"\352\352\352\377\357\357\357\377\357\357\357\377\363\363\363\377\357\357"
"\357\377\357\357\357\377\357\357\357\377\360\360\360\377\360\360\360\377"
"\357\357\357\377\357\357\357\377\351\351\351\377\346\346\346\377\340\340"
"\340\377\340\340\340\377\340\340\340\377\340\340\340\377\346\346\346\377"
"\351\351\351\377\357\357\357\377\354\354\354\377\355\355\355\377\355\355"
"\355\377\354\354\354\377\354\354\354\377\355\355\355\377\352\352\352\377"
"\352\352\352\377",
};
/* GIMP RGBA C-Source image dump (text_silk.c) */
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[64 * 64 * 4 + 1];
} text_silk = {
64, 64, 4,
"\377\377\377\366\377\377\377\372\377\377\377\375\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\377\377\377\377\374\377\377"
"\377\366\377\377\377\365\377\377\377\364\377\377\377\366\377\377\377\370"
"\377\377\377\365\377\377\377\362\377\377\377\364\377\377\377\366\377\377"
"\377\370\377\377\377\372\377\377\377\363\377\377\377\354\377\377\377\350"
"\377\377\377\351\377\377\377\352\377\377\377\354\377\377\377\356\377\377"
"\377\361\377\377\377\366\377\377\377\372\377\377\377\375\377\377\377\375"
"\377\377\377\373\377\377\377\365\377\377\377\366\377\377\377\371\377\377"
"\377\372\377\377\377\374\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\366\377\377"
"\377\357\377\377\377\350\377\377\377\346\377\377\377\342\377\377\377\335"
"\377\377\377\346\377\377\377\351\377\377\377\351\377\377\377\357\377\377"
"\377\357\377\377\377\363\377\377\377\363\377\377\377\361\377\377\377\361"
"\377\377\377\362\377\377\377\357\377\377\377\365\377\377\377\372\377\377"
"\377\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\377\377\377"
"\377\375\377\377\377\370\377\377\377\365\377\377\377\364\377\377\377\367"
"\377\377\377\370\377\377\377\363\377\377\377\357\377\377\377\356\377\377"
"\377\360\377\377\377\364\377\377\377\370\377\377\377\365\377\377\377\355"
"\377\377\377\350\377\377\377\347\377\377\377\344\377\377\377\344\377\377"
"\377\352\377\377\377\357\377\377\377\362\377\377\377\370\377\377\377\374"
"\377\377\377\372\377\377\377\366\377\377\377\362\377\377\377\363\377\377"
"\377\363\377\377\377\363\377\377\377\365\377\377\377\371\377\377\377\375"
"\377\377\377\375\377\377\377\376\377\377\377\377\377\377\377\377\377\377"
"\377\373\377\377\377\363\377\377\377\352\377\377\377\347\377\377\377\346"
"\377\377\377\342\377\377\377\345\377\377\377\344\377\377\377\340\377\377"
"\377\344\377\377\377\351\377\377\377\355\377\377\377\356\377\377\377\357"
"\377\377\377\354\377\377\377\354\377\377\377\356\377\377\377\364\377\377"
"\377\371\377\377\377\375\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\376\377\377\377\374\377\377\377\373\377\377\377\372"
"\377\377\377\374\377\377\377\372\377\377\377\362\377\377\377\360\377\377"
"\377\356\377\377\377\357\377\377\377\366\377\377\377\367\377\377\377\361"
"\377\377\377\351\377\377\377\346\377\377\377\350\377\377\377\344\377\377"
"\377\340\377\377\377\347\377\377\377\360\377\377\377\361\377\377\377\365"
"\377\377\377\370\377\377\377\365\377\377\377\362\377\377\377\356\377\377"
"\377\355\377\377\377\355\377\377\377\354\377\377\377\356\377\377\377\360"
"\377\377\377\364\377\377\377\370\377\377\377\372\377\377\377\377\377\377"
"\377\377\377\377\377\372\377\377\377\364\377\377\377\352\377\377\377\342"
"\377\377\377\342\377\377\377\340\377\377\377\342\377\377\377\342\377\377"
"\377\333\377\377\377\327\377\377\377\336\377\377\377\345\377\377\377\352"
"\377\377\377\357\377\377\377\355\377\377\377\354\377\377\377\357\377\377"
"\377\364\377\377\377\371\377\377\377\374\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\372\377\377\377\366\377\377"
"\377\363\377\377\377\362\377\377\377\365\377\377\377\370\377\377\377\365"
"\377\377\377\357\377\377\377\352\377\377\377\351\377\377\377\355\377\377"
"\377\351\377\377\377\343\377\377\377\347\377\377\377\360\377\377\377\364"
"\377\377\377\366\377\377\377\365\377\377\377\363\377\377\377\360\377\377"
"\377\351\377\377\377\346\377\377\377\352\377\377\377\353\377\377\377\347"
"\377\377\377\352\377\377\377\361\377\377\377\365\377\377\377\370\377\377"
"\377\376\377\377\377\376\377\377\377\366\377\377\377\361\377\377\377\353"
"\377\377\377\336\377\377\377\332\377\377\377\334\377\377\377\335\377\377"
"\377\336\377\377\377\327\377\377\377\316\377\377\377\322\377\377\377\333"
"\377\377\377\344\377\377\377\357\377\377\377\357\377\377\377\357\377\377"
"\377\361\377\377\377\364\377\377\377\372\377\377\377\375\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\366\377\377"
"\377\365\377\377\377\365\377\377\377\370\377\377\377\374\377\377\377\374"
"\377\377\377\366\377\377\377\360\377\377\377\353\377\377\377\353\377\377"
"\377\361\377\377\377\356\377\377\377\353\377\377\377\357\377\377\377\365"
"\377\377\377\371\377\377\377\371\377\377\377\367\377\377\377\361\377\377"
"\377\354\377\377\377\351\377\377\377\351\377\377\377\352\377\377\377\350"
"\377\377\377\343\377\377\377\354\377\377\377\366\377\377\377\373\377\377"
"\377\374\377\377\377\375\377\377\377\374\377\377\377\363\377\377\377\351"
"\377\377\377\342\377\377\377\332\377\377\377\333\377\377\377\340\377\377"
"\377\341\377\377\377\340\377\377\377\326\377\377\377\312\377\377\377\317"
"\377\377\377\327\377\377\377\343\377\377\377\357\377\377\377\360\377\377"
"\377\361\377\377\377\357\377\377\377\364\377\377\377\372\377\377\377\376"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\372\377\377\377\371\377\377\377\372\377\377\377\374\377\377\377\377"
"\377\377\377\377\377\377\377\371\377\377\377\357\377\377\377\355\377\377"
"\377\360\377\377\377\365\377\377\377\365\377\377\377\362\377\377\377\365"
"\377\377\377\372\377\377\377\374\377\377\377\372\377\377\377\366\377\377"
"\377\361\377\377\377\360\377\377\377\356\377\377\377\356\377\377\377\353"
"\377\377\377\347\377\377\377\347\377\377\377\361\377\377\377\372\377\377"
"\377\377\377\377\377\377\377\377\377\373\377\377\377\365\377\377\377\355"
"\377\377\377\345\377\377\377\335\377\377\377\333\377\377\377\337\377\377"
"\377\344\377\377\377\347\377\377\377\343\377\377\377\330\377\377\377\317"
"\377\377\377\317\377\377\377\322\377\377\377\337\377\377\377\352\377\377"
"\377\354\377\377\377\356\377\377\377\364\377\377\377\367\377\377\377\372"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\376\377\377\377\376\377\377\377\377\377\377\377\377"
"\377\377\377\375\377\377\377\373\377\377\377\370\377\377\377\363\377\377"
"\377\361\377\377\377\363\377\377\377\366\377\377\377\367\377\377\377\365"
"\377\377\377\371\377\377\377\373\377\377\377\371\377\377\377\370\377\377"
"\377\364\377\377\377\360\377\377\377\361\377\377\377\357\377\377\377\356"
"\377\377\377\357\377\377\377\357\377\377\377\361\377\377\377\366\377\377"
"\377\372\377\377\377\375\377\377\377\377\377\377\377\370\377\377\377\361"
"\377\377\377\355\377\377\377\351\377\377\377\342\377\377\377\337\377\377"
"\377\340\377\377\377\345\377\377\377\350\377\377\377\343\377\377\377\334"
"\377\377\377\325\377\377\377\320\377\377\377\316\377\377\377\335\377\377"
"\377\351\377\377\377\356\377\377\377\361\377\377\377\370\377\377\377\372"
"\377\377\377\375\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\376\377\377\377\375\377\377\377\377"
"\377\377\377\377\377\377\377\372\377\377\377\365\377\377\377\363\377\377"
"\377\365\377\377\377\363\377\377\377\363\377\377\377\366\377\377\377\366"
"\377\377\377\370\377\377\377\374\377\377\377\372\377\377\377\364\377\377"
"\377\361\377\377\377\357\377\377\377\354\377\377\377\356\377\377\377\353"
"\377\377\377\355\377\377\377\362\377\377\377\367\377\377\377\373\377\377"
"\377\375\377\377\377\374\377\377\377\374\377\377\377\375\377\377\377\371"
"\377\377\377\363\377\377\377\356\377\377\377\350\377\377\377\343\377\377"
"\377\342\377\377\377\344\377\377\377\350\377\377\377\350\377\377\377\346"
"\377\377\377\340\377\377\377\333\377\377\377\330\377\377\377\331\377\377"
"\377\342\377\377\377\354\377\377\377\362\377\377\377\367\377\377\377\366"
"\377\377\377\366\377\377\377\373\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\376\377\377\377\372\377\377\377\374"
"\377\377\377\375\377\377\377\373\377\377\377\370\377\377\377\364\377\377"
"\377\361\377\377\377\365\377\377\377\365\377\377\377\365\377\377\377\367"
"\377\377\377\365\377\377\377\370\377\377\377\373\377\377\377\372\377\377"
"\377\366\377\377\377\357\377\377\377\351\377\377\377\351\377\377\377\354"
"\377\377\377\352\377\377\377\360\377\377\377\363\377\377\377\370\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\370\377\377\377\363\377\377\377\356\377\377\377\350\377\377"
"\377\344\377\377\377\342\377\377\377\343\377\377\377\352\377\377\377\354"
"\377\377\377\352\377\377\377\343\377\377\377\340\377\377\377\335\377\377"
"\377\340\377\377\377\346\377\377\377\356\377\377\377\362\377\377\377\367"
"\377\377\377\363\377\377\377\361\377\377\377\367\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\374\377\377\377\370\377\377\377\366"
"\377\377\377\372\377\377\377\372\377\377\377\367\377\377\377\367\377\377"
"\377\366\377\377\377\365\377\377\377\366\377\377\377\362\377\377\377\361"
"\377\377\377\364\377\377\377\364\377\377\377\370\377\377\377\372\377\377"
"\377\374\377\377\377\373\377\377\377\363\377\377\377\355\377\377\377\353"
"\377\377\377\352\377\377\377\354\377\377\377\364\377\377\377\367\377\377"
"\377\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\372\377\377\377\362\377\377\377\356\377\377"
"\377\350\377\377\377\346\377\377\377\342\377\377\377\342\377\377\377\353"
"\377\377\377\361\377\377\377\356\377\377\377\353\377\377\377\346\377\377"
"\377\337\377\377\377\341\377\377\377\351\377\377\377\361\377\377\377\362"
"\377\377\377\364\377\377\377\361\377\377\377\360\377\377\377\370\377\377"
"\377\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\375\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\372"
"\377\377\377\365\377\377\377\364\377\377\377\365\377\377\377\364\377\377"
"\377\364\377\377\377\364\377\377\377\364\377\377\377\361\377\377\377\352"
"\377\377\377\354\377\377\377\357\377\377\377\362\377\377\377\372\377\377"
"\377\376\377\377\377\375\377\377\377\373\377\377\377\365\377\377\377\361"
"\377\377\377\363\377\377\377\362\377\377\377\363\377\377\377\370\377\377"
"\377\373\377\377\377\376\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\363\377\377"
"\377\353\377\377\377\346\377\377\377\346\377\377\377\347\377\377\377\352"
"\377\377\377\356\377\377\377\361\377\377\377\356\377\377\377\357\377\377"
"\377\354\377\377\377\350\377\377\377\350\377\377\377\360\377\377\377\366"
"\377\377\377\363\377\377\377\362\377\377\377\361\377\377\377\364\377\377"
"\377\374\377\377\377\376\377\377\377\376\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\374\377\377"
"\377\377\377\377\377\375\377\377\377\374\377\377\377\375\377\377\377\376"
"\377\377\377\374\377\377\377\366\377\377\377\361\377\377\377\363\377\377"
"\377\366\377\377\377\365\377\377\377\363\377\377\377\361\377\377\377\355"
"\377\377\377\344\377\377\377\351\377\377\377\355\377\377\377\360\377\377"
"\377\372\377\377\377\377\377\377\377\377\377\377\377\372\377\377\377\366"
"\377\377\377\367\377\377\377\370\377\377\377\371\377\377\377\371\377\377"
"\377\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\377\377"
"\377\366\377\377\377\357\377\377\377\351\377\377\377\350\377\377\377\354"
"\377\377\377\360\377\377\377\361\377\377\377\363\377\377\377\357\377\377"
"\377\361\377\377\377\357\377\377\377\355\377\377\377\360\377\377\377\363"
"\377\377\377\365\377\377\377\365\377\377\377\364\377\377\377\370\377\377"
"\377\370\377\377\377\375\377\377\377\375\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375\377\377"
"\377\372\377\377\377\376\377\377\377\376\377\377\377\376\377\377\377\377"
"\377\377\377\376\377\377\377\372\377\377\377\365\377\377\377\362\377\377"
"\377\361\377\377\377\363\377\377\377\365\377\377\377\367\377\377\377\363"
"\377\377\377\353\377\377\377\341\377\377\377\345\377\377\377\356\377\377"
"\377\365\377\377\377\372\377\377\377\377\377\377\377\377\377\377\377\374"
"\377\377\377\367\377\377\377\371\377\377\377\372\377\377\377\375\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\375\377\377\377\370\377\377\377\363\377\377\377\357\377\377\377\356"
"\377\377\377\357\377\377\377\357\377\377\377\360\377\377\377\362\377\377"
"\377\357\377\377\377\361\377\377\377\356\377\377\377\355\377\377\377\365"
"\377\377\377\367\377\377\377\366\377\377\377\372\377\377\377\373\377\377"
"\377\376\377\377\377\374\377\377\377\376\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\374\377\377\377\371\377\377\377\375\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\374\377\377\377\370\377\377\377\364\377\377"
"\377\361\377\377\377\356\377\377\377\355\377\377\377\362\377\377\377\365"
"\377\377\377\357\377\377\377\353\377\377\377\344\377\377\377\344\377\377"
"\377\353\377\377\377\365\377\377\377\374\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\370\377\377\377\367\377\377\377\371\377\377"
"\377\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\372\377\377"
"\377\372\377\377\377\371\377\377\377\370\377\377\377\364\377\377\377\362"
"\377\377\377\361\377\377\377\357\377\377\377\356\377\377\377\354\377\377"
"\377\357\377\377\377\357\377\377\377\361\377\377\377\361\377\377\377\361"
"\377\377\377\366\377\377\377\373\377\377\377\376\377\377\377\377\377\377"
"\377\377\377\377\377\375\377\377\377\374\377\377\377\376\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\376\377\377\377\376\377\377\377\374\377\377\377\376\377\377\377\377"
"\377\377\377\377\377\377\377\372\377\377\377\370\377\377\377\367\377\377"
"\377\365\377\377\377\362\377\377\377\356\377\377\377\355\377\377\377\356"
"\377\377\377\355\377\377\377\350\377\377\377\352\377\377\377\355\377\377"
"\377\354\377\377\377\355\377\377\377\363\377\377\377\374\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\372\377\377\377\371\377\377"
"\377\372\377\377\377\374\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\374\377\377"
"\377\364\377\377\377\361\377\377\377\362\377\377\377\365\377\377\377\366"
"\377\377\377\364\377\377\377\361\377\377\377\356\377\377\377\355\377\377"
"\377\353\377\377\377\361\377\377\377\360\377\377\377\356\377\377\377\362"
"\377\377\377\363\377\377\377\367\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\372\377\377\377\365\377\377\377\372"
"\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\377\377\377"
"\377\377\377\377\377\376\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\372\377\377\377\365\377\377\377\366\377\377"
"\377\366\377\377\377\364\377\377\377\363\377\377\377\361\377\377\377\360"
"\377\377\377\357\377\377\377\351\377\377\377\350\377\377\377\354\377\377"
"\377\361\377\377\377\364\377\377\377\364\377\377\377\364\377\377\377\371"
"\377\377\377\373\377\377\377\373\377\377\377\373\377\377\377\370\377\377"
"\377\371\377\377\377\374\377\377\377\375\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\373\377\377"
"\377\370\377\377\377\362\377\377\377\356\377\377\377\356\377\377\377\361"
"\377\377\377\365\377\377\377\364\377\377\377\361\377\377\377\360\377\377"
"\377\360\377\377\377\361\377\377\377\365\377\377\377\361\377\377\377\353"
"\377\377\377\357\377\377\377\365\377\377\377\372\377\377\377\376\377\377"
"\377\377\377\377\377\377\377\377\377\376\377\377\377\366\377\377\377\357"
"\377\377\377\365\377\377\377\372\377\377\377\373\377\377\377\373\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\376\377\377\377\374\377\377\377\367\377\377\377\363\377\377"
"\377\366\377\377\377\366\377\377\377\364\377\377\377\367\377\377\377\365"
"\377\377\377\362\377\377\377\363\377\377\377\353\377\377\377\353\377\377"
"\377\355\377\377\377\362\377\377\377\366\377\377\377\365\377\377\377\363"
"\377\377\377\363\377\377\377\365\377\377\377\363\377\377\377\366\377\377"
"\377\363\377\377\377\362\377\377\377\370\377\377\377\372\377\377\377\372"
"\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\375\377\377"
"\377\374\377\377\377\367\377\377\377\363\377\377\377\357\377\377\377\355"
"\377\377\377\362\377\377\377\366\377\377\377\367\377\377\377\364\377\377"
"\377\362\377\377\377\357\377\377\377\360\377\377\377\361\377\377\377\356"
"\377\377\377\347\377\377\377\350\377\377\377\357\377\377\377\366\377\377"
"\377\370\377\377\377\370\377\377\377\372\377\377\377\373\377\377\377\357"
"\377\377\377\351\377\377\377\356\377\377\377\364\377\377\377\370\377\377"
"\377\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\375\377\377\377\374\377\377\377\370\377\377"
"\377\365\377\377\377\364\377\377\377\362\377\377\377\362\377\377\377\365"
"\377\377\377\364\377\377\377\365\377\377\377\365\377\377\377\356\377\377"
"\377\353\377\377\377\356\377\377\377\364\377\377\377\366\377\377\377\365"
"\377\377\377\363\377\377\377\357\377\377\377\355\377\377\377\354\377\377"
"\377\353\377\377\377\352\377\377\377\353\377\377\377\362\377\377\377\370"
"\377\377\377\373\377\377\377\376\377\377\377\376\377\377\377\372\377\377"
"\377\374\377\377\377\375\377\377\377\372\377\377\377\366\377\377\377\362"
"\377\377\377\361\377\377\377\366\377\377\377\372\377\377\377\367\377\377"
"\377\364\377\377\377\357\377\377\377\352\377\377\377\355\377\377\377\352"
"\377\377\377\346\377\377\377\343\377\377\377\344\377\377\377\351\377\377"
"\377\355\377\377\377\355\377\377\377\356\377\377\377\362\377\377\377\364"
"\377\377\377\353\377\377\377\344\377\377\377\346\377\377\377\352\377\377"
"\377\357\377\377\377\371\377\377\377\376\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\374\377\377\377\372\377\377"
"\377\370\377\377\377\365\377\377\377\362\377\377\377\357\377\377\377\355"
"\377\377\377\355\377\377\377\354\377\377\377\362\377\377\377\365\377\377"
"\377\362\377\377\377\356\377\377\377\357\377\377\377\364\377\377\377\363"
"\377\377\377\362\377\377\377\362\377\377\377\356\377\377\377\356\377\377"
"\377\355\377\377\377\351\377\377\377\351\377\377\377\353\377\377\377\357"
"\377\377\377\370\377\377\377\373\377\377\377\374\377\377\377\375\377\377"
"\377\370\377\377\377\370\377\377\377\372\377\377\377\372\377\377\377\371"
"\377\377\377\367\377\377\377\366\377\377\377\370\377\377\377\370\377\377"
"\377\361\377\377\377\356\377\377\377\350\377\377\377\346\377\377\377\353"
"\377\377\377\347\377\377\377\337\377\377\377\342\377\377\377\346\377\377"
"\377\347\377\377\377\350\377\377\377\350\377\377\377\350\377\377\377\355"
"\377\377\377\361\377\377\377\351\377\377\377\340\377\377\377\340\377\377"
"\377\343\377\377\377\353\377\377\377\367\377\377\377\374\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\372\377\377\377\371\377\377"
"\377\370\377\377\377\372\377\377\377\372\377\377\377\363\377\377\377\356"
"\377\377\377\350\377\377\377\346\377\377\377\344\377\377\377\353\377\377"
"\377\363\377\377\377\363\377\377\377\356\377\377\377\355\377\377\377\361"
"\377\377\377\360\377\377\377\361\377\377\377\361\377\377\377\357\377\377"
"\377\360\377\377\377\361\377\377\377\360\377\377\377\355\377\377\377\353"
"\377\377\377\360\377\377\377\367\377\377\377\371\377\377\377\371\377\377"
"\377\370\377\377\377\365\377\377\377\366\377\377\377\370\377\377\377\372"
"\377\377\377\370\377\377\377\367\377\377\377\371\377\377\377\370\377\377"
"\377\365\377\377\377\355\377\377\377\344\377\377\377\337\377\377\377\341"
"\377\377\377\344\377\377\377\342\377\377\377\340\377\377\377\340\377\377"
"\377\342\377\377\377\342\377\377\377\346\377\377\377\347\377\377\377\346"
"\377\377\377\351\377\377\377\354\377\377\377\342\377\377\377\334\377\377"
"\377\337\377\377\377\344\377\377\377\360\377\377\377\370\377\377\377\371"
"\377\377\377\372\377\377\377\372\377\377\377\365\377\377\377\367\377\377"
"\377\370\377\377\377\371\377\377\377\375\377\377\377\374\377\377\377\365"
"\377\377\377\356\377\377\377\344\377\377\377\334\377\377\377\332\377\377"
"\377\342\377\377\377\354\377\377\377\354\377\377\377\350\377\377\377\350"
"\377\377\377\354\377\377\377\354\377\377\377\357\377\377\377\361\377\377"
"\377\361\377\377\377\363\377\377\377\363\377\377\377\362\377\377\377\360"
"\377\377\377\355\377\377\377\355\377\377\377\360\377\377\377\363\377\377"
"\377\365\377\377\377\363\377\377\377\365\377\377\377\367\377\377\377\367"
"\377\377\377\372\377\377\377\370\377\377\377\365\377\377\377\366\377\377"
"\377\363\377\377\377\357\377\377\377\350\377\377\377\335\377\377\377\326"
"\377\377\377\332\377\377\377\333\377\377\377\332\377\377\377\336\377\377"
"\377\333\377\377\377\340\377\377\377\347\377\377\377\352\377\377\377\347"
"\377\377\377\346\377\377\377\347\377\377\377\346\377\377\377\340\377\377"
"\377\336\377\377\377\337\377\377\377\350\377\377\377\363\377\377\377\371"
"\377\377\377\367\377\377\377\365\377\377\377\364\377\377\377\363\377\377"
"\377\366\377\377\377\366\377\377\377\367\377\377\377\373\377\377\377\373"
"\377\377\377\365\377\377\377\362\377\377\377\346\377\377\377\325\377\377"
"\377\322\377\377\377\332\377\377\377\346\377\377\377\347\377\377\377\345"
"\377\377\377\346\377\377\377\346\377\377\377\347\377\377\377\352\377\377"
"\377\353\377\377\377\360\377\377\377\365\377\377\377\365\377\377\377\365"
"\377\377\377\362\377\377\377\360\377\377\377\357\377\377\377\353\377\377"
"\377\357\377\377\377\364\377\377\377\366\377\377\377\371\377\377\377\371"
"\377\377\377\370\377\377\377\372\377\377\377\371\377\377\377\362\377\377"
"\377\362\377\377\377\357\377\377\377\351\377\377\377\344\377\377\377\330"
"\377\377\377\316\377\377\377\322\377\377\377\327\377\377\377\327\377\377"
"\377\326\377\377\377\325\377\377\377\335\377\377\377\350\377\377\377\354"
"\377\377\377\352\377\377\377\350\377\377\377\344\377\377\377\343\377\377"
"\377\340\377\377\377\344\377\377\377\346\377\377\377\356\377\377\377\366"
"\377\377\377\371\377\377\377\365\377\377\377\362\377\377\377\362\377\377"
"\377\363\377\377\377\364\377\377\377\364\377\377\377\365\377\377\377\370"
"\377\377\377\371\377\377\377\363\377\377\377\362\377\377\377\353\377\377"
"\377\336\377\377\377\325\377\377\377\330\377\377\377\343\377\377\377\344"
"\377\377\377\343\377\377\377\343\377\377\377\341\377\377\377\347\377\377"
"\377\354\377\377\377\356\377\377\377\363\377\377\377\366\377\377\377\367"
"\377\377\377\371\377\377\377\365\377\377\377\361\377\377\377\363\377\377"
"\377\355\377\377\377\356\377\377\377\364\377\377\377\372\377\377\377\374"
"\377\377\377\374\377\377\377\374\377\377\377\373\377\377\377\370\377\377"
"\377\363\377\377\377\364\377\377\377\360\377\377\377\350\377\377\377\340"
"\377\377\377\317\377\377\377\306\377\377\377\322\377\377\377\327\377\377"
"\377\325\377\377\377\324\377\377\377\326\377\377\377\334\377\377\377\344"
"\377\377\377\351\377\377\377\353\377\377\377\354\377\377\377\352\377\377"
"\377\344\377\377\377\347\377\377\377\351\377\377\377\354\377\377\377\360"
"\377\377\377\370\377\377\377\372\377\377\377\366\377\377\377\363\377\377"
"\377\361\377\377\377\364\377\377\377\370\377\377\377\370\377\377\377\371"
"\377\377\377\370\377\377\377\364\377\377\377\361\377\377\377\362\377\377"
"\377\355\377\377\377\344\377\377\377\333\377\377\377\327\377\377\377\335"
"\377\377\377\341\377\377\377\342\377\377\377\342\377\377\377\343\377\377"
"\377\352\377\377\377\360\377\377\377\364\377\377\377\366\377\377\377\370"
"\377\377\377\372\377\377\377\372\377\377\377\365\377\377\377\365\377\377"
"\377\365\377\377\377\356\377\377\377\355\377\377\377\363\377\377\377\372"
"\377\377\377\374\377\377\377\375\377\377\377\377\377\377\377\375\377\377"
"\377\373\377\377\377\367\377\377\377\365\377\377\377\361\377\377\377\346"
"\377\377\377\327\377\377\377\310\377\377\377\302\377\377\377\316\377\377"
"\377\326\377\377\377\325\377\377\377\332\377\377\377\341\377\377\377\342"
"\377\377\377\344\377\377\377\351\377\377\377\354\377\377\377\361\377\377"
"\377\361\377\377\377\353\377\377\377\357\377\377\377\356\377\377\377\356"
"\377\377\377\356\377\377\377\365\377\377\377\367\377\377\377\364\377\377"
"\377\364\377\377\377\364\377\377\377\366\377\377\377\373\377\377\377\372"
"\377\377\377\372\377\377\377\372\377\377\377\364\377\377\377\357\377\377"
"\377\356\377\377\377\347\377\377\377\335\377\377\377\333\377\377\377\325"
"\377\377\377\333\377\377\377\344\377\377\377\351\377\377\377\350\377\377"
"\377\351\377\377\377\355\377\377\377\362\377\377\377\365\377\377\377\367"
"\377\377\377\372\377\377\377\372\377\377\377\367\377\377\377\361\377\377"
"\377\365\377\377\377\366\377\377\377\362\377\377\377\356\377\377\377\363"
"\377\377\377\372\377\377\377\371\377\377\377\372\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\376\377\377\377\371\377\377\377\364"
"\377\377\377\347\377\377\377\322\377\377\377\307\377\377\377\303\377\377"
"\377\312\377\377\377\331\377\377\377\333\377\377\377\340\377\377\377\345"
"\377\377\377\347\377\377\377\350\377\377\377\353\377\377\377\357\377\377"
"\377\363\377\377\377\365\377\377\377\361\377\377\377\366\377\377\377\364"
"\377\377\377\363\377\377\377\364\377\377\377\367\377\377\377\370\377\377"
"\377\365\377\377\377\365\377\377\377\365\377\377\377\367\377\377\377\374"
"\377\377\377\373\377\377\377\374\377\377\377\374\377\377\377\366\377\377"
"\377\355\377\377\377\350\377\377\377\337\377\377\377\327\377\377\377\324"
"\377\377\377\317\377\377\377\333\377\377\377\347\377\377\377\351\377\377"
"\377\351\377\377\377\356\377\377\377\364\377\377\377\366\377\377\377\370"
"\377\377\377\372\377\377\377\372\377\377\377\370\377\377\377\366\377\377"
"\377\364\377\377\377\365\377\377\377\367\377\377\377\366\377\377\377\361"
"\377\377\377\361\377\377\377\366\377\377\377\367\377\377\377\370\377\377"
"\377\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\373"
"\377\377\377\362\377\377\377\350\377\377\377\333\377\377\377\317\377\377"
"\377\307\377\377\377\305\377\377\377\322\377\377\377\335\377\377\377\343"
"\377\377\377\351\377\377\377\354\377\377\377\354\377\377\377\356\377\377"
"\377\363\377\377\377\367\377\377\377\372\377\377\377\372\377\377\377\374"
"\377\377\377\371\377\377\377\370\377\377\377\371\377\377\377\371\377\377"
"\377\372\377\377\377\371\377\377\377\367\377\377\377\365\377\377\377\366"
"\377\377\377\372\377\377\377\373\377\377\377\376\377\377\377\376\377\377"
"\377\364\377\377\377\355\377\377\377\347\377\377\377\337\377\377\377\335"
"\377\377\377\331\377\377\377\324\377\377\377\334\377\377\377\343\377\377"
"\377\346\377\377\377\354\377\377\377\360\377\377\377\364\377\377\377\366"
"\377\377\377\370\377\377\377\373\377\377\377\370\377\377\377\364\377\377"
"\377\365\377\377\377\367\377\377\377\365\377\377\377\366\377\377\377\365"
"\377\377\377\362\377\377\377\361\377\377\377\360\377\377\377\361\377\377"
"\377\366\377\377\377\373\377\377\377\377\377\377\377\377\377\377\377\373"
"\377\377\377\364\377\377\377\353\377\377\377\350\377\377\377\342\377\377"
"\377\325\377\377\377\320\377\377\377\314\377\377\377\315\377\377\377\332"
"\377\377\377\342\377\377\377\352\377\377\377\362\377\377\377\363\377\377"
"\377\362\377\377\377\365\377\377\377\370\377\377\377\372\377\377\377\376"
"\377\377\377\372\377\377\377\372\377\377\377\367\377\377\377\371\377\377"
"\377\374\377\377\377\373\377\377\377\373\377\377\377\372\377\377\377\366"
"\377\377\377\367\377\377\377\370\377\377\377\367\377\377\377\373\377\377"
"\377\373\377\377\377\365\377\377\377\354\377\377\377\347\377\377\377\345"
"\377\377\377\343\377\377\377\336\377\377\377\336\377\377\377\342\377\377"
"\377\344\377\377\377\353\377\377\377\361\377\377\377\361\377\377\377\361"
"\377\377\377\364\377\377\377\366\377\377\377\366\377\377\377\364\377\377"
"\377\364\377\377\377\366\377\377\377\370\377\377\377\367\377\377\377\366"
"\377\377\377\365\377\377\377\365\377\377\377\365\377\377\377\362\377\377"
"\377\356\377\377\377\363\377\377\377\374\377\377\377\374\377\377\377\372"
"\377\377\377\364\377\377\377\353\377\377\377\347\377\377\377\354\377\377"
"\377\351\377\377\377\341\377\377\377\337\377\377\377\332\377\377\377\324"
"\377\377\377\327\377\377\377\340\377\377\377\351\377\377\377\363\377\377"
"\377\371\377\377\377\370\377\377\377\367\377\377\377\366\377\377\377\366"
"\377\377\377\371\377\377\377\372\377\377\377\374\377\377\377\367\377\377"
"\377\370\377\377\377\373\377\377\377\374\377\377\377\377\377\377\377\377"
"\377\377\377\374\377\377\377\373\377\377\377\367\377\377\377\363\377\377"
"\377\366\377\377\377\365\377\377\377\360\377\377\377\347\377\377\377\344"
"\377\377\377\350\377\377\377\344\377\377\377\336\377\377\377\340\377\377"
"\377\347\377\377\377\350\377\377\377\357\377\377\377\362\377\377\377\363"
"\377\377\377\365\377\377\377\362\377\377\377\361\377\377\377\361\377\377"
"\377\362\377\377\377\365\377\377\377\367\377\377\377\367\377\377\377\370"
"\377\377\377\367\377\377\377\370\377\377\377\367\377\377\377\365\377\377"
"\377\367\377\377\377\365\377\377\377\363\377\377\377\370\377\377\377\367"
"\377\377\377\365\377\377\377\361\377\377\377\351\377\377\377\347\377\377"
"\377\353\377\377\377\355\377\377\377\354\377\377\377\355\377\377\377\347"
"\377\377\377\343\377\377\377\344\377\377\377\350\377\377\377\355\377\377"
"\377\364\377\377\377\372\377\377\377\372\377\377\377\371\377\377\377\370"
"\377\377\377\370\377\377\377\367\377\377\377\372\377\377\377\370\377\377"
"\377\364\377\377\377\362\377\377\377\370\377\377\377\374\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\370\377\377\377\363\377\377"
"\377\363\377\377\377\366\377\377\377\363\377\377\377\353\377\377\377\345"
"\377\377\377\342\377\377\377\346\377\377\377\350\377\377\377\345\377\377"
"\377\344\377\377\377\350\377\377\377\352\377\377\377\361\377\377\377\364"
"\377\377\377\364\377\377\377\365\377\377\377\357\377\377\377\351\377\377"
"\377\355\377\377\377\364\377\377\377\367\377\377\377\366\377\377\377\367"
"\377\377\377\371\377\377\377\370\377\377\377\371\377\377\377\370\377\377"
"\377\366\377\377\377\371\377\377\377\372\377\377\377\365\377\377\377\365"
"\377\377\377\364\377\377\377\357\377\377\377\356\377\377\377\353\377\377"
"\377\347\377\377\377\352\377\377\377\360\377\377\377\364\377\377\377\365"
"\377\377\377\363\377\377\377\363\377\377\377\360\377\377\377\357\377\377"
"\377\362\377\377\377\371\377\377\377\374\377\377\377\374\377\377\377\374"
"\377\377\377\372\377\377\377\371\377\377\377\371\377\377\377\370\377\377"
"\377\361\377\377\377\356\377\377\377\354\377\377\377\365\377\377\377\372"
"\377\377\377\374\377\377\377\377\377\377\377\371\377\377\377\361\377\377"
"\377\361\377\377\377\361\377\377\377\362\377\377\377\364\377\377\377\363"
"\377\377\377\355\377\377\377\350\377\377\377\346\377\377\377\350\377\377"
"\377\355\377\377\377\355\377\377\377\355\377\377\377\356\377\377\377\361"
"\377\377\377\360\377\377\377\355\377\377\377\353\377\377\377\351\377\377"
"\377\345\377\377\377\347\377\377\377\357\377\377\377\365\377\377\377\367"
"\377\377\377\366\377\377\377\371\377\377\377\371\377\377\377\374\377\377"
"\377\376\377\377\377\373\377\377\377\373\377\377\377\373\377\377\377\371"
"\377\377\377\372\377\377\377\370\377\377\377\361\377\377\377\356\377\377"
"\377\353\377\377\377\353\377\377\377\361\377\377\377\365\377\377\377\370"
"\377\377\377\371\377\377\377\372\377\377\377\374\377\377\377\367\377\377"
"\377\363\377\377\377\365\377\377\377\373\377\377\377\373\377\377\377\375"
"\377\377\377\375\377\377\377\374\377\377\377\374\377\377\377\374\377\377"
"\377\370\377\377\377\355\377\377\377\347\377\377\377\352\377\377\377\363"
"\377\377\377\365\377\377\377\371\377\377\377\372\377\377\377\363\377\377"
"\377\355\377\377\377\357\377\377\377\361\377\377\377\362\377\377\377\370"
"\377\377\377\375\377\377\377\366\377\377\377\356\377\377\377\351\377\377"
"\377\347\377\377\377\356\377\377\377\361\377\377\377\356\377\377\377\355"
"\377\377\377\354\377\377\377\352\377\377\377\351\377\377\377\343\377\377"
"\377\342\377\377\377\342\377\377\377\345\377\377\377\354\377\377\377\364"
"\377\377\377\367\377\377\377\366\377\377\377\370\377\377\377\372\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375"
"\377\377\377\375\377\377\377\377\377\377\377\374\377\377\377\366\377\377"
"\377\360\377\377\377\355\377\377\377\360\377\377\377\365\377\377\377\367"
"\377\377\377\372\377\377\377\374\377\377\377\375\377\377\377\375\377\377"
"\377\374\377\377\377\372\377\377\377\371\377\377\377\371\377\377\377\373"
"\377\377\377\375\377\377\377\374\377\377\377\375\377\377\377\377\377\377"
"\377\377\377\377\377\366\377\377\377\353\377\377\377\346\377\377\377\351"
"\377\377\377\357\377\377\377\361\377\377\377\367\377\377\377\370\377\377"
"\377\363\377\377\377\356\377\377\377\357\377\377\377\365\377\377\377\367"
"\377\377\377\374\377\377\377\377\377\377\377\374\377\377\377\366\377\377"
"\377\361\377\377\377\356\377\377\377\361\377\377\377\360\377\377\377\352"
"\377\377\377\353\377\377\377\352\377\377\377\352\377\377\377\354\377\377"
"\377\343\377\377\377\337\377\377\377\337\377\377\377\346\377\377\377\356"
"\377\377\377\364\377\377\377\366\377\377\377\367\377\377\377\371\377\377"
"\377\372\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\377\377"
"\377\366\377\377\377\363\377\377\377\364\377\377\377\365\377\377\377\366"
"\377\377\377\370\377\377\377\375\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\372\377\377\377\366"
"\377\377\377\371\377\377\377\375\377\377\377\374\377\377\377\373\377\377"
"\377\375\377\377\377\375\377\377\377\361\377\377\377\345\377\377\377\343"
"\377\377\377\350\377\377\377\355\377\377\377\357\377\377\377\363\377\377"
"\377\366\377\377\377\366\377\377\377\363\377\377\377\364\377\377\377\366"
"\377\377\377\370\377\377\377\374\377\377\377\377\377\377\377\377\377\377"
"\377\375\377\377\377\370\377\377\377\365\377\377\377\365\377\377\377\360"
"\377\377\377\354\377\377\377\356\377\377\377\356\377\377\377\354\377\377"
"\377\354\377\377\377\347\377\377\377\340\377\377\377\337\377\377\377\347"
"\377\377\377\354\377\377\377\361\377\377\377\362\377\377\377\361\377\377"
"\377\365\377\377\377\372\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\370\377\377\377\367\377\377\377\367\377\377\377\366"
"\377\377\377\371\377\377\377\374\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374"
"\377\377\377\367\377\377\377\365\377\377\377\371\377\377\377\373\377\377"
"\377\372\377\377\377\372\377\377\377\370\377\377\377\356\377\377\377\340"
"\377\377\377\340\377\377\377\344\377\377\377\350\377\377\377\355\377\377"
"\377\360\377\377\377\361\377\377\377\363\377\377\377\364\377\377\377\365"
"\377\377\377\370\377\377\377\372\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\375\377\377\377\370\377\377\377\367\377\377\377\366"
"\377\377\377\361\377\377\377\354\377\377\377\354\377\377\377\356\377\377"
"\377\353\377\377\377\347\377\377\377\346\377\377\377\342\377\377\377\345"
"\377\377\377\352\377\377\377\351\377\377\377\354\377\377\377\355\377\377"
"\377\354\377\377\377\364\377\377\377\374\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\374\377\377\377\374\377\377\377\367"
"\377\377\377\365\377\377\377\371\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\375\377\377\377\372\377\377\377\366\377\377\377\365\377\377"
"\377\366\377\377\377\370\377\377\377\367\377\377\377\365\377\377\377\356"
"\377\377\377\340\377\377\377\335\377\377\377\340\377\377\377\340\377\377"
"\377\346\377\377\377\352\377\377\377\350\377\377\377\354\377\377\377\361"
"\377\377\377\364\377\377\377\372\377\377\377\375\377\377\377\376\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\374\377\377\377\372"
"\377\377\377\372\377\377\377\363\377\377\377\353\377\377\377\354\377\377"
"\377\357\377\377\377\352\377\377\377\346\377\377\377\346\377\377\377\345"
"\377\377\377\346\377\377\377\347\377\377\377\351\377\377\377\351\377\377"
"\377\347\377\377\377\351\377\377\377\363\377\377\377\372\377\377\377\374"
"\377\377\377\372\377\377\377\372\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\373\377\377\377\370\377\377\377\371\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\375\377\377\377\372\377\377\377\370\377\377\377\366\377\377"
"\377\363\377\377\377\364\377\377\377\366\377\377\377\367\377\377\377\364"
"\377\377\377\355\377\377\377\341\377\377\377\334\377\377\377\335\377\377"
"\377\333\377\377\377\336\377\377\377\337\377\377\377\335\377\377\377\346"
"\377\377\377\360\377\377\377\366\377\377\377\373\377\377\377\374\377\377"
"\377\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\364\377\377\377\353\377\377"
"\377\355\377\377\377\360\377\377\377\351\377\377\377\347\377\377\377\350"
"\377\377\377\351\377\377\377\350\377\377\377\344\377\377\377\347\377\377"
"\377\352\377\377\377\350\377\377\377\350\377\377\377\354\377\377\377\360"
"\377\377\377\361\377\377\377\356\377\377\377\364\377\377\377\374\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\375\377\377\377\375\377\377\377\375\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\374\377\377\377\372\377\377\377\371\377\377\377\366\377\377"
"\377\362\377\377\377\363\377\377\377\365\377\377\377\370\377\377\377\370"
"\377\377\377\363\377\377\377\354\377\377\377\343\377\377\377\335\377\377"
"\377\332\377\377\377\330\377\377\377\327\377\377\377\327\377\377\377\332"
"\377\377\377\344\377\377\377\355\377\377\377\367\377\377\377\373\377\377"
"\377\371\377\377\377\373\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\371\377\377\377\360\377\377"
"\377\350\377\377\377\347\377\377\377\353\377\377\377\347\377\377\377\345"
"\377\377\377\352\377\377\377\356\377\377\377\357\377\377\377\353\377\377"
"\377\350\377\377\377\353\377\377\377\353\377\377\377\346\377\377\377\345"
"\377\377\377\350\377\377\377\352\377\377\377\351\377\377\377\357\377\377"
"\377\364\377\377\377\374\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\374"
"\377\377\377\374\377\377\377\373\377\377\377\371\377\377\377\365\377\377"
"\377\361\377\377\377\355\377\377\377\362\377\377\377\365\377\377\377\366"
"\377\377\377\367\377\377\377\364\377\377\377\354\377\377\377\343\377\377"
"\377\332\377\377\377\325\377\377\377\326\377\377\377\325\377\377\377\325"
"\377\377\377\333\377\377\377\342\377\377\377\350\377\377\377\366\377\377"
"\377\374\377\377\377\372\377\377\377\372\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\372\377\377\377\366\377\377\377\357\377\377"
"\377\354\377\377\377\352\377\377\377\350\377\377\377\352\377\377\377\350"
"\377\377\377\350\377\377\377\361\377\377\377\365\377\377\377\364\377\377"
"\377\364\377\377\377\355\377\377\377\352\377\377\377\350\377\377\377\345"
"\377\377\377\344\377\377\377\344\377\377\377\345\377\377\377\346\377\377"
"\377\350\377\377\377\354\377\377\377\370\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\375\377\377\377\375\377\377\377\377\377\377\377\377\377\377\377\375"
"\377\377\377\372\377\377\377\371\377\377\377\370\377\377\377\367\377\377"
"\377\363\377\377\377\356\377\377\377\354\377\377\377\360\377\377\377\357"
"\377\377\377\357\377\377\377\362\377\377\377\363\377\377\377\344\377\377"
"\377\333\377\377\377\330\377\377\377\330\377\377\377\325\377\377\377\327"
"\377\377\377\335\377\377\377\337\377\377\377\346\377\377\377\356\377\377"
"\377\366\377\377\377\374\377\377\377\372\377\377\377\367\377\377\377\372"
"\377\377\377\375\377\377\377\372\377\377\377\363\377\377\377\352\377\377"
"\377\350\377\377\377\353\377\377\377\353\377\377\377\352\377\377\377\354"
"\377\377\377\354\377\377\377\360\377\377\377\370\377\377\377\372\377\377"
"\377\372\377\377\377\367\377\377\377\360\377\377\377\355\377\377\377\347"
"\377\377\377\342\377\377\377\341\377\377\377\340\377\377\377\340\377\377"
"\377\335\377\377\377\336\377\377\377\344\377\377\377\361\377\377\377\374"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\377\377"
"\377\372\377\377\377\372\377\377\377\372\377\377\377\374\377\377\377\377"
"\377\377\377\374\377\377\377\366\377\377\377\365\377\377\377\366\377\377"
"\377\367\377\377\377\363\377\377\377\356\377\377\377\355\377\377\377\352"
"\377\377\377\347\377\377\377\351\377\377\377\352\377\377\377\352\377\377"
"\377\341\377\377\377\325\377\377\377\325\377\377\377\333\377\377\377\327"
"\377\377\377\325\377\377\377\335\377\377\377\345\377\377\377\360\377\377"
"\377\370\377\377\377\374\377\377\377\375\377\377\377\370\377\377\377\364"
"\377\377\377\366\377\377\377\365\377\377\377\363\377\377\377\360\377\377"
"\377\346\377\377\377\345\377\377\377\347\377\377\377\352\377\377\377\354"
"\377\377\377\355\377\377\377\357\377\377\377\365\377\377\377\373\377\377"
"\377\373\377\377\377\375\377\377\377\370\377\377\377\362\377\377\377\362"
"\377\377\377\354\377\377\377\342\377\377\377\340\377\377\377\332\377\377"
"\377\325\377\377\377\325\377\377\377\330\377\377\377\337\377\377\377\352"
"\377\377\377\365\377\377\377\375\377\377\377\377\377\377\377\376\377\377"
"\377\372\377\377\377\367\377\377\377\367\377\377\377\365\377\377\377\366"
"\377\377\377\370\377\377\377\370\377\377\377\362\377\377\377\360\377\377"
"\377\362\377\377\377\363\377\377\377\355\377\377\377\347\377\377\377\347"
"\377\377\377\344\377\377\377\347\377\377\377\352\377\377\377\350\377\377"
"\377\346\377\377\377\343\377\377\377\332\377\377\377\323\377\377\377\325"
"\377\377\377\327\377\377\377\332\377\377\377\340\377\377\377\354\377\377"
"\377\371\377\377\377\375\377\377\377\377\377\377\377\376\377\377\377\370"
"\377\377\377\364\377\377\377\363\377\377\377\360\377\377\377\356\377\377"
"\377\352\377\377\377\345\377\377\377\350\377\377\377\350\377\377\377\354"
"\377\377\377\357\377\377\377\360\377\377\377\360\377\377\377\366\377\377"
"\377\374\377\377\377\376\377\377\377\377\377\377\377\370\377\377\377\365"
"\377\377\377\365\377\377\377\362\377\377\377\355\377\377\377\343\377\377"
"\377\321\377\377\377\307\377\377\377\314\377\377\377\325\377\377\377\332"
"\377\377\377\343\377\377\377\356\377\377\377\370\377\377\377\375\377\377"
"\377\375\377\377\377\371\377\377\377\364\377\377\377\362\377\377\377\360"
"\377\377\377\362\377\377\377\363\377\377\377\362\377\377\377\357\377\377"
"\377\354\377\377\377\351\377\377\377\352\377\377\377\347\377\377\377\340"
"\377\377\377\337\377\377\377\343\377\377\377\350\377\377\377\345\377\377"
"\377\343\377\377\377\344\377\377\377\337\377\377\377\337\377\377\377\333"
"\377\377\377\327\377\377\377\333\377\377\377\344\377\377\377\350\377\377"
"\377\361\377\377\377\372\377\377\377\374\377\377\377\377\377\377\377\377"
"\377\377\377\371\377\377\377\365\377\377\377\361\377\377\377\353\377\377"
"\377\353\377\377\377\347\377\377\377\347\377\377\377\355\377\377\377\353"
"\377\377\377\353\377\377\377\354\377\377\377\355\377\377\377\357\377\377"
"\377\365\377\377\377\372\377\377\377\376\377\377\377\376\377\377\377\370"
"\377\377\377\370\377\377\377\367\377\377\377\367\377\377\377\365\377\377"
"\377\346\377\377\377\321\377\377\377\312\377\377\377\311\377\377\377\312"
"\377\377\377\325\377\377\377\340\377\377\377\353\377\377\377\366\377\377"
"\377\371\377\377\377\370\377\377\377\366\377\377\377\363\377\377\377\363"
"\377\377\377\362\377\377\377\362\377\377\377\355\377\377\377\350\377\377"
"\377\347\377\377\377\350\377\377\377\345\377\377\377\341\377\377\377\334"
"\377\377\377\333\377\377\377\333\377\377\377\336\377\377\377\337\377\377"
"\377\332\377\377\377\337\377\377\377\340\377\377\377\336\377\377\377\343"
"\377\377\377\347\377\377\377\341\377\377\377\340\377\377\377\350\377\377"
"\377\355\377\377\377\366\377\377\377\372\377\377\377\375\377\377\377\377"
"\377\377\377\377\377\377\377\372\377\377\377\367\377\377\377\361\377\377"
"\377\355\377\377\377\354\377\377\377\350\377\377\377\350\377\377\377\355"
"\377\377\377\353\377\377\377\351\377\377\377\351\377\377\377\351\377\377"
"\377\356\377\377\377\362\377\377\377\371\377\377\377\376\377\377\377\375"
"\377\377\377\367\377\377\377\370\377\377\377\371\377\377\377\372\377\377"
"\377\367\377\377\377\353\377\377\377\334\377\377\377\325\377\377\377\317"
"\377\377\377\314\377\377\377\325\377\377\377\337\377\377\377\352\377\377"
"\377\363\377\377\377\367\377\377\377\365\377\377\377\365\377\377\377\366"
"\377\377\377\365\377\377\377\362\377\377\377\356\377\377\377\351\377\377"
"\377\344\377\377\377\343\377\377\377\346\377\377\377\346\377\377\377\334"
"\377\377\377\325\377\377\377\331\377\377\377\332\377\377\377\332\377\377"
"\377\330\377\377\377\322\377\377\377\330\377\377\377\335\377\377\377\336"
"\377\377\377\341\377\377\377\347\377\377\377\346\377\377\377\351\377\377"
"\377\357\377\377\377\365\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\371\377\377\377\366\377\377"
"\377\357\377\377\377\355\377\377\377\353\377\377\377\351\377\377\377\353"
"\377\377\377\355\377\377\377\353\377\377\377\351\377\377\377\353\377\377"
"\377\352\377\377\377\360\377\377\377\363\377\377\377\370\377\377\377\377"
"\377\377\377\374\377\377\377\366\377\377\377\367\377\377\377\370\377\377"
"\377\371\377\377\377\370\377\377\377\363\377\377\377\351\377\377\377\341"
"\377\377\377\332\377\377\377\324\377\377\377\330\377\377\377\337\377\377"
"\377\353\377\377\377\363\377\377\377\367\377\377\377\364\377\377\377\361"
"\377\377\377\361\377\377\377\361\377\377\377\356\377\377\377\350\377\377"
"\377\346\377\377\377\346\377\377\377\347\377\377\377\347\377\377\377\347"
"\377\377\377\340\377\377\377\337\377\377\377\342\377\377\377\337\377\377"
"\377\337\377\377\377\334\377\377\377\324\377\377\377\327\377\377\377\337"
"\377\377\377\344\377\377\377\344\377\377\377\350\377\377\377\353\377\377"
"\377\357\377\377\377\364\377\377\377\372\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\373\377\377"
"\377\370\377\377\377\362\377\377\377\356\377\377\377\352\377\377\377\353"
"\377\377\377\357\377\377\377\361\377\377\377\361\377\377\377\355\377\377"
"\377\360\377\377\377\362\377\377\377\367\377\377\377\371\377\377\377\371"
"\377\377\377\371\377\377\377\370\377\377\377\366\377\377\377\370\377\377"
"\377\370\377\377\377\370\377\377\377\371\377\377\377\371\377\377\377\362"
"\377\377\377\354\377\377\377\343\377\377\377\327\377\377\377\331\377\377"
"\377\337\377\377\377\354\377\377\377\364\377\377\377\365\377\377\377\362"
"\377\377\377\360\377\377\377\354\377\377\377\356\377\377\377\355\377\377"
"\377\350\377\377\377\344\377\377\377\350\377\377\377\353\377\377\377\350"
"\377\377\377\350\377\377\377\351\377\377\377\347\377\377\377\347\377\377"
"\377\345\377\377\377\340\377\377\377\337\377\377\377\334\377\377\377\334"
"\377\377\377\342\377\377\377\352\377\377\377\353\377\377\377\361\377\377"
"\377\364\377\377\377\364\377\377\377\370\377\377\377\372\377\377\377\376"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\375\377\377\377\370\377\377\377\364\377\377\377\360\377\377\377\356"
"\377\377\377\356\377\377\377\361\377\377\377\365\377\377\377\370\377\377"
"\377\364\377\377\377\370\377\377\377\371\377\377\377\373\377\377\377\377"
"\377\377\377\373\377\377\377\365\377\377\377\365\377\377\377\365\377\377"
"\377\365\377\377\377\370\377\377\377\374\377\377\377\373\377\377\377\371"
"\377\377\377\364\377\377\377\356\377\377\377\352\377\377\377\343\377\377"
"\377\337\377\377\377\337\377\377\377\347\377\377\377\353\377\377\377\356"
"\377\377\377\360\377\377\377\362\377\377\377\361\377\377\377\356\377\377"
"\377\354\377\377\377\352\377\377\377\352\377\377\377\353\377\377\377\355"
"\377\377\377\352\377\377\377\357\377\377\377\362\377\377\377\355\377\377"
"\377\352\377\377\377\351\377\377\377\344\377\377\377\346\377\377\377\347"
"\377\377\377\345\377\377\377\350\377\377\377\361\377\377\377\360\377\377"
"\377\365\377\377\377\370\377\377\377\371\377\377\377\373\377\377\377\372"
"\377\377\377\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\373\377\377\377\370\377\377\377\365\377\377\377\364"
"\377\377\377\363\377\377\377\362\377\377\377\363\377\377\377\370\377\377"
"\377\374\377\377\377\375\377\377\377\377\377\377\377\375\377\377\377\377"
"\377\377\377\377\377\377\377\375\377\377\377\370\377\377\377\370\377\377"
"\377\366\377\377\377\363\377\377\377\370\377\377\377\375\377\377\377\372"
"\377\377\377\365\377\377\377\361\377\377\377\352\377\377\377\352\377\377"
"\377\350\377\377\377\340\377\377\377\336\377\377\377\342\377\377\377\343"
"\377\377\377\353\377\377\377\360\377\377\377\362\377\377\377\364\377\377"
"\377\364\377\377\377\361\377\377\377\356\377\377\377\357\377\377\377\361"
"\377\377\377\356\377\377\377\354\377\377\377\364\377\377\377\370\377\377"
"\377\362\377\377\377\357\377\377\377\356\377\377\377\353\377\377\377\354"
"\377\377\377\356\377\377\377\362\377\377\377\363\377\377\377\366\377\377"
"\377\362\377\377\377\367\377\377\377\367\377\377\377\367\377\377\377\371"
"\377\377\377\367\377\377\377\371\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\376\377\377\377\372\377\377\377\370\377\377\377\371"
"\377\377\377\370\377\377\377\366\377\377\377\367\377\377\377\370\377\377"
"\377\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\377\377"
"\377\371\377\377\377\367\377\377\377\363\377\377\377\363\377\377\377\366"
"\377\377\377\363\377\377\377\361\377\377\377\356\377\377\377\346\377\377"
"\377\345\377\377\377\344\377\377\377\334\377\377\377\334\377\377\377\342"
"\377\377\377\347\377\377\377\361\377\377\377\365\377\377\377\366\377\377"
"\377\373\377\377\377\373\377\377\377\366\377\377\377\361\377\377\377\364"
"\377\377\377\370\377\377\377\364\377\377\377\357\377\377\377\365\377\377"
"\377\372\377\377\377\365\377\377\377\361\377\377\377\362\377\377\377\363"
"\377\377\377\364\377\377\377\362\377\377\377\365\377\377\377\370\377\377"
"\377\374\377\377\377\371\377\377\377\374\377\377\377\375\377\377\377\372"
"\377\377\377\371\377\377\377\373\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\376\377\377\377\372\377\377\377\371"
"\377\377\377\374\377\377\377\372\377\377\377\367\377\377\377\371\377\377"
"\377\375\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\375\377\377\377\370\377\377\377\364\377\377\377\361"
"\377\377\377\356\377\377\377\355\377\377\377\355\377\377\377\350\377\377"
"\377\342\377\377\377\342\377\377\377\337\377\377\377\331\377\377\377\331"
"\377\377\377\342\377\377\377\353\377\377\377\365\377\377\377\371\377\377"
"\377\374\377\377\377\377\377\377\377\373\377\377\377\365\377\377\377\364"
"\377\377\377\370\377\377\377\372\377\377\377\373\377\377\377\370\377\377"
"\377\370\377\377\377\372\377\377\377\371\377\377\377\371\377\377\377\371"
"\377\377\377\374\377\377\377\377\377\377\377\372\377\377\377\370\377\377"
"\377\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\375\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374"
"\377\377\377\371\377\377\377\372\377\377\377\373\377\377\377\370\377\377"
"\377\370\377\377\377\372\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\372\377\377\377\365"
"\377\377\377\365\377\377\377\361\377\377\377\354\377\377\377\350\377\377"
"\377\342\377\377\377\337\377\377\377\343\377\377\377\335\377\377\377\330"
"\377\377\377\330\377\377\377\340\377\377\377\353\377\377\377\365\377\377"
"\377\373\377\377\377\373\377\377\377\373\377\377\377\372\377\377\377\370"
"\377\377\377\371\377\377\377\374\377\377\377\374\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\376\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\373\377\377\377\371\377\377\377\366\377\377"
"\377\366\377\377\377\365\377\377\377\367\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\373"
"\377\377\377\371\377\377\377\370\377\377\377\365\377\377\377\355\377\377"
"\377\347\377\377\377\347\377\377\377\347\377\377\377\350\377\377\377\346"
"\377\377\377\341\377\377\377\336\377\377\377\345\377\377\377\357\377\377"
"\377\367\377\377\377\371\377\377\377\371\377\377\377\371\377\377\377\370"
"\377\377\377\372\377\377\377\375\377\377\377\376\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\374\377\377\377\371\377\377"
"\377\362\377\377\377\362\377\377\377\361\377\377\377\365\377\377\377\376"
"\377\377\377\377\377\377\377\375\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\376\377\377\377\374\377\377\377\374\377\377\377\370\377\377"
"\377\364\377\377\377\361\377\377\377\362\377\377\377\361\377\377\377\356"
"\377\377\377\355\377\377\377\352\377\377\377\346\377\377\377\350\377\377"
"\377\360\377\377\377\366\377\377\377\367\377\377\377\366\377\377\377\370"
"\377\377\377\372\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\372\377\377"
"\377\367\377\377\377\362\377\377\377\361\377\377\377\361\377\377\377\361"
"\377\377\377\366\377\377\377\371\377\377\377\373\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\375\377\377"
"\377\374\377\377\377\374\377\377\377\373\377\377\377\373\377\377\377\372"
"\377\377\377\367\377\377\377\363\377\377\377\362\377\377\377\362\377\377"
"\377\363\377\377\377\364\377\377\377\367\377\377\377\371\377\377\377\367"
"\377\377\377\372\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\372\377\377\377\372\377\377\377\365\377\377\377\360\377\377\377\362"
"\377\377\377\361\377\377\377\361\377\377\377\366\377\377\377\370\377\377"
"\377\372\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\376\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\375\377\377\377\372\377\377\377\367\377\377"
"\377\370\377\377\377\372\377\377\377\373\377\377\377\372\377\377\377\372"
"\377\377\377\372\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\372\377\377\377\363"
"\377\377\377\362\377\377\377\363\377\377\377\364\377\377\377\367\377\377"
"\377\363\377\377\377\361\377\377\377\372\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\374\377\377"
"\377\372\377\377\377\372\377\377\377\375\377\377\377\377\377\377\377\375"
"\377\377\377\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\376"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\371\377\377\377\364\377\377\377\367\377\377\377\366\377\377"
"\377\362\377\377\377\360\377\377\377\361\377\377\377\367\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\375\377\377\377\375\377\377\377\376\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\374\377\377\377\374\377\377\377\374\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\376"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\375\377\377\377\372\377\377\377\372\377\377"
"\377\364\377\377\377\355\377\377\377\355\377\377\377\363\377\377\377\372"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375\377\377"
"\377\374\377\377\377\374\377\377\377\373\377\377\377\372\377\377\377\374"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\375\377\377\377\375\377\377\377\376\377\377\377\376"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375\377\377"
"\377\367\377\377\377\363\377\377\377\361\377\377\377\360\377\377\377\365"
"\377\377\377\372\377\377\377\377\377\377\377\377\377\377\377\376\377\377"
"\377\371\377\377\377\366\377\377\377\367\377\377\377\364\377\377\377\364"
"\377\377\377\371\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\373\377\377\377\361\377\377\377\361\377\377\377\365\377\377\377\366"
"\377\377\377\370\377\377\377\372\377\377\377\373\377\377\377\375\377\377"
"\377\374\377\377\377\372\377\377\377\370\377\377\377\366\377\377\377\364"
"\377\377\377\364\377\377\377\366\377\377\377\375\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\377\377"
"\377\370\377\377\377\376\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\371\377\377\377\364\377\377\377\362\377\377\377\366"
"\377\377\377\370\377\377\377\370\377\377\377\370\377\377\377\371\377\377"
"\377\372\377\377\377\371\377\377\377\371\377\377\377\366\377\377\377\364"
"\377\377\377\364\377\377\377\366\377\377\377\370\377\377\377\373\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\375\377\377\377\373\377\377"
"\377\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\376\377\377\377\374\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\377\377"
"\377\372\377\377\377\373\377\377\377\377\377\377\377\377\377\377\377\376"
"\377\377\377\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\373\377\377\377\367\377\377\377\366\377\377\377\370"
"\377\377\377\373\377\377\377\372\377\377\377\365\377\377\377\364\377\377"
"\377\364\377\377\377\370\377\377\377\371\377\377\377\371\377\377\377\370"
"\377\377\377\366\377\377\377\363\377\377\377\366\377\377\377\373\377\377"
"\377\375\377\377\377\375\377\377\377\376\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\367\377\377\377\361\377\377"
"\377\362\377\377\377\366\377\377\377\366\377\377\377\372\377\377\377\376"
"\377\377\377\375\377\377\377\374\377\377\377\375\377\377\377\375\377\377"
"\377\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\372\377\377\377\375\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\374\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\375\377\377\377\372\377\377\377\366\377\377\377\367"
"\377\377\377\371\377\377\377\373\377\377\377\374\377\377\377\371\377\377"
"\377\364\377\377\377\361\377\377\377\362\377\377\377\361\377\377\377\363"
"\377\377\377\367\377\377\377\370\377\377\377\365\377\377\377\365\377\377"
"\377\372\377\377\377\376\377\377\377\375\377\377\377\374\377\377\377\374"
"\377\377\377\375\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\370\377\377\377\356\377\377"
"\377\353\377\377\377\351\377\377\377\347\377\377\377\351\377\377\377\362"
"\377\377\377\372\377\377\377\370\377\377\377\364\377\377\377\370\377\377"
"\377\375\377\377\377\372\377\377\377\372\377\377\377\376\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377\375\377\377"
"\377\372\377\377\377\370\377\377\377\370\377\377\377\372\377\377\377\370"
"\377\377\377\365\377\377\377\366\377\377\377\370\377\377\377\374\377\377"
"\377\374\377\377\377\371\377\377\377\363\377\377\377\356\377\377\377\351"
"\377\377\377\354\377\377\377\360\377\377\377\362\377\377\377\363\377\377"
"\377\364\377\377\377\371\377\377\377\374\377\377\377\374\377\377\377\373"
"\377\377\377\372\377\377\377\371\377\377\377\376\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\364\377\377"
"\377\353\377\377\377\347\377\377\377\343\377\377\377\335\377\377\377\336"
"\377\377\377\351\377\377\377\361\377\377\377\361\377\377\377\361\377\377"
"\377\363\377\377\377\370\377\377\377\370\377\377\377\366\377\377\377\367"
"\377\377\377\374",
};
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vrml_aux.cpp
*/
#include "vrml_aux.h"
char SkipGetChar ( FILE* File )
{
char c;
bool re_parse;
if( (c = fgetc( File )) == EOF )
{
//DBG( printf( "EOF\n" ) );
return EOF;
}
//DBG( printf( "c %c 0x%02X\n", c, c ) );
do
{
re_parse = false;
if ((c == ' ') || (c == '\t') || (c == '{') || (c == '['))
{
//DBG( printf( "Skipping space \\t or { or [\n" ) );
do
{
if( (c = fgetc( File )) == EOF )
{
//DBG( printf( "EOF\n" ) );
return EOF;
}
}
while((c == ' ') || (c == '\t') || (c == '{') || (c == '['));
}
if ((c == '#') || (c == '\n') || (c == '\r') || (c == 0) || (c == ','))
{
if (c == '#')
{
//DBG( printf( "Skipping # \\n or \\r or 0, 0x%02X\n", c ) );
do
{
if( (c = fgetc( File )) == EOF )
{
//DBG( printf( "EOF\n" ) );
return EOF;
}
}
while((c != '\n') && (c != '\r') && (c != 0) && (c != ','));
}
else
{
if( (c = fgetc( File )) == EOF )
{
//DBG( printf( "EOF\n" ) );
return EOF;
}
}
re_parse = true;
}
}while(re_parse == true);
return c;
}
char* GetNextTag( FILE* File, char* tag )
{
char c = SkipGetChar( File );
if (c == EOF)
{
return NULL;
}
tag[0] = c;
tag[1] = 0;
//DBG( printf( "tag[0] %c\n", tag[0] ) );
if( (c != '}') && (c != ']') )
{
char *dst = &tag[1];
while (fscanf( File, "%c", dst))
{
if( (*dst == ' ') || (*dst == '[') || (*dst == '{') || (*dst == '\t') || (*dst == '\n')|| (*dst == '\r') )
{
*dst = 0;
break;
}
dst++;
}
//DBG( printf( "tag %s\n", tag ) );
c = SkipGetChar( File );
if (c != EOF)
{
// Puts again the read char in the buffer
ungetc( c, File );
}
}
return tag;
}
int read_NotImplemented( FILE* File, char closeChar)
{
char c;
//DBG( printf( "look for %c\n", closeChar) );
while( (c = fgetc( File )) != EOF )
{
if( c == '{' )
{
//DBG( printf( "{\n") );
read_NotImplemented( File, '}' );
} else if( c == '[' )
{
//DBG( printf( "[\n") );
read_NotImplemented( File, ']' );
} else if( c == closeChar )
{
//DBG( printf( "%c\n", closeChar) );
return 0;
}
}
DBG( printf( " NotImplemented failed\n" ) );
return -1;
}
int parseVertexList( FILE* File, std::vector< glm::vec3 > &dst_vector)
{
//DBG( printf( " parseVertexList\n" ) );
dst_vector.clear();
glm::vec3 vertex;
while( parseVertex ( File, vertex ) == 3 )
{
dst_vector.push_back( vertex );
}
return 0;
}
int parseVertex( FILE* File, glm::vec3 &dst_vertex )
{
float a,b,c;
int ret = fscanf( File, "%e %e %e", &a, &b, &c );
dst_vertex.x = a;
dst_vertex.y = b;
dst_vertex.z = c;
char s = SkipGetChar( File );
if (s != EOF)
{
// Puts again the read char in the buffer
ungetc( s, File );
}
//DBG( printf( "ret%d(%.9f,%.9f,%.9f)", ret, a,b,c) );
return ret;
}
int parseFloat( FILE* File, float *dst_float )
{
float value;
int ret = fscanf( File, "%e", &value );
*dst_float = value;
return ret;
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vrml_aux.h
*/
#ifndef _VRML_AUX_H
#define _VRML_AUX_H
#include <fctsys.h>
#include <common.h>
#include <macros.h>
#include <base_struct.h>
#include <gal/opengl/glm/glm.hpp>
#include <vector>
#include <kicad_string.h>
#include <info3d_visu.h>
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
#include <wx/glcanvas.h>
int read_NotImplemented( FILE* File, char closeChar);
char SkipGetChar ( FILE* File );
int parseVertexList( FILE* File, std::vector< glm::vec3 > &dst_vector);
int parseVertex( FILE* File, glm::vec3 &dst_vertex );
int parseFloat( FILE* File, float *dst_float );
char* GetNextTag( FILE* File, char* tag );
#endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vrml_v1_modelparser.cpp
*/
#include <fctsys.h>
#include <vector>
#include <macros.h>
#include <kicad_string.h>
#include <info3d_visu.h>
#include "3d_struct.h"
#include "modelparsers.h"
#include "vrml_aux.h"
VRML1_MODEL_PARSER::VRML1_MODEL_PARSER( S3D_MASTER* aMaster ) :
S3D_MODEL_PARSER( aMaster )
{
m_model = NULL;
m_file = NULL;
}
VRML1_MODEL_PARSER::~VRML1_MODEL_PARSER()
{
for( unsigned int idx = 0; idx < childs.size(); idx++ )
{
delete childs[idx];
}
}
void VRML1_MODEL_PARSER::Load( const wxString aFilename )
{
char text[128];
//DBG( printf( "Load %s\n", static_cast<const char*>(aFilename.mb_str()) ) );
m_file = wxFopen( aFilename, wxT( "rt" ) );
if( m_file == NULL )
{
return;
}
glShadeModel( GL_SMOOTH );
glEnable( GL_NORMALIZE );
glm::vec3 matScale( GetMaster()->m_MatScale.x, GetMaster()->m_MatScale.y, GetMaster()->m_MatScale.z );
glm::vec3 matRot( GetMaster()->m_MatRotation.x, GetMaster()->m_MatRotation.y, GetMaster()->m_MatRotation.z );
glm::vec3 matPos( GetMaster()->m_MatPosition.x, GetMaster()->m_MatPosition.y, GetMaster()->m_MatPosition.z );
#define SCALE_3D_CONV ((IU_PER_MILS * 1000.0f) / UNITS3D_TO_UNITSPCB)
//glPushMatrix();
glTranslatef( matPos.x * SCALE_3D_CONV, matPos.y * SCALE_3D_CONV, matPos.z * SCALE_3D_CONV );
glRotatef( matRot.z, 0.0f, 0.0f, 1.0f );
glRotatef( matRot.y, 0.0f, 1.0f, 0.0f );
glRotatef( matRot.x, 1.0f, 0.0f, 0.0f );
glScalef( matScale.x, matScale.y, matScale.z );
float vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
glScalef( vrmlunits_to_3Dunits, vrmlunits_to_3Dunits, vrmlunits_to_3Dunits );
// Switch the locale to standard C (needed to print floating point numbers like 1.3)
SetLocaleTo_C_standard();
childs.clear();
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == '}' ) || ( *text == ']' ) )
{
continue;
}
if( strcmp( text, "Separator" ) == 0 )
{
m_model = new S3D_MESH();
childs.push_back( m_model );
read_separator();
}
}
fclose( m_file );
SetLocaleTo_Default(); // revert to the current locale
//DBG( printf( "chils size:%lu\n", childs.size() ) );
if( GetMaster()->IsOpenGlAllowed() )
{
for( unsigned int idx = 0; idx < childs.size(); idx++ )
{
childs[idx]->openGL_RenderAllChilds();
}
}
}
int VRML1_MODEL_PARSER::read_separator()
{
char text[128];
//DBG( printf( "Separator\n" ) );
while( GetNextTag( m_file, text) )
{
if( strcmp( text, "Material" ) == 0 )
{
readMaterial( );
} else if( strcmp( text, "Coordinate3" ) == 0 )
{
readCoordinate3();
} else if( strcmp( text, "IndexedFaceSet" ) == 0 )
{
readIndexedFaceSet();
} else if( strcmp( text, "Separator" ) == 0 )
{
S3D_MESH *parent = m_model;
S3D_MESH *new_mesh_model = new S3D_MESH();
m_model->childs.push_back( new_mesh_model );
m_model = new_mesh_model;
// recursive
read_separator();
m_model = parent;
}else if ( ( *text != '}' ) )
{
//DBG( printf( "read_NotImplemented %s\n", text ) );
read_NotImplemented( m_file, '}');
} else
{
break;
}
}
return 0;
}
int VRML1_MODEL_PARSER::readMaterial()
{
char text[128];
S3D_MATERIAL* material = NULL;
//DBG( printf( " readMaterial\n" ) );
wxString mat_name;
material = new S3D_MATERIAL( GetMaster(), mat_name );
GetMaster()->Insert( material );
m_model->m_Materials = material;
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
return 0;
}
if( strcmp( text, "ambientColor" ) == 0 )
{
readMaterial_ambientColor();
} else if( strcmp( text, "diffuseColor" ) == 0 )
{
readMaterial_diffuseColor( );
} else if( strcmp( text, "emissiveColor" ) == 0 )
{
readMaterial_emissiveColor( );
}else if( strcmp( text, "specularColor" ) == 0 )
{
readMaterial_specularColor( );
}else if( strcmp( text, "shininess" ) == 0 )
{
readMaterial_shininess( );
}else if( strcmp( text, "transparency" ) == 0 )
{
readMaterial_transparency( );
}
}
return -1;
}
int VRML1_MODEL_PARSER::readCoordinate3( )
{
char text[128];
//DBG( printf( " readCoordinate3\n" ) );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
return 0;
}
if( strcmp( text, "point" ) == 0 )
{
readCoordinate3_point( );
}
}
return -1;
}
int VRML1_MODEL_PARSER::readIndexedFaceSet( )
{
char text[128];
//DBG( printf( " readIndexedFaceSet\n" ) );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
return 0;
}
if( strcmp( text, "coordIndex" ) == 0 )
{
readIndexedFaceSet_coordIndex( );
} else if( strcmp( text, "materialIndex" ) == 0 )
{
readIndexedFaceSet_materialIndex( );
}
}
return -1;
}
int VRML1_MODEL_PARSER::readMaterial_ambientColor( )
{
//DBG( printf( " readMaterial_ambientColor\n" ) );
return parseVertexList( m_file, m_model->m_Materials->m_AmbientColor);
}
int VRML1_MODEL_PARSER::readMaterial_diffuseColor( )
{
//DBG( printf( " readMaterial_diffuseColor\n" ) );
return parseVertexList( m_file, m_model->m_Materials->m_DiffuseColor);
}
int VRML1_MODEL_PARSER::readMaterial_emissiveColor( )
{
//DBG( printf( " readMaterial_emissiveColor\n" ) );
int ret = parseVertexList( m_file, m_model->m_Materials->m_EmissiveColor);
if( GetMaster()->m_use_modelfile_emissiveColor == false)
{
m_model->m_Materials->m_EmissiveColor.clear();
}
return ret;
}
int VRML1_MODEL_PARSER::readMaterial_specularColor()
{
//DBG( printf( " readMaterial_specularColor\n" ) );
int ret = parseVertexList( m_file, m_model->m_Materials->m_SpecularColor );
if( GetMaster()->m_use_modelfile_specularColor == false)
{
m_model->m_Materials->m_SpecularColor.clear();
}
return ret;
}
int VRML1_MODEL_PARSER::readMaterial_shininess( )
{
//DBG( printf( " readMaterial_shininess\n" ) );
m_model->m_Materials->m_Shininess.clear();
float shininess_value;
while( fscanf( m_file, "%f,", &shininess_value ) )
{
// VRML value is normalized and openGL expects a value 0 - 128
shininess_value = shininess_value * 128.0f;
m_model->m_Materials->m_Shininess.push_back( shininess_value );
}
if( GetMaster()->m_use_modelfile_shininess == false )
{
m_model->m_Materials->m_Shininess.clear();
}
//DBG( printf( " m_Shininess.size: %ld\n", m_model->m_Materials->m_Shininess.size() ) );
return 0;
}
int VRML1_MODEL_PARSER::readMaterial_transparency()
{
//DBG( printf( " readMaterial_transparency\n" ) );
m_model->m_Materials->m_Transparency.clear();
float tmp;
while( fscanf (m_file, "%f,", &tmp) )
{
m_model->m_Materials->m_Transparency.push_back( tmp );
}
if( GetMaster()->m_use_modelfile_transparency == false )
{
m_model->m_Materials->m_Transparency.clear();
}
//DBG( printf( " m_Transparency.size: %ld\n", m_model->m_Materials->m_Transparency.size() ) );
return 0;
}
int VRML1_MODEL_PARSER::readCoordinate3_point()
{
//DBG( printf( " readCoordinate3_point\n" ) );
if( parseVertexList( m_file, m_model->m_Point ) == 0 )
{
return 0;
}
return -1;
}
int VRML1_MODEL_PARSER::readIndexedFaceSet_coordIndex()
{
//DBG( printf( " readIndexedFaceSet_coordIndex\n" ) );
m_model->m_CoordIndex.clear();
glm::ivec3 coord;
int dummy; // should be -1
while( fscanf( m_file, "%d,%d,%d,%d,", &coord[0], &coord[1], &coord[2], &dummy ) )
{
std::vector<int> coord_list;
coord_list.resize( 3 );
coord_list[0] = coord[0];
coord_list[1] = coord[1];
coord_list[2] = coord[2];
if( (coord[0] == coord[1]) ||
(coord[0] == coord[2]) ||
(coord[2] == coord[1]) )
{
//DBG( printf( " invalid coordIndex at index %lu (%d, %d, %d, %d)\n", m_model->m_CoordIndex.size()+1,coord[0], coord[1], coord[2], dummy ) );
}
if (dummy != -1)
{
//DBG( printf( " Error at index %lu, -1 Expected, got %d\n", m_model->m_CoordIndex.size()+1, dummy ) );
}
m_model->m_CoordIndex.push_back( coord_list );
}
//DBG( printf( " m_CoordIndex.size: %ld\n", m_model->m_CoordIndex.size() ) );
return 0;
}
int VRML1_MODEL_PARSER::readIndexedFaceSet_materialIndex()
{
//DBG( printf( " readIndexedFaceSet_materialIndex\n" ) );
m_model->m_MaterialIndex.clear();
int index;
while( fscanf( m_file, "%d,", &index ) )
{
m_model->m_MaterialIndex.push_back( index );
}
//DBG( printf( " m_MaterialIndex.size: %ld\n", m_model->m_MaterialIndex.size() ) );
return 0;
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 2013 Tuomas Vaherkoski <tuomasvaherkoski@gmail.com>
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras@wanadoo.fr
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vrml_v2_modelparser.cpp
*/
#include <fctsys.h>
#include <vector>
#include <macros.h>
#include <kicad_string.h>
#include <info3d_visu.h>
#include "3d_struct.h"
#include "modelparsers.h"
#include "vrml_aux.h"
VRML2_MODEL_PARSER::VRML2_MODEL_PARSER( S3D_MASTER* aMaster ) :
S3D_MODEL_PARSER( aMaster )
{
m_model = NULL;
}
VRML2_MODEL_PARSER::~VRML2_MODEL_PARSER()
{
for(unsigned int idx = 0; idx < childs.size(); idx++)
{
delete childs[idx];
}
}
void VRML2_MODEL_PARSER::Load( const wxString aFilename )
{
char text[128];
//DBG( printf( "Load %s\n", static_cast<const char*>(aFilename.mb_str()) ) );
m_file = wxFopen( aFilename, wxT( "rt" ) );
if( m_file == NULL )
{
return;
}
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
glm::vec3 matScale( GetMaster()->m_MatScale.x, GetMaster()->m_MatScale.y, GetMaster()->m_MatScale.z );
glm::vec3 matRot( GetMaster()->m_MatRotation.x, GetMaster()->m_MatRotation.y, GetMaster()->m_MatRotation.z );
glm::vec3 matPos( GetMaster()->m_MatPosition.x, GetMaster()->m_MatPosition.y, GetMaster()->m_MatPosition.z );
#define SCALE_3D_CONV ((IU_PER_MILS * 1000.0f) / UNITS3D_TO_UNITSPCB)
//glPushMatrix();
glTranslatef( matPos.x * SCALE_3D_CONV, matPos.y * SCALE_3D_CONV, matPos.z * SCALE_3D_CONV );
glRotatef( matRot.z, 0.0f, 0.0f, 1.0f );
glRotatef( matRot.y, 0.0f, 1.0f, 0.0f );
glRotatef( matRot.x, 1.0f, 0.0f, 0.0f );
glScalef( matScale.x, matScale.y, matScale.z );
float vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
glScalef( vrmlunits_to_3Dunits, vrmlunits_to_3Dunits, vrmlunits_to_3Dunits );
// Switch the locale to standard C (needed to print floating point numbers like 1.3)
SetLocaleTo_C_standard();
childs.clear();
while( GetNextTag( m_file, text ) )
{
if( ( text == NULL ) || ( *text == '}' ) || ( *text == ']' ) )
{
continue;
}
if( strcmp( text, "Transform" ) == 0 )
{
m_model = new S3D_MESH();
childs.push_back( m_model );
read_Transform();
} else if( strcmp( text, "DEF" ) == 0 )
{
m_model = new S3D_MESH();
childs.push_back( m_model );
read_DEF();
}
}
fclose( m_file );
SetLocaleTo_Default(); // revert to the current locale
//DBG( printf( "chils size:%lu\n", childs.size() ) );
if( GetMaster()->IsOpenGlAllowed() )
{
for( unsigned int idx = 0; idx < childs.size(); idx++ )
{
childs[idx]->openGL_RenderAllChilds();
}
}
}
int VRML2_MODEL_PARSER::read_Transform()
{
char text[128];
///DBG( printf( "Transform\n" ) );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
//DBG( printf( " } Exit Transform\n" ) );
break;
}
if( strcmp( text, "translation" ) == 0 )
{
parseVertex( m_file, m_model->m_translation );
} else if( strcmp( text, "rotation" ) == 0 )
{
fscanf( m_file, "%f %f %f %f", &m_model->m_rotation[0], &m_model->m_rotation[1], &m_model->m_rotation[2], &m_model->m_rotation[3]);
m_model->m_rotation[3] = m_model->m_rotation[3] * 180.0f / 3.14f; // !TODO: use constants or functions
} else if( strcmp( text, "scale" ) == 0 )
{
parseVertex( m_file, m_model->m_scale );
} else if( strcmp( text, "scaleOrientation" ) == 0 )
{
fscanf( m_file, "%f %f %f %f", &m_model->m_scaleOrientation[0], &m_model->m_scaleOrientation[1], &m_model->m_scaleOrientation[2], &m_model->m_scaleOrientation[3]);
} else if( strcmp( text, "center" ) == 0 )
{
parseVertex( m_file, m_model->m_center );
} else if( strcmp( text, "children" ) == 0 )
{
// skip
} else if( strcmp( text, "Switch" ) == 0 )
{
// skip
} else if( strcmp( text, "whichChoice" ) == 0 )
{
int dummy;
fscanf( m_file, "%d", &dummy );
} else if( strcmp( text, "choice" ) == 0 )
{
// skip
} else if( strcmp( text, "Group" ) == 0 )
{
// skip
} else if( strcmp( text, "Shape" ) == 0 )
{
S3D_MESH *parent = m_model;
S3D_MESH *new_mesh_model = new S3D_MESH();
m_model->childs.push_back( new_mesh_model );
m_model = new_mesh_model;
read_Shape();
m_model = parent;
} else if( strcmp( text, "DEF" ) == 0 )
{
read_DEF();
} else
{
//DBG( printf( " %s NotImplemented\n", text ) );
read_NotImplemented( m_file, '}' );
}
}
return 0;
}
int VRML2_MODEL_PARSER::read_DEF()
{
char text[128];
GetNextTag( m_file, text);
//DBG( printf( "DEF %s ", text ) );
while( GetNextTag( m_file, text ) )
{
if( ( text == NULL ) || ( *text == ']' ) )
{
//DBG( printf( " skiping %c\n", *text) );
continue;
}
if( ( *text == '}' ) )
{
//DBG( printf( " } Exit DEF\n") );
return 0;
}
if( strcmp( text, "Transform" ) == 0 )
{
return read_Transform ();
} else if( strcmp( text, "children" ) == 0 )
{
// skip
} else if( strcmp( text, "Switch" ) == 0 )
{
// skip
} else if( strcmp( text, "whichChoice" ) == 0 )
{
// skip
} else if( strcmp( text, "choice" ) == 0 )
{
// skip
}else if( strcmp( text, "Shape" ) == 0 )
{
S3D_MESH *parent = m_model;
S3D_MESH *new_mesh_model = new S3D_MESH();
m_model->childs.push_back( new_mesh_model );
m_model = new_mesh_model;
read_Shape();
m_model = parent;
}
}
//DBG( printf( " DEF failed\n" ) );
return -1;
}
int VRML2_MODEL_PARSER::read_Shape()
{
char text[128];
//DBG( printf( " Shape\n") );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
//DBG( printf( " } Exit Shape\n") );
return 0;
}
if( strcmp( text, "appearance" ) == 0 )
{
//skip
} else if( strcmp( text, "Appearance" ) == 0 )
{
read_Appearance();
} else if( strcmp( text, "geometry" ) == 0 )
{
//skip
} else if( strcmp( text, "IndexedFaceSet" ) == 0 )
{
read_IndexedFaceSet();
} else
{
//DBG( printf( " %s NotImplemented\n", text ) );
read_NotImplemented( m_file, '}' );
}
}
//DBG( printf( " Shape failed\n") );
return -1;
}
int VRML2_MODEL_PARSER::read_Appearance()
{
char text[128];
//DBG( printf( " Appearance\n") );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
return 0;
}
if( strcmp( text, "material" ) == 0 )
{
read_material();
}
}
//DBG( printf( " Appearance failed\n") );
return -1;
}
int VRML2_MODEL_PARSER::read_material()
{
S3D_MATERIAL* material = NULL;
char text[128];
//DBG( printf( " material ") );
if( GetNextTag( m_file, text ) )
{
if( strcmp( text, "Material" ) == 0 )
{
wxString mat_name;
material = new S3D_MATERIAL( GetMaster(), mat_name );
GetMaster()->Insert( material );
m_model->m_Materials = material;
if( strcmp( text, "Material" ) == 0 )
{
return read_Material();
}
} else if( strcmp( text, "DEF" ) == 0 )
{
//DBG( printf( "DEF") );
if( GetNextTag( m_file, text ) )
{
//DBG( printf( "%s", text ) );
wxString mat_name;
mat_name = FROM_UTF8( text );
material = new S3D_MATERIAL( GetMaster(), mat_name );
GetMaster()->Insert( material );
m_model->m_Materials = material;
if( GetNextTag( m_file, text ) )
{
if( strcmp( text, "Material" ) == 0 )
{
return read_Material();
}
}
}
} else if( strcmp( text, "USE" ) == 0 )
{
//DBG( printf( "USE") );
if( GetNextTag( m_file, text ) )
{
//DBG( printf( "%s\n", text ) );
wxString mat_name;
mat_name = FROM_UTF8( text );
for( material = GetMaster()->m_Materials; material; material = material->Next() )
{
if( material->m_Name == mat_name )
{
m_model->m_Materials = material;
return 0;
}
}
//DBG( printf( " read_material error: material not found\n" ) );
}
}
}
//DBG( printf( " failed material\n") );
return -1;
}
int VRML2_MODEL_PARSER::read_Material()
{
char text[128];
glm::vec3 vertex;
//DBG( printf( " Material\n") );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
return 0;
}
if( strcmp( text, "diffuseColor" ) == 0 )
{
//DBG( printf( " diffuseColor") );
parseVertex ( m_file, vertex);
//DBG( printf( "\n") );
m_model->m_Materials->m_DiffuseColor.push_back( vertex );
} else if( strcmp( text, "emissiveColor" ) == 0 )
{
//DBG( printf( " emissiveColor") );
parseVertex ( m_file, vertex);
//DBG( printf( "\n") );
if( GetMaster()->m_use_modelfile_emissiveColor == true )
{
m_model->m_Materials->m_EmissiveColor.push_back( vertex );
}
} else if( strcmp( text, "specularColor" ) == 0 )
{
//DBG( printf( " specularColor") );
parseVertex ( m_file, vertex);
//DBG( printf( "\n") );
if( GetMaster()->m_use_modelfile_specularColor == true )
{
m_model->m_Materials->m_SpecularColor.push_back( vertex );
}
} else if( strcmp( text, "ambientIntensity" ) == 0 )
{
float ambientIntensity;
parseFloat( m_file, &ambientIntensity );
//DBG( printf( " ambientIntensity %f\n", ambientIntensity) );
if( GetMaster()->m_use_modelfile_ambientIntensity == true )
{
m_model->m_Materials->m_AmbientColor.push_back( glm::vec3( ambientIntensity, ambientIntensity, ambientIntensity ) );
}
} else if( strcmp( text, "transparency" ) == 0 )
{
float transparency;
parseFloat( m_file, &transparency );
//DBG( printf( " transparency %f\n", transparency) );
if( GetMaster()->m_use_modelfile_transparency == true )
{
m_model->m_Materials->m_Transparency.push_back( transparency );
}
} else if( strcmp( text, "shininess" ) == 0 )
{
float shininess;
parseFloat( m_file, &shininess );
//DBG( printf( " shininess %f\n", shininess) );
// VRML value is normalized and openGL expects a value 0 - 128
if( GetMaster()->m_use_modelfile_shininess == true )
{
shininess = shininess * 128.0f;
m_model->m_Materials->m_Shininess.push_back( shininess );
}
}
}
DBG( printf( " Material failed\n") );
return -1;
}
int VRML2_MODEL_PARSER::read_IndexedFaceSet()
{
char text[128];
//DBG( printf( " IndexedFaceSet\n") );
m_normalPerVertex = false;
colorPerVertex = false;
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
//DBG( printf( " } Exit IndexedFaceSet\n") );
return 0;
}
if( strcmp( text, "normalPerVertex" ) == 0 )
{
if( GetNextTag( m_file, text ) )
{
if( strcmp( text, "TRUE" ) == 0 )
{
//DBG( printf( " m_normalPerVertex TRUE\n") );
m_normalPerVertex = true;
}
}
} else if( strcmp( text, "colorPerVertex" ) == 0 )
{
GetNextTag( m_file, text );
if( strcmp( text, "TRUE" ) )
{
//DBG( printf( " colorPerVertex = true\n") );
colorPerVertex = true;
} else
{
colorPerVertex = false;
}
} else if( strcmp( text, "Coordinate" ) == 0 )
{
read_Coordinate();
} else if( strcmp( text, "Normal" ) == 0 )
{
//read_Normal();
read_NotImplemented( m_file, '}' );
} else if( strcmp( text, "normalIndex" ) == 0 )
{
//DBG( printf( " normalIndex NotImplemented\n" ) );
read_NotImplemented( m_file, ']' );
} else if( strcmp( text, "Color" ) == 0 )
{
read_Color();
} else if( strcmp( text, "coordIndex" ) == 0 )
{
read_coordIndex();
} else if( strcmp( text, "colorIndex" ) == 0 )
{
read_colorIndex();
}
}
DBG( printf( " IndexedFaceSet failed %s\n", text) );
return -1;
}
int VRML2_MODEL_PARSER::read_colorIndex()
{
//DBG( printf( " read_colorIndex\n" ) );
m_model->m_MaterialIndex.clear();
if( colorPerVertex == true )
{
int index;
int first_index;
while( fscanf( m_file, "%d, ", &index ) )
{
if( index == -1 )
{
// it only implemented color per face, so it will store as the first in the list
m_model->m_MaterialIndex.push_back( first_index );
} else
{
first_index = index;
}
}
} else
{
int index;
while( fscanf( m_file, "%d,", &index ) )
{
m_model->m_MaterialIndex.push_back( index );
}
}
//DBG( printf( " m_MaterialIndex.size: %ld\n", m_model->m_MaterialIndex.size() ) );
return 0;
}
int VRML2_MODEL_PARSER::read_coordIndex()
{
//DBG( printf( " read_coordIndex\n" ) );
m_model->m_CoordIndex.clear();
glm::ivec3 coord;
int dummy; // should be -1
std::vector<int> coord_list;
coord_list.clear();
while( fscanf (m_file, "%d, ", &dummy ) == 1 )
{
if( dummy == -1 )
{
m_model->m_CoordIndex.push_back( coord_list );
//DBG( printf( " size: %lu ", coord_list.size()) );
coord_list.clear();
} else
{
coord_list.push_back( dummy );
//DBG( printf( "%d ", dummy) );
}
}
//DBG( printf( " m_CoordIndex.size: %ld\n", m_model->m_CoordIndex.size() ) );
return 0;
}
int VRML2_MODEL_PARSER::read_Color()
{
char text[128];
//DBG( printf( " read_Color\n") );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
//DBG( printf( " m_DiffuseColor.size: %ld\n", m_model->m_Materials->m_DiffuseColor.size() ) );
return 0;
}
if( strcmp( text, "color" ) == 0 )
{
parseVertexList( m_file, m_model->m_Materials->m_DiffuseColor );
}
}
//DBG( printf( " read_Color failed\n") );
return -1;
}
int VRML2_MODEL_PARSER::read_Normal()
{
char text[128];
//DBG( printf( " Normal\n") );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
//DBG( printf( " m_PerFaceNormalsNormalized.size: %lu\n", m_model->m_PerFaceNormalsNormalized.size() ) );
return 0;
}
if( strcmp( text, "vector" ) == 0 )
{
if(m_normalPerVertex == false )
{
parseVertexList( m_file, m_model->m_PerFaceNormalsNormalized );
} else
{
parseVertexList( m_file, m_model->m_PerVertexNormalsNormalized );
//DBG( printf( " m_PerVertexNormalsNormalized.size: %lu\n", m_model->m_PerVertexNormalsNormalized.size() ) );
}
}
}
return -1;
}
int VRML2_MODEL_PARSER::read_Coordinate()
{
char text[128];
//DBG( printf( " Coordinate\n") );
while( GetNextTag( m_file, text ) )
{
if ( ( text == NULL ) || ( *text == ']' ) )
{
continue;
}
if ( ( *text == '}' ) )
{
//DBG( printf( " m_Point.size: %lu\n", m_model->m_Point.size() ) );
return 0;
}
if( strcmp( text, "point" ) == 0 )
{
parseVertexList( m_file, m_model->m_Point);
}
}
return -1;
}
......@@ -37,540 +37,65 @@
#include "3d_struct.h"
#include "modelparsers.h"
// separator chars
static const char* sep_chars = " \t\n\r";
VRML_MODEL_PARSER::VRML_MODEL_PARSER( S3D_MASTER* aMaster ) :
S3D_MODEL_PARSER( aMaster )
{}
VRML_MODEL_PARSER::~VRML_MODEL_PARSER()
{}
void VRML_MODEL_PARSER::Load( const wxString aFilename )
{
char line[1024], * text;
FILE* file;
int LineNum = 0;
file = wxFopen( aFilename, wxT( "rt" ) );
if( file == NULL )
{
return;
}
// Switch the locale to standard C (needed to print floating point numbers like 1.3)
SetLocaleTo_C_standard();
while( GetLine( file, line, &LineNum, 512 ) )
{
text = strtok( line, sep_chars );
if ( text == NULL )
continue;
if( stricmp( text, "DEF" ) == 0 || stricmp( text, "Transform" ) == 0 || stricmp( text, "Group" ) == 0 )
{
while( GetLine( file, line, &LineNum, 512 ) )
{
text = strtok( line, sep_chars );
if( text == NULL )
continue;
if( *text == '}' )
break;
if( stricmp( text, "children" ) == 0 )
{
readChildren( file, &LineNum );
}
}
}
}
fclose( file );
SetLocaleTo_Default(); // revert to the current locale
vrml1_parser = new VRML1_MODEL_PARSER( aMaster );
vrml2_parser = new VRML2_MODEL_PARSER( aMaster );
}
int VRML_MODEL_PARSER::readMaterial( FILE* file, int* LineNum )
VRML_MODEL_PARSER::~VRML_MODEL_PARSER()
{
char line[512], * text, * command;
wxString mat_name;
S3D_MATERIAL* material = NULL;
command = strtok( NULL, sep_chars );
text = strtok( NULL, sep_chars );
mat_name = FROM_UTF8( text );
if( stricmp( command, "USE" ) == 0 )
if( vrml1_parser )
{
for( material = GetMaster()->m_Materials; material; material = material->Next() )
{
if( material->m_Name == mat_name )
{
material->SetMaterial();
return 1;
}
}
DBG( printf( "ReadMaterial error: material not found\n" ) );
return 0;
delete vrml1_parser;
}
if( stricmp( command, "DEF" ) == 0 || stricmp( command,"Transform" ) == 0 || stricmp( command, "Material") == 0)
if( vrml2_parser )
{
material = new S3D_MATERIAL( GetMaster(), mat_name );
GetMaster()->Insert( material );
while( GetLine( file, line, LineNum, 512 ) )
{
text = strtok( line, sep_chars );
if( text == NULL )
continue;
if( text[0] == '}' )
{
material->SetMaterial();
return 0;
}
if( stricmp( text, "diffuseColor" ) == 0 )
{
text = strtok( NULL, sep_chars );
material->m_DiffuseColor.x = atof( text );
text = strtok( NULL, sep_chars );
material->m_DiffuseColor.y = atof( text );
text = strtok( NULL, sep_chars );
material->m_DiffuseColor.z = atof( text );
}
else if( stricmp( text, "emissiveColor" ) == 0 )
{
text = strtok( NULL, sep_chars );
material->m_EmissiveColor.x = atof( text );
text = strtok( NULL, sep_chars );
material->m_EmissiveColor.y = atof( text );
text = strtok( NULL, sep_chars );
material->m_EmissiveColor.z = atof( text );
}
else if( strnicmp( text, "specularColor", 13 ) == 0 )
{
text = strtok( NULL, sep_chars );
material->m_SpecularColor.x = atof( text );
text = strtok( NULL, sep_chars );
material->m_SpecularColor.y = atof( text );
text = strtok( NULL, sep_chars );
material->m_SpecularColor.z = atof( text );
}
else if( strnicmp( text, "ambientIntensity", 16 ) == 0 )
{
text = strtok( NULL, sep_chars );
material->m_AmbientIntensity = atof( text );
}
else if( strnicmp( text, "transparency", 12 ) == 0 )
{
text = strtok( NULL, sep_chars );
material->m_Transparency = atof( text );
}
else if( strnicmp( text, "shininess", 9 ) == 0 )
{
text = strtok( NULL, sep_chars );
material->m_Shininess = atof( text );
}
}
delete vrml2_parser;
}
return -1;
}
int VRML_MODEL_PARSER::readChildren( FILE* file, int* LineNum )
void VRML_MODEL_PARSER::Load( const wxString aFilename )
{
char line[1024], * text;
while( GetLine( file, line, LineNum, 512 ) )
{
text = strtok( line, sep_chars );
if( *text == '[' )
continue;
if( *text == ']' )
return 0;
if( *text == ',' )
continue;
if( stricmp( text, "Shape" ) == 0 )
{
readShape( file, LineNum );
}
else
{
DBG( printf( "ReadChildren error line %d <%s> \n", *LineNum, text ) );
break;
}
}
return 1;
}
char line[12];
FILE* file;
// DBG( printf( "Load %s\n", static_cast<const char*>(aFilename.mb_str()) ) );
int VRML_MODEL_PARSER::readShape( FILE* file, int* LineNum )
{
char line[1024], * text;
int err = 1;
file = wxFopen( aFilename, wxT( "rt" ) );
while( GetLine( file, line, LineNum, 512 ) )
if( file == NULL )
{
text = strtok( line, sep_chars );
if( *text == '}' )
{
err = 0;
break;
}
if( *text == '{' )
{
continue;
}
if( stricmp( text, "appearance" ) == 0 )
{
readAppearance( file, LineNum );
}
else if( stricmp( text, "geometry" ) == 0 )
{
readGeometry( file, LineNum );
}
else
{
DBG( printf( "ReadShape error line %d <%s> \n", *LineNum, text ) );
break;
}
return;
}
return err;
}
int VRML_MODEL_PARSER::readAppearance( FILE* file, int* LineNum )
{
char line[1024], * text;
int err = 1;
while( GetLine( file, line, LineNum, 512 ) )
if( fgets( line, 11, file ) == NULL )
{
text = strtok( line, sep_chars );
if( *text == '}' )
{
err = 0;
break;
}
if( *text == '{' )
{
continue;
}
if( stricmp( text, "material" ) == 0 )
{
readMaterial( file, LineNum );
}
else
{
DBG( printf( "ReadAppearance error line %d <%s> \n", *LineNum, text ) );
break;
}
fclose( file );
return;
}
return err;
}
void VRML_MODEL_PARSER::readCoordsList( FILE* file, char* text_buffer,
std::vector< double >& aList, int* LineNum )
{
unsigned int ii = 0, jj = 0;
char* text;
bool HasData = false;
bool StartData = false;
bool EndNode = false;
char string_num[512];
text = text_buffer;
while( !EndNode )
fclose( file );
if( stricmp( line, "#VRML V2.0" ) == 0)
{
if( *text == 0 ) // Needs data !
{
text = text_buffer;
GetLine( file, text_buffer, LineNum, 512 );
}
while( !EndNode && *text )
{
switch( *text )
{
case '[':
StartData = true;
jj = 0;
string_num[jj] = 0;
break;
case '}':
EndNode = true;
break;
case ']':
case '\t':
case ' ':
case ',':
jj = 0;
if( !StartData || !HasData )
break;
aList.push_back( atof( string_num ) );
string_num[jj] = 0;
ii++;
HasData = false;
//DBG( printf( "About to parser a #VRML V2.0 file\n" ) );
vrml2_parser->Load( aFilename );
if( *text == ']' )
{
StartData = false;
}
break;
default:
if( !StartData )
break;
if( jj >= sizeof( string_num ) )
break;
string_num[jj] = *text;
jj++;
string_num[jj] = 0;
HasData = true;
break;
}
text++;
}
return;
}
}
int VRML_MODEL_PARSER::readGeometry( FILE* file, int* LineNum )
{
char line[1024], buffer[1024], * text;
int err = 1;
std::vector< double > points;
std::vector< double > list;
double vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
while( GetLine( file, line, LineNum, 512 ) )
else if( stricmp( line, "#VRML V1.0" ) == 0)
{
strcpy( buffer, line );
text = strtok( buffer, sep_chars );
if( text == NULL )
continue;
if( *text == '}' )
{
err = 0;
break;
}
if( stricmp( text, "creaseAngle" ) == 0 )
{
continue;
}
if( *text == '{' )
{
continue;
}
//DBG( printf( "About to parser a #VRML V1.0 file\n" ) );
vrml1_parser->Load( aFilename );
if( stricmp( text, "normalPerVertex" ) == 0 )
{
text = strtok( NULL, " ,\t\n\r" );
if( text && stricmp( text, "true" ) == 0 )
{
}
else
{
}
continue;
}
if( stricmp( text, "colorPerVertex" ) == 0 )
{
text = strtok( NULL, " ,\t\n\r" );
if( text && stricmp( text, "true" ) == 0 )
{
}
else
{
}
continue;
}
if( stricmp( text, "normal" ) == 0 )
{
readCoordsList( file, line, list, LineNum );
list.clear();
continue;
}
if( stricmp( text, "normalIndex" ) == 0 )
{
while( GetLine( file, line, LineNum, 512 ) )
{
text = strtok( line, " ,\t\n\r" );
while( text )
{
if( *text == ']' )
break;
text = strtok( NULL, " ,\t\n\r" );
}
if( text && (*text == ']') )
break;
}
continue;
}
if( stricmp( text, "color" ) == 0 )
{
readCoordsList( file, line, list, LineNum );
list.clear();
continue;
}
if( stricmp( text, "solid" ) == 0 )
{
// ignore solid
continue;
}
if( stricmp( text, "colorIndex" ) == 0 )
{
while( GetLine( file, line, LineNum, 512 ) )
{
text = strtok( line, " ,\t\n\r" );
while( text )
{
if( *text == ']' )
break;
text = strtok( NULL, " ,\t\n\r" );
}
if( text && (*text == ']') )
break;
}
continue;
}
if( stricmp( text, "coord" ) == 0 )
{
readCoordsList( file, line, points, LineNum );
}
else if( stricmp( text, "coordIndex" ) == 0 )
{
if( points.size() < 3 || points.size() % 3 != 0 )
{
wxLogError( wxT( "3D geometry read error <%s> at line %d." ),
GetChars( FROM_UTF8( text ) ), *LineNum );
err = 1;
break;
}
std::vector< int > coordIndex;
std::vector< S3D_VERTEX > vertices;
while( GetLine( file, line, LineNum, 512 ) )
{
int jj;
text = strtok( line, " ,\t\n\r" );
while( text )
{
if( *text == ']' )
break;
jj = atoi( text );
if( jj < 0 )
{
for( jj = 0; jj < (int) coordIndex.size(); jj++ )
{
int kk = coordIndex[jj] * 3;
if( (kk < 0) || ((kk + 3) > (int)points.size()) )
{
wxLogError( wxT( "3D geometry index read error <%s> at line %d." ),
GetChars( FROM_UTF8( text ) ), *LineNum );
err = 1;
break;
}
S3D_VERTEX vertex;
vertex.x = points[kk];
vertex.y = points[kk + 1];
vertex.z = points[kk + 2];
vertices.push_back( vertex );
}
if( GetMaster()->IsOpenGlAllowed() )
{
GetMaster()->ObjectCoordsTo3DUnits( vertices );
TransfertToGLlist( vertices, vrmlunits_to_3Dunits );
}
vertices.clear();
coordIndex.clear();
}
else
{
coordIndex.push_back( jj );
}
text = strtok( NULL, " ,\t\n\r" );
}
if( text && (*text == ']') )
break;
}
}
else
{
wxLogError( wxT( "3D geometry read error <%s> at line %d." ),
GetChars( FROM_UTF8( text ) ), *LineNum );
err = 1;
break;
}
return;
}
return err;
DBG( printf( "Unknown VRML file format: %s\n", line ) );
}
......@@ -66,6 +66,28 @@ void X3D_MODEL_PARSER::Load( const wxString aFilename )
return;
}
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
glm::vec3 matScale(GetMaster()->m_MatScale.x, GetMaster()->m_MatScale.y, GetMaster()->m_MatScale.z );
glm::vec3 matRot(GetMaster()->m_MatRotation.x, GetMaster()->m_MatRotation.y, GetMaster()->m_MatRotation.z );
glm::vec3 matPos(GetMaster()->m_MatPosition.x, GetMaster()->m_MatPosition.y, GetMaster()->m_MatPosition.z );
//glPushMatrix();
glTranslatef( matPos.x, matPos.y, matPos.z);
glRotatef( matRot.z, 0.0f, 0.0f, 1.0f);
glRotatef( matRot.y, 0.0f, 1.0f, 0.0f);
glRotatef( matRot.x, 1.0f, 0.0f, 0.0f);
glScalef( matScale.x, matScale.y, matScale.z );
// Switch the locale to standard C (needed to print floating point numbers)
LOCALE_IO toggle;
childs.clear();
// Shapes are inside of Transform nodes
// Transform node contains information about
// transition, scale and rotation of the shape
......@@ -76,12 +98,25 @@ void X3D_MODEL_PARSER::Load( const wxString aFilename )
node_it != transforms.end();
node_it++ )
{
m_model = new S3D_MESH();
childs.push_back( m_model );
readTransform( *node_it );
}
//DBG( printf( "chils size:%lu\n", childs.size() ) );
if( GetMaster()->IsOpenGlAllowed() )
{
for( unsigned int idx = 0; idx < childs.size(); idx++ )
{
childs[idx]->openGL_RenderAllChilds();
}
}
}
wxString X3D_MODEL_PARSER::VRML_representation()
wxString X3D_MODEL_PARSER::VRML2_representation()
{
wxString output;
......@@ -188,6 +223,8 @@ void X3D_MODEL_PARSER::readTransform( wxXmlNode* aTransformNode )
void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
{
glm::vec3 color;
PROPERTY_MAP properties;
GetNodeProperties( aMatNode, properties );
......@@ -199,22 +236,33 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
S3D_MATERIAL* material = new S3D_MATERIAL( GetMaster(), properties[ wxT( "DEF" ) ] );
GetMaster()->Insert( material );
m_model->m_Materials = material;
if( !parseDoubleTriplet( properties[ wxT( "diffuseColor" ) ],
material->m_DiffuseColor ) )
color ) )
{
DBG( printf("diffuseColor parsing error") );
} else
{
// Do not use this diffuse color
}
if( !parseDoubleTriplet( properties[ wxT( "specularColor" ) ],
material->m_SpecularColor ) )
color ) )
{
DBG( printf("specularColor parsing error") );
} else
{
m_model->m_Materials->m_SpecularColor.push_back( color );
}
if( !parseDoubleTriplet( properties[ wxT( "emissiveColor" ) ],
material->m_EmissiveColor ) )
color ) )
{
DBG( printf("emissiveColor parsing error") );
} else
{
m_model->m_Materials->m_EmissiveColor.push_back( color );
}
wxStringTokenizer values;
......@@ -222,7 +270,7 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
if( values.GetNextToken().ToDouble( &amb ) )
{
material->m_AmbientIntensity = amb;
m_model->m_Materials->m_AmbientColor.push_back( glm::vec3( amb, amb, amb ) );
}
else
{
......@@ -233,7 +281,9 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
if( values.GetNextToken().ToDouble( &shine ) )
{
material->m_Shininess = shine;
// VRML value is normalized and openGL expects a value 0 - 128
shine = shine * 128.0f;
m_model->m_Materials->m_Shininess.push_back( shine );
}
else
{
......@@ -244,15 +294,13 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
if( values.GetNextToken().ToDouble( &transp ) )
{
material->m_Transparency = transp;
m_model->m_Materials->m_Transparency.push_back( transp );
}
else
{
DBG( printf( "trans error") );
}
material->SetMaterial();
// VRML
wxString vrml_material;
PROPERTY_MAP::const_iterator p = ++properties.begin(); // skip DEF
......@@ -278,32 +326,33 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
wxString vrml_material;
vrml_material.Append( wxString::Format( wxT( "specularColor %f %f %f\n" ),
material->m_SpecularColor.x,
material->m_SpecularColor.y,
material->m_SpecularColor.z ) );
material->m_SpecularColor[0].x,
material->m_SpecularColor[0].y,
material->m_SpecularColor[0].z ) );
/*
vrml_material.Append( wxString::Format( wxT( "diffuseColor %f %f %f\n" ),
material->m_DiffuseColor.x,
material->m_DiffuseColor.y,
material->m_DiffuseColor.z ) );
material->m_DiffuseColor[0].x,
material->m_DiffuseColor[0].y,
material->m_DiffuseColor[0].z ) );
*/
vrml_material.Append( wxString::Format( wxT( "emissiveColor %f %f %f\n" ),
material->m_EmissiveColor.x,
material->m_EmissiveColor.y,
material->m_EmissiveColor.z ) );
material->m_EmissiveColor[0].x,
material->m_EmissiveColor[0].y,
material->m_EmissiveColor[0].z ) );
vrml_material.Append( wxString::Format( wxT( "ambientIntensity %f\n"),
material->m_AmbientIntensity ) );
material->m_AmbientColor[0].x ) );
vrml_material.Append( wxString::Format( wxT( "shininess %f\n"),
material->m_Shininess ) );
material->m_Shininess[0] ) );
vrml_material.Append( wxString::Format( wxT( "transparency %f\n"),
material->m_Transparency ) );
material->m_Transparency[0] ) );
vrml_materials.push_back( vrml_material );
material->SetMaterial();
m_model->m_Materials = material;
return;
}
}
......@@ -318,9 +367,17 @@ bool X3D_MODEL_PARSER::parseDoubleTriplet( const wxString& aData,
{
wxStringTokenizer tokens(aData);
return tokens.GetNextToken().ToDouble( &aResult.x ) &&
tokens.GetNextToken().ToDouble( &aResult.y ) &&
tokens.GetNextToken().ToDouble( &aResult.z );
double x,y,z;
bool ret = tokens.GetNextToken().ToDouble( &x ) &&
tokens.GetNextToken().ToDouble( &y ) &&
tokens.GetNextToken().ToDouble( &z );
aResult.x = x;
aResult.y = y;
aResult.z = z;
return ret;
}
......@@ -373,16 +430,20 @@ void X3D_MODEL_PARSER::readIndexedFaceSet( wxXmlNode* aFaceNode,
double angle = 0.0;
wxStringTokenizer tokens(aTransformProps[ wxT( "rotation" ) ]);
if( !(tokens.GetNextToken().ToDouble( &rotation.x ) &&
tokens.GetNextToken().ToDouble( &rotation.y ) &&
tokens.GetNextToken().ToDouble( &rotation.z ) &&
double x,y,z;
if( !(tokens.GetNextToken().ToDouble( &x ) &&
tokens.GetNextToken().ToDouble( &y ) &&
tokens.GetNextToken().ToDouble( &z ) &&
tokens.GetNextToken().ToDouble( &angle ) ) )
{
DBG( printf("rotation read error") );
}
double vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits *
UNITS3D_TO_UNITSPCB;
else
{
rotation.x = x;
rotation.y = y;
rotation.z = z;
}
/* Step 2: Read all coordinate points
* ---------------------------- */
......@@ -439,7 +500,12 @@ void X3D_MODEL_PARSER::readIndexedFaceSet( wxXmlNode* aFaceNode,
point.y += translation.y;
point.z += translation.z;
triplets.push_back(point);
//triplets.push_back(point);
double vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
point *= vrmlunits_to_3Dunits;
m_model->m_Point.push_back( point );
// VRML
vrml_pointlist.Append( wxString::Format( wxT( "%f %f %f\n" ), point.x, point.y, point.z ) );
......@@ -447,18 +513,66 @@ void X3D_MODEL_PARSER::readIndexedFaceSet( wxXmlNode* aFaceNode,
vrml_points.push_back( vrml_pointlist );
/* Step 3: Read all color points
* ---------------------------- */
std::vector< double > color_points;
NODE_LIST color;
GetChildsByName( aFaceNode, wxT( "Color" ), color);
PROPERTY_MAP color_properties;
// IndexedFaceSet has one Coordinate child node
GetNodeProperties( color[0], color_properties );
// Save points to vector as doubles
wxStringTokenizer colorpoint_tokens( color_properties[ wxT("color") ] );
double color_point = 0.0;
while( colorpoint_tokens.HasMoreTokens() )
{
if( colorpoint_tokens.GetNextToken().ToDouble( &color_point ) )
{
color_points.push_back( color_point );
}
else
{
wxLogError( wxT( "Error converting to double" ) );
}
}
if( color_points.size() % 3 != 0 )
{
DBG( printf( "Number of points is incorrect" ) );
return;
}
/* Create 3D face color from 3 color points
*/
for( unsigned id = 0; id < color_points.size() / 3; id++ )
{
m_model->m_MaterialIndex.push_back( id );
int color_triplet_indx = id * 3;
glm::vec3 colorface( color_points[ color_triplet_indx + 0 ],
color_points[ color_triplet_indx + 1 ],
color_points[ color_triplet_indx + 2 ] );
m_model->m_Materials->m_DiffuseColor.push_back( colorface );
}
/* -- Read coordinate indexes -- */
PROPERTY_MAP faceset_properties;
GetNodeProperties( aFaceNode, faceset_properties );
std::vector< S3D_VERTEX > vertices;
std::vector< int > coordIndex;
wxString coordIndex_str = faceset_properties[ wxT( "coordIndex" ) ];
wxStringTokenizer index_tokens( coordIndex_str );
wxString vrml_coord_indx_list;
std::vector<int> coord_list;
coord_list.clear();
while( index_tokens.HasMoreTokens() )
{
long index = 0;
......@@ -470,28 +584,14 @@ void X3D_MODEL_PARSER::readIndexedFaceSet( wxXmlNode* aFaceNode,
{
/* Step 4: Apply geometry to Master object
* --------------------------------------- */
std::vector<int>::const_iterator id;
for( id = coordIndex.begin();
id != coordIndex.end();
id++ )
{
vertices.push_back( triplets.at( *id ) );
}
if( GetMaster()->IsOpenGlAllowed() )
{
GetMaster()->ObjectCoordsTo3DUnits( vertices );
TransfertToGLlist( vertices, vrmlunits_to_3Dunits );
}
m_model->m_CoordIndex.push_back( coord_list );
vertices.clear();
coordIndex.clear();
coord_list.clear();
vrml_coord_indx_list.Append( wxT( "-1\n" ) );
}
else
{
coordIndex.push_back( index );
coord_list.push_back( index );
vrml_coord_indx_list.Append( wxString::Format( wxT( "%u " ), index ) );
}
}
......
......@@ -144,6 +144,7 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
break;
case BLOCK_DRAG: // Drag
case BLOCK_DRAG_ITEM: // Drag a given item (not used here)
case BLOCK_MOVE: // Move
case BLOCK_COPY: // Copy
itemsCount = MarkItemsInBloc( currentModule, GetScreen()->m_BlockLocate );
......
......@@ -281,11 +281,13 @@ public:
* @param glcanvas = the openGL canvas
* @param aAllowNonTransparentObjects = true to load non transparent objects
* @param aAllowTransparentObjects = true to load non transparent objects
* @param aSideToLoad = false will load not fliped, true will load fliped objects
* in openGL, transparent objects should be drawn *after* non transparent objects
*/
void ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas,
bool aAllowNonTransparentObjects,
bool aAllowTransparentObjects );
bool aAllowTransparentObjects,
bool aSideToLoad );
/**
* function TransformPadsShapesWithClearanceToPolygon
......
......@@ -1325,7 +1325,7 @@ static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule
try
{
aOutputFile << " children [\n ";
aOutputFile << TO_UTF8( parser->VRML_representation() ) << " ]\n";
aOutputFile << TO_UTF8( parser->VRML2_representation() ) << " ]\n";
aOutputFile << " }\n";
}
catch( const std::exception& e )
......
......@@ -1936,7 +1936,7 @@ void LEGACY_PLUGIN::load3D( MODULE* aModule )
else if( TESTLINE( "Sc" ) ) // Scale
{
sscanf( line + SZ( "Sc" ), "%lf %lf %lf\n",
sscanf( line + SZ( "Sc" ), "%f %f %f\n",
&t3D->m_MatScale.x,
&t3D->m_MatScale.y,
&t3D->m_MatScale.z );
......@@ -1944,7 +1944,7 @@ void LEGACY_PLUGIN::load3D( MODULE* aModule )
else if( TESTLINE( "Of" ) ) // Offset
{
sscanf( line + SZ( "Of" ), "%lf %lf %lf\n",
sscanf( line + SZ( "Of" ), "%f %f %f\n",
&t3D->m_MatPosition.x,
&t3D->m_MatPosition.y,
&t3D->m_MatPosition.z );
......@@ -1952,7 +1952,7 @@ void LEGACY_PLUGIN::load3D( MODULE* aModule )
else if( TESTLINE( "Ro" ) ) // Rotation
{
sscanf( line + SZ( "Ro" ), "%lf %lf %lf\n",
sscanf( line + SZ( "Ro" ), "%f %f %f\n",
&t3D->m_MatRotation.x,
&t3D->m_MatRotation.y,
&t3D->m_MatRotation.z );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment