diff --git a/3d-viewer/3d_aux.cpp b/3d-viewer/3d_aux.cpp index a8ccab2b8d..2a5c758fcd 100644 --- a/3d-viewer/3d_aux.cpp +++ b/3d-viewer/3d_aux.cpp @@ -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 ); diff --git a/3d-viewer/3d_canvas.cpp b/3d-viewer/3d_canvas.cpp index db1ace2851..807af4e6d4 100644 --- a/3d-viewer/3d_canvas.cpp +++ b/3d-viewer/3d_canvas.cpp @@ -16,17 +16,23 @@ #include +#ifdef __WINDOWS__ +#include // must be included before gl.h +#endif + #include <3d_viewer.h> #include <3d_canvas.h> #include #include #include <3d_viewer_id.h> +#include +#include // ----------------- // helper function (from wxWidgets, opengl/cube.cpp sample // ----------------- -void CheckGLError() +void CheckGLError(const char *aFileName, int aLineNumber) { GLenum errLast = GL_NO_ERROR; @@ -47,7 +53,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 +84,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 +497,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 +551,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 +559,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 +571,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 +650,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 ); diff --git a/3d-viewer/3d_canvas.h b/3d-viewer/3d_canvas.h index b68541dfdf..6831cc8a04 100644 --- a/3d-viewer/3d_canvas.h +++ b/3d-viewer/3d_canvas.h @@ -43,10 +43,11 @@ #endif #include <3d_struct.h> - +#include + 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_ */ diff --git a/3d-viewer/3d_class.cpp b/3d-viewer/3d_class.cpp index b364d23e5b..3aae8e8c17 100644 --- a/3d-viewer/3d_class.cpp +++ b/3d-viewer/3d_class.cpp @@ -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; } diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index 14a04ff7bd..277218bdd4 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -1,7 +1,7 @@ /* * 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,16 @@ #include #include +#ifdef __WINDOWS__ +#include // must be included before gl.h +#endif + #include <3d_viewer.h> #include <3d_canvas.h> #include #include #include <3d_draw_basic_functions.h> -// Imported function: -extern void CheckGLError(); - /* Helper function * returns true if aLayer should be displayed, false otherwise */ @@ -99,6 +100,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,13 +360,90 @@ 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(); - - // *MUST* be called *after* SetCurrent( ): - glViewport( 0, 0, ClientSize.x, ClientSize.y ); + 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, size.x, size.y ); + + // 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 GLfloat mat[4][4]; @@ -134,6 +458,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 +472,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 +503,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 +562,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 +594,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 +612,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 +628,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 +788,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; im_Track; track; track = track->Next() ) + if ( !g_Parm_3D_Visu.GetFlag( FL_SHOW_BOARD_BODY ) ) { - const VIA *via = dynamic_cast(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(track); + + 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 pads holes (vertical cylinders) - for( const MODULE* module = pcb->m_Modules; module; module = module->Next() ) + if( g_Parm_3D_Visu.IsRealisticMode() ) { - for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) - Draw3DPadHole( pad ); + SetGLEpoxyColor( 0.9 ); + if( g_Parm_3D_Visu.HightQualityMode() ) + { + SetGLTexture( m_text_pcb, 35.0f ); + } } + else + { + EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts ); + SetGLColor( color, 0.7 ); + } + + float 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 + 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 ); + + // 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; + + 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 ); + + // Build holes list + allLayerHoles.ExportTo( polysetHoles ); + + // remove holes + currLayerPolyset -= polysetHoles; + + bufferPcbOutlines.RemoveAllContours(); + bufferPcbOutlines.ImportFrom( currLayerPolyset ); // Draw board substrate: if( bufferPcbOutlines.GetCornersCount() && - ( realistic_mode || g_Parm_3D_Visu.GetFlag( FL_SHOW_BOARD_BODY ) ) ) + ( g_Parm_3D_Visu.GetFlag( FL_SHOW_BOARD_BODY ) ) ) { - 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 - { - 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; - - // Add polygons, without holes - bufferPcbOutlines.ExportTo( currLayerPolyset ); - - // Build holes list - allLayerHoles.ExportTo( polysetHoles ); - - // remove holes - currLayerPolyset -= polysetHoles; - - bufferPcbOutlines.RemoveAllContours(); - bufferPcbOutlines.ImportFrom( currLayerPolyset ); // 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 +1396,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 +1419,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] = glGenLists( 1 ); - BuildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID], - m_glLists[GL_ID_3DSHAPES_TRANSP] ); + 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_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 +1451,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 +1463,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 +1472,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 +1666,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 diff --git a/3d-viewer/3d_draw_basic_functions.cpp b/3d-viewer/3d_draw_basic_functions.cpp index 81654c4af7..b5d76f9884 100644 --- a/3d-viewer/3d_draw_basic_functions.cpp +++ b/3d-viewer/3d_draw_basic_functions.cpp @@ -33,10 +33,7 @@ #include <3d_viewer.h> #include #include <3d_draw_basic_functions.h> - -// Imported function: -extern void TransfertToGLlist( std::vector& aVertices, double aBiuTo3DUnits ); -extern void CheckGLError(); +#include // 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 ); diff --git a/3d-viewer/3d_draw_basic_functions.h b/3d-viewer/3d_draw_basic_functions.h index a4fb60ab34..5cccba689f 100644 --- a/3d-viewer/3d_draw_basic_functions.h +++ b/3d-viewer/3d_draw_basic_functions.h @@ -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_ diff --git a/3d-viewer/3d_frame.cpp b/3d-viewer/3d_frame.cpp index 3ae8cb0853..c3c487ed3a 100644 --- a/3d-viewer/3d_frame.cpp +++ b/3d-viewer/3d_frame.cpp @@ -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 ); diff --git a/3d-viewer/3d_material.cpp b/3d-viewer/3d_material.cpp new file mode 100644 index 0000000000..ece265d25e --- /dev/null +++ b/3d-viewer/3d_material.cpp @@ -0,0 +1,136 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * 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 +#include <3d_struct.h> +#include <3d_material.h> + +#ifdef __WXMAC__ +# ifdef __DARWIN__ +# include +# else +# include +# endif +#else +# include +#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 ); + } +} + diff --git a/3d-viewer/3d_material.h b/3d-viewer/3d_material.h new file mode 100644 index 0000000000..180825d105 --- /dev/null +++ b/3d-viewer/3d_material.h @@ -0,0 +1,66 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * 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 +#include +#include + +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 diff --git a/3d-viewer/3d_mesh_model.cpp b/3d-viewer/3d_mesh_model.cpp new file mode 100644 index 0000000000..b951733d50 --- /dev/null +++ b/3d-viewer/3d_mesh_model.cpp @@ -0,0 +1,387 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * 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 + +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 ); + } +} diff --git a/3d-viewer/3d_mesh_model.h b/3d-viewer/3d_mesh_model.h new file mode 100644 index 0000000000..d8dda92122 --- /dev/null +++ b/3d-viewer/3d_mesh_model.h @@ -0,0 +1,100 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef __WXMAC__ +# ifdef __DARWIN__ +# include +# else +# include +# endif +#else +# include +#endif +#include + +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 > 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 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 > 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 diff --git a/3d-viewer/3d_struct.h b/3d-viewer/3d_struct.h index 2a82effd93..34384ad29d 100644 --- a/3d-viewer/3d_struct.h +++ b/3d-viewer/3d_struct.h @@ -1,6 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * + * Copyright (C) 2014 Mario Luzeiro * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com * Copyright (C) 2011 Wayne Stambaugh * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors. @@ -32,8 +33,9 @@ #include #include - - +#include <3d_material.h> +#include + /* 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(); diff --git a/3d-viewer/CMakeLists.txt b/3d-viewer/CMakeLists.txt index 56af4eba6a..31cf55bc5b 100644 --- a/3d-viewer/CMakeLists.txt +++ b/3d-viewer/CMakeLists.txt @@ -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}) diff --git a/3d-viewer/info3d_visu.cpp b/3d-viewer/info3d_visu.cpp index 23b5400e52..a0417689b2 100644 --- a/3d-viewer/info3d_visu.cpp +++ b/3d-viewer/info3d_visu.cpp @@ -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 } diff --git a/3d-viewer/info3d_visu.h b/3d-viewer/info3d_visu.h index 4b00ecc768..663f5c53e1 100644 --- a/3d-viewer/info3d_visu.h +++ b/3d-viewer/info3d_visu.h @@ -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) diff --git a/3d-viewer/modelparsers.h b/3d-viewer/modelparsers.h index d1c5f23461..ba9f038be3 100644 --- a/3d-viewer/modelparsers.h +++ b/3d-viewer/modelparsers.h @@ -32,13 +32,9 @@ #include #include #include - +#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 childs; + std::vector< wxString > vrml_materials; std::vector< wxString > vrml_points; std::vector< wxString > vrml_coord_indexes; @@ -137,8 +137,97 @@ private: void rotate( S3D_VERTEX& aCoordinate, S3D_VERTEX& aRotAxis, double angle ); }; + + /** - * class WRL_MODEL_PARSER + * class VRML2_MODEL_PARSER + * Parses + */ +class VRML2_MODEL_PARSER: public S3D_MODEL_PARSER +{ +public: + VRML2_MODEL_PARSER( S3D_MASTER* aMaster ); + ~VRML2_MODEL_PARSER(); + void Load( const wxString aFilename ); + + /** + * Return string representing VRML2 file in vrml2 format + * Function Load must be called before this function, otherwise empty + * data set is returned. + */ + 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 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 ); + + /** + * Return string representing VRML2 file in vrml2 format + * Function Load must be called before this function, otherwise empty + * data set is returned. + */ + 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 childs; + S3D_MATERIAL *m_Materials; + FILE *m_file; + wxString m_Filename; +}; + +/** + * class VRML_MODEL_PARSER * Parses */ class VRML_MODEL_PARSER: public S3D_MODEL_PARSER @@ -149,45 +238,9 @@ public: 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 - */ - 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 ); - - /** - * 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 [" - */ - void readCoordsList( FILE* file, char* text_buffer, std::vector< double >& aList, - int* LineNum ); + VRML1_MODEL_PARSER *vrml1_parser; + VRML2_MODEL_PARSER *vrml2_parser; }; + #endif // MODELPARSERS_H diff --git a/3d-viewer/textures/text_pcb.c b/3d-viewer/textures/text_pcb.c new file mode 100644 index 0000000000..653b0930db --- /dev/null +++ b/3d-viewer/textures/text_pcb.c @@ -0,0 +1,922 @@ +/* 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", +}; + diff --git a/3d-viewer/textures/text_silk.c b/3d-viewer/textures/text_silk.c new file mode 100644 index 0000000000..c73e59cd84 --- /dev/null +++ b/3d-viewer/textures/text_silk.c @@ -0,0 +1,922 @@ +/* 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", +}; + diff --git a/3d-viewer/vrml_aux.cpp b/3d-viewer/vrml_aux.cpp new file mode 100644 index 0000000000..4a0e875daf --- /dev/null +++ b/3d-viewer/vrml_aux.cpp @@ -0,0 +1,206 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * 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; +} diff --git a/3d-viewer/vrml_aux.h b/3d-viewer/vrml_aux.h new file mode 100644 index 0000000000..479a4039fc --- /dev/null +++ b/3d-viewer/vrml_aux.h @@ -0,0 +1,58 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef __WXMAC__ +# ifdef __DARWIN__ +# include +# else +# include +# endif +#else +# include +#endif +#include + +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 diff --git a/3d-viewer/vrml_v1_modelparser.cpp b/3d-viewer/vrml_v1_modelparser.cpp new file mode 100644 index 0000000000..d95dac985f --- /dev/null +++ b/3d-viewer/vrml_v1_modelparser.cpp @@ -0,0 +1,444 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * 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 +#include +#include +#include +#include + +#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(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 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; +} diff --git a/3d-viewer/vrml_v2_modelparser.cpp b/3d-viewer/vrml_v2_modelparser.cpp new file mode 100644 index 0000000000..9202610149 --- /dev/null +++ b/3d-viewer/vrml_v2_modelparser.cpp @@ -0,0 +1,737 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2013 Tuomas Vaherkoski + * Copyright (C) 2012 Jean-Pierre Charras, jp.charras@wanadoo.fr + * Copyright (C) 2011 Wayne Stambaugh + * 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 +#include +#include +#include +#include + +#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(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 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; +} + diff --git a/3d-viewer/vrmlmodelparser.cpp b/3d-viewer/vrmlmodelparser.cpp index 0e3877eea4..e7d1bcdec1 100644 --- a/3d-viewer/vrmlmodelparser.cpp +++ b/3d-viewer/vrmlmodelparser.cpp @@ -37,23 +37,34 @@ #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 ) -{} +{ + vrml1_parser = new VRML1_MODEL_PARSER( aMaster ); + vrml2_parser = new VRML2_MODEL_PARSER( aMaster ); +} VRML_MODEL_PARSER::~VRML_MODEL_PARSER() -{} +{ + if( vrml1_parser ) + { + delete vrml1_parser; + } + if( vrml2_parser ) + { + delete vrml2_parser; + } +} void VRML_MODEL_PARSER::Load( const wxString aFilename ) { - char line[1024], * text; + char line[12]; FILE* file; - int LineNum = 0; + + // DBG( printf( "Load %s\n", static_cast(aFilename.mb_str()) ) ); file = wxFopen( aFilename, wxT( "rt" ) ); @@ -62,515 +73,29 @@ void VRML_MODEL_PARSER::Load( const wxString aFilename ) 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 ) ) + if( fgets( line, 11, file ) == NULL ) { - 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 ); + + return; } - fclose( file ); - SetLocaleTo_Default(); // revert to the current locale -} - - -int VRML_MODEL_PARSER::readMaterial( FILE* file, int* LineNum ) -{ - 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( stricmp( line, "#VRML V2.0" ) == 0) { - for( material = GetMaster()->m_Materials; material; material = material->Next() ) - { - if( material->m_Name == mat_name ) - { - material->SetMaterial(); - return 1; - } - } + //DBG( printf( "About to parser a #VRML V2.0 file\n" ) ); + vrml2_parser->Load( aFilename ); - DBG( printf( "ReadMaterial error: material not found\n" ) ); - return 0; + return; + } + else if( stricmp( line, "#VRML V1.0" ) == 0) + { + //DBG( printf( "About to parser a #VRML V1.0 file\n" ) ); + vrml1_parser->Load( aFilename ); + + return; } - if( stricmp( command, "DEF" ) == 0 || stricmp( command,"Transform" ) == 0 || stricmp( command, "Material") == 0) - { - 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 ); - } - } - } - - return -1; -} - - -int VRML_MODEL_PARSER::readChildren( FILE* file, int* LineNum ) -{ - 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; -} - - -int VRML_MODEL_PARSER::readShape( FILE* file, int* LineNum ) -{ - char line[1024], * text; - int err = 1; - - while( GetLine( file, line, LineNum, 512 ) ) - { - 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 err; -} - - -int VRML_MODEL_PARSER::readAppearance( FILE* file, int* LineNum ) -{ - char line[1024], * text; - int err = 1; - - while( GetLine( file, line, LineNum, 512 ) ) - { - 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; - } - } - - 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 ) - { - 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; - - 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++; - } - } -} - - -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 ) ) - { - 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; - } - - 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 err; + DBG( printf( "Unknown VRML file format: %s\n", line ) ); } diff --git a/3d-viewer/x3dmodelparser.cpp b/3d-viewer/x3dmodelparser.cpp index e4f7d283b2..8d87e39c0b 100644 --- a/3d-viewer/x3dmodelparser.cpp +++ b/3d-viewer/x3dmodelparser.cpp @@ -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 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::const_iterator id; + m_model->m_CoordIndex.push_back( coord_list ); - 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 ); - } - - 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 ) ); } } diff --git a/pcbnew/block_module_editor.cpp b/pcbnew/block_module_editor.cpp index abba8d6d01..cd2b295435 100644 --- a/pcbnew/block_module_editor.cpp +++ b/pcbnew/block_module_editor.cpp @@ -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 ); diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index b1309d758d..ddae865bd4 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -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 diff --git a/pcbnew/exporters/export_vrml.cpp b/pcbnew/exporters/export_vrml.cpp index 94413fe66e..5ed34e30ec 100644 --- a/pcbnew/exporters/export_vrml.cpp +++ b/pcbnew/exporters/export_vrml.cpp @@ -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 ) diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index e92c20454c..ceca0ddb4d 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -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 );