merge in a year's worth of CERN work

This commit is contained in:
Dick Hollenbeck 2013-10-29 19:10:24 -05:00
commit 3e18a46758
508 changed files with 176177 additions and 978 deletions

View File

@ -414,6 +414,6 @@ void CALLBACK tessErrorCB( GLenum errorCode )
errorStr = gluErrorString( errorCode ); errorStr = gluErrorString( errorCode );
// DEBUG // // DEBUG //
D( printf( "Tess ERROR: %s\n", errorStr ); ) DBG( printf( "Tess ERROR: %s\n", errorStr ); )
#endif #endif
} }

View File

@ -115,7 +115,7 @@ int VRML_MODEL_PARSER::readMaterial( FILE* file, int* LineNum )
} }
} }
D( printf( "ReadMaterial error: material not found\n" ) ); DBG( printf( "ReadMaterial error: material not found\n" ) );
return 0; return 0;
} }
@ -207,7 +207,7 @@ int VRML_MODEL_PARSER::readChildren( FILE* file, int* LineNum )
} }
else else
{ {
D( printf( "ReadChildren error line %d <%s> \n", *LineNum, text ) ); DBG( printf( "ReadChildren error line %d <%s> \n", *LineNum, text ) );
break; break;
} }
} }
@ -241,7 +241,7 @@ int VRML_MODEL_PARSER::readShape( FILE* file, int* LineNum )
} }
else else
{ {
D( printf( "ReadShape error line %d <%s> \n", *LineNum, text ) ); DBG( printf( "ReadShape error line %d <%s> \n", *LineNum, text ) );
break; break;
} }
} }
@ -271,7 +271,7 @@ int VRML_MODEL_PARSER::readAppearance( FILE* file, int* LineNum )
} }
else else
{ {
D( printf( "ReadAppearance error line %d <%s> \n", *LineNum, text ) ); DBG( printf( "ReadAppearance error line %d <%s> \n", *LineNum, text ) );
break; break;
} }
} }

View File

@ -197,19 +197,19 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
if( !parseDoubleTriplet( properties[ wxT( "diffuseColor" ) ], if( !parseDoubleTriplet( properties[ wxT( "diffuseColor" ) ],
material->m_DiffuseColor ) ) material->m_DiffuseColor ) )
{ {
D( printf("diffuseColor parsing error") ); DBG( printf("diffuseColor parsing error") );
} }
if( !parseDoubleTriplet( properties[ wxT( "specularColor" ) ], if( !parseDoubleTriplet( properties[ wxT( "specularColor" ) ],
material->m_SpecularColor ) ) material->m_SpecularColor ) )
{ {
D( printf("specularColor parsing error") ); DBG( printf("specularColor parsing error") );
} }
if( !parseDoubleTriplet( properties[ wxT( "emissiveColor" ) ], if( !parseDoubleTriplet( properties[ wxT( "emissiveColor" ) ],
material->m_EmissiveColor ) ) material->m_EmissiveColor ) )
{ {
D( printf("emissiveColor parsing error") ); DBG( printf("emissiveColor parsing error") );
} }
wxStringTokenizer values; wxStringTokenizer values;
@ -221,7 +221,7 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
} }
else else
{ {
D( printf( "ambienterror" ) ); DBG( printf( "ambienterror" ) );
} }
values.SetString( properties[ wxT( "shininess" ) ] ); values.SetString( properties[ wxT( "shininess" ) ] );
@ -232,7 +232,7 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
} }
else else
{ {
D( printf( "shininess error" ) ); DBG( printf( "shininess error" ) );
} }
values.SetString( properties[ wxT( "transparency" ) ] ); values.SetString( properties[ wxT( "transparency" ) ] );
@ -243,7 +243,7 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
} }
else else
{ {
D( printf( "trans error") ); DBG( printf( "trans error") );
} }
material->SetMaterial(); material->SetMaterial();
@ -303,7 +303,7 @@ void X3D_MODEL_PARSER::readMaterial( wxXmlNode* aMatNode )
} }
} }
D( printf( "ReadMaterial error: material not found\n" ) ); DBG( printf( "ReadMaterial error: material not found\n" ) );
} }
} }
@ -373,7 +373,7 @@ void X3D_MODEL_PARSER::readIndexedFaceSet( wxXmlNode* aFaceNode,
tokens.GetNextToken().ToDouble( &rotation.z ) && tokens.GetNextToken().ToDouble( &rotation.z ) &&
tokens.GetNextToken().ToDouble( &angle ) ) ) tokens.GetNextToken().ToDouble( &angle ) ) )
{ {
D( printf("rotation read error") ); DBG( printf("rotation read error") );
} }
double vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * double vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits *
@ -407,7 +407,7 @@ void X3D_MODEL_PARSER::readIndexedFaceSet( wxXmlNode* aFaceNode,
if( points.size() % 3 != 0 ) if( points.size() % 3 != 0 )
{ {
D( printf( "Number of points is incorrect" ) ); DBG( printf( "Number of points is incorrect" ) );
return; return;
} }

View File

@ -39,7 +39,7 @@ option( KICAD_SCRIPTING_MODULES
option( KICAD_SCRIPTING_WXPYTHON option( KICAD_SCRIPTING_WXPYTHON
"set this option ON to build wxpython implementation for wx interface building in python and py.shell" "set this option ON to build wxpython implementation for wx interface building in python and py.shell"
) )
# when option KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES is enabled: # when option KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES is enabled:
# PYTHON_EXECUTABLE can be defined when invoking cmake # PYTHON_EXECUTABLE can be defined when invoking cmake
# ( use -DPYTHON_EXECUTABLE=<python path>/python.exe or python2 ) # ( use -DPYTHON_EXECUTABLE=<python path>/python.exe or python2 )
@ -230,12 +230,27 @@ include( ExternalProject )
#================================================ #================================================
include( CheckFindPackageResult ) include( CheckFindPackageResult )
# Turn on wxWidgets compatibility mode for some classes
add_definitions(-DWX_COMPATIBILITY)
####################### #######################
# Find OpenGL library # # Find OpenGL library #
####################### #######################
find_package( OpenGL QUIET ) find_package( OpenGL QUIET )
check_find_package_result( OPENGL_FOUND "OpenGL" ) check_find_package_result( OPENGL_FOUND "OpenGL" )
#####################
# Find GLEW library #
#####################
find_package(GLEW)
check_find_package_result(GLEW_FOUND "GLEW")
######################
# Find Cairo library #
######################
find_package(Cairo 1.8.1 QUIET)
check_find_package_result(CAIRO_FOUND "Cairo")
# Download boost and possibly build parts of it # Download boost and possibly build parts of it
################################################# #################################################
include( download_boost ) include( download_boost )
@ -360,6 +375,7 @@ add_subdirectory( cvpcb )
add_subdirectory( eeschema ) add_subdirectory( eeschema )
add_subdirectory( gerbview ) add_subdirectory( gerbview )
add_subdirectory( kicad ) add_subdirectory( kicad )
add_subdirectory( lib_dxf )
add_subdirectory( pcbnew ) add_subdirectory( pcbnew )
add_subdirectory( polygon ) add_subdirectory( polygon )
add_subdirectory( pagelayout_editor ) add_subdirectory( pagelayout_editor )
@ -375,12 +391,14 @@ add_subdirectory( tools )
add_dependencies( pcbnew boost ) add_dependencies( pcbnew boost )
add_dependencies( eeschema boost ) add_dependencies( eeschema boost )
add_dependencies( cvpcb boost ) add_dependencies( cvpcb boost )
add_dependencies( gal boost )
add_dependencies( common boost ) add_dependencies( common boost )
add_dependencies( pcbcommon boost ) add_dependencies( pcbcommon boost )
add_dependencies( 3d-viewer boost ) add_dependencies( 3d-viewer boost )
add_dependencies( pcad2kicadpcb boost ) add_dependencies( pcad2kicadpcb boost )
add_dependencies( polygon boost ) add_dependencies( polygon boost )
add_dependencies( pl_editor boost ) add_dependencies( pl_editor boost )
add_dependencies( pnsrouter boost )
############# #############

View File

@ -0,0 +1,168 @@
# - Try to find the CAIRO library
# Once done this will define
#
# CAIRO_ROOT_DIR - Set this variable to the root installation of CAIRO
#
# Read-Only variables:
# CAIRO_FOUND - system has the CAIRO library
# CAIRO_INCLUDE_DIR - the CAIRO include directory
# CAIRO_LIBRARIES - The libraries needed to use CAIRO
# CAIRO_VERSION - This is set to $major.$minor.$revision (eg. 0.9.8)
#=============================================================================
# Copyright 2012 Dmitry Baryshnikov <polimax at mail dot ru>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
if (UNIX)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(_CAIRO cairo)
endif (PKG_CONFIG_FOUND)
endif (UNIX)
SET(_CAIRO_ROOT_HINTS
$ENV{CAIRO}
${CAIRO_ROOT_DIR}
)
SET(_CAIRO_ROOT_PATHS
$ENV{CAIRO}/src
/usr
/usr/local
)
SET(_CAIRO_ROOT_HINTS_AND_PATHS
HINTS ${_CAIRO_ROOT_HINTS}
PATHS ${_CAIRO_ROOT_PATHS}
)
FIND_PATH(CAIRO_INCLUDE_DIR
NAMES
cairo.h
HINTS
${_CAIRO_INCLUDEDIR}
${_CAIRO_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
include
"include/cairo"
)
IF(WIN32 AND NOT CYGWIN)
# MINGW should go here too
IF(MSVC)
# Implementation details:
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
FIND_LIBRARY(CAIRO_DEBUG
NAMES
cairod
${_CAIRO_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
"lib"
"VC"
"lib/VC"
)
FIND_LIBRARY(CAIRO_RELEASE
NAMES
cairo
${_CAIRO_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
"lib"
"VC"
"lib/VC"
)
if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
if(NOT CAIRO_DEBUG)
set(CAIRO_DEBUG ${CAIRO_RELEASE})
endif(NOT CAIRO_DEBUG)
set( CAIRO_LIBRARIES
optimized ${CAIRO_RELEASE} debug ${CAIRO_DEBUG}
)
else()
set( CAIRO_LIBRARIES ${CAIRO_RELEASE})
endif()
MARK_AS_ADVANCED(CAIRO_DEBUG CAIRO_RELEASE)
ELSEIF(MINGW)
# same player, for MingW
FIND_LIBRARY(CAIRO
NAMES
cairo
${_CAIRO_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
"lib"
"lib/MinGW"
)
MARK_AS_ADVANCED(CAIRO)
set( CAIRO_LIBRARIES ${CAIRO})
ELSE(MSVC)
# Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues:
FIND_LIBRARY(CAIRO
NAMES
cairo
HINTS
${_CAIRO_LIBDIR}
${_CAIRO_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
lib
)
MARK_AS_ADVANCED(CAIRO)
set( CAIRO_LIBRARIES ${CAIRO} )
ENDIF(MSVC)
ELSE(WIN32 AND NOT CYGWIN)
FIND_LIBRARY(CAIRO_LIBRARY
NAMES
cairo
HINTS
${_CAIRO_LIBDIR}
${_CAIRO_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
"lib"
"local/lib"
)
MARK_AS_ADVANCED(CAIRO_LIBRARY)
# compat defines
SET(CAIRO_LIBRARIES ${CAIRO_LIBRARY})
ENDIF(WIN32 AND NOT CYGWIN)
# if (CAIRO_INCLUDE_DIR)
# file(READ "${CAIRO_INCLUDE_DIR}/gcore/gdal_version.h" _wxgisgdal_VERSION_H_CONTENTS)
# string(REGEX REPLACE ".*# define[ \t]+GDAL_RELEASE_NAME[ \t]+\"([0-9A-Za-z.]+)\".*"
# "\\1" CAIRO_VERSION ${_wxgisgdal_VERSION_H_CONTENTS})
# set(CAIRO_VERSION ${CAIRO_VERSION} CACHE INTERNAL "The version number for wxgisgdal libraries")
# endif (CAIRO_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
# if (CAIRO_VERSION)
# find_package_handle_standard_args(CAIRO
# REQUIRED_VARS
# CAIRO_LIBRARIES
# CAIRO_INCLUDE_DIR
# VERSION_VAR
# CAIRO_VERSION
# FAIL_MESSAGE
# "Could NOT find CAIRO, try to set the path to CAIRO root folder in the system variable CAIRO_ROOT_DIR"
# )
# else (CAIRO_VERSION)
find_package_handle_standard_args(CAIRO "Could NOT find CAIRO, try to set the path to CAIRO root folder in the system variable CAIRO"
CAIRO_LIBRARIES
CAIRO_INCLUDE_DIR
)
# endif (CAIRO_VERSION)
MARK_AS_ADVANCED(CAIRO_INCLUDE_DIR CAIRO_LIBRARIES)

109
CMakeModules/FindGLEW.cmake Normal file
View File

@ -0,0 +1,109 @@
# Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
# - try to find glew library and include files
# GLEW_INCLUDE_DIR, where to find GL/glew.h, etc.
# GLEW_LIBRARIES, the libraries to link against
# GLEW_FOUND, If false, do not try to use GLEW.
# Also defined, but not for general use are:
# GLEW_GLEW_LIBRARY = the full path to the glew library.
IF (WIN32)
IF(CYGWIN)
FIND_PATH( GLEW_INCLUDE_DIR GL/glew.h)
FIND_LIBRARY( GLEW_GLEW_LIBRARY glew32
${OPENGL_LIBRARY_DIR}
/usr/lib/w32api
/usr/X11R6/lib
)
ELSE(CYGWIN)
FIND_PATH( GLEW_INCLUDE_DIR GL/glew.h
$ENV{GLEW_ROOT_PATH}/include
)
FIND_LIBRARY( GLEW_GLEW_LIBRARY
NAMES glew glew32 glew32s
PATHS
$ENV{GLEW_ROOT_PATH}/lib
${OPENGL_LIBRARY_DIR}
)
ENDIF(CYGWIN)
ELSE (WIN32)
IF (APPLE)
# These values for Apple could probably do with improvement.
FIND_PATH( GLEW_INCLUDE_DIR GL/glew.h
/System/Library/Frameworks/GLEW.framework/Versions/A/Headers
/opt/local/include
${OPENGL_LIBRARY_DIR}
)
FIND_LIBRARY( GLEW_GLEW_LIBRARY GLEW
/opt/local/lib
)
ELSE (APPLE)
FIND_PATH( GLEW_INCLUDE_DIR GL/glew.h
/usr/include/GL
/usr/openwin/share/include
/usr/openwin/include
/usr/X11R6/include
/usr/include/X11
/opt/graphics/OpenGL/include
/opt/graphics/OpenGL/contrib/libglew
)
FIND_LIBRARY( GLEW_GLEW_LIBRARY GLEW
/usr/openwin/lib
/usr/X11R6/lib
)
ENDIF (APPLE)
ENDIF (WIN32)
SET( GLEW_FOUND "NO" )
IF(GLEW_INCLUDE_DIR)
IF(GLEW_GLEW_LIBRARY)
# Is -lXi and -lXmu required on all platforms that have it?
# If not, we need some way to figure out what platform we are on.
SET( GLEW_LIBRARIES
${GLEW_GLEW_LIBRARY}
${GLEW_cocoa_LIBRARY}
)
SET( GLEW_FOUND "YES" )
#The following deprecated settings are for backwards compatibility with CMake1.4
SET (GLEW_LIBRARY ${GLEW_LIBRARIES})
SET (GLEW_INCLUDE_PATH ${GLEW_INCLUDE_DIR})
ENDIF(GLEW_GLEW_LIBRARY)
ENDIF(GLEW_INCLUDE_DIR)
IF(GLEW_FOUND)
IF(NOT GLEW_FIND_QUIETLY)
MESSAGE(STATUS "Found Glew: ${GLEW_LIBRARIES}")
ENDIF(NOT GLEW_FIND_QUIETLY)
ELSE(GLEW_FOUND)
IF(GLEW_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Glew")
ENDIF(GLEW_FIND_REQUIRED)
ENDIF(GLEW_FOUND)
MARK_AS_ADVANCED(
GLEW_INCLUDE_DIR
GLEW_GLEW_LIBRARY
GLEW_Xmu_LIBRARY
GLEW_Xi_LIBRARY
)

View File

@ -0,0 +1,57 @@
# CMake script file to process a GLSL source file, so it can be included
# in C array and compiled in to an application.
# number of input files
list( LENGTH inputFiles shadersNumber )
# check if GLSL source files were updated since the last time
set( update "FALSE" )
foreach( inputFile ${inputFiles} )
if( ${inputFile} IS_NEWER_THAN ${outputFile} )
set( update "TRUE" )
endif( ${inputFile} IS_NEWER_THAN ${outputFile} )
endforeach( inputFile ${inputFiles} )
if( NOT update )
message( "Headers are up-to-date" )
return()
endif( NOT update )
# write header
file( WRITE ${outputFile} "// Do not edit this file, it is autogenerated by CMake.
#ifndef SHADER_SRC_H
#define SHADER_SRC_H
const unsigned int shaders_number = ${shadersNumber};
const char* shaders_src[] =
{\n" )
foreach( inputFile ${inputFiles} )
# put the input file name into the output file
file( APPEND ${outputFile} "\n// ${inputFile}" )
# process the input file
file( READ ${inputFile} contents )
# remove /* */ comments
string( REGEX REPLACE "/\\*.*\\*/" "" contents "${contents}" )
# remove // comments
string( REGEX REPLACE "//[^\n]*" "" contents "${contents}" )
# remove whitespaces at the beginning of each line
string( REGEX REPLACE "\n([\t ])*" "\n" contents "${contents}" )
# remove unnecessary spaces
string( REGEX REPLACE " *([\\*/+&\\|,=<>\(\)]) *" "\\1" contents "${contents}" )
# remove empty lines & wrap every line in "" and add '\n' at the end of each line
string( REGEX REPLACE "\n+" "\\\\n\"\n\"" contents "${contents}" )
# remove unnecessary " & \n from the beginning and the end of contents
string( REGEX REPLACE "^\\\\n\"" "" contents "${contents}" )
string( REGEX REPLACE "\"$" "," contents "${contents}" )
file( APPEND ${outputFile} "${contents}" )
endforeach( inputFile ${inputFiles} )
# write footer
file( APPEND ${outputFile} "};
#endif /* SHADER_SRC_H */" )

View File

@ -0,0 +1,11 @@
So, finally we've got an integrated interactive, push-and-sometimes-shove router, although with a very limited user interface:
- Edit->Interactive router launches the tool,
- while routing: 'V' key places a via,
- '+' and '-' keys cycle through available layers,
- '/' key switches track posture.
Via/track dimensions are taken from the netclasses.
There are no other options available for the time being - promise to add them soon :)
Tom

View File

@ -3,12 +3,65 @@ include_directories(BEFORE ${INC_BEFORE})
include_directories( include_directories(
./dialogs ./dialogs
./dialog_about ./dialog_about
${CAIRO_INCLUDE_DIR}
${GLEW_INCLUDE_DIR}
../3d-viewer ../3d-viewer
../pcbnew ../pcbnew
../polygon ../polygon
${INC_AFTER} ${INC_AFTER}
) )
# Generate header files containing shader programs
# Order of input files is significant
add_custom_command(
OUTPUT gal/opengl/shader_src.h
COMMAND ${CMAKE_COMMAND}
-DinputFiles="${PROJECT_SOURCE_DIR}/common/gal/opengl/shader.vert\\;${PROJECT_SOURCE_DIR}/common/gal/opengl/shader.frag"
-DoutputFile="shader_src.h"
-P ${CMAKE_MODULE_PATH}/Shaders.cmake
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/common/gal/opengl
COMMENT "Generating headers containing GLSL source code"
)
add_custom_target(
shader_headers ALL
DEPENDS gal/opengl/shader_src.h
)
set(GAL_SRCS
# Common part
drawpanel_gal.cpp
painter.cpp
worksheet_viewitem.cpp
gal/graphics_abstraction_layer.cpp
gal/stroke_font.cpp
gal/color4d.cpp
view/wx_view_controls.cpp
# OpenGL GAL
gal/opengl/opengl_gal.cpp
gal/opengl/shader.cpp
gal/opengl/vertex_item.cpp
gal/opengl/vertex_container.cpp
gal/opengl/cached_container.cpp
gal/opengl/noncached_container.cpp
gal/opengl/vertex_manager.cpp
gal/opengl/gpu_manager.cpp
gal/opengl/opengl_compositor.cpp
# Cairo GAL
gal/cairo/cairo_gal.cpp
gal/cairo/cairo_compositor.cpp
)
add_library(gal STATIC ${GAL_SRCS})
add_dependencies(gal shader_headers)
# Only for win32 cross compilation using MXE
if(WIN32 AND MSYS)
add_definitions(-DGLEW_STATIC)
endif(WIN32 AND MSYS)
set(COMMON_ABOUT_DLG_SRCS set(COMMON_ABOUT_DLG_SRCS
dialog_about/AboutDialog_main.cpp dialog_about/AboutDialog_main.cpp
dialog_about/dialog_about.cpp dialog_about/dialog_about.cpp
@ -95,6 +148,32 @@ set(COMMON_SRCS
zoom.cpp zoom.cpp
) )
enable_language(C CXX ASM)
set_source_files_properties(system/fcontext.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
set(COMMON_SRCS
${COMMON_SRCS}
view/view.cpp
view/view_item.cpp
view/view_group.cpp
math/math_util.cpp
system/fcontext.s
tool/tool_base.cpp
tool/tool_manager.cpp
tool/tool_dispatcher.cpp
tool/tool_event.cpp
tool/tool_interactive.cpp
tool/action_manager.cpp
tool/context_menu.cpp
geometry/seg.cpp
geometry/shape_line_chain.cpp
geometry/shape_collisions.cpp
geometry/shape_index.cpp
)
add_library(common STATIC ${COMMON_SRCS}) add_library(common STATIC ${COMMON_SRCS})
set(PCB_COMMON_SRCS set(PCB_COMMON_SRCS
@ -151,6 +230,10 @@ set(PCB_COMMON_SRCS
fp_lib_table.cpp fp_lib_table.cpp
) )
set(PCB_COMMON_SRCS
${PCB_COMMON_SRCS}
../pcbnew/pcb_painter.cpp
)
# add -DPCBNEW to compilation of these PCBNEW sources # add -DPCBNEW to compilation of these PCBNEW sources
set_source_files_properties( ${PCB_COMMON_SRCS} PROPERTIES set_source_files_properties( ${PCB_COMMON_SRCS} PROPERTIES

View File

@ -38,6 +38,10 @@
#include "../eeschema/dialogs/dialog_schematic_find.h" #include "../eeschema/dialogs/dialog_schematic_find.h"
const wxString traceFindReplace( wxT( "KicadFindReplace" ) );
enum textbox { enum textbox {
ID_TEXTBOX_LIST = 8010 ID_TEXTBOX_LIST = 8010
}; };
@ -190,8 +194,28 @@ bool EDA_ITEM::Replace( wxFindReplaceData& aSearchData, wxString& aText )
wxCHECK_MSG( IsReplaceable(), false, wxCHECK_MSG( IsReplaceable(), false,
wxT( "Attempt to replace text in <" ) + GetClass() + wxT( "> item." ) ); wxT( "Attempt to replace text in <" ) + GetClass() + wxT( "> item." ) );
return aText.Replace( aSearchData.GetFindString(), wxString searchString = (aSearchData.GetFlags() & wxFR_MATCHCASE) ? aText.Upper() : aText;
aSearchData.GetReplaceString(), false ) != 0;
int result = searchString.Find( (aSearchData.GetFlags() & wxFR_MATCHCASE) ?
aSearchData.GetFindString() :
aSearchData.GetFindString().Upper() );
if( result == wxNOT_FOUND )
return false;
wxString prefix = aText.Left( result );
wxString suffix;
if( aSearchData.GetFindString().length() + result < aText.length() )
suffix = aText.Right( aText.length() - ( aSearchData.GetFindString().length() + result ) );
wxLogTrace( traceFindReplace, wxT( "Replacing '%s', prefix '%s', replace '%s', suffix '%s'." ),
GetChars( aText ), GetChars( prefix ), GetChars( aSearchData.GetReplaceString() ),
GetChars( suffix ) );
aText = prefix + aSearchData.GetReplaceString() + suffix;
return true;
} }
@ -222,6 +246,22 @@ EDA_ITEM& EDA_ITEM::operator=( const EDA_ITEM& aItem )
} }
const BOX2I EDA_ITEM::ViewBBox() const
{
// Basic fallback
return BOX2I( VECTOR2I( GetBoundingBox().GetOrigin() ),
VECTOR2I( GetBoundingBox().GetSize() ) );
}
void EDA_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
{
// Basic fallback
aCount = 1;
aLayers[0] = 0;
}
#if defined(DEBUG) #if defined(DEBUG)
// A function that should have been in wxWidgets // A function that should have been in wxWidgets

View File

@ -35,6 +35,7 @@
#include <macros.h> #include <macros.h>
#include <id.h> #include <id.h>
#include <class_drawpanel.h> #include <class_drawpanel.h>
#include <class_drawpanel_gal.h>
#include <class_base_screen.h> #include <class_base_screen.h>
#include <msgpanel.h> #include <msgpanel.h>
#include <wxstruct.h> #include <wxstruct.h>
@ -42,10 +43,11 @@
#include <kicad_device_context.h> #include <kicad_device_context.h>
#include <dialog_helpers.h> #include <dialog_helpers.h>
#include <base_units.h> #include <base_units.h>
#include <vector2d.h> #include <math/box2.h>
#include <wx/fontdlg.h> #include <wx/fontdlg.h>
#include <view/view.h>
#include <gal/graphics_abstraction_layer.h>
/** /**
* Definition for enabling and disabling scroll bar setting trace output. See the * Definition for enabling and disabling scroll bar setting trace output. See the
@ -100,6 +102,8 @@ EDA_DRAW_FRAME::EDA_DRAW_FRAME( wxWindow* aParent,
m_HotkeysZoomAndGridList = NULL; m_HotkeysZoomAndGridList = NULL;
m_canvas = NULL; m_canvas = NULL;
m_galCanvas = NULL;
m_galCanvasActive = false;
m_messagePanel = NULL; m_messagePanel = NULL;
m_currentScreen = NULL; m_currentScreen = NULL;
m_toolId = ID_NO_TOOL_SELECTED; m_toolId = ID_NO_TOOL_SELECTED;
@ -224,6 +228,12 @@ void EDA_DRAW_FRAME::SkipNextLeftButtonReleaseEvent()
void EDA_DRAW_FRAME::OnToggleGridState( wxCommandEvent& aEvent ) void EDA_DRAW_FRAME::OnToggleGridState( wxCommandEvent& aEvent )
{ {
SetGridVisibility( !IsGridVisible() ); SetGridVisibility( !IsGridVisible() );
if( m_galCanvasActive )
{
m_galCanvas->GetGAL()->SetGridVisibility( IsGridVisible() );
m_galCanvas->GetView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
}
m_canvas->Refresh(); m_canvas->Refresh();
} }
@ -376,7 +386,15 @@ void EDA_DRAW_FRAME::OnSelectGrid( wxCommandEvent& event )
m_LastGridSizeId = id - ID_POPUP_GRID_LEVEL_1000; m_LastGridSizeId = id - ID_POPUP_GRID_LEVEL_1000;
screen->SetGrid( id ); screen->SetGrid( id );
SetCrossHairPosition( RefPos( true ) ); SetCrossHairPosition( RefPos( true ) );
Refresh();
if( m_galCanvasActive )
{
m_galCanvas->GetGAL()->SetGridSize( VECTOR2D( screen->GetGrid().m_Size.x,
screen->GetGrid().m_Size.y ) );
m_galCanvas->GetView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
}
m_canvas->Refresh();
} }
@ -403,7 +421,21 @@ void EDA_DRAW_FRAME::OnSelectZoom( wxCommandEvent& event )
return; return;
GetScreen()->SetZoom( selectedZoom ); GetScreen()->SetZoom( selectedZoom );
RedrawScreen( GetScrollCenterPosition(), false );
if( m_galCanvasActive )
{
// Apply computed view settings to GAL
KIGFX::VIEW* view = m_galCanvas->GetView();
KIGFX::GAL* gal = m_galCanvas->GetGAL();
double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor();
double zoom = 1.0 / ( zoomFactor * GetZoom() );
view->SetScale( zoom );
m_galCanvas->Refresh();
}
else
RedrawScreen( GetScrollCenterPosition(), false );
} }
} }
@ -738,7 +770,7 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
DSIZE clientSizeIU( clientSizeDU.x / scale, clientSizeDU.y / scale ); DSIZE clientSizeIU( clientSizeDU.x / scale, clientSizeDU.y / scale );
// Full drawing or "page" rectangle in internal units // Full drawing or "page" rectangle in internal units
DBOX pageRectIU( 0, 0, GetPageSizeIU().x, GetPageSizeIU().y ); DBOX pageRectIU( wxPoint( 0, 0 ), wxSize( GetPageSizeIU().x, GetPageSizeIU().y ) );
// The upper left corner of the client rectangle in internal units. // The upper left corner of the client rectangle in internal units.
double xIU = aCenterPositionIU.x - clientSizeIU.x / 2.0; double xIU = aCenterPositionIU.x - clientSizeIU.x / 2.0;
@ -748,11 +780,11 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
if( screen->m_Center ) if( screen->m_Center )
{ {
// half page offset. // half page offset.
xIU += pageRectIU.width / 2.0; xIU += pageRectIU.GetWidth() / 2.0;
yIU += pageRectIU.height / 2.0; yIU += pageRectIU.GetHeight() / 2.0;
} }
DBOX clientRectIU( xIU, yIU, clientSizeIU.x, clientSizeIU.y ); DBOX clientRectIU( wxPoint( xIU, yIU ), wxSize( clientSizeIU.x, clientSizeIU.y ) );
wxPoint centerPositionIU; wxPoint centerPositionIU;
// put "int" limits on the clientRect // put "int" limits on the clientRect
@ -765,13 +797,13 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
if( clientRectIU.GetBottom() > VIRT_MAX ) if( clientRectIU.GetBottom() > VIRT_MAX )
clientRectIU.MoveBottomTo( VIRT_MAX ); clientRectIU.MoveBottomTo( VIRT_MAX );
centerPositionIU.x = KiROUND( clientRectIU.x + clientRectIU.width/2 ); centerPositionIU.x = KiROUND( clientRectIU.GetX() + clientRectIU.GetWidth() / 2 );
centerPositionIU.y = KiROUND( clientRectIU.y + clientRectIU.height/2 ); centerPositionIU.y = KiROUND( clientRectIU.GetY() + clientRectIU.GetHeight() / 2 );
if( screen->m_Center ) if( screen->m_Center )
{ {
centerPositionIU.x -= KiROUND( pageRectIU.width / 2.0 ); centerPositionIU.x -= KiROUND( pageRectIU.GetWidth() / 2.0 );
centerPositionIU.y -= KiROUND( pageRectIU.height / 2.0 ); centerPositionIU.y -= KiROUND( pageRectIU.GetHeight() / 2.0 );
} }
DSIZE virtualSizeIU; DSIZE virtualSizeIU;
@ -782,26 +814,26 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
} }
else else
{ {
double pageCenterX = pageRectIU.x + ( pageRectIU.width / 2 ); double pageCenterX = pageRectIU.GetX() + ( pageRectIU.GetWidth() / 2 );
double clientCenterX = clientRectIU.x + ( clientRectIU.width / 2 ); double clientCenterX = clientRectIU.GetX() + ( clientRectIU.GetWidth() / 2 );
if( clientRectIU.width > pageRectIU.width ) if( clientRectIU.GetWidth() > pageRectIU.GetWidth() )
{ {
if( pageCenterX > clientCenterX ) if( pageCenterX > clientCenterX )
virtualSizeIU.x = ( pageCenterX - clientRectIU.GetLeft() ) * 2; virtualSizeIU.x = ( pageCenterX - clientRectIU.GetLeft() ) * 2;
else if( pageCenterX < clientCenterX ) else if( pageCenterX < clientCenterX )
virtualSizeIU.x = ( clientRectIU.GetRight() - pageCenterX ) * 2; virtualSizeIU.x = ( clientRectIU.GetRight() - pageCenterX ) * 2;
else else
virtualSizeIU.x = clientRectIU.width; virtualSizeIU.x = clientRectIU.GetWidth();
} }
else else
{ {
if( pageCenterX > clientCenterX ) if( pageCenterX > clientCenterX )
virtualSizeIU.x = pageRectIU.width + ( (pageRectIU.GetLeft() - clientRectIU.GetLeft() ) * 2 ); virtualSizeIU.x = pageRectIU.GetWidth() + ( (pageRectIU.GetLeft() - clientRectIU.GetLeft() ) * 2 );
else if( pageCenterX < clientCenterX ) else if( pageCenterX < clientCenterX )
virtualSizeIU.x = pageRectIU.width + ( (clientRectIU.GetRight() - pageRectIU.GetRight() ) * 2 ); virtualSizeIU.x = pageRectIU.GetWidth() + ( (clientRectIU.GetRight() - pageRectIU.GetRight() ) * 2 );
else else
virtualSizeIU.x = pageRectIU.width; virtualSizeIU.x = pageRectIU.GetWidth();
} }
} }
@ -811,28 +843,28 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
} }
else else
{ {
double pageCenterY = pageRectIU.y + ( pageRectIU.height / 2 ); double pageCenterY = pageRectIU.GetY() + ( pageRectIU.GetHeight() / 2 );
double clientCenterY = clientRectIU.y + ( clientRectIU.height / 2 ); double clientCenterY = clientRectIU.GetY() + ( clientRectIU.GetHeight() / 2 );
if( clientRectIU.height > pageRectIU.height ) if( clientRectIU.GetHeight() > pageRectIU.GetHeight() )
{ {
if( pageCenterY > clientCenterY ) if( pageCenterY > clientCenterY )
virtualSizeIU.y = ( pageCenterY - clientRectIU.GetTop() ) * 2; virtualSizeIU.y = ( pageCenterY - clientRectIU.GetTop() ) * 2;
else if( pageCenterY < clientCenterY ) else if( pageCenterY < clientCenterY )
virtualSizeIU.y = ( clientRectIU.GetBottom() - pageCenterY ) * 2; virtualSizeIU.y = ( clientRectIU.GetBottom() - pageCenterY ) * 2;
else else
virtualSizeIU.y = clientRectIU.height; virtualSizeIU.y = clientRectIU.GetHeight();
} }
else else
{ {
if( pageCenterY > clientCenterY ) if( pageCenterY > clientCenterY )
virtualSizeIU.y = pageRectIU.height + virtualSizeIU.y = pageRectIU.GetHeight() +
( ( pageRectIU.GetTop() - clientRectIU.GetTop() ) * 2 ); ( ( pageRectIU.GetTop() - clientRectIU.GetTop() ) * 2 );
else if( pageCenterY < clientCenterY ) else if( pageCenterY < clientCenterY )
virtualSizeIU.y = pageRectIU.height + virtualSizeIU.y = pageRectIU.GetHeight() +
( ( clientRectIU.GetBottom() - pageRectIU.GetBottom() ) * 2 ); ( ( clientRectIU.GetBottom() - pageRectIU.GetBottom() ) * 2 );
else else
virtualSizeIU.y = pageRectIU.height; virtualSizeIU.y = pageRectIU.GetHeight();
} }
} }
@ -847,8 +879,8 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
} }
else else
{ {
screen->m_DrawOrg.x = -KiROUND( ( virtualSizeIU.x - pageRectIU.width ) / 2.0 ); screen->m_DrawOrg.x = -KiROUND( ( virtualSizeIU.x - pageRectIU.GetWidth() ) / 2.0 );
screen->m_DrawOrg.y = -KiROUND( ( virtualSizeIU.y - pageRectIU.height ) / 2.0 ); screen->m_DrawOrg.y = -KiROUND( ( virtualSizeIU.y - pageRectIU.GetHeight() ) / 2.0 );
} }
/* Always set scrollbar pixels per unit to 1 unless you want the zoom /* Always set scrollbar pixels per unit to 1 unless you want the zoom
@ -867,8 +899,8 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
// center position at the center of client rectangle. // center position at the center of client rectangle.
SetScrollCenterPosition( centerPositionIU ); SetScrollCenterPosition( centerPositionIU );
double posX = centerPositionIU.x - clientRectIU.width /2.0 - screen->m_DrawOrg.x; double posX = centerPositionIU.x - clientRectIU.GetWidth() / 2.0 - screen->m_DrawOrg.x;
double posY = centerPositionIU.y - clientRectIU.height/2.0 - screen->m_DrawOrg.y; double posY = centerPositionIU.y - clientRectIU.GetHeight() / 2.0 - screen->m_DrawOrg.y;
// Convert scroll bar position to device units. // Convert scroll bar position to device units.
posX = KiROUND( posX * scale ); posX = KiROUND( posX * scale );
@ -919,6 +951,61 @@ void EDA_DRAW_FRAME::AdjustScrollBars( const wxPoint& aCenterPositionIU )
screen->m_ScrollbarPos.y, noRefresh ); screen->m_ScrollbarPos.y, noRefresh );
} }
void EDA_DRAW_FRAME::UseGalCanvas( bool aEnable )
{
KIGFX::VIEW* view = m_galCanvas->GetView();
KIGFX::GAL* gal = m_galCanvas->GetGAL();
double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor();
// Display the same view after canvas switching
if( aEnable )
{
BASE_SCREEN* screen = GetScreen();
// Switch to GAL rendering
if( !m_galCanvasActive )
{
// Set up viewport
double zoom = 1.0 / ( zoomFactor * m_canvas->GetZoom() );
view->SetScale( zoom );
view->SetCenter( VECTOR2D( m_canvas->GetScreenCenterLogicalPosition() ) );
}
// Set up grid settings
gal->SetGridVisibility( IsGridVisible() );
gal->SetGridSize( VECTOR2D( screen->GetGridSize().x, screen->GetGridSize().y ) );
gal->SetGridOrigin( VECTOR2D( GetGridOrigin() ) );
}
else
{
// Switch to standard rendering
if( m_galCanvasActive )
{
// Change view settings only if GAL was active previously
double zoom = 1.0 / ( zoomFactor * view->GetScale() );
m_canvas->SetZoom( zoom );
VECTOR2D center = view->GetCenter();
RedrawScreen( wxPoint( center.x, center.y ), false );
}
}
m_canvas->SetEvtHandlerEnabled( !aEnable );
m_galCanvas->SetEvtHandlerEnabled( aEnable );
// Switch panes
m_auimgr.GetPane( wxT( "DrawFrame" ) ).Show( !aEnable );
m_auimgr.GetPane( wxT( "DrawFrameGal" ) ).Show( aEnable );
m_auimgr.Update();
m_galCanvasActive = aEnable;
if( aEnable )
m_galCanvas->SetFocus();
}
//-----< BASE_SCREEN API moved here >-------------------------------------------- //-----< BASE_SCREEN API moved here >--------------------------------------------
wxPoint EDA_DRAW_FRAME::GetCrossHairPosition( bool aInvertY ) const wxPoint EDA_DRAW_FRAME::GetCrossHairPosition( bool aInvertY ) const
@ -986,4 +1073,3 @@ void EDA_DRAW_FRAME::SetScrollCenterPosition( const wxPoint& aPoint )
} }
//-----</BASE_SCREEN API moved here >-------------------------------------------- //-----</BASE_SCREEN API moved here >--------------------------------------------

View File

@ -34,6 +34,7 @@
#include <macros.h> #include <macros.h>
#include <id.h> #include <id.h>
#include <class_drawpanel.h> #include <class_drawpanel.h>
#include <class_drawpanel_gal.h>
#include <class_base_screen.h> #include <class_base_screen.h>
#include <wxstruct.h> #include <wxstruct.h>
@ -84,10 +85,17 @@ END_EVENT_TABLE()
EDA_DRAW_PANEL::EDA_DRAW_PANEL( EDA_DRAW_FRAME* parent, int id, EDA_DRAW_PANEL::EDA_DRAW_PANEL( EDA_DRAW_FRAME* parent, int id,
const wxPoint& pos, const wxSize& size ) : const wxPoint& pos, const wxSize& size ) :
#if wxCHECK_VERSION( 2, 9, 5 )
wxScrolledWindow( parent, id, pos, size, wxBORDER | wxHSCROLL | wxVSCROLL )
#else
wxScrolledWindow( parent, id, pos, size, wxBORDER | wxHSCROLL | wxVSCROLL | wxALWAYS_SHOW_SB ) wxScrolledWindow( parent, id, pos, size, wxBORDER | wxHSCROLL | wxVSCROLL | wxALWAYS_SHOW_SB )
#endif
{ {
wxASSERT( parent ); wxASSERT( parent );
#if wxCHECK_VERSION( 2, 9, 5 )
ShowScrollbars( wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS );
#endif
m_scrollIncrementX = std::min( size.x / 8, 10 ); m_scrollIncrementX = std::min( size.x / 8, 10 );
m_scrollIncrementY = std::min( size.y / 8, 10 ); m_scrollIncrementY = std::min( size.y / 8, 10 );
@ -288,6 +296,19 @@ void EDA_DRAW_PANEL::RefreshDrawingRect( const EDA_RECT& aRect, bool aEraseBackg
} }
void EDA_DRAW_PANEL::Refresh( bool eraseBackground, const wxRect* rect )
{
if( GetParent()->IsGalCanvasActive() )
{
GetParent()->GetGalCanvas()->Refresh();
}
else
{
wxScrolledWindow::Refresh( eraseBackground, rect );
}
}
wxPoint EDA_DRAW_PANEL::GetScreenCenterLogicalPosition() wxPoint EDA_DRAW_PANEL::GetScreenCenterLogicalPosition()
{ {
wxSize size = GetClientSize() / 2; wxSize size = GetClientSize() / 2;

251
common/drawpanel_gal.cpp Normal file
View File

@ -0,0 +1,251 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <wx/wx.h>
#include <wx/frame.h>
#include <wx/window.h>
#include <wx/event.h>
#include <wx/colour.h>
#include <wx/filename.h>
#include <class_drawpanel_gal.h>
#include <view/view.h>
#include <view/wx_view_controls.h>
#include <pcb_painter.h>
#include <gal/graphics_abstraction_layer.h>
#include <gal/opengl/opengl_gal.h>
#include <gal/cairo/cairo_gal.h>
#include <tool/tool_dispatcher.h>
#include <tool/tool_manager.h>
#ifdef __WXDEBUG__
#include <profile.h>
#endif /* __WXDEBUG__ */
#define METRIC_UNIT_LENGTH (1e9)
EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWindowId,
const wxPoint& aPosition, const wxSize& aSize,
GalType aGalType ) :
wxWindow( aParentWindow, aWindowId, aPosition, aSize )
{
m_gal = NULL;
m_currentGal = GAL_TYPE_NONE;
m_view = NULL;
m_painter = NULL;
m_eventDispatcher = NULL;
SwitchBackend( aGalType );
SetBackgroundStyle( wxBG_STYLE_CUSTOM );
// Initial display settings
m_gal->SetLookAtPoint( VECTOR2D( 0, 0 ) );
m_gal->SetZoomFactor( 1.0 );
m_gal->ComputeWorldScreenMatrix();
m_painter = new KIGFX::PCB_PAINTER( m_gal );
m_view = new KIGFX::VIEW( true );
m_view->SetPainter( m_painter );
m_view->SetGAL( m_gal );
m_viewControls = new KIGFX::WX_VIEW_CONTROLS( m_view, this );
Connect( wxEVT_PAINT, wxPaintEventHandler( EDA_DRAW_PANEL_GAL::onPaint ), NULL, this );
Connect( wxEVT_SIZE, wxSizeEventHandler( EDA_DRAW_PANEL_GAL::onSize ), NULL, this );
/* Generic events for the Tool Dispatcher */
Connect( wxEVT_MOTION, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_LEFT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_LEFT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_RIGHT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_RIGHT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_MIDDLE_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_MIDDLE_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) );
Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
Connect( wxEVT_ENTER_WINDOW, wxEventHandler( EDA_DRAW_PANEL_GAL::onEnter ), NULL, this );
Connect( KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE,
wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
m_refreshTimer.SetOwner( this );
Connect( wxEVT_TIMER, wxTimerEventHandler( EDA_DRAW_PANEL_GAL::onRefreshTimer ), NULL, this );
this->SetFocus();
}
EDA_DRAW_PANEL_GAL::~EDA_DRAW_PANEL_GAL()
{
if( m_painter )
delete m_painter;
if( m_viewControls )
delete m_viewControls;
if( m_view )
delete m_view;
if( m_gal )
delete m_gal;
}
void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
{
m_pendingRefresh = false;
m_lastRefresh = wxGetLocalTimeMillis();
m_gal->BeginDrawing();
m_gal->SetBackgroundColor( KIGFX::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
m_gal->ClearScreen();
m_view->ClearTargets();
// Grid has to be redrawn only when the NONCACHED target is redrawn
if( m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) )
m_gal->DrawGrid();
m_view->Redraw();
m_gal->DrawCursor( m_viewControls->GetCursorPosition() );
m_gal->EndDrawing();
}
void EDA_DRAW_PANEL_GAL::onSize( wxSizeEvent& aEvent )
{
m_gal->ResizeScreen( aEvent.GetSize().x, aEvent.GetSize().y );
m_view->MarkTargetDirty( KIGFX::TARGET_CACHED );
m_view->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
}
void EDA_DRAW_PANEL_GAL::onRefreshTimer( wxTimerEvent& aEvent )
{
wxPaintEvent redrawEvent;
wxPostEvent( this, redrawEvent );
}
void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect )
{
if( m_pendingRefresh )
return;
wxLongLong t = wxGetLocalTimeMillis();
wxLongLong delta = t - m_lastRefresh;
if( delta >= MinRefreshPeriod )
{
wxPaintEvent redrawEvent;
wxPostEvent( this, redrawEvent );
m_pendingRefresh = true;
}
else
{
// One shot timer
m_refreshTimer.Start( ( MinRefreshPeriod - delta ).ToLong(), true );
m_pendingRefresh = true;
}
}
void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
{
// Protect from refreshing during backend switch
m_pendingRefresh = true;
m_refreshTimer.Stop();
// Do not do anything if the currently used GAL is correct
if( aGalType == m_currentGal && m_gal != NULL )
return;
delete m_gal;
switch( aGalType )
{
case GAL_TYPE_OPENGL:
m_gal = new KIGFX::OPENGL_GAL( this, this, this );
break;
case GAL_TYPE_CAIRO:
m_gal = new KIGFX::CAIRO_GAL( this, this, this );
break;
case GAL_TYPE_NONE:
return;
}
m_gal->SetWorldUnitLength( 1.0 / METRIC_UNIT_LENGTH * 2.54 ); // 1 inch in nanometers
m_gal->SetScreenDPI( 106 ); // Display resolution setting
m_gal->ComputeWorldScreenMatrix();
wxSize size = GetClientSize();
m_gal->ResizeScreen( size.GetX(), size.GetY() );
if( m_painter )
m_painter->SetGAL( m_gal );
if( m_view )
{
m_view->SetGAL( m_gal );
m_view->RecacheAllItems( true );
}
m_currentGal = aGalType;
m_pendingRefresh = false;
}
void EDA_DRAW_PANEL_GAL::onEvent( wxEvent& aEvent )
{
if( !m_eventDispatcher )
{
aEvent.Skip();
return;
}
else
{
m_eventDispatcher->DispatchWxEvent( aEvent );
}
Refresh();
}
void EDA_DRAW_PANEL_GAL::onEnter( wxEvent& aEvent )
{
// Getting focus is necessary in order to receive key events properly
SetFocus();
}
void EDA_DRAW_PANEL_GAL::skipEvent( wxEvent& aEvent )
{
// This is necessary for CHAR_HOOK event to generate KEY_UP and KEY_DOWN events
aEvent.Skip();
}

View File

@ -32,6 +32,13 @@
#include <trigo.h> // RotatePoint #include <trigo.h> // RotatePoint
#include <class_drawpanel.h> // EDA_DRAW_PANEL #include <class_drawpanel.h> // EDA_DRAW_PANEL
// until bzr rev 4410, Y position of vertical justification
// of multiline texts was incorrectly calculated for BOTTOM
// and CENTER vertical justification. (Only the first line was justified)
// If this line is left uncommented, the bug is fixed, but
// creates a (very minor) issue for existing texts, mainly in Pcbnew
// because the text position is sometimes critical.
#define FIX_MULTILINE_VERT_JUSTIF
// Conversion to application internal units defined at build time. // Conversion to application internal units defined at build time.
#if defined( PCBNEW ) #if defined( PCBNEW )
@ -90,6 +97,16 @@ int EDA_TEXT::LenSize( const wxString& aLine ) const
return ReturnGraphicTextWidth( aLine, m_Size.x, m_Italic, m_Bold ); return ReturnGraphicTextWidth( aLine, m_Size.x, m_Italic, m_Bold );
} }
/**
* Function GetInterline
* return the distance between 2 text lines
* has meaning only for multiline texts
*/
int EDA_TEXT::GetInterline( int aTextThickness ) const
{
int thickness = aTextThickness <= 0 ? m_Thickness : aTextThickness;
return (( m_Size.y * 14 ) / 10) + thickness;
}
EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const
{ {
@ -98,6 +115,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const
wxArrayString* list = NULL; wxArrayString* list = NULL;
wxString text = m_Text; wxString text = m_Text;
int thickness = ( aThickness < 0 ) ? m_Thickness : aThickness; int thickness = ( aThickness < 0 ) ? m_Thickness : aThickness;
int linecount = 1;
if( m_MultilineAllowed ) if( m_MultilineAllowed )
{ {
@ -109,12 +127,14 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const
text = list->Item( aLine ); text = list->Item( aLine );
else else
text = list->Item( 0 ); text = list->Item( 0 );
linecount = list->GetCount();
} }
} }
// calculate the H and V size // calculate the H and V size
int dx = LenSize( text ); int dx = LenSize( text );
int dy = GetInterline(); int dy = GetInterline( aThickness );
/* Creates bounding box (rectangle) for an horizontal text */ /* Creates bounding box (rectangle) for an horizontal text */
wxSize textsize = wxSize( dx, dy ); wxSize textsize = wxSize( dx, dy );
@ -175,7 +195,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const
break; break;
case GR_TEXT_VJUSTIFY_CENTER: case GR_TEXT_VJUSTIFY_CENTER:
rect.SetY( rect.GetY() - (dy / 2) ); rect.SetY( rect.GetY() - ( dy / 2) );
break; break;
case GR_TEXT_VJUSTIFY_BOTTOM: case GR_TEXT_VJUSTIFY_BOTTOM:
@ -183,6 +203,30 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const
break; break;
} }
if( linecount > 1 )
{
#ifdef FIX_MULTILINE_VERT_JUSTIF
int yoffset;
linecount -= 1;
switch( m_VJustify )
{
case GR_TEXT_VJUSTIFY_TOP:
break;
case GR_TEXT_VJUSTIFY_CENTER:
yoffset = linecount * GetInterline() / 2;
rect.SetY( rect.GetY() - yoffset );
break;
case GR_TEXT_VJUSTIFY_BOTTOM:
yoffset = linecount * GetInterline( aThickness );
rect.SetY( rect.GetY() - yoffset );
break;
}
#endif
}
rect.Inflate( thickness / 2 ); rect.Inflate( thickness / 2 );
rect.Normalize(); // Make h and v sizes always >= 0 rect.Normalize(); // Make h and v sizes always >= 0
@ -227,15 +271,31 @@ void EDA_TEXT::Draw( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aOffset,
offset.y = GetInterline(); offset.y = GetInterline();
#ifdef FIX_MULTILINE_VERT_JUSTIF
if( list->Count() > 1 )
{
switch( m_VJustify )
{
case GR_TEXT_VJUSTIFY_TOP:
break;
case GR_TEXT_VJUSTIFY_CENTER:
pos.y -= ( list->Count() - 1 ) * offset.y / 2;
break;
case GR_TEXT_VJUSTIFY_BOTTOM:
pos.y -= ( list->Count() - 1 ) * offset.y;
break;
}
}
#endif
RotatePoint( &offset, m_Orient ); RotatePoint( &offset, m_Orient );
for( unsigned i = 0; i<list->Count(); i++ ) for( unsigned i = 0; i<list->Count(); i++ )
{ {
wxString txt = list->Item( i ); wxString txt = list->Item( i );
drawOneLineOfText( aClipBox, aDC, aOffset, aColor, drawOneLineOfText( aClipBox, aDC, aOffset, aColor,
aDrawMode, aFillMode, aDrawMode, aFillMode, txt, pos );
i ? UNSPECIFIED_COLOR : aAnchor_color,
txt, pos );
pos += offset; pos += offset;
} }
@ -243,15 +303,21 @@ void EDA_TEXT::Draw( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aOffset,
} }
else else
drawOneLineOfText( aClipBox, aDC, aOffset, aColor, drawOneLineOfText( aClipBox, aDC, aOffset, aColor,
aDrawMode, aFillMode, aDrawMode, aFillMode, m_Text, m_Pos );
aAnchor_color, m_Text, m_Pos );
// Draw text anchor, if requested
if( aAnchor_color != UNSPECIFIED_COLOR )
{
GRDrawAnchor( aClipBox, aDC,
m_Pos.x + aOffset.x, m_Pos.y + aOffset.y,
DIM_ANCRE_TEXTE, aAnchor_color );
}
} }
void EDA_TEXT::drawOneLineOfText( EDA_RECT* aClipBox, wxDC* aDC, void EDA_TEXT::drawOneLineOfText( EDA_RECT* aClipBox, wxDC* aDC,
const wxPoint& aOffset, EDA_COLOR_T aColor, const wxPoint& aOffset, EDA_COLOR_T aColor,
GR_DRAWMODE aDrawMode, EDA_DRAW_MODE_T aFillMode, GR_DRAWMODE aDrawMode, EDA_DRAW_MODE_T aFillMode,
EDA_COLOR_T aAnchor_color,
wxString& aText, wxPoint aPos ) wxString& aText, wxPoint aPos )
{ {
int width = m_Thickness; int width = m_Thickness;
@ -262,14 +328,6 @@ void EDA_TEXT::drawOneLineOfText( EDA_RECT* aClipBox, wxDC* aDC,
if( aDrawMode != UNSPECIFIED_DRAWMODE ) if( aDrawMode != UNSPECIFIED_DRAWMODE )
GRSetDrawMode( aDC, aDrawMode ); GRSetDrawMode( aDC, aDrawMode );
// Draw text anchor, if requested
if( aAnchor_color != UNSPECIFIED_COLOR )
{
GRDrawAnchor( aClipBox, aDC,
aPos.x + aOffset.x, aPos.y + aOffset.y,
DIM_ANCRE_TEXTE, aAnchor_color );
}
if( aFillMode == SKETCH ) if( aFillMode == SKETCH )
width = -width; width = -width;

View File

@ -0,0 +1,152 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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:O//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 cairo_compositor.cpp
* @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
* later compositing into a single image (Cairo flavour).
*/
#include <gal/cairo/cairo_compositor.h>
#include <wx/log.h>
using namespace KIGFX;
CAIRO_COMPOSITOR::CAIRO_COMPOSITOR( cairo_t** aMainContext ) :
m_current( 0 ), m_currentContext( aMainContext ), m_mainContext( *aMainContext )
{
}
CAIRO_COMPOSITOR::~CAIRO_COMPOSITOR()
{
clean();
}
void CAIRO_COMPOSITOR::Initialize()
{
// Nothing has to be done
}
void CAIRO_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight )
{
clean();
m_width = aWidth;
m_height = aHeight;
m_stride = cairo_format_stride_for_width( CAIRO_FORMAT_ARGB32, m_width );
m_bufferSize = m_stride * m_height;
}
unsigned int CAIRO_COMPOSITOR::CreateBuffer()
{
// Pixel storage
BitmapPtr bitmap( new unsigned int[m_bufferSize] );
memset( bitmap.get(), 0x00, m_bufferSize * sizeof(int) );
// Create the Cairo surface
cairo_surface_t* surface = cairo_image_surface_create_for_data(
(unsigned char*) bitmap.get(),
CAIRO_FORMAT_ARGB32, m_width,
m_height, m_stride );
cairo_t* context = cairo_create( surface );
#ifdef __WXDEBUG__
cairo_status_t status = cairo_status( context );
wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" );
#endif /* __WXDEBUG__ */
// Set default settings for the buffer
cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL );
cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND );
cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );
// Use the same transformation matrix as the main context
cairo_get_matrix( m_mainContext, &m_matrix );
cairo_set_matrix( context, &m_matrix );
// Store the new buffer
CAIRO_BUFFER buffer = { context, surface, bitmap };
m_buffers.push_back( buffer );
return usedBuffers();
}
void CAIRO_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
{
wxASSERT_MSG( aBufferHandle <= usedBuffers(), wxT( "Tried to use a not existing buffer" ) );
// Get currently used transformation matrix, so it can be applied to the new buffer
cairo_get_matrix( *m_currentContext, &m_matrix );
m_current = aBufferHandle - 1;
*m_currentContext = m_buffers[m_current].context;
// Apply the current transformation matrix
cairo_set_matrix( *m_currentContext, &m_matrix );
}
void CAIRO_COMPOSITOR::ClearBuffer()
{
// Clear the pixel storage
memset( m_buffers[m_current].bitmap.get(), 0x00, m_bufferSize * sizeof(int) );
}
void CAIRO_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle )
{
wxASSERT_MSG( aBufferHandle <= usedBuffers(), wxT( "Tried to use a not existing buffer" ) );
// Reset the transformation matrix, so it is possible to composite images using
// screen coordinates instead of world coordinates
cairo_get_matrix( m_mainContext, &m_matrix );
cairo_identity_matrix( m_mainContext );
// Draw the selected buffer contents
cairo_set_source_surface( m_mainContext, m_buffers[aBufferHandle - 1].surface, 0.0, 0.0 );
cairo_paint( m_mainContext );
// Restore the transformation matrix
cairo_set_matrix( m_mainContext, &m_matrix );
}
void CAIRO_COMPOSITOR::clean()
{
CAIRO_BUFFERS::const_iterator it;
for( it = m_buffers.begin(); it != m_buffers.end(); ++it )
{
cairo_destroy( it->context );
cairo_surface_destroy( it->surface );
}
m_buffers.clear();
}

File diff suppressed because it is too large Load Diff

179
common/gal/color4d.cpp Normal file
View File

@ -0,0 +1,179 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* Color class
*
* 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
*/
#include <gal/color4d.h>
using namespace KIGFX;
COLOR4D::COLOR4D( EDA_COLOR_T aColor )
{
r = g_ColorRefs[aColor].m_Red / 255.0;
g = g_ColorRefs[aColor].m_Green / 255.0;
b = g_ColorRefs[aColor].m_Blue / 255.0;
a = 1.0;
}
#ifdef WX_COMPATIBILITY
COLOR4D::COLOR4D( const wxColour& aColor )
{
r = aColor.Red();
g = aColor.Green();
b = aColor.Blue();
a = aColor.Alpha();
}
#endif
const bool COLOR4D::operator==( const COLOR4D& aColor )
{
return a == aColor.a && r == aColor.r && g == aColor.g && b == aColor.b;
}
const bool COLOR4D::operator!=( const COLOR4D& aColor )
{
return a != aColor.a || r != aColor.r || g != aColor.g || b != aColor.b;
}
void COLOR4D::ToHSV( double& aOutH, double& aOutS, double& aOutV ) const
{
double min, max, delta;
min = r < g ? r : g;
min = min < b ? min : b;
max = r > g ? r : g;
max = max > b ? max : b;
aOutV = max; // v
delta = max - min;
if( max > 0.0 )
{
aOutS = ( delta / max ); // s
}
else
{
// r = g = b = 0 // s = 0, v is undefined
aOutS = 0.0;
aOutH = NAN; // its now undefined
return;
}
if( r >= max ) // > is bogus, just keeps compiler happy
aOutH = ( g - b ) / delta; // between yellow & magenta
else if( g >= max )
aOutH = 2.0 + ( b - r ) / delta; // between cyan & yellow
else
aOutH = 4.0 + ( r - g ) / delta; // between magenta & cyan
aOutH *= 60.0; // degrees
if( aOutH < 0.0 )
aOutH += 360.0;
}
void COLOR4D::FromHSV( double aInH, double aInS, double aInV )
{
double hh, p, q, t, ff;
long i;
if( aInS <= 0.0 ) // < is bogus, just shuts up warnings
{
r = aInV;
g = aInV;
b = aInV;
return;
}
hh = aInH;
if( hh >= 360.0 )
hh = 0.0;
hh /= 60.0;
i = (long) hh;
ff = hh - i;
p = aInV * ( 1.0 - aInS );
q = aInV * ( 1.0 - ( aInS * ff ) );
t = aInV * ( 1.0 - ( aInS * ( 1.0 - ff ) ) );
switch( i )
{
case 0:
r = aInV;
g = t;
b = p;
break;
case 1:
r = q;
g = aInV;
b = p;
break;
case 2:
r = p;
g = aInV;
b = t;
break;
case 3:
r = p;
g = q;
b = aInV;
break;
case 4:
r = t;
g = p;
b = aInV;
break;
case 5:
default:
r = aInV;
g = p;
b = q;
break;
}
}
COLOR4D& COLOR4D::Saturate( double aFactor )
{
double h, s, v;
ToHSV( h, s, v );
FromHSV( h, aFactor, 1.0 );
return *this;
}

View File

@ -0,0 +1,243 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* Graphics Abstraction Layer (GAL) - base class
*
* 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
*/
#include <wx/log.h>
#include <gal/graphics_abstraction_layer.h>
#include <gal/definitions.h>
using namespace KIGFX;
GAL::GAL() :
strokeFont( this )
{
// Set the default values for the internal variables
SetIsFill( false );
SetIsStroke( true );
SetFillColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
SetZoomFactor( 1.0 );
SetDepthRange( VECTOR2D( GAL::MIN_DEPTH, GAL::MAX_DEPTH ) );
SetFlip( false, false );
SetLineWidth( 1.0 );
// Set grid defaults
SetGridVisibility( true );
SetGridStyle( GRID_STYLE_LINES );
SetGridOriginMarkerSize( 15 );
SetGridDrawThreshold( 10 );
SetCoarseGrid( 10 );
SetGridLineWidth( 0.5 );
// Initialize the cursor shape
SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
SetCursorSize( 80 );
SetCursorEnabled( false );
strokeFont.LoadNewStrokeFont( newstroke_font, newstroke_font_bufsize );
}
GAL::~GAL()
{
}
void GAL::SetTextAttributes( const EDA_TEXT* aText )
{
strokeFont.SetGlyphSize( VECTOR2D( aText->GetSize() ) );
strokeFont.SetHorizontalJustify( aText->GetHorizJustify() );
strokeFont.SetVerticalJustify( aText->GetVertJustify() );
strokeFont.SetBold( aText->IsBold() );
strokeFont.SetItalic( aText->IsItalic() );
strokeFont.SetMirrored( aText->IsMirrored() );
}
void GAL::ComputeWorldScreenMatrix()
{
ComputeWorldScale();
worldScreenMatrix.SetIdentity();
MATRIX3x3D translation;
translation.SetIdentity();
translation.SetTranslation( 0.5 * screenSize );
MATRIX3x3D scale;
scale.SetIdentity();
scale.SetScale( VECTOR2D( worldScale, worldScale ) );
MATRIX3x3D flip;
flip.SetIdentity();
flip.SetScale( VECTOR2D( flipX, flipY ) );
MATRIX3x3D lookat;
lookat.SetIdentity();
lookat.SetTranslation( -lookAtPoint );
worldScreenMatrix = translation * flip * scale * lookat * worldScreenMatrix;
screenWorldMatrix = worldScreenMatrix.Inverse();
}
void GAL::DrawGrid()
{
if( !gridVisibility )
return;
SetTarget( TARGET_NONCACHED );
// Draw the origin marker
double origSize = static_cast<double>( gridOriginMarkerSize ) / worldScale;
SetLayerDepth( GAL::GRID_DEPTH );
SetIsFill( false );
SetIsStroke( true );
SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
SetLineWidth( gridLineWidth / worldScale );
DrawLine( gridOrigin + VECTOR2D( -origSize, -origSize ),
gridOrigin + VECTOR2D( origSize, origSize ) );
DrawLine( gridOrigin + VECTOR2D( -origSize, origSize ),
gridOrigin + VECTOR2D( origSize, -origSize ) );
DrawCircle( gridOrigin, origSize * 0.7 );
// Draw the grid
// For the drawing the start points, end points and increments have
// to be calculated in world coordinates
VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
VECTOR2D worldEndPoint = screenWorldMatrix * screenSize;
int gridScreenSizeDense = round( gridSize.x * worldScale );
int gridScreenSizeCoarse = round( gridSize.x * static_cast<double>( gridTick ) * worldScale );
// Compute the line marker or point radius of the grid
double marker = 2.0 * gridLineWidth / worldScale;
double doubleMarker = 2.0 * marker;
// Check if the grid would not be too dense
if( std::max( gridScreenSizeDense, gridScreenSizeCoarse ) > gridDrawThreshold )
{
// Compute grid variables
int gridStartX = round( worldStartPoint.x / gridSize.x );
int gridEndX = round( worldEndPoint.x / gridSize.x );
int gridStartY = round( worldStartPoint.y / gridSize.y );
int gridEndY = round( worldEndPoint.y / gridSize.y );
// Swap the coordinates, if they have not the right order
SWAP( gridEndX, <, gridStartX );
SWAP( gridEndY, <, gridStartY );
// Correct the index, else some lines are not correctly painted
gridStartX -= 1;
gridStartY -= 1;
gridEndX += 1;
gridEndY += 1;
// Draw the grid behind all other layers
SetLayerDepth( depthRange.y * 0.75 );
if( gridStyle == GRID_STYLE_LINES )
{
SetIsFill( false );
SetIsStroke( true );
SetStrokeColor( gridColor );
// Now draw the grid, every coarse grid line gets the double width
for( int j = gridStartY; j < gridEndY; j += 1 )
{
if( j % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
SetLineWidth( doubleMarker );
else
SetLineWidth( marker );
if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridDrawThreshold )
|| gridScreenSizeDense > gridDrawThreshold )
{
drawGridLine( VECTOR2D( gridStartX * gridSize.x, j * gridSize.y ),
VECTOR2D( gridEndX * gridSize.x, j * gridSize.y ) );
}
}
for( int i = gridStartX; i < gridEndX; i += 1 )
{
if( i % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
SetLineWidth( doubleMarker );
else
SetLineWidth( marker );
if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridDrawThreshold )
|| gridScreenSizeDense > gridDrawThreshold )
{
drawGridLine( VECTOR2D( i * gridSize.x, gridStartY * gridSize.y ),
VECTOR2D( i * gridSize.x, gridEndY * gridSize.y ) );
}
}
}
else // Dotted grid
{
bool tickX, tickY;
SetIsFill( true );
SetIsStroke( false );
SetFillColor( gridColor );
for( int j = gridStartY; j < gridEndY; j += 1 )
{
if( j % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
tickY = true;
else
tickY = false;
for( int i = gridStartX; i < gridEndX; i += 1 )
{
if( i % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
tickX = true;
else
tickX = false;
if( tickX || tickY || gridScreenSizeDense > gridDrawThreshold )
{
double radius = ( tickX && tickY ) ? doubleMarker : marker;
DrawRectangle( VECTOR2D( i * gridSize.x - radius,
j * gridSize.y - radius ),
VECTOR2D( i * gridSize.x + radius,
j * gridSize.y + radius ) );
}
}
}
}
}
}
VECTOR2D GAL::GetGridPoint( VECTOR2D aPoint ) const
{
VECTOR2D pointWorld = ToWorld( aPoint );
pointWorld.x = round( pointWorld.x / gridSize.x ) * gridSize.x;
pointWorld.y = round( pointWorld.y / gridSize.y ) * gridSize.y;
return ToScreen( pointWorld );
}

View File

@ -0,0 +1,550 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 cached_container.cpp
* @brief Class to store instances of VERTEX with caching. It allows storing VERTEX objects and
* associates them with VERTEX_ITEMs. This leads to a possibility of caching vertices data in the
* GPU memory and a fast reuse of that data.
*/
#include <gal/opengl/cached_container.h>
#include <gal/opengl/vertex_manager.h>
#include <gal/opengl/vertex_item.h>
#include <gal/opengl/shader.h>
#include <wx/log.h>
#include <list>
#ifdef __WXDEBUG__
#include <profile.h>
#endif /* __WXDEBUG__ */
using namespace KIGFX;
CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
VERTEX_CONTAINER( aSize ), m_item( NULL )
{
// In the beginning there is only free space
m_freeChunks.insert( CHUNK( aSize, 0 ) );
}
void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
{
wxASSERT( aItem != NULL );
m_item = aItem;
m_itemSize = m_item->GetSize();
m_chunkSize = m_itemSize;
if( m_itemSize == 0 )
m_items.insert( m_item ); // The item was not stored before
else
m_chunkOffset = m_item->GetOffset();
#if CACHED_CONTAINER_TEST > 1
wxLogDebug( wxT( "Adding/editing item 0x%08lx (size %d)" ), (long) m_item, m_itemSize );
#endif
}
void CACHED_CONTAINER::FinishItem()
{
wxASSERT( m_item != NULL );
wxASSERT( m_item->GetSize() == m_itemSize );
// Finishing the previously edited item
if( m_itemSize < m_chunkSize )
{
// There is some not used but reserved memory left, so we should return it to the pool
int itemOffset = m_item->GetOffset();
// Add the not used memory back to the pool
m_freeChunks.insert( CHUNK( m_chunkSize - m_itemSize, itemOffset + m_itemSize ) );
m_freeSpace += ( m_chunkSize - m_itemSize );
// mergeFreeChunks(); // veery slow and buggy
}
#if CACHED_CONTAINER_TEST > 1
wxLogDebug( wxT( "Finishing item 0x%08lx (size %d)" ), (long) m_item, m_itemSize );
test();
m_item = NULL; // electric fence
#endif
}
VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
{
wxASSERT( m_item != NULL );
if( m_failed )
return NULL;
if( m_itemSize + aSize > m_chunkSize )
{
// There is not enough space in the currently reserved chunk, so we have to resize it
// Reserve a bigger memory chunk for the current item and
// make it multiple of 3 to store triangles
m_chunkSize = ( 2 * m_itemSize ) + aSize + ( 3 - aSize % 3 );
// Save the current size before reallocating
m_chunkOffset = reallocate( m_chunkSize );
if( m_chunkOffset > m_currentSize )
{
m_failed = true;
return NULL;
}
}
VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize];
m_itemSize += aSize;
// Now the item officially possesses the memory chunk
m_item->setSize( m_itemSize );
// The content has to be updated
m_dirty = true;
#if CACHED_CONTAINER_TEST > 1
test();
#endif
#if CACHED_CONTAINER_TEST > 2
showFreeChunks();
showReservedChunks();
#endif
return reserved;
}
void CACHED_CONTAINER::Delete( VERTEX_ITEM* aItem )
{
wxASSERT( aItem != NULL );
wxASSERT( m_items.find( aItem ) != m_items.end() );
int size = aItem->GetSize();
int offset = aItem->GetOffset();
#if CACHED_CONTAINER_TEST > 1
wxLogDebug( wxT( "Removing 0x%08lx (size %d offset %d)" ), (long) aItem, size, offset );
#endif
// Insert a free memory chunk entry in the place where item was stored
if( size > 0 )
{
m_freeChunks.insert( CHUNK( size, offset ) );
m_freeSpace += size;
// Indicate that the item is not stored in the container anymore
aItem->setSize( 0 );
}
m_items.erase( aItem );
#if CACHED_CONTAINER_TEST > 1
test();
#endif
// Dynamic memory freeing, there is no point in holding
// a large amount of memory when there is no use for it
if( m_freeSpace > ( m_currentSize / 2 ) && m_currentSize > m_initialSize )
{
resizeContainer( m_currentSize / 2 );
}
}
void CACHED_CONTAINER::Clear()
{
// Change size to the default one
m_vertices = static_cast<VERTEX*>( realloc( m_vertices,
m_initialSize * sizeof( VERTEX ) ) );
// Reset state variables
m_freeSpace = m_initialSize;
m_currentSize = m_initialSize;
m_failed = false;
// Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held
// in the container anymore
ITEMS::iterator it;
for( it = m_items.begin(); it != m_items.end(); ++it )
{
( *it )->setSize( 0 );
}
m_items.clear();
// Now there is only free space left
m_freeChunks.clear();
m_freeChunks.insert( CHUNK( m_freeSpace, 0 ) );
}
VERTEX* CACHED_CONTAINER::GetVertices( const VERTEX_ITEM* aItem ) const
{
int offset = aItem->GetOffset();
return &m_vertices[offset];
}
unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize )
{
wxASSERT( aSize > 0 );
#if CACHED_CONTAINER_TEST > 2
wxLogDebug( wxT( "Resize 0x%08lx from %d to %d" ), (long) m_item, m_itemSize, aSize );
#endif
// Is there enough space to store vertices?
if( m_freeSpace < aSize )
{
bool result;
// Would it be enough to double the current space?
if( aSize < m_freeSpace + m_currentSize )
{
// Yes: exponential growing
result = resizeContainer( m_currentSize * 2 );
}
else
{
// No: grow to the nearest bigger power of 2
result = resizeContainer( getPowerOf2( m_currentSize * 2 + aSize ) );
}
if( !result )
return UINT_MAX;
}
// Look for the free space chunk of at least given size
FREE_CHUNK_MAP::iterator newChunk = m_freeChunks.lower_bound( aSize );
if( newChunk == m_freeChunks.end() )
{
// In the case when there is enough space to store the vertices,
// but the free space is not continous we should defragment the container
if( !defragment() )
return UINT_MAX;
// Update the current offset
m_chunkOffset = m_item->GetOffset();
// We can take the first free chunk, as there is only one after defragmentation
// and we can be sure that it provides enough space to store the object
newChunk = m_freeChunks.begin();
}
// Parameters of the allocated cuhnk
unsigned int chunkSize = newChunk->first;
unsigned int chunkOffset = newChunk->second;
wxASSERT( chunkSize >= aSize );
wxASSERT( chunkOffset < m_currentSize );
// Check if the item was previously stored in the container
if( m_itemSize > 0 )
{
#if CACHED_CONTAINER_TEST > 3
wxLogDebug( wxT( "Moving 0x%08x from 0x%08x to 0x%08x" ),
(int) m_item, oldChunkOffset, chunkOffset );
#endif
// The item was reallocated, so we have to copy all the old data to the new place
memcpy( &m_vertices[chunkOffset], &m_vertices[m_chunkOffset],
m_itemSize * VertexSize );
// Free the space previously used by the chunk
wxASSERT( m_itemSize > 0 );
m_freeChunks.insert( CHUNK( m_itemSize, m_chunkOffset ) );
m_freeSpace += m_itemSize;
}
// Remove the allocated chunk from the free space pool
m_freeChunks.erase( newChunk );
// If there is some space left, return it to the pool - add an entry for it
if( chunkSize > aSize )
{
m_freeChunks.insert( CHUNK( chunkSize - aSize, chunkOffset + aSize ) );
}
m_freeSpace -= aSize;
// mergeFreeChunks(); // veery slow and buggy
m_item->setOffset( chunkOffset );
return chunkOffset;
}
bool CACHED_CONTAINER::defragment( VERTEX* aTarget )
{
#if CACHED_CONTAINER_TEST > 0
wxLogDebug( wxT( "Defragmenting" ) );
prof_counter totalTime;
prof_start( &totalTime, false );
#endif
if( aTarget == NULL )
{
// No target was specified, so we have to reallocate our own space
aTarget = static_cast<VERTEX*>( malloc( m_currentSize * sizeof( VERTEX ) ) );
if( aTarget == NULL )
{
wxLogError( wxT( "Run out of memory" ) );
return false;
}
}
int newOffset = 0;
ITEMS::iterator it, it_end;
for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
{
VERTEX_ITEM* item = *it;
int itemOffset = item->GetOffset();
int itemSize = item->GetSize();
// Move an item to the new container
memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VertexSize );
// Update new offset
item->setOffset( newOffset );
// Move to the next free space
newOffset += itemSize;
}
free( m_vertices );
m_vertices = aTarget;
// Now there is only one big chunk of free memory
m_freeChunks.clear();
wxASSERT( m_freeSpace > 0 );
m_freeChunks.insert( CHUNK( m_freeSpace, m_currentSize - m_freeSpace ) );
#if CACHED_CONTAINER_TEST > 0
prof_end( &totalTime );
wxLogDebug( wxT( "Defragmented the container storing %d vertices / %.1f ms" ),
m_currentSize - m_freeSpace, (double) totalTime.value / 1000.0 );
#endif
return true;
}
void CACHED_CONTAINER::mergeFreeChunks()
{
if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
return;
#if CACHED_CONTAINER_TEST > 0
prof_counter totalTime;
prof_start( &totalTime, false );
#endif
// Reversed free chunks map - this one stores chunk size with its offset as the key
std::list<CHUNK> freeChunks;
FREE_CHUNK_MAP::const_iterator it, it_end;
for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it )
{
freeChunks.push_back( std::make_pair( it->second, it->first ) );
}
m_freeChunks.clear();
freeChunks.sort();
std::list<CHUNK>::const_iterator itf, itf_end;
unsigned int offset = freeChunks.front().first;
unsigned int size = freeChunks.front().second;
freeChunks.pop_front();
for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf )
{
if( itf->first == offset + size )
{
// These chunks can be merged, so just increase the current chunk size and go on
size += itf->second;
}
else
{
// These chunks cannot be merged
// So store the previous one
m_freeChunks.insert( std::make_pair( size, offset ) );
// and let's check the next chunk
offset = itf->first;
size = itf->second;
}
}
// Add the last one
m_freeChunks.insert( std::make_pair( size, offset ) );
#if CACHED_CONTAINER_TEST > 0
prof_end( &totalTime );
wxLogDebug( wxT( "Merged free chunks / %.1f ms" ), (double) totalTime.value / 1000.0 );
#endif
test();
}
bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize )
{
wxASSERT( aNewSize != m_currentSize );
#if CACHED_CONTAINER_TEST > 0
wxLogDebug( wxT( "Resizing container from %d to %d" ), m_currentSize, aNewSize );
#endif
VERTEX* newContainer;
if( aNewSize < m_currentSize )
{
// Shrinking container
// Sanity check, no shrinking if we cannot fit all the data
if( reservedSpace() > aNewSize )
return false;
newContainer = static_cast<VERTEX*>( malloc( aNewSize * sizeof( VERTEX ) ) );
if( newContainer == NULL )
{
wxLogError( wxT( "Run out of memory" ) );
return false;
}
// Defragment directly to the new, smaller container
defragment( newContainer );
// We have to correct freeChunks after defragmentation
m_freeChunks.clear();
wxASSERT( aNewSize - reservedSpace() > 0 );
m_freeChunks.insert( CHUNK( aNewSize - reservedSpace(), reservedSpace() ) );
}
else
{
// Enlarging container
newContainer = static_cast<VERTEX*>( realloc( m_vertices, aNewSize * sizeof( VERTEX ) ) );
if( newContainer == NULL )
{
wxLogError( wxT( "Run out of memory" ) );
return false;
}
// Add an entry for the new memory chunk at the end of the container
m_freeChunks.insert( CHUNK( aNewSize - m_currentSize, m_currentSize ) );
}
m_vertices = newContainer;
m_freeSpace += ( aNewSize - m_currentSize );
m_currentSize = aNewSize;
return true;
}
unsigned int CACHED_CONTAINER::getPowerOf2( unsigned int aNumber ) const
{
unsigned int power = 1;
while( power < aNumber && power != 0 )
power <<= 1;
return power;
}
#ifdef CACHED_CONTAINER_TEST
void CACHED_CONTAINER::showFreeChunks()
{
FreeChunkMap::iterator it;
wxLogDebug( wxT( "Free chunks:" ) );
for( it = m_freeChunks.begin(); it != m_freeChunks.end(); ++it )
{
unsigned int offset = getChunkOffset( *it );
unsigned int size = getChunkSize( *it );
wxASSERT( size > 0 );
wxLogDebug( wxT( "[0x%08x-0x%08x] (size %d)" ),
offset, offset + size - 1, size );
}
}
void CACHED_CONTAINER::showReservedChunks()
{
Items::iterator it;
wxLogDebug( wxT( "Reserved chunks:" ) );
for( it = m_items.begin(); it != m_items.end(); ++it )
{
VERTEX_ITEM* item = *it;
unsigned int offset = item->GetOffset();
unsigned int size = item->GetSize();
wxASSERT( size > 0 );
wxLogDebug( wxT( "[0x%08x-0x%08x] @ 0x%08lx (size %d)" ),
offset, offset + size - 1, (long) item, size );
}
}
void CACHED_CONTAINER::test()
{
// Free space check
unsigned int freeSpace = 0;
FreeChunkMap::iterator itf;
for( itf = m_freeChunks.begin(); itf != m_freeChunks.end(); ++itf )
freeSpace += getChunkSize( *itf );
wxASSERT( freeSpace == m_freeSpace );
// Reserved space check
/*unsigned int reservedSpace = 0;
Items::iterator itr;
for( itr = m_items.begin(); itr != m_items.end(); ++itr )
reservedSpace += ( *itr )->GetSize();
reservedSpace += m_itemSize; // Add the current chunk size
wxASSERT( ( freeSpace + reservedSpace ) == m_currentSize );*/
// Overlapping check TBD
}
#endif /* CACHED_CONTAINER_TEST */

View File

@ -0,0 +1,286 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 gpu_manager.cpp
* @brief Class to handle uploading vertices and indices to GPU in drawing purposes.
*/
#include <gal/opengl/gpu_manager.h>
#include <gal/opengl/cached_container.h>
#include <gal/opengl/noncached_container.h>
#include <gal/opengl/shader.h>
#include <typeinfo>
#include <wx/log.h>
#ifdef __WXDEBUG__
#include <profile.h>
#endif
using namespace KIGFX;
GPU_MANAGER* GPU_MANAGER::MakeManager( VERTEX_CONTAINER* aContainer )
{
if( typeid( *aContainer ) == typeid( CACHED_CONTAINER ) )
return new GPU_CACHED_MANAGER( aContainer );
else if( typeid( *aContainer ) == typeid( NONCACHED_CONTAINER ) )
return new GPU_NONCACHED_MANAGER( aContainer );
wxASSERT_MSG( false, "Not handled container type" );
return NULL;
}
GPU_MANAGER::GPU_MANAGER( VERTEX_CONTAINER* aContainer ) :
m_isDrawing( false ), m_container( aContainer ), m_shader( NULL )
{
}
GPU_MANAGER::~GPU_MANAGER()
{
}
void GPU_MANAGER::SetShader( SHADER& aShader )
{
m_shader = &aShader;
m_shaderAttrib = m_shader->GetAttribute( "attrShaderParams" );
if( m_shaderAttrib == -1 )
{
wxLogFatalError( wxT( "Could not get the shader attribute location" ) );
}
}
// Cached manager
GPU_CACHED_MANAGER::GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer ) :
GPU_MANAGER( aContainer ), m_buffersInitialized( false ),
m_indicesSize( 0 )
{
// Allocate the biggest possible buffer for indices
m_indices.reset( new GLuint[aContainer->GetSize()] );
}
GPU_CACHED_MANAGER::~GPU_CACHED_MANAGER()
{
if( m_buffersInitialized )
{
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_verticesBuffer );
}
}
void GPU_CACHED_MANAGER::Initialize()
{
wxASSERT( !m_buffersInitialized );
if( !m_buffersInitialized )
{
glGenBuffers( 1, &m_verticesBuffer );
m_buffersInitialized = true;
}
}
void GPU_CACHED_MANAGER::BeginDrawing()
{
wxASSERT( !m_isDrawing );
if( m_container->IsDirty() )
uploadToGpu();
// Number of vertices to be drawn in the EndDrawing()
m_indicesSize = 0;
// Set the indices pointer to the beginning of the indices-to-draw buffer
m_indicesPtr = m_indices.get();
m_isDrawing = true;
}
void GPU_CACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
{
wxASSERT( m_isDrawing );
// Copy indices of items that should be drawn to GPU memory
for( unsigned int i = aOffset; i < aOffset + aSize; *m_indicesPtr++ = i++ );
m_indicesSize += aSize;
}
void GPU_CACHED_MANAGER::DrawAll()
{
wxASSERT( m_isDrawing );
m_indicesSize = m_container->GetSize();
for( unsigned int i = 0; i < m_indicesSize; *m_indicesPtr++ = i++ );
}
void GPU_CACHED_MANAGER::EndDrawing()
{
wxASSERT( m_isDrawing );
// Prepare buffers
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
// Bind vertices data buffers
glBindBuffer( GL_ARRAY_BUFFER, m_verticesBuffer );
glVertexPointer( CoordStride, GL_FLOAT, VertexSize, 0 );
glColorPointer( ColorStride, GL_UNSIGNED_BYTE, VertexSize, (GLvoid*) ColorOffset );
if( m_shader != NULL ) // Use shader if applicable
{
m_shader->Use();
glEnableVertexAttribArray( m_shaderAttrib );
glVertexAttribPointer( m_shaderAttrib, ShaderStride, GL_FLOAT, GL_FALSE,
VertexSize, (GLvoid*) ShaderOffset );
}
glDrawElements( GL_TRIANGLES, m_indicesSize, GL_UNSIGNED_INT, (GLvoid*) m_indices.get() );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
// Deactivate vertex array
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
if( m_shader != NULL )
{
glDisableVertexAttribArray( m_shaderAttrib );
m_shader->Deactivate();
}
m_isDrawing = false;
}
void GPU_CACHED_MANAGER::uploadToGpu()
{
#ifdef __WXDEBUG__
prof_counter totalTime;
prof_start( &totalTime, false );
#endif /* __WXDEBUG__ */
if( !m_buffersInitialized )
Initialize();
int bufferSize = m_container->GetSize();
GLfloat* vertices = (GLfloat*) m_container->GetAllVertices();
// Upload vertices coordinates and shader types to GPU memory
glBindBuffer( GL_ARRAY_BUFFER, m_verticesBuffer );
glBufferData( GL_ARRAY_BUFFER, bufferSize * VertexSize, vertices, GL_DYNAMIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
// Allocate the biggest possible buffer for indices
m_indices.reset( new GLuint[bufferSize] );
if( glGetError() != GL_NO_ERROR )
{
wxLogError( wxT( "Error during data upload to the GPU memory" ) );
}
#ifdef __WXDEBUG__
prof_end( &totalTime );
wxLogDebug( wxT( "Uploading %d vertices to GPU / %.1f ms" ),
bufferSize, (double) totalTime.value / 1000.0 );
#endif /* __WXDEBUG__ */
}
// Noncached manager
GPU_NONCACHED_MANAGER::GPU_NONCACHED_MANAGER( VERTEX_CONTAINER* aContainer ) :
GPU_MANAGER( aContainer )
{
}
void GPU_NONCACHED_MANAGER::Initialize()
{
// Nothing has to be intialized
}
void GPU_NONCACHED_MANAGER::BeginDrawing()
{
// Nothing has to be prepared
}
void GPU_NONCACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
{
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
void GPU_NONCACHED_MANAGER::DrawAll()
{
// This is the default use case, nothing has to be done
// The real rendering takes place in the EndDrawing() function
}
void GPU_NONCACHED_MANAGER::EndDrawing()
{
VERTEX* vertices = m_container->GetAllVertices();
GLfloat* coordinates = (GLfloat*) ( vertices );
GLubyte* colors = (GLubyte*) ( vertices ) + ColorOffset;
// Prepare buffers
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( CoordStride, GL_FLOAT, VertexSize, coordinates );
glColorPointer( ColorStride, GL_UNSIGNED_BYTE, VertexSize, colors );
if( m_shader != NULL ) // Use shader if applicable
{
GLfloat* shaders = (GLfloat*) ( vertices ) + ShaderOffset / sizeof(GLfloat);
m_shader->Use();
glEnableVertexAttribArray( m_shaderAttrib );
glVertexAttribPointer( m_shaderAttrib, ShaderStride, GL_FLOAT, GL_FALSE,
VertexSize, shaders );
}
glDrawArrays( GL_TRIANGLES, 0, m_container->GetSize() );
// Deactivate vertex array
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
if( m_shader != NULL )
{
glDisableVertexAttribArray( m_shaderAttrib );
m_shader->Deactivate();
}
}

View File

@ -0,0 +1,89 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 noncached_container.cpp
* @brief Class to store instances of VERTEX without caching. It allows a fast one-frame drawing
* and then clearing the buffer and starting from scratch.
*/
#include <gal/opengl/noncached_container.h>
#include <cstdlib>
using namespace KIGFX;
NONCACHED_CONTAINER::NONCACHED_CONTAINER( unsigned int aSize ) :
VERTEX_CONTAINER( aSize ), m_freePtr( 0 )
{
}
NONCACHED_CONTAINER::~NONCACHED_CONTAINER()
{
}
void NONCACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
{
// Nothing has to be done, as the noncached container
// does not care about VERTEX_ITEMs ownership
}
VERTEX* NONCACHED_CONTAINER::Allocate( unsigned int aSize )
{
if( m_freeSpace < aSize )
{
// Double the space
VERTEX* newVertices = static_cast<VERTEX*>( realloc( m_vertices,
m_currentSize * 2 *
sizeof(VERTEX) ) );
if( newVertices != NULL )
{
m_vertices = newVertices;
m_freeSpace += m_currentSize;
m_currentSize *= 2;
}
else
{
return NULL;
}
}
VERTEX* freeVertex = &m_vertices[m_freePtr];
// Move to the next free chunk
m_freePtr += aSize;
m_freeSpace -= aSize;
return freeVertex;
}
void NONCACHED_CONTAINER::Clear()
{
m_freePtr = 0;
m_freeSpace = m_currentSize;
}

View File

@ -0,0 +1,292 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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:O//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 opengl_compositor.cpp
* @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
* later compositing into a single image (OpenGL flavour).
*/
#include <gal/opengl/opengl_compositor.h>
#include <wx/log.h>
using namespace KIGFX;
OPENGL_COMPOSITOR::OPENGL_COMPOSITOR() :
m_initialized( false ), m_current( 0 )
{
}
OPENGL_COMPOSITOR::~OPENGL_COMPOSITOR()
{
if( m_initialized )
clean();
}
void OPENGL_COMPOSITOR::Initialize()
{
if( m_initialized )
return;
// Get the maximum number of buffers
glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, (GLint*) &m_maxBuffers );
// We need framebuffer objects for drawing the screen contents
// Generate framebuffer and a depth buffer
glGenFramebuffersEXT( 1, &m_framebuffer );
glBindFramebufferEXT( GL_FRAMEBUFFER, m_framebuffer );
m_currentFbo = m_framebuffer;
// Allocate memory for the depth buffer
// Attach the depth buffer to the framebuffer
glGenRenderbuffersEXT( 1, &m_depthBuffer );
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_depthBuffer );
// Use here a size of 24 bits for the depth buffer, 8 bits for the stencil buffer
// this is required later for anti-aliasing
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL, m_width, m_height );
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER_EXT, m_depthBuffer );
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER_EXT, m_depthBuffer );
// Unbind the framebuffer, so by default all the rendering goes directly to the display
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, DIRECT_RENDERING );
m_currentFbo = 0;
m_initialized = true;
}
void OPENGL_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight )
{
if( m_initialized )
clean();
m_width = aWidth;
m_height = aHeight;
}
unsigned int OPENGL_COMPOSITOR::CreateBuffer()
{
wxASSERT( m_initialized );
if( usedBuffers() >= m_maxBuffers )
{
wxLogError( wxT( "Cannot create more framebuffers. OpenGL rendering backend requires at"
"least 3 framebuffers. You may try to update/change "
"your graphic drivers." ) );
return 0; // Unfortunately we have no more free buffers left
}
// GL_COLOR_ATTACHMENTn are consecutive integers
GLuint attachmentPoint = GL_COLOR_ATTACHMENT0 + usedBuffers();
GLuint textureTarget;
// Generate the texture for the pixel storage
glGenTextures( 1, &textureTarget );
glBindTexture( GL_TEXTURE_2D, textureTarget );
// Set texture parameters
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
// Bind the texture to the specific attachment point, clear and rebind the screen
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_framebuffer );
m_currentFbo = m_framebuffer;
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, attachmentPoint, GL_TEXTURE_2D, textureTarget, 0 );
// Check the status, exit if the framebuffer can't be created
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
if( status != GL_FRAMEBUFFER_COMPLETE_EXT )
{
switch( status )
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
wxLogFatalError( wxT( "Cannot create the framebuffer." ) );
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
wxLogFatalError( wxT( "The framebuffer attachment points are incomplete." ) );
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
wxLogFatalError( wxT( "The framebuffer does not have at least "
"one image attached to it." ) );
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
wxLogFatalError( wxT( "The framebuffer read buffer is incomplete." ) );
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
wxLogFatalError( wxT( "The combination of internal formats of the attached images "
"violates an implementation-dependent set of restrictions." ) );
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
wxLogFatalError( wxT( "GL_RENDERBUFFER_SAMPLES is not the same "
"for all attached renderbuffers" ) );
break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT:
wxLogFatalError( wxT( "Framebuffer incomplete layer targets errors." ) );
break;
default:
wxLogFatalError( wxT( "Cannot create the framebuffer." ) );
break;
}
return 0;
}
ClearBuffer();
// Return to direct rendering (we were asked only to create a buffer, not switch to one)
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, DIRECT_RENDERING );
m_currentFbo = DIRECT_RENDERING;
// Store the new buffer
OPENGL_BUFFER buffer = { textureTarget, attachmentPoint };
m_buffers.push_back( buffer );
return usedBuffers();
}
void OPENGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
{
if( aBufferHandle > usedBuffers() )
return;
// Change the rendering destination to the selected attachment point
if( aBufferHandle == DIRECT_RENDERING )
{
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, DIRECT_RENDERING );
m_currentFbo = DIRECT_RENDERING;
}
else if( m_currentFbo != m_framebuffer )
{
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_framebuffer );
m_currentFbo = m_framebuffer;
}
if( m_currentFbo != DIRECT_RENDERING )
{
m_current = aBufferHandle - 1;
glDrawBuffer( m_buffers[m_current].attachmentPoint );
}
}
void OPENGL_COMPOSITOR::ClearBuffer()
{
wxASSERT( m_initialized );
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
void OPENGL_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle )
{
wxASSERT( m_initialized );
if( aBufferHandle == 0 || aBufferHandle > usedBuffers() )
{
wxLogError( wxT( "Wrong framebuffer handle" ) );
return;
}
// Switch to the main framebuffer and blit the scene
glBindFramebufferEXT( GL_FRAMEBUFFER, DIRECT_RENDERING );
m_currentFbo = DIRECT_RENDERING;
// Depth test has to be disabled to make transparency working
glDisable( GL_DEPTH_TEST );
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
// Enable texturing and bind the main texture
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_buffers[aBufferHandle - 1].textureTarget );
// Draw a full screen quad with the texture
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glBegin( GL_TRIANGLES );
glTexCoord2f( 0.0f, 1.0f );
glVertex2f( -1.0f, -1.0f );
glTexCoord2f( 1.0f, 1.0f );
glVertex2f( 1.0f, -1.0f );
glTexCoord2f( 1.0f, 0.0f );
glVertex2f( 1.0f, 1.0f );
glTexCoord2f( 0.0f, 1.0f );
glVertex2f( -1.0f, -1.0f );
glTexCoord2f( 1.0f, 0.0f );
glVertex2f( 1.0f, 1.0f );
glTexCoord2f( 0.0f, 0.0f );
glVertex2f( -1.0f, 1.0f );
glEnd();
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
void OPENGL_COMPOSITOR::clean()
{
wxASSERT( m_initialized );
glDeleteFramebuffersEXT( 1, &m_framebuffer );
glDeleteRenderbuffersEXT( 1, &m_depthBuffer );
OPENGL_BUFFERS::const_iterator it;
for( it = m_buffers.begin(); it != m_buffers.end(); ++it )
{
glDeleteTextures( 1, &it->textureTarget );
}
m_buffers.clear();
m_initialized = false;
}
GLuint OPENGL_COMPOSITOR::m_currentFbo = DIRECT_RENDERING;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,281 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* Graphics Abstraction Layer (GAL) for OpenGL
*
* Shader class
*
* 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
*/
#include <iostream>
#include <fstream>
#include <wx/log.h>
#include <gal/opengl/shader.h>
#include "shader_src.h"
using namespace KIGFX;
SHADER::SHADER() :
isProgramCreated( false ),
isShaderLinked( false ),
active( false ),
maximumVertices( 4 ),
geomInputType( GL_LINES ),
geomOutputType( GL_LINES )
{
}
SHADER::~SHADER()
{
if( isProgramCreated )
{
// Delete the shaders and the program
for( std::deque<GLuint>::iterator it = shaderNumbers.begin(); it != shaderNumbers.end();
it++ )
{
glDeleteShader( *it );
}
glDeleteProgram( programNumber );
}
}
bool SHADER::LoadBuiltinShader( unsigned int aShaderNumber, SHADER_TYPE aShaderType )
{
if( aShaderNumber >= shaders_number )
return false;
return addSource( std::string( shaders_src[aShaderNumber] ), aShaderType );
}
bool SHADER::LoadShaderFromFile( const std::string& aShaderSourceName, SHADER_TYPE aShaderType )
{
// Load shader sources
const std::string shaderSource = readSource( aShaderSourceName );
return addSource( shaderSource, aShaderType );
}
void SHADER::ConfigureGeometryShader( GLuint maxVertices, GLuint geometryInputType,
GLuint geometryOutputType )
{
maximumVertices = maxVertices;
geomInputType = geometryInputType;
geomOutputType = geometryOutputType;
}
bool SHADER::Link()
{
// Shader linking
glLinkProgram( programNumber );
programInfo( programNumber );
// Check the Link state
glGetObjectParameterivARB( programNumber, GL_OBJECT_LINK_STATUS_ARB,
(GLint*) &isShaderLinked );
#ifdef __WXDEBUG__
if( !isShaderLinked )
{
int maxLength;
glGetProgramiv( programNumber, GL_INFO_LOG_LENGTH, &maxLength );
maxLength = maxLength + 1;
char* linkInfoLog = new char[maxLength];
glGetProgramInfoLog( programNumber, maxLength, &maxLength, linkInfoLog );
std::cerr << "Shader linking error:" << std::endl;
std::cerr << linkInfoLog;
delete[] linkInfoLog;
}
#endif /* __WXDEBUG__ */
return isShaderLinked;
}
int SHADER::AddParameter( const std::string& aParameterName )
{
GLint location = glGetUniformLocation( programNumber, aParameterName.c_str() );
if( location != -1 )
{
parameterLocation.push_back( location );
}
return location;
}
void SHADER::SetParameter( int parameterNumber, float value ) const
{
glUniform1f( parameterLocation[parameterNumber], value );
}
void SHADER::SetParameter( int parameterNumber, int value ) const
{
glUniform1i( parameterLocation[parameterNumber], value );
}
int SHADER::GetAttribute( std::string aAttributeName ) const
{
return glGetAttribLocation( programNumber, aAttributeName.c_str() );
}
void SHADER::programInfo( GLuint aProgram )
{
GLint glInfoLogLength = 0;
GLint writtenChars = 0;
// Get the length of the info string
glGetProgramiv( aProgram, GL_INFO_LOG_LENGTH, &glInfoLogLength );
// Print the information
if( glInfoLogLength > 2 )
{
GLchar* glInfoLog = new GLchar[glInfoLogLength];
glGetProgramInfoLog( aProgram, glInfoLogLength, &writtenChars, glInfoLog );
wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) );
delete[] glInfoLog;
}
}
void SHADER::shaderInfo( GLuint aShader )
{
GLint glInfoLogLength = 0;
GLint writtenChars = 0;
// Get the length of the info string
glGetShaderiv( aShader, GL_INFO_LOG_LENGTH, &glInfoLogLength );
// Print the information
if( glInfoLogLength > 2 )
{
GLchar* glInfoLog = new GLchar[glInfoLogLength];
glGetShaderInfoLog( aShader, glInfoLogLength, &writtenChars, glInfoLog );
wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) );
delete[] glInfoLog;
}
}
std::string SHADER::readSource( std::string aShaderSourceName )
{
// Open the shader source for reading
std::ifstream inputFile( aShaderSourceName.c_str(), std::ifstream::in );
std::string shaderSource;
if( !inputFile )
{
wxLogError( wxString::FromUTF8( "Can't read the shader source: " ) +
wxString( aShaderSourceName.c_str(), wxConvUTF8 ) );
exit( 1 );
}
std::string shaderSourceLine;
// Read all lines from the text file
while( getline( inputFile, shaderSourceLine ) )
{
shaderSource += shaderSourceLine;
shaderSource += "\n";
}
return shaderSource;
}
bool SHADER::addSource( const std::string& aShaderSource, SHADER_TYPE aShaderType )
{
if( isShaderLinked )
{
wxLogError( wxString::FromUTF8( "Shader is already linked!" ) );
}
// Create the program
if( !isProgramCreated )
{
programNumber = glCreateProgram();
isProgramCreated = true;
}
// Create a shader
GLuint shaderNumber = glCreateShader( aShaderType );
shaderNumbers.push_back( shaderNumber );
// Get the program info
programInfo( programNumber );
// Copy to char array
char* source = new char[aShaderSource.size() + 1];
strcpy( source, aShaderSource.c_str() );
const char** source_ = (const char**) ( &source );
// Attach the source
glShaderSource( shaderNumber, 1, source_, NULL );
programInfo( programNumber );
// Delete the allocated char array
delete[] source;
// Compile and attach shader to the program
glCompileShader( shaderNumber );
GLint status;
glGetShaderiv( shaderNumber, GL_COMPILE_STATUS, &status );
if( status != GL_TRUE )
{
wxLogError( wxT( "Shader compilation error" ) );
shaderInfo( shaderNumber );
return false;
}
glAttachShader( programNumber, shaderNumber );
programInfo( programNumber );
// Special handling for the geometry shader
if( aShaderType == SHADER_TYPE_GEOMETRY )
{
glProgramParameteriEXT( programNumber, GL_GEOMETRY_VERTICES_OUT_EXT, maximumVertices );
glProgramParameteriEXT( programNumber, GL_GEOMETRY_INPUT_TYPE_EXT, geomInputType );
glProgramParameteriEXT( programNumber, GL_GEOMETRY_OUTPUT_TYPE_EXT, geomOutputType );
}
return true;
}

View File

@ -0,0 +1,75 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* Fragment shader
*
* 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
*/
#version 120
// Shader types
const float SHADER_LINE = 1.0f;
const float SHADER_FILLED_CIRCLE = 2.0f;
const float SHADER_STROKED_CIRCLE = 3.0f;
varying vec4 shaderParams;
varying vec2 circleCoords;
void filledCircle( vec2 aCoord )
{
if( dot( aCoord, aCoord ) < 1.0f )
gl_FragColor = gl_Color;
else
discard;
}
void strokedCircle( vec2 aCoord, float aRadius, float aWidth )
{
float outerRadius = aRadius + ( aWidth / 2 );
float innerRadius = aRadius - ( aWidth / 2 );
float relWidth = innerRadius / outerRadius;
if( ( dot( aCoord, aCoord ) < 1.0f ) &&
( dot( aCoord, aCoord ) > relWidth * relWidth ) )
gl_FragColor = gl_Color;
else
discard;
}
void main()
{
if( shaderParams[0] == SHADER_FILLED_CIRCLE )
{
filledCircle( circleCoords );
}
else if( shaderParams[0] == SHADER_STROKED_CIRCLE )
{
strokedCircle( circleCoords, shaderParams[2], shaderParams[3] );
}
else
{
// Simple pass-through
gl_FragColor = gl_Color;
}
}

View File

@ -0,0 +1,98 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* Vertex shader
*
* 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
*/
#version 120
// Shader types
const float SHADER_LINE = 1.0f;
const float SHADER_FILLED_CIRCLE = 2.0f;
const float SHADER_STROKED_CIRCLE = 3.0f;
// Minimum line width
const float MIN_WIDTH = 1.0f;
attribute vec4 attrShaderParams;
varying vec4 shaderParams;
varying vec2 circleCoords;
void main()
{
// Pass attributes to the fragment shader
shaderParams = attrShaderParams;
if( shaderParams[0] == SHADER_LINE )
{
float lineWidth = shaderParams[3];
float worldScale = gl_ModelViewMatrix[0][0];
float scale;
// Make lines appear to be at least 1 pixel wide
if( worldScale * lineWidth < MIN_WIDTH )
scale = MIN_WIDTH / ( worldScale * lineWidth );
else
scale = 1.0f;
gl_Position = gl_ModelViewProjectionMatrix *
( gl_Vertex + vec4( shaderParams.yz * scale, 0.0, 0.0 ) );
}
else if( ( shaderParams[0] == SHADER_STROKED_CIRCLE ) ||
( shaderParams[0] == SHADER_FILLED_CIRCLE ) )
{
// Compute relative circle coordinates basing on indices
// Circle
if( shaderParams[1] == 1.0f )
circleCoords = vec2( -sqrt( 3.0f ), -1.0f );
else if( shaderParams[1] == 2.0f )
circleCoords = vec2( sqrt( 3.0f ), -1.0f );
else if( shaderParams[1] == 3.0f )
circleCoords = vec2( 0.0f, 2.0f );
// Semicircle
else if( shaderParams[1] == 4.0f )
circleCoords = vec2( -3.0f / sqrt( 3.0f ), 0.0f );
else if( shaderParams[1] == 5.0f )
circleCoords = vec2( 3.0f / sqrt( 3.0f ), 0.0f );
else if( shaderParams[1] == 6.0f )
circleCoords = vec2( 0.0f, 2.0f );
// Make the line appear to be at least 1 pixel wide
float lineWidth = shaderParams[3];
float worldScale = gl_ModelViewMatrix[0][0];
// Make lines appear to be at least 1 pixel width
if( worldScale * lineWidth < MIN_WIDTH )
shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth );
gl_Position = ftransform();
}
else
{
// Pass through the coordinates like in the fixed pipeline
gl_Position = ftransform();
}
gl_FrontColor = gl_Color;
}

View File

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 vertex_container.cpp
* @brief Class to store vertices and handle transfers between system memory and GPU memory.
*/
#include <gal/opengl/vertex_container.h>
#include <gal/opengl/cached_container.h>
#include <gal/opengl/noncached_container.h>
#include <gal/opengl/shader.h>
#include <wx/log.h>
using namespace KIGFX;
VERTEX_CONTAINER* VERTEX_CONTAINER::MakeContainer( bool aCached )
{
if( aCached )
return new CACHED_CONTAINER;
else
return new NONCACHED_CONTAINER;
}
VERTEX_CONTAINER::VERTEX_CONTAINER( unsigned int aSize ) :
m_freeSpace( aSize ), m_currentSize( aSize ), m_initialSize( aSize ), m_failed( false )
{
m_vertices = static_cast<VERTEX*>( malloc( aSize * sizeof( VERTEX ) ) );
}
VERTEX_CONTAINER::~VERTEX_CONTAINER()
{
free( m_vertices );
}

View File

@ -0,0 +1,53 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 vertex_item.cpp
* @brief Class to handle an item held in a container.
*/
#include <gal/opengl/vertex_item.h>
#include <gal/opengl/vertex_manager.h>
#include <cstring>
using namespace KIGFX;
VERTEX_ITEM::VERTEX_ITEM( const VERTEX_MANAGER& aManager ) :
m_manager( aManager ), m_offset( 0 ), m_size( 0 )
{
// As the item is created, we are going to modify it, so call to SetItem() is needed
m_manager.SetItem( *this );
}
VERTEX_ITEM::~VERTEX_ITEM()
{
m_manager.FreeItem( *this );
}
VERTEX* VERTEX_ITEM::GetVertices() const
{
return m_manager.GetVertices( *this );
}

View File

@ -0,0 +1,217 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 vertex_manager.cpp
* @brief Class to control vertex container and GPU with possibility of emulating old-style OpenGL
* 1.0 state machine using modern OpenGL methods.
*/
#include <gal/opengl/vertex_manager.h>
#include <gal/opengl/cached_container.h>
#include <gal/opengl/noncached_container.h>
#include <gal/opengl/gpu_manager.h>
#include <gal/opengl/vertex_item.h>
using namespace KIGFX;
VERTEX_MANAGER::VERTEX_MANAGER( bool aCached ) :
m_noTransform( true ), m_transform( 1.0f )
{
m_container.reset( VERTEX_CONTAINER::MakeContainer( aCached ) );
m_gpu.reset( GPU_MANAGER::MakeManager( m_container.get() ) );
// There is no shader used by default
for( unsigned int i = 0; i < ShaderStride; ++i )
m_shader[i] = 0.0f;
}
void VERTEX_MANAGER::Vertex( GLfloat aX, GLfloat aY, GLfloat aZ ) const
{
// Obtain the pointer to the vertex in the currently used container
VERTEX* newVertex = m_container->Allocate( 1 );
if( newVertex == NULL )
{
wxLogError( wxT( "Vertex allocation error" ) );
return;
}
putVertex( *newVertex, aX, aY, aZ );
}
void VERTEX_MANAGER::Vertices( const VERTEX aVertices[], unsigned int aSize ) const
{
// Obtain pointer to the vertex in currently used container
VERTEX* newVertex = m_container->Allocate( aSize );
if( newVertex == NULL )
{
wxLogError( wxT( "Vertex allocation error" ) );
return;
}
// Put vertices in already allocated memory chunk
for( unsigned int i = 0; i < aSize; ++i )
{
putVertex( newVertex[i], aVertices[i].x, aVertices[i].y, aVertices[i].z );
}
}
void VERTEX_MANAGER::SetItem( VERTEX_ITEM& aItem ) const
{
m_container->SetItem( &aItem );
}
void VERTEX_MANAGER::FinishItem() const
{
m_container->FinishItem();
}
void VERTEX_MANAGER::FreeItem( VERTEX_ITEM& aItem ) const
{
m_container->Delete( &aItem );
}
void VERTEX_MANAGER::ChangeItemColor( const VERTEX_ITEM& aItem, const COLOR4D& aColor ) const
{
unsigned int size = aItem.GetSize();
unsigned int offset = aItem.GetOffset();
VERTEX* vertex = m_container->GetVertices( offset );
for( unsigned int i = 0; i < size; ++i )
{
vertex->r = aColor.r * 255.0;
vertex->g = aColor.g * 255.0;
vertex->b = aColor.b * 255.0;
vertex->a = aColor.a * 255.0;
vertex++;
}
m_container->SetDirty();
}
void VERTEX_MANAGER::ChangeItemDepth( const VERTEX_ITEM& aItem, GLfloat aDepth ) const
{
unsigned int size = aItem.GetSize();
unsigned int offset = aItem.GetOffset();
VERTEX* vertex = m_container->GetVertices( offset );
for( unsigned int i = 0; i < size; ++i )
{
vertex->z = aDepth;
vertex++;
}
m_container->SetDirty();
}
VERTEX* VERTEX_MANAGER::GetVertices( const VERTEX_ITEM& aItem ) const
{
if( aItem.GetSize() == 0 )
return NULL; // The item is not stored in the container
return m_container->GetVertices( aItem.GetOffset() );
}
void VERTEX_MANAGER::SetShader( SHADER& aShader ) const
{
m_gpu->SetShader( aShader );
}
void VERTEX_MANAGER::Clear() const
{
m_container->Clear();
}
void VERTEX_MANAGER::BeginDrawing() const
{
m_gpu->BeginDrawing();
}
void VERTEX_MANAGER::DrawItem( const VERTEX_ITEM& aItem ) const
{
int size = aItem.GetSize();
if( size > 0 )
{
int offset = aItem.GetOffset();
m_gpu->DrawIndices( offset, size );
}
}
void VERTEX_MANAGER::EndDrawing() const
{
m_gpu->EndDrawing();
}
void VERTEX_MANAGER::putVertex( VERTEX& aTarget, GLfloat aX, GLfloat aY, GLfloat aZ ) const
{
// Modify the vertex according to the currently used transformations
if( m_noTransform )
{
// Simply copy coordinates, when the transform matrix is the identity matrix
aTarget.x = aX;
aTarget.y = aY;
aTarget.z = aZ;
}
else
{
// Apply transformations
glm::vec4 transVertex( aX, aY, aZ, 1.0f );
transVertex = m_transform * transVertex;
aTarget.x = transVertex.x;
aTarget.y = transVertex.y;
aTarget.z = transVertex.z;
}
// Apply currently used color
aTarget.r = m_color[0];
aTarget.g = m_color[1];
aTarget.b = m_color[2];
aTarget.a = m_color[3];
// Apply currently used shader
for( unsigned int j = 0; j < ShaderStride; ++j )
{
aTarget.shader[j] = m_shader[j];
}
}

305
common/gal/stroke_font.cpp Normal file
View File

@ -0,0 +1,305 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* Stroke font class
*
* 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
*/
#include <gal/stroke_font.h>
#include <gal/graphics_abstraction_layer.h>
using namespace KIGFX;
const double STROKE_FONT::LINE_HEIGHT_RATIO = 1.6;
STROKE_FONT::STROKE_FONT( GAL* aGal ) :
m_gal( aGal ),
m_bold( false ),
m_italic( false ),
m_mirrored( false )
{
// Default values
m_scaleFactor = 1.0 / 21.0;
m_glyphSize = VECTOR2D( 10.0, 10.0 );
m_verticalJustify = GR_TEXT_VJUSTIFY_BOTTOM;
m_horizontalJustify = GR_TEXT_HJUSTIFY_LEFT;
}
STROKE_FONT::~STROKE_FONT()
{
}
bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize )
{
m_glyphs.clear();
m_glyphBoundingBoxes.clear();
for( int j = 0; j < aNewStrokeFontSize; j++ )
{
GLYPH glyph;
double glyphStartX = 0.0;
double glyphEndX = 0.0;
VECTOR2D glyphBoundingX;
std::deque<VECTOR2D> pointList;
int i = 0;
while( aNewStrokeFont[j][i] )
{
VECTOR2D point( 0.0, 0.0 );
char coordinate[2] = { 0, };
for( int k = 0; k < 2; k++ )
{
coordinate[k] = aNewStrokeFont[j][i + k];
}
if( i < 2 )
{
// The first two values contain the width of the char
glyphStartX = coordinate[0] - 'R';
glyphEndX = coordinate[1] - 'R';
glyphBoundingX = VECTOR2D( 0, glyphEndX - glyphStartX );
}
else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) )
{
// Raise pen
if( pointList.size() > 0 )
glyph.push_back( pointList );
pointList.clear();
}
else
{
// Every coordinate description of the Hershey format has an offset,
// it has to be subtracted
point.x = (double) ( coordinate[0] - 'R' ) - glyphStartX;
point.y = (double) ( coordinate[1] - 'R' ) - 11.0;
pointList.push_back( point );
}
i += 2;
}
if( pointList.size() > 0 )
glyph.push_back( pointList );
m_glyphs.push_back( glyph );
// Compute the bounding box of the glyph
m_glyphBoundingBoxes.push_back( computeBoundingBox( glyph, glyphBoundingX ) );
}
return true;
}
BOX2D STROKE_FONT::computeBoundingBox( const GLYPH& aGLYPH, const VECTOR2D& aGLYPHBoundingX ) const
{
BOX2D boundingBox;
std::deque<VECTOR2D> boundingPoints;
boundingPoints.push_back( VECTOR2D( aGLYPHBoundingX.x, 0 ) );
boundingPoints.push_back( VECTOR2D( aGLYPHBoundingX.y, 0 ) );
for( GLYPH::const_iterator pointListIt = aGLYPH.begin(); pointListIt != aGLYPH.end(); ++pointListIt )
{
for( std::deque<VECTOR2D>::const_iterator pointIt = pointListIt->begin();
pointIt != pointListIt->end(); ++pointIt )
{
boundingPoints.push_back( VECTOR2D( aGLYPHBoundingX.x, pointIt->y ) );
}
}
boundingBox.Compute( boundingPoints );
return boundingBox;
}
void STROKE_FONT::Draw( std::string aText, const VECTOR2D& aPosition, double aRotationAngle )
{
// By default overbar is turned off
m_overbar = false;
// Context needs to be saved before any transformations
m_gal->Save();
m_gal->Translate( aPosition );
m_gal->Rotate( -aRotationAngle );
// Split multiline strings into separate ones and draw them line by line
size_t newlinePos = aText.find( '\n' );
if( newlinePos != std::string::npos )
{
VECTOR2D nextlinePosition = VECTOR2D( 0.0, m_glyphSize.y * LINE_HEIGHT_RATIO );
Draw( aText.substr( newlinePos + 1 ), nextlinePosition, 0.0 );
aText = aText.substr( 0, newlinePos );
}
// Compute the text size
VECTOR2D textsize = computeTextSize( aText );
// Adjust the text position to the given alignment
switch( m_horizontalJustify )
{
case GR_TEXT_HJUSTIFY_CENTER:
m_gal->Translate( VECTOR2D( -textsize.x / 2.0, 0 ) );
break;
case GR_TEXT_HJUSTIFY_RIGHT:
if( !m_mirrored )
m_gal->Translate( VECTOR2D( -textsize.x, 0 ) );
break;
case GR_TEXT_HJUSTIFY_LEFT:
if( m_mirrored )
m_gal->Translate( VECTOR2D( -textsize.x, 0 ) );
break;
default:
break;
}
switch( m_verticalJustify )
{
case GR_TEXT_VJUSTIFY_CENTER:
m_gal->Translate( VECTOR2D( 0, textsize.y / 2.0 ) );
break;
case GR_TEXT_VJUSTIFY_TOP:
m_gal->Translate( VECTOR2D( 0, textsize.y ) );
break;
case GR_TEXT_VJUSTIFY_BOTTOM:
break;
default:
break;
}
double xOffset, glyphSizeX;
if( m_mirrored )
{
// In case of mirrored text invert the X scale of points and their X direction
// (m_glyphSize.x) and start drawing from the position where text normally should end
// (textsize.x)
xOffset = textsize.x;
glyphSizeX = -m_glyphSize.x;
}
else
{
xOffset = 0.0;
glyphSizeX = m_glyphSize.x;
}
double scaleY = m_scaleFactor * m_glyphSize.y;
double scaleX = m_scaleFactor * glyphSizeX;
m_gal->SetIsStroke( true );
m_gal->SetIsFill( false );
if( m_bold )
{
m_gal->SetLineWidth( m_gal->GetLineWidth() * 1.3 );
}
for( std::string::const_iterator chIt = aText.begin(); chIt != aText.end(); chIt++ )
{
if( *chIt == '~' )
{
m_overbar = !m_overbar;
continue;
}
GLYPH_LIST::iterator glyphIt = m_glyphs.begin();
std::deque<BOX2D>::iterator bbIt = m_glyphBoundingBoxes.begin();
advance( glyphIt, (int) ( *chIt ) - (int) ' ' );
advance( bbIt, (int) ( *chIt ) - (int) ' ' );
GLYPH glyph = *glyphIt;
for( GLYPH::iterator pointListIt = glyph.begin(); pointListIt != glyph.end();
pointListIt++ )
{
std::deque<VECTOR2D> pointListScaled;
for( std::deque<VECTOR2D>::iterator pointIt = pointListIt->begin();
pointIt != pointListIt->end(); pointIt++ )
{
VECTOR2D pointPos( pointIt->x * scaleX + xOffset, pointIt->y * scaleY );
if( m_italic )
{
// FIXME should be done other way - referring to the lowest Y value of point
// because now italic fonts are translated a bit
pointPos.x += pointPos.y * 0.1;
}
pointListScaled.push_back( pointPos );
}
m_gal->DrawPolyline( pointListScaled );
}
if( m_overbar )
{
VECTOR2D startOverbar( xOffset, -textsize.y * 1.2 );
VECTOR2D endOverbar( xOffset + m_scaleFactor * glyphSizeX * bbIt->GetEnd().x,
-textsize.y * 1.2 );
m_gal->DrawLine( startOverbar, endOverbar );
}
xOffset += m_scaleFactor * glyphSizeX * bbIt->GetEnd().x;
}
m_gal->Restore();
}
VECTOR2D STROKE_FONT::computeTextSize( const std::string& aText ) const
{
VECTOR2D result = VECTOR2D( 0.0, m_glyphSize.y );
for( std::string::const_iterator chIt = aText.begin(); chIt != aText.end(); chIt++ )
{
if( *chIt == '~' )
continue;
std::deque<BOX2D>::const_iterator bbIt = m_glyphBoundingBoxes.begin();
advance( bbIt, (int) ( *chIt ) - (int) ' ' );
result.x += m_scaleFactor * m_glyphSize.x * bbIt->GetEnd().x;
}
return result;
}

157
common/geometry/seg.cpp Normal file
View File

@ -0,0 +1,157 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <geometry/seg.h>
template <typename T>
int sgn( T aVal )
{
return ( T( 0 ) < aVal ) - ( aVal < T( 0 ) );
}
bool SEG::PointCloserThan( const VECTOR2I& aP, int aDist ) const
{
VECTOR2I d = B - A;
ecoord dist_sq = (ecoord) aDist * aDist;
SEG::ecoord l_squared = d.Dot( d );
SEG::ecoord t = d.Dot( aP - A );
if( t <= 0 || !l_squared )
return ( aP - A ).SquaredEuclideanNorm() < dist_sq;
else if( t >= l_squared )
return ( aP - B ).SquaredEuclideanNorm() < dist_sq;
int dxdy = abs( d.x ) - abs( d.y );
if( ( dxdy >= -1 && dxdy <= 1 ) || abs( d.x ) <= 1 || abs( d.y ) <= 1 )
{
int ca = -sgn( d.y );
int cb = sgn( d.x );
int cc = -ca * A.x - cb * A.y;
ecoord num = ca * aP.x + cb * aP.y + cc;
num *= num;
if( ca && cb )
num >>= 1;
if( num > ( dist_sq + 100 ) )
return false;
else if( num < ( dist_sq - 100 ) )
return true;
}
VECTOR2I nearest;
nearest.x = A.x + rescale( t, (ecoord) d.x, l_squared );
nearest.y = A.y + rescale( t, (ecoord) d.y, l_squared );
return ( nearest - aP ).SquaredEuclideanNorm() <= dist_sq;
}
SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
{
// fixme: rather inefficient....
if( Intersect( aSeg ) )
return 0;
const VECTOR2I pts[4] =
{
aSeg.NearestPoint( A ) - A,
aSeg.NearestPoint( B ) - B,
NearestPoint( aSeg.A ) - aSeg.A,
NearestPoint( aSeg.B ) - aSeg.B
};
ecoord m = VECTOR2I::ECOORD_MAX;
for( int i = 0; i < 4; i++ )
m = std::min( m, pts[i].SquaredEuclideanNorm() );
return m;
}
OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines ) const
{
const VECTOR2I e( B - A );
const VECTOR2I f( aSeg.B - aSeg.A );
const VECTOR2I ac( aSeg.A - A );
ecoord d = f.Cross( e );
ecoord p = f.Cross( ac );
ecoord q = e.Cross( ac );
if( d == 0 )
return OPT_VECTOR2I();
if( !aLines && d > 0 && ( q < 0 || q > d || p < 0 || p > d ) )
return OPT_VECTOR2I();
if( !aLines && d < 0 && ( q < d || p < d || p > 0 || q > 0 ) )
return OPT_VECTOR2I();
if( !aLines && aIgnoreEndpoints && ( q == 0 || q == d ) && ( p == 0 || p == d ) )
return OPT_VECTOR2I();
VECTOR2I ip( aSeg.A.x + rescale( q, (ecoord) f.x, d ),
aSeg.A.y + rescale( q, (ecoord) f.y, d ) );
return ip;
}
bool SEG::ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ) const
{
return (ecoord) ( aC.y - aA.y ) * ( aB.x - aA.x ) > (ecoord) ( aB.y - aA.y ) * ( aC.x - aA.x );
}
bool SEG::Collide( const SEG& aSeg, int aClearance ) const
{
// check for intersection
// fixme: move to a method
if( ccw( A, aSeg.A, aSeg.B ) != ccw( B, aSeg.A, aSeg.B ) &&
ccw( A, B, aSeg.A ) != ccw( A, B, aSeg.B ) )
return true;
#define CHK( _seg, _pt ) \
if( (_seg).PointCloserThan( _pt, aClearance ) ) return true;
CHK( *this, aSeg.A );
CHK( *this, aSeg.B );
CHK( aSeg, A );
CHK( aSeg, B );
#undef CHK
return false;
}
bool SEG::Contains( const VECTOR2I& aP ) const
{
return PointCloserThan( aP, 1 );
}

View File

@ -0,0 +1,242 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <math/vector2d.h>
#include <geometry/shape.h>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_circle.h>
#include <geometry/shape_rect.h>
typedef VECTOR2I::extended_type ecoord;
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
ecoord min_dist_sq = min_dist * min_dist;
const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
ecoord dist_sq = delta.SquaredEuclideanNorm();
if( dist_sq >= min_dist_sq )
return false;
if( aNeedMTV )
aMTV = delta.Resize( sqrt( abs( min_dist_sq - dist_sq ) ) + 1 );
return true;
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
const VECTOR2I c = aB.GetCenter();
const VECTOR2I p0 = aA.GetPosition();
const VECTOR2I size = aA.GetSize();
const ecoord r = aB.GetRadius();
const ecoord min_dist = aClearance + r;
const ecoord min_dist_sq = min_dist * min_dist;
if( aA.BBox( 0 ).Contains( c ) )
return true;
const VECTOR2I vts[] =
{
VECTOR2I( p0.x, p0.y ),
VECTOR2I( p0.x, p0.y + size.y ),
VECTOR2I( p0.x + size.x, p0.y + size.y ),
VECTOR2I( p0.x + size.x, p0.y ),
VECTOR2I( p0.x, p0.y )
};
ecoord nearest_seg_dist_sq = VECTOR2I::ECOORD_MAX;
VECTOR2I nearest;
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
if( !inside )
{
for( int i = 0; i < 4; i++ )
{
const SEG seg( vts[i], vts[i + 1] );
ecoord dist_sq = seg.SquaredDistance( c );
if( dist_sq < min_dist_sq )
{
if( !aNeedMTV )
return true;
else
{
nearest = seg.NearestPoint( c );
nearest_seg_dist_sq = dist_sq;
}
}
}
}
if( nearest_seg_dist_sq >= min_dist_sq && !inside )
return false;
VECTOR2I delta = c - nearest;
if( !aNeedMTV )
return true;
if( inside )
aMTV = -delta.Resize( sqrt( abs( r * r + nearest_seg_dist_sq ) + 1 ) );
else
aMTV = delta.Resize( sqrt( abs( r * r - nearest_seg_dist_sq ) + 1 ) );
return true;
}
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
for( int s = 0; s < aB.SegmentCount(); s++ )
{
if( aA.Collide( aB.CSegment( s ), aClearance ) )
return true;
}
return false;
}
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
for( int i = 0; i < aB.SegmentCount(); i++ )
if( aA.Collide( aB.CSegment( i ), aClearance ) )
return true;
return false;
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
for( int s = 0; s < aB.SegmentCount(); s++ )
{
SEG seg = aB.CSegment( s );
if( aA.Collide( seg, aClearance ) )
return true;
}
return false;
}
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
switch( aA->Type() )
{
case SH_RECT:
switch( aB->Type() )
{
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
break;
case SH_CIRCLE:
switch( aB->Type() )
{
case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_CIRCLE*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN *>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
break;
case SH_LINE_CHAIN:
switch( aB->Type() )
{
case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
break;
default:
break;
}
bool unsupported_collision = true;
assert( unsupported_collision == false );
return false;
}
bool SHAPE::Collide( const SHAPE* aShape, int aClerance, VECTOR2I& aMTV ) const
{
return CollideShapes( this, aShape, aClerance, true, aMTV );
}
bool SHAPE::Collide( const SHAPE* aShape, int aClerance ) const
{
VECTOR2I dummy;
return CollideShapes( this, aShape, aClerance, false, dummy );
}

View File

@ -0,0 +1,32 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Jacobo Aragunde Pérez
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <geometry/shape_index.h>
template <>
const SHAPE* shapeFunctor( SHAPE* aItem )
{
return aItem;
}

View File

@ -0,0 +1,537 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <geometry/shape_line_chain.h>
#include <geometry/shape_circle.h>
using namespace std;
using boost::optional;
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const
{
assert( false );
return false;
}
bool SHAPE_LINE_CHAIN::Collide( const BOX2I& aBox, int aClearance ) const
{
assert( false );
return false;
}
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const
{
BOX2I box_a( aSeg.A, aSeg.B - aSeg.A );
BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
for( int i = 0; i < SegmentCount(); i++ )
{
const SEG& s = CSegment( i );
BOX2I box_b( s.A, s.B - s.A );
BOX2I::ecoord_type d = box_a.SquaredDistance( box_b );
if( d < dist_sq )
{
if( s.Collide( aSeg, aClearance ) )
return true;
}
}
return false;
}
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const
{
SHAPE_LINE_CHAIN a( *this );
reverse( a.m_points.begin(), a.m_points.end() );
a.m_closed = m_closed;
return a;
}
int SHAPE_LINE_CHAIN::Length() const
{
int l = 0;
for( int i = 0; i < SegmentCount(); i++ )
l += CSegment( i ).Length();
return l;
}
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP )
{
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
if( aStartIndex == aEndIndex )
m_points[aStartIndex] = aP;
else
{
m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 );
m_points[aStartIndex] = aP;
}
}
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine )
{
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() );
}
void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
{
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
}
int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP ) const
{
int d = INT_MAX;
for( int s = 0; s < SegmentCount(); s++ )
d = min( d, CSegment( s ).Distance( aP ) );
return d;
}
int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP )
{
int ii = -1;
int min_dist = 2;
ii = Find( aP );
if( ii >= 0 )
return ii;
for( int s = 0; s < SegmentCount(); s++ )
{
const SEG seg = CSegment( s );
int dist = seg.Distance( aP );
// make sure we are not producing a 'slightly concave' primitive. This might happen
// if aP lies very close to one of already existing points.
if( dist < min_dist && seg.A != aP && seg.B != aP )
{
min_dist = dist;
ii = s;
}
}
if( ii >= 0 )
{
m_points.insert( m_points.begin() + ii + 1, aP );
return ii + 1;
}
return -1;
}
int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const
{
for( int s = 0; s< PointCount(); s++ )
if( CPoint( s ) == aP )
return s;
return -1;
}
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const
{
SHAPE_LINE_CHAIN rv;
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
for( int i = aStartIndex; i <= aEndIndex; i++ )
rv.Append( m_points[i] );
return rv;
}
struct compareOriginDistance
{
compareOriginDistance( VECTOR2I& aOrigin ) :
m_origin( aOrigin ) {};
bool operator()( const SHAPE_LINE_CHAIN::INTERSECTION& aA,
const SHAPE_LINE_CHAIN::INTERSECTION& aB )
{
return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
}
VECTOR2I m_origin;
};
int SHAPE_LINE_CHAIN::Intersect( const SEG& aSeg, INTERSECTIONS& aIp ) const
{
for( int s = 0; s < SegmentCount(); s++ )
{
OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg );
if( p )
{
INTERSECTION is;
is.our = CSegment( s );
is.their = aSeg;
is.p = *p;
aIp.push_back( is );
}
}
compareOriginDistance comp( aSeg.A );
sort( aIp.begin(), aIp.end(), comp );
return aIp.size();
}
int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, INTERSECTIONS& aIp ) const
{
BOX2I bb_other = aChain.BBox();
for( int s1 = 0; s1 < SegmentCount(); s1++ )
{
const SEG& a = CSegment( s1 );
const BOX2I bb_cur( a.A, a.B - a.A );
if( !bb_other.Intersects( bb_cur ) )
continue;
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
{
const SEG& b = aChain.CSegment( s2 );
INTERSECTION is;
if( a.Collinear( b ) )
{
if( a.Contains( b.A ) ) { is.p = b.A; aIp.push_back( is ); }
if( a.Contains( b.B ) ) { is.p = b.B; aIp.push_back( is ); }
if( b.Contains( a.A ) ) { is.p = a.A; aIp.push_back( is ); }
if( b.Contains( a.B ) ) { is.p = a.B; aIp.push_back( is ); }
}
else
{
OPT_VECTOR2I p = a.Intersect( b );
if( p )
{
is.p = *p;
is.our = a;
is.their = b;
aIp.push_back( is );
}
}
}
}
return aIp.size();
for( int s1 = 0; s1 < SegmentCount(); s1++ )
{
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
{
const SEG& a = CSegment( s1 );
const SEG& b = aChain.CSegment( s2 );
OPT_VECTOR2I p = a.Intersect( b );
INTERSECTION is;
if( p )
{
is.p = *p;
is.our = a;
is.their = b;
aIp.push_back( is );
}
else if( a.Collinear( b ) )
{
if( a.A != b.A && a.A != b.B && b.Contains( a.A ) )
{
is.p = a.A;
is.our = a;
is.their = b;
aIp.push_back( is );
}
else if( a.B != b.A && a.B != b.B && b.Contains( a.B ) )
{
is.p = a.B;
is.our = a;
is.their = b;
aIp.push_back( is );
}
}
}
}
return aIp.size();
}
int SHAPE_LINE_CHAIN::PathLength( const VECTOR2I& aP ) const
{
int sum = 0;
for( int i = 0; i < SegmentCount(); i++ )
{
const SEG seg = CSegment( i );
int d = seg.Distance( aP );
if( d <= 1 )
{
sum += ( aP - seg.A ).EuclideanNorm();
return sum;
}
else
sum += seg.Length();
}
return -1;
}
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP ) const
{
if( !m_closed || SegmentCount() < 3 )
return false;
int cur = CSegment( 0 ).Side( aP );
if( cur == 0 )
return false;
for( int i = 1; i < SegmentCount(); i++ )
{
const SEG s = CSegment( i );
if( aP == s.A || aP == s.B ) // edge does not belong to the interior!
return false;
if( s.Side( aP ) != cur )
return false;
}
return true;
}
bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP ) const
{
if( SegmentCount() < 1 )
return m_points[0] == aP;
for( int i = 1; i < SegmentCount(); i++ )
{
const SEG s = CSegment( i );
if( s.A == aP || s.B == aP )
return true;
if( s.Distance( aP ) <= 1 )
return true;
}
return false;
}
const optional<SHAPE_LINE_CHAIN::INTERSECTION> SHAPE_LINE_CHAIN::SelfIntersecting() const
{
for( int s1 = 0; s1 < SegmentCount(); s1++ )
{
for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ )
{
const VECTOR2I s2a = CSegment( s2 ).A, s2b = CSegment( s2 ).B;
if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) )
{
INTERSECTION is;
is.our = CSegment( s1 );
is.their = CSegment( s2 );
is.p = s2a;
return is;
}
else if( CSegment( s1 ).Contains( s2b ) )
{
INTERSECTION is;
is.our = CSegment( s1 );
is.their = CSegment( s2 );
is.p = s2b;
return is;
}
else
{
OPT_VECTOR2I p = CSegment( s1 ).Intersect( CSegment( s2 ), true );
if( p )
{
INTERSECTION is;
is.our = CSegment( s1 );
is.their = CSegment( s2 );
is.p = *p;
return is;
}
}
}
}
return optional<INTERSECTION>();
}
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
{
vector<VECTOR2I> pts_unique;
if( PointCount() < 2 )
{
return *this;
}
else if( PointCount() == 2 )
{
if( m_points[0] == m_points[1] )
m_points.erase( m_points.end() );
return *this;
}
int i = 0;
int np = PointCount();
// stage 1: eliminate duplicate vertices
while( i < np )
{
int j = i + 1;
while( j < np && CPoint( i ) == CPoint( j ) )
j++;
pts_unique.push_back( CPoint( i ) );
i = j;
}
m_points.clear();
np = pts_unique.size();
i = 0;
// stage 1: eliminate collinear segments
while( i < np - 2 )
{
const VECTOR2I p0 = pts_unique[i];
const VECTOR2I p1 = pts_unique[i + 1];
int n = i;
while( n < np - 2 && SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 )
n++;
m_points.push_back( p0 );
if( n > i )
i = n;
if( n == np )
{
m_points.push_back( pts_unique[n - 1] );
return *this;
}
i++;
}
if( np > 1 )
m_points.push_back( pts_unique[np - 2] );
m_points.push_back( pts_unique[np - 1] );
return *this;
}
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const
{
int min_d = INT_MAX;
int nearest = 0;
for( int i = 0; i < SegmentCount(); i++ )
{
int d = CSegment( i ).Distance( aP );
if( d < min_d )
{
min_d = d;
nearest = i;
}
}
return CSegment( nearest ).NearestPoint( aP );
}
const string SHAPE_LINE_CHAIN::Format() const
{
stringstream ss;
ss << m_points.size() << " " << ( m_closed ? 1 : 0 ) << " ";
for( int i = 0; i < PointCount(); i++ )
ss << m_points[i].x << " " << m_points[i].y << " "; // Format() << " ";
return ss.str();
}

View File

@ -1488,12 +1488,12 @@ bool ColorIsLight( EDA_COLOR_T aColor )
EDA_COLOR_T ColorFindNearest( const wxColour &aColor ) EDA_COLOR_T ColorFindNearest( const wxColour &aColor )
{ {
EDA_COLOR_T candidate = BLACK; return ColorFindNearest( aColor.Red(), aColor.Green(), aColor.Blue() );
}
// These are ints because we will subtract them later EDA_COLOR_T ColorFindNearest( int aR, int aG, int aB )
int r = aColor.Red(); {
int g = aColor.Green(); EDA_COLOR_T candidate = BLACK;
int b = aColor.Blue();
/* Find the 'nearest' color in the palette. This is fun. There is /* Find the 'nearest' color in the palette. This is fun. There is
a gazilion of metrics for the color space and no one of the a gazilion of metrics for the color space and no one of the
@ -1511,11 +1511,11 @@ EDA_COLOR_T ColorFindNearest( const wxColour &aColor )
for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) ) for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) )
{ {
const StructColors &c = g_ColorRefs[trying]; const StructColors &c = g_ColorRefs[trying];
int distance = (r - c.m_Red) * (r - c.m_Red) + int distance = (aR - c.m_Red) * (aR - c.m_Red) +
(g - c.m_Green) * (g - c.m_Green) + (aG - c.m_Green) * (aG - c.m_Green) +
(b - c.m_Blue) * (b - c.m_Blue); (aB - c.m_Blue) * (aB - c.m_Blue);
if( distance < nearest_distance && c.m_Red >= r && if( distance < nearest_distance && c.m_Red >= aR &&
c.m_Green >= g && c.m_Blue >= b ) c.m_Green >= aG && c.m_Blue >= aB )
{ {
nearest_distance = distance; nearest_distance = distance;
candidate = trying; candidate = trying;

View File

@ -65,7 +65,7 @@ void GRID_TRICKS::getSelectedArea()
wxArrayInt cols = m_grid->GetSelectedCols(); wxArrayInt cols = m_grid->GetSelectedCols();
wxArrayInt rows = m_grid->GetSelectedRows(); wxArrayInt rows = m_grid->GetSelectedRows();
D(printf("topLeft.Count():%zd botRight:Count():%zd\n", topLeft.Count(), botRight.Count() );) DBG(printf("topLeft.Count():%zd botRight:Count():%zd\n", topLeft.Count(), botRight.Count() );)
if( topLeft.Count() && botRight.Count() ) if( topLeft.Count() && botRight.Count() )
{ {
@ -97,7 +97,7 @@ void GRID_TRICKS::getSelectedArea()
m_sel_col_count = 0; m_sel_col_count = 0;
} }
//D(printf("m_sel_row_start:%d m_sel_col_start:%d m_sel_row_count:%d m_sel_col_count:%d\n", m_sel_row_start, m_sel_col_start, m_sel_row_count, m_sel_col_count );) //DBG(printf("m_sel_row_start:%d m_sel_col_start:%d m_sel_row_count:%d m_sel_col_count:%d\n", m_sel_row_start, m_sel_col_start, m_sel_row_count, m_sel_col_count );)
} }

87
common/math/math_util.cpp Normal file
View File

@ -0,0 +1,87 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
* Copyright (C) CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <cmath>
#include <cstdlib>
#include <climits>
#include <math/math_util.h>
template <>
int rescale( int aNumerator, int aValue, int aDenominator )
{
return (int) ( (int64_t) aNumerator * (int64_t) aValue / (int64_t) aDenominator );
}
template <>
int64_t rescale( int64_t aNumerator, int64_t aValue, int64_t aDenominator )
{
int64_t r = 0;
int64_t sign = ( ( aNumerator < 0 ) ? -1 : 1 ) * ( aDenominator < 0 ? -1 : 1 ) *
( aValue < 0 ? -1 : 1 );
int64_t a = std::abs( aNumerator );
int64_t b = std::abs( aValue );
int64_t c = std::abs( aDenominator );
r = c / 2;
if( b <= INT_MAX && c <= INT_MAX )
{
if( a <= INT_MAX )
return sign * ( ( a * b + r ) / c );
else
return sign * ( a / c * b + ( a % c * b + r ) / c);
}
else
{
uint64_t a0 = a & 0xFFFFFFFF;
uint64_t a1 = a >> 32;
uint64_t b0 = b & 0xFFFFFFFF;
uint64_t b1 = b >> 32;
uint64_t t1 = a0 * b1 + a1 * b0;
uint64_t t1a = t1 << 32;
int i;
a0 = a0 * b0 + t1a;
a1 = a1 * b1 + ( t1 >> 32 ) + ( a0 < t1a );
a0 += r;
a1 += ( (uint64_t) a0 ) < r;
for( i = 63; i >= 0; i-- )
{
a1 += a1 + ( ( a0 >> i ) & 1 );
t1 += t1;
if( (uint64_t) c <= a1 )
{
a1 -= c;
t1++;
}
}
return t1 * sign;
}
}

81
common/painter.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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
*/
#include <painter.h>
#include <gal/graphics_abstraction_layer.h>
using namespace KIGFX;
RENDER_SETTINGS::RENDER_SETTINGS()
{
// Set the default initial values
m_highlightFactor = 0.5;
m_selectFactor = 0.5;
m_layerOpacity = 0.8;
m_highlightEnabled = false;
m_hiContrastEnabled = false;
m_hiContrastFactor = 0.2;
m_outlineWidth = 1;
m_worksheetLineWidth = 100000;
// Store the predefined colors used in KiCad in format used by GAL
for( int i = 0; i < NBCOLORS; i++ )
{
m_legacyColorMap[g_ColorRefs[i].m_Numcolor] = COLOR4D( (double) g_ColorRefs[i].m_Red / 255.0,
(double) g_ColorRefs[i].m_Green / 255.0,
(double) g_ColorRefs[i].m_Blue / 255.0,
m_layerOpacity );
}
}
RENDER_SETTINGS::~RENDER_SETTINGS()
{
}
void RENDER_SETTINGS::update()
{
m_hiContrastColor = COLOR4D( m_hiContrastFactor, m_hiContrastFactor, m_highlightFactor,
m_layerOpacity );
}
PAINTER::PAINTER( GAL* aGal ) :
m_gal( aGal ), m_brightenedColor( 0.0, 1.0, 0.0, 0.9 )
{
}
PAINTER::~PAINTER()
{
}
void PAINTER::SetGAL( GAL* aGal )
{
m_gal = aGal;
}

147
common/profile.h Normal file
View File

@ -0,0 +1,147 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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 profile.h:
* @brief Simple profiling functions for measuring code execution time.
*/
#ifndef __TPROFILE_H
#define __TPROFILE_H
#include <sys/time.h>
#include <stdint.h>
/**
* Function rdtsc
* Returns processor's time-stamp counter. Main purpose is precise time measuring of code
* execution time.
* @return unsigned long long - Value of time-stamp counter.
*/
#if defined(__i386__)
static __inline__ unsigned long long rdtsc()
{
unsigned long long int x;
__asm__ volatile ( ".byte 0x0f, 0x31" : "=A" ( x ) );
return x;
}
#elif defined(__x86_64__)
static __inline__ unsigned long long rdtsc()
{
unsigned hi, lo;
__asm__ __volatile__ ( "rdtsc" : "=a" ( lo ), "=d" ( hi ) );
return ( (unsigned long long) lo ) | ( ( (unsigned long long) hi ) << 32 );
}
#elif defined(__powerpc__)
static __inline__ unsigned long long rdtsc()
{
unsigned long long int result = 0;
unsigned long int upper, lower, tmp;
__asm__ volatile (
"0: \n"
"\tmftbu %0 \n"
"\tmftb %1 \n"
"\tmftbu %2 \n"
"\tcmpw %2,%0 \n"
"\tbne 0b \n"
: "=r" ( upper ), "=r" ( lower ), "=r" ( tmp )
);
result = upper;
result = result << 32;
result = result | lower;
return result;
}
#endif /* __powerpc__ */
// Fixme: OS X version
/**
* Function get_tics
* Returns the number of microseconds that have elapsed since the system was started.
* @return uint64_t Number of microseconds.
*/
static inline uint64_t get_tics()
{
struct timeval tv;
gettimeofday( &tv, NULL );
return (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
}
/**
* Structure for storing data related to profiling counters.
*/
struct prof_counter
{
uint64_t value; /// Stored timer value
bool use_rdtsc; /// Method of time measuring (rdtsc or tics)
};
/**
* Function prof_start
* Begins code execution time counting for a given profiling counter.
* @param cnt is the counter which should be started.
* @param use_rdtsc tells if processor's time-stamp counter should be used for time counting.
* Otherwise is system tics method will be used. IMPORTANT: time-stamp counter should not
* be used on multicore machines executing threaded code.
*/
static inline void prof_start( prof_counter* cnt, bool use_rdtsc )
{
cnt->use_rdtsc = use_rdtsc;
if( use_rdtsc )
{
cnt->value = rdtsc();
}
else
{
cnt->value = get_tics();
}
}
/**
* Function prof_stop
* Ends code execution time counting for a given profiling counter.
* @param cnt is the counter which should be stopped.
*/
static inline void prof_end( prof_counter* cnt )
{
if( cnt->use_rdtsc )
cnt->value = rdtsc() - cnt->value;
else
cnt->value = get_tics() - cnt->value;
}
#endif

View File

@ -39,8 +39,6 @@
#include <protos.h> #include <protos.h>
const wxString traceFindReplace( wxT( "KicadFindReplace" ) );
const wxString traceFindItem( wxT( "KicadFindItem" ) ); const wxString traceFindItem( wxT( "KicadFindItem" ) );

40
common/system/fcontext.s Normal file
View File

@ -0,0 +1,40 @@
/*
Boost::Context assembly wrapper - done to avoid compiling the whole boost binary library
which may be unpleasant, in particular under Windows (we don't support VC++, while boost::context
does not support mingw */
#ifdef __APPLE__
#if __i386__
#include "jump_i386_sysv_macho_gas.S"
#include "make_i386_sysv_macho_gas.S"
#elif __x86_64__
#include "jump_x86_64_sysv_macho_gas.S"
#include "make_x86_64_sysv_macho_gas.S"
#else
#error "Missing make_fcontext & jump_fcontext routines for this architecture"
#endif
#else
#if __i386__
#ifdef __WIN32__
#include "jump_i386_pe_gas.S"
#include "make_i386_pe_gas.S"
#else
#include "jump_i386_sysv_elf_gas.S"
#include "make_i386_sysv_elf_gas.S"
#endif
#elif __x86_64__
#include "jump_x86_64_sysv_elf_gas.S"
#include "make_x86_64_sysv_elf_gas.S"
#else
#error "Missing make_fcontext & jump_fcontext routines for this architecture"
#endif
#endif

View File

@ -0,0 +1,56 @@
/* Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
.global _jump_fcontext
.text
.align 2
_jump_fcontext:
mov 0x4(%esp),%ecx
mov %edi,(%ecx)
mov %esi,0x4(%ecx)
mov %ebx,0x8(%ecx)
mov %ebp,0xc(%ecx)
mov %fs:0x18,%edx
mov (%edx),%eax
mov %eax,0x24(%ecx)
mov 0x4(%edx),%eax
mov %eax,0x18(%ecx)
mov 0x8(%edx),%eax
mov %eax,0x20(%ecx)
mov 0x10(%edx),%eax
mov %eax,0x28(%ecx)
lea 0x4(%esp),%eax
mov %eax,0x10(%ecx)
mov (%esp),%eax
mov %eax,0x14(%ecx)
mov 0x8(%esp),%edx
mov (%edx),%edi
mov 0x4(%edx),%esi
mov 0x8(%edx),%ebx
mov 0xc(%edx),%ebp
mov 0x10(%esp),%eax
test %eax,%eax
je _jump_fcontext+0x5f
stmxcsr 0x2c(%ecx)
fnstcw 0x30(%ecx)
ldmxcsr 0x2c(%edx)
fldcw 0x30(%edx)
mov %edx,%ecx
mov %fs:0x18,%edx
mov 0x24(%ecx),%eax
mov %eax,(%edx)
mov 0x18(%ecx),%eax
mov %eax,0x4(%edx)
mov 0x20(%ecx),%eax
mov %eax,0x8(%edx)
mov 0x28(%ecx),%eax
mov %eax,0x10(%edx)
mov 0xc(%esp),%eax
mov 0x10(%ecx),%esp
mov %eax,0x4(%esp)
mov 0x14(%ecx),%ecx
jmp *%ecx

View File

@ -0,0 +1,72 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/********************************************************************
* *
* -------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | *
* -------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | *
* -------------------------------------------------------------- *
* | EDI | ESI | EBX | EBP | ESP | EIP | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 6 | 7 | | *
* -------------------------------------------------------------- *
* | 0x18 | 0x1c | | *
* -------------------------------------------------------------- *
* | sp | size | | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 8 | 9 | | *
* -------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* -------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* -------------------------------------------------------------- *
* *
* *****************************************************************/
.text
.globl jump_fcontext
.align 2
.type jump_fcontext,@function
jump_fcontext:
movl 0x4(%esp), %ecx /* load address of the first fcontext_t arg */
movl %edi, (%ecx) /* save EDI */
movl %esi, 0x4(%ecx) /* save ESI */
movl %ebx, 0x8(%ecx) /* save EBX */
movl %ebp, 0xc(%ecx) /* save EBP */
leal 0x4(%esp), %eax /* exclude the return address */
movl %eax, 0x10(%ecx) /* save as stack pointer */
movl (%esp), %eax /* load return address */
movl %eax, 0x14(%ecx) /* save return address */
movl 0x8(%esp), %edx /* load address of the second fcontext_t arg */
movl (%edx), %edi /* restore EDI */
movl 0x4(%edx), %esi /* restore ESI */
movl 0x8(%edx), %ebx /* restore EBX */
movl 0xc(%edx), %ebp /* restore EBP */
movl 0x10(%esp), %eax /* check if fpu enve preserving was requested */
test %eax, %eax
je 1f
stmxcsr 0x20(%ecx) /* save MMX control and status word */
fnstcw 0x24(%ecx) /* save x87 control word */
ldmxcsr 0x20(%edx) /* restore MMX control and status word */
fldcw 0x24(%edx) /* restore x87 control word */
1:
movl 0xc(%esp), %eax /* use third arg as return value after jump */
movl 0x10(%edx), %esp /* restore ESP */
movl %eax, 0x4(%esp) /* use third arg as first arg in context function */
movl 0x14(%edx), %edx /* fetch the address to return to */
jmp *%edx /* indirect jump to context */
.size jump_fcontext,.-jump_fcontext

View File

@ -0,0 +1,70 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/********************************************************************
* *
* -------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | *
* -------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | *
* -------------------------------------------------------------- *
* | EDI | ESI | EBX | EBP | ESP | EIP | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 6 | 7 | | *
* -------------------------------------------------------------- *
* | 0x18 | 0x1c | | *
* -------------------------------------------------------------- *
* | sp | size | | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 8 | 9 | | *
* -------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* -------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* -------------------------------------------------------------- *
* *
* *****************************************************************/
.text
.globl _jump_fcontext
.align 2
_jump_fcontext:
movl 0x4(%esp), %ecx /* load address of the first fcontext_t arg */
movl %edi, (%ecx) /* save EDI */
movl %esi, 0x4(%ecx) /* save ESI */
movl %ebx, 0x8(%ecx) /* save EBX */
movl %ebp, 0xc(%ecx) /* save EBP */
leal 0x4(%esp), %eax /* exclude the return address */
movl %eax, 0x10(%ecx) /* save as stack pointer */
movl (%esp), %eax /* load return address */
movl %eax, 0x14(%ecx) /* save return address */
movl 0x8(%esp), %edx /* load address of the second fcontext_t arg */
movl (%edx), %edi /* restore EDI */
movl 0x4(%edx), %esi /* restore ESI */
movl 0x8(%edx), %ebx /* restore EBX */
movl 0xc(%edx), %ebp /* restore EBP */
movl 0x10(%esp), %eax /* check if fpu enve preserving was requested */
test %eax, %eax
je 1f
stmxcsr 0x20(%ecx) /* save MMX control and status word */
fnstcw 0x24(%ecx) /* save x87 control word */
ldmxcsr 0x20(%edx) /* restore MMX control and status word */
fldcw 0x24(%edx) /* restore x87 control word */
1:
movl 0xc(%esp), %eax /* use third arg as return value after jump */
movl 0x10(%edx), %esp /* restore ESP */
movl %eax, 0x4(%esp) /* use third arg as first arg in context function */
movl 0x14(%edx), %edx /* fetch the address to return to */
jmp *%edx /* indirect jump to context */

View File

@ -0,0 +1,82 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | RBX | R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBP | RSP | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | 0x48 | 0x4c | | *
* ---------------------------------------------------------------------------------- *
* | sp | size | | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 20 | 21 | | *
* ---------------------------------------------------------------------------------- *
* | 0x50 | 0x54 | | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* ---------------------------------------------------------------------------------- *
* *
* **************************************************************************************/
.text
.globl jump_fcontext
.type jump_fcontext,@function
.align 8
jump_fcontext:
movq %rbx, (%rdi) /* save RBX */
movq %r12, 0x8(%rdi) /* save R12 */
movq %r13, 0x10(%rdi) /* save R13 */
movq %r14, 0x18(%rdi) /* save R14 */
movq %r15, 0x20(%rdi) /* save R15 */
movq %rbp, 0x28(%rdi) /* save RBP */
cmp $0, %rcx
je 1f
stmxcsr 0x50(%rdi) /* save MMX control and status word */
fnstcw 0x54(%rdi) /* save x87 control word */
ldmxcsr 0x50(%rsi) /* restore MMX control and status word */
fldcw 0x54(%rsi) /* restore x87 control word */
1:
leaq 0x8(%rsp), %rax /* exclude the return address and save as stack pointer */
movq %rax, 0x30(%rdi) /* save as stack pointer */
movq (%rsp), %rax /* save return address */
movq %rax, 0x38(%rdi) /* save return address as RIP */
movq (%rsi), %rbx /* restore RBX */
movq 0x8(%rsi), %r12 /* restore R12 */
movq 0x10(%rsi), %r13 /* restore R13 */
movq 0x18(%rsi), %r14 /* restore R14 */
movq 0x20(%rsi), %r15 /* restore R15 */
movq 0x28(%rsi), %rbp /* restore RBP */
movq 0x30(%rsi), %rsp /* restore RSP */
movq 0x38(%rsi), %rcx /* fetch the address to return to */
movq %rdx, %rax /* use third arg as return value after jump */
movq %rdx, %rdi /* use third arg as first arg in context function */
jmp *%rcx /* indirect jump to context */
.size jump_fcontext,.-jump_fcontext

View File

@ -0,0 +1,80 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | RBX | R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBP | RSP | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | 0x48 | 0x4c | | *
* ---------------------------------------------------------------------------------- *
* | sp | size | | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 20 | 21 | | *
* ---------------------------------------------------------------------------------- *
* | 0x50 | 0x54 | | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* ---------------------------------------------------------------------------------- *
* *
* **************************************************************************************/
.text
.globl _jump_fcontext
.align 8
_jump_fcontext:
movq %rbx, (%rdi) /* save RBX */
movq %r12, 0x8(%rdi) /* save R12 */
movq %r13, 0x10(%rdi) /* save R13 */
movq %r14, 0x18(%rdi) /* save R14 */
movq %r15, 0x20(%rdi) /* save R15 */
movq %rbp, 0x28(%rdi) /* save RBP */
cmp $0, %rcx
je 1f
stmxcsr 0x50(%rdi) /* save MMX control and status word */
fnstcw 0x54(%rdi) /* save x87 control word */
ldmxcsr 0x50(%rsi) /* restore MMX control and status word */
fldcw 0x54(%rsi) /* restore x87 control word */
1:
leaq 0x8(%rsp), %rax /* exclude the return address and save as stack pointer */
movq %rax, 0x30(%rdi) /* save as stack pointer */
movq (%rsp), %rax /* save return address */
movq %rax, 0x38(%rdi) /* save return address as RIP */
movq (%rsi), %rbx /* restore RBX */
movq 0x8(%rsi), %r12 /* restore R12 */
movq 0x10(%rsi), %r13 /* restore R13 */
movq 0x18(%rsi), %r14 /* restore R14 */
movq 0x20(%rsi), %r15 /* restore R15 */
movq 0x28(%rsi), %rbp /* restore RBP */
movq 0x30(%rsi), %rsp /* restore RSP */
movq 0x38(%rsi), %rcx /* fetch the address to return to */
movq %rdx, %rax /* use third arg as return value after jump */
movq %rdx, %rdi /* use third arg as first arg in context function */
jmp *%rcx /* indirect jump to context */

View File

@ -0,0 +1,50 @@
/* Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
.global _make_fcontext
.text
.align 2
_make_fcontext:
mov 0x4(%esp),%eax
lea -0x34(%eax),%eax
and $0xfffffff0,%eax
mov 0x4(%esp),%ecx
mov %ecx,0x18(%eax)
mov 0x8(%esp),%edx
mov %edx,0x1c(%eax)
neg %edx
lea (%edx,%ecx,1),%ecx
mov %ecx,0x20(%eax)
mov 0xc(%esp),%ecx
mov %ecx,0x14(%eax)
stmxcsr 0x2c(%eax)
fnstcw 0x30(%eax)
lea -0x1c(%eax),%edx
mov %edx,0x10(%eax)
mov $0x0,%ecx
mov %ecx,(%edx)
mov %fs:0x18,%ecx
mov (%ecx),%edx
inc %edx
je _make_fcontext+0x4c // <_make_fcontext+0x4c>
dec %edx
xchg %edx,%ecx
jmp _make_fcontext+0x42 // <_make_fcontext+0x42>
mov 0x4(%ecx),%ecx
mov 0x10(%eax),%edx
mov %ecx,0x18(%edx)
mov $0xffffffff,%ecx
mov %ecx,0x14(%edx)
lea 0x14(%edx),%ecx
mov %ecx,0x24(%eax)
ret
finish:
xor %eax,%eax
mov %eax,(%esp)
call finish+0xa
hlt

View File

@ -0,0 +1,77 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/********************************************************************
* *
* -------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | *
* -------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | *
* -------------------------------------------------------------- *
* | EDI | ESI | EBX | EBP | ESP | EIP | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 6 | 7 | | *
* -------------------------------------------------------------- *
* | 0x18 | 0x1c | | *
* -------------------------------------------------------------- *
* | sp | size | | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 8 | 9 | | *
* -------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* -------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* -------------------------------------------------------------- *
* *
* *****************************************************************/
.text
.globl make_fcontext
.align 2
.type make_fcontext,@function
make_fcontext:
movl 0x4(%esp), %eax /* load 1. arg of make_fcontext, pointer to context stack (base) */
leal -0x28(%eax), %eax /* reserve space for fcontext_t at top of context stack */
/* shift address in EAX to lower 16 byte boundary */
/* == pointer to fcontext_t and address of context stack */
andl $-16, %eax
movl 0x4(%esp), %edx /* load 1. arg of make_fcontext, pointer to context stack (base) */
movl %edx, 0x18(%eax) /* save address of context stack (base) in fcontext_t */
movl 0x8(%esp), %edx /* load 2. arg of make_fcontext, context stack size */
movl %edx, 0x1c(%eax) /* save stack size in fcontext_t */
movl 0xc(%esp), %edx /* load 3. arg of make_fcontext, pointer to context function */
movl %edx, 0x14(%eax) /* save address of context function in fcontext_t */
stmxcsr 0x20(%eax) /* save MMX control and status word */
fnstcw 0x24(%eax) /* save x87 control word */
leal -0x8(%eax), %edx /* reserve space for the last frame on context stack; (ESP - 0x4) % 16 == 0 */
movl %edx, 0x10(%eax) /* save address in EDX as stack pointer for context function */
call 1f
1: popl %ecx /* address of label 2 */
addl $finish-1b, %ecx /* compute abs address of label finish */
movl %ecx, (%edx) /* save address of finish as return address for context functions */
/* entered after context function returns */
ret
finish:
/* ESP points to same address as ESP on entry of context function + 0x4 */
call 2f
2: popl %ebx /* address of label 3 */
addl $_GLOBAL_OFFSET_TABLE_+[.-2b], %ebx /* compute address of GOT and store it in EBX */
xorl %eax, %eax
movl %eax, (%esp) /* exit code is zero */
call _exit@PLT /* exit application */
hlt
.size make_fcontext,.-make_fcontext

View File

@ -0,0 +1,71 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/********************************************************************
* *
* -------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | *
* -------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | *
* -------------------------------------------------------------- *
* | EDI | ESI | EBX | EBP | ESP | EIP | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 6 | 7 | | *
* -------------------------------------------------------------- *
* | 0x18 | 0x1c | | *
* -------------------------------------------------------------- *
* | sp | size | | *
* -------------------------------------------------------------- *
* -------------------------------------------------------------- *
* | 8 | 9 | | *
* -------------------------------------------------------------- *
* | 0x20 | 0x24 | | *
* -------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* -------------------------------------------------------------- *
* *
* *****************************************************************/
.text
.globl _make_fcontext
.align 2
_make_fcontext:
movl 0x4(%esp), %eax /* load 1. arg of make_fcontext, pointer to context stack (base) */
leal -0x28(%eax), %eax /* reserve space for fcontext_t at top of context stack */
/* shift address in EAX to lower 16 byte boundary */
/* == pointer to fcontext_t and address of context stack */
andl $-16, %eax
movl 0x4(%esp), %edx /* load 1. arg of make_fcontext, pointer to context stack (base) */
movl %edx, 0x18(%eax) /* save address of stack pointer (base) in fcontext_t */
movl 0x8(%esp), %edx /* load 2. arg of make_fcontext, context stack size */
movl %edx, 0x1c(%eax) /* save stack size in fcontext_t */
movl 0xc(%esp), %edx /* load 3. arg of make_fcontext, pointer to context function */
movl %edx, 0x14(%eax) /* save address of context fcuntion in fcontext_t */
stmxcsr 0x20(%eax) /* save MMX control and status word */
fnstcw 0x24(%eax) /* save x87 control word */
leal -0x14(%eax), %edx /* reserve space for the last frame on context stack */
movl %edx, 0x10(%eax) /* save address in EDX as stack pointer for context function */
call 1f
1: popl %ecx /* address of label 1 */
addl $finish-1b, %ecx /* compute abs address of label finish */
movl %ecx, (%edx) /* save address of finish as return address for context function */
/* entered after context function returns */
ret
finish:
/* ESP points to same address as ESP on entry of context function + 0x4 */
xorl %eax, %eax
movl %eax, (%esp) /* exit code is zero */
call __exit /* exit application */
hlt

View File

@ -0,0 +1,81 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | RBX | R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBP | RSP | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | 0x48 | 0x4c | | *
* ---------------------------------------------------------------------------------- *
* | sp | size | | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 20 | 21 | | *
* ---------------------------------------------------------------------------------- *
* | 0x50 | 0x54 | | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* ---------------------------------------------------------------------------------- *
* *
* **************************************************************************************/
.text
.globl make_fcontext
#ifndef __APPLE__
.type make_fcontext,@function
#endif
.align 8
make_fcontext:
leaq -0x58(%rdi), %rax /* reserve space for fcontext_t at top of context stack */
/* shift address in RAX to lower 16 byte boundary */
/* == pointer to fcontext_t and address of context stack */
andq $-16, %rax
movq %rdi, 0x40(%rax) /* save address of context stack pointer (base) in fcontext_t */
movq %rsi, 0x48(%rax) /* save context stack size in fcontext_t */
movq %rdx, 0x38(%rax) /* save address of context function in fcontext_t */
stmxcsr 0x50(%rax) /* save MMX control and status word */
fnstcw 0x54(%rax) /* save x87 control word */
leaq -0x8(%rax), %rdx /* reserve space for the return address on context stack, (RSP - 0x8) % 16 == 0 */
movq %rdx, 0x30(%rax) /* save address in RDX as stack pointer for context function */
leaq finish(%rip), %rcx /* compute abs address of label finish */
movq %rcx, (%rdx) /* save address of finish as return address for context function */
/* entered after context function returns */
ret /* return pointer to fcontext_t placed on context stack */
finish:
/* RSP points to same address as RSP on entry of context function + 0x8 */
xorq %rdi, %rdi /* exit code is zero */
call _exit@PLT /* exit application */
hlt
#ifndef __APPLE__
.size make_fcontext,.-make_fcontext
#endif

View File

@ -0,0 +1,71 @@
/*
Copyright Oliver Kowalke 2009.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
/****************************************************************************************
* *
* ---------------------------------------------------------------------------------- *
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
* | RBX | R12 | R13 | R14 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
* | R15 | RBP | RSP | RIP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 16 | 17 | 18 | 19 | | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | 0x48 | 0x4c | | *
* ---------------------------------------------------------------------------------- *
* | sp | size | | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 20 | 21 | | *
* ---------------------------------------------------------------------------------- *
* | 0x50 | 0x54 | | *
* ---------------------------------------------------------------------------------- *
* | fc_mxcsr|fc_x87_cw| | *
* ---------------------------------------------------------------------------------- *
* *
* **************************************************************************************/
.text
.globl _make_fcontext
.align 8
_make_fcontext:
leaq -0x58(%rdi), %rax /* reserve space for fcontext_t at top of context stack */
/* shift address in RAX to lower 16 byte boundary */
/* == pointer to fcontext_t and address of context stack */
movabs $-16, %r8
andq %r8, %rax
movq %rdi, 0x40(%rax) /* save address of stack pointer (base) in fcontext_t */
movq %rsi, 0x48(%rax) /* save stack size in fcontext_t */
movq %rdx, 0x38(%rax) /* save address of context function in fcontext_t */
stmxcsr 0x50(%rax) /* save MMX control and status word */
fnstcw 0x54(%rax) /* save x87 control word */
leaq -0x8(%rax), %rdx /* reserve space for the return address on context stack, (RSP - 0x8) % 16 == 0 */
movq %rdx, 0x30(%rax) /* save address in RDX as stack pointer for context function */
leaq finish(%rip), %rcx /* compute abs address of label finish */
movq %rcx, (%rdx) /* save address of finish as return address for context function */
/* entered after context function returns */
ret /* return pointer to fcontext_t placed on context stack */
finish:
/* RSP points to same address as RSP on entry of context function + 0x8 */
xorq %rdi, %rdi /* exit code is zero */
call __exit /* exit application */

View File

@ -0,0 +1,106 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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
*/
#include <tool/action_manager.h>
#include <tool/tool_manager.h>
#include <tool/tool_event.h>
#include <tool/tool_action.h>
#include <cassert>
ACTION_MANAGER::ACTION_MANAGER( TOOL_MANAGER* aToolManager ) :
m_toolMgr( aToolManager )
{
}
void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction )
{
assert( aAction->GetId() == -1 ); // Check if the TOOL_ACTION was not registered before
aAction->setId( MakeActionId( aAction->m_name ) );
m_actionNameIndex[aAction->m_name] = aAction;
m_actionIdIndex[aAction->m_id] = aAction;
if( aAction->HasHotKey() )
m_actionHotKeys[aAction->m_currentHotKey] = aAction;
aAction->setActionMgr( this );
}
void ACTION_MANAGER::UnregisterAction( TOOL_ACTION* aAction )
{
// Indicate that the ACTION_MANAGER no longer care about the object
aAction->setActionMgr( NULL );
aAction->setId( -1 );
m_actionNameIndex.erase( aAction->m_name );
m_actionIdIndex.erase( aAction->m_id );
if( aAction->HasHotKey() )
m_actionHotKeys.erase( aAction->m_currentHotKey );
}
int ACTION_MANAGER::MakeActionId( const std::string& aActionName )
{
static int currentActionId = 1;
return currentActionId++;
}
bool ACTION_MANAGER::RunAction( const std::string& aActionName ) const
{
std::map<std::string, TOOL_ACTION*>::const_iterator it = m_actionNameIndex.find( aActionName );
if( it == m_actionNameIndex.end() )
return false; // no action with given name found
runAction( it->second );
return true;
}
bool ACTION_MANAGER::RunHotKey( int aHotKey ) const
{
std::map<int, TOOL_ACTION*>::const_iterator it = m_actionHotKeys.find( aHotKey );
if( it == m_actionHotKeys.end() )
return false; // no appropriate action found for the hotkey
runAction( it->second );
return true;
}
void ACTION_MANAGER::runAction( const TOOL_ACTION* aAction ) const
{
TOOL_EVENT event = aAction->MakeEvent();
m_toolMgr->ProcessEvent( event );
}

View File

@ -0,0 +1,182 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
#include <tool/tool_interactive.h>
#include <tool/context_menu.h>
#include <cassert>
CONTEXT_MENU::CONTEXT_MENU() :
m_titleSet( false ), m_handler( this ), m_tool( NULL )
{
m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
// Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu );
m_menu.AddPendingEvent( menuEvent );
}
CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) :
m_titleSet( aMenu.m_titleSet ), m_handler( this ), m_tool( aMenu.m_tool )
{
m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
// Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu );
m_menu.AddPendingEvent( menuEvent );
// Copy all the menu entries
for( unsigned i = 0; i < aMenu.m_menu.GetMenuItemCount(); ++i )
{
wxMenuItem* item = aMenu.m_menu.FindItemByPosition( i );
m_menu.Append( new wxMenuItem( &m_menu, item->GetId(), item->GetItemLabel(),
wxEmptyString, wxITEM_NORMAL ) );
}
// Copy tool actions that are available to choose from context menu
m_toolActions = aMenu.m_toolActions;
}
void CONTEXT_MENU::SetTitle( const wxString& aTitle )
{
// TODO handle an empty string (remove title and separator)
// Unfortunately wxMenu::SetTitle() does nothing..
if( m_titleSet )
{
m_menu.FindItemByPosition( 0 )->SetItemLabel( aTitle );
}
else
{
m_menu.InsertSeparator( 0 );
m_menu.Insert( 0, new wxMenuItem( &m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) );
m_titleSet = true;
}
}
void CONTEXT_MENU::Add( const wxString& aLabel, int aId )
{
#ifdef DEBUG
if( m_menu.FindItem( aId ) != NULL )
wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in"
"undefined behaviour" ) );
#endif
m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) );
}
void CONTEXT_MENU::Add( const TOOL_ACTION& aAction )
{
/// ID numbers for tool actions need to have a value higher than m_actionId
int id = m_actionId + aAction.GetId();
wxString menuEntry;
if( aAction.HasHotKey() )
menuEntry = wxString( ( aAction.GetMenuItem() + '\t' +
getHotKeyDescription( aAction ) ).c_str(), wxConvUTF8 );
else
menuEntry = wxString( aAction.GetMenuItem().c_str(), wxConvUTF8 );
m_menu.Append( new wxMenuItem( &m_menu, id, menuEntry,
wxString( aAction.GetDescription().c_str(), wxConvUTF8 ), wxITEM_NORMAL ) );
m_toolActions[id] = &aAction;
}
void CONTEXT_MENU::Clear()
{
m_titleSet = false;
// Remove all the entries from context menu
for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i )
m_menu.Destroy( m_menu.FindItemByPosition( 0 ) );
m_toolActions.clear();
}
std::string CONTEXT_MENU::getHotKeyDescription( const TOOL_ACTION& aAction ) const
{
int hotkey = aAction.GetHotKey();
std::string description = "";
if( hotkey & MD_ALT )
description += "ALT+";
if( hotkey & MD_CTRL )
description += "CTRL+";
if( hotkey & MD_SHIFT )
description += "SHIFT+";
// TODO dispatch keys such as Fx, TAB, PG_UP/DN, HOME, END, etc.
description += char( hotkey & ~MD_MODIFIER_MASK );
return description;
}
void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent )
{
TOOL_EVENT evt;
wxEventType type = aEvent.GetEventType();
// When the currently chosen item in the menu is changed, an update event is issued.
// For example, the selection tool can use this to dynamically highlight the current item
// from selection clarification popup.
if( type == wxEVT_MENU_HIGHLIGHT )
evt = TOOL_EVENT( TC_COMMAND, TA_CONTEXT_MENU_UPDATE, aEvent.GetId() );
// One of menu entries was selected..
else if( type == wxEVT_COMMAND_MENU_SELECTED )
{
// Check if there is a TOOL_ACTION for the given ID
if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 )
{
evt = m_menu->m_toolActions[aEvent.GetId()]->MakeEvent();
}
else
{
// Handling non-action menu entries (e.g. items in clarification list)
evt = TOOL_EVENT( TC_COMMAND, TA_CONTEXT_MENU_CHOICE, aEvent.GetId() );
}
}
// forward the action/update event to the TOOL_MANAGER
if( m_menu->m_tool )
m_menu->m_tool->GetManager()->ProcessEvent( evt );
}

49
common/tool/tool_base.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
KIGFX::VIEW* TOOL_BASE::getView() const
{
return m_toolMgr->GetView();
}
KIGFX::VIEW_CONTROLS* TOOL_BASE::getViewControls() const
{
return m_toolMgr->GetViewControls();
}
wxWindow* TOOL_BASE::getEditFrameInt() const
{
return m_toolMgr->GetEditFrame();
}
EDA_ITEM* TOOL_BASE::getModelInt() const
{
return m_toolMgr->GetModel();
}

View File

@ -0,0 +1,280 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <wxPcbStruct.h>
#include <wxBasePcbFrame.h>
#include <tool/tool_manager.h>
#include <tool/tool_dispatcher.h>
#include <view/view.h>
#include <view/wx_view_controls.h>
#include <class_drawpanel_gal.h>
#include <pcbnew_id.h>
#include <boost/optional.hpp>
#include <boost/foreach.hpp>
using boost::optional;
///> Stores information about a mouse button state
struct TOOL_DISPATCHER::BUTTON_STATE
{
BUTTON_STATE( TOOL_MOUSE_BUTTONS aButton, const wxEventType& aDownEvent,
const wxEventType& aUpEvent ) :
button( aButton ),
downEvent( aDownEvent ),
upEvent( aUpEvent )
{};
///> Flag indicating that dragging is active for the given button.
bool dragging;
///> Flag indicating that the given button is pressed.
bool pressed;
///> Point where dragging has started (in world coordinates).
VECTOR2D dragOrigin;
///> Point where click event has occurred.
VECTOR2D downPosition;
///> Difference between drag origin point and current mouse position (expressed as distance in
///> pixels).
double dragMaxDelta;
///> Determines the mouse button for which information are stored.
TOOL_MOUSE_BUTTONS button;
///> The type of wxEvent that determines mouse button press.
wxEventType downEvent;
///> The type of wxEvent that determines mouse button release.
wxEventType upEvent;
///> Time stamp for the last mouse button press event.
wxLongLong downTimestamp;
///> Restores initial state.
void Reset()
{
dragging = false;
pressed = false;
}
};
TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame ) :
m_toolMgr( aToolMgr ), m_editFrame( aEditFrame )
{
m_buttons.push_back( new BUTTON_STATE( BUT_LEFT, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP ) );
m_buttons.push_back( new BUTTON_STATE( BUT_RIGHT, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP ) );
m_buttons.push_back( new BUTTON_STATE( BUT_MIDDLE, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP ) );
ResetState();
}
TOOL_DISPATCHER::~TOOL_DISPATCHER()
{
BOOST_FOREACH( BUTTON_STATE* st, m_buttons )
delete st;
}
void TOOL_DISPATCHER::ResetState()
{
BOOST_FOREACH( BUTTON_STATE* st, m_buttons )
st->Reset();
}
KIGFX::VIEW* TOOL_DISPATCHER::getView()
{
return m_editFrame->GetGalCanvas()->GetView();
}
bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion )
{
BUTTON_STATE* st = m_buttons[aIndex];
wxEventType type = aEvent.GetEventType();
optional<TOOL_EVENT> evt;
bool isClick = false;
bool up = type == st->upEvent;
bool down = type == st->downEvent;
int mods = decodeModifiers<wxMouseEvent>( static_cast<wxMouseEvent*>( &aEvent ) );
int args = st->button | mods;
if( down ) // Handle mouse button press
{
st->downTimestamp = wxGetLocalTimeMillis();
st->dragOrigin = m_lastMousePos;
st->downPosition = m_lastMousePos;
st->dragMaxDelta = 0;
st->pressed = true;
evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DOWN, args );
}
else if( up ) // Handle mouse button release
{
st->pressed = false;
if( st->dragging )
{
wxLongLong t = wxGetLocalTimeMillis();
// Determine if it was just a single click or beginning of dragging
if( t - st->downTimestamp < DragTimeThreshold &&
st->dragMaxDelta < DragDistanceThreshold )
isClick = true;
else
evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_UP, args );
}
else
isClick = true;
if( isClick )
evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_CLICK, args );
st->dragging = false;
}
if( st->pressed && aMotion )
{
st->dragging = true;
double dragPixelDistance =
getView()->ToScreen( m_lastMousePos - st->dragOrigin, false ).EuclideanNorm();
st->dragMaxDelta = std::max( st->dragMaxDelta, dragPixelDistance );
wxLongLong t = wxGetLocalTimeMillis();
if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold )
{
evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DRAG, args );
evt->SetMouseDragOrigin( st->dragOrigin );
evt->SetMouseDelta( m_lastMousePos - st->dragOrigin );
}
}
if( evt )
{
evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
m_toolMgr->ProcessEvent( *evt );
return true;
}
return false;
}
void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
{
bool motion = false, buttonEvents = false;
optional<TOOL_EVENT> evt;
int type = aEvent.GetEventType();
// Mouse handling
if( type == wxEVT_MOTION || type == wxEVT_MOUSEWHEEL ||
type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP ||
// Event issued whem mouse retains position in screen coordinates,
// but changes in world coordinates (eg. autopanning)
type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
{
VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition();
VECTOR2D pos = getView()->ToWorld( screenPos );
if( pos != m_lastMousePos || type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
{
motion = true;
m_lastMousePos = pos;
}
for( unsigned int i = 0; i < m_buttons.size(); i++ )
buttonEvents |= handleMouseButton( aEvent, i, motion );
if( !buttonEvents && motion )
{
evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_MOTION );
evt->SetMousePosition( pos );
}
}
// Keyboard handling
else if( type == wxEVT_KEY_UP || type == wxEVT_KEY_DOWN )
{
wxKeyEvent* ke = static_cast<wxKeyEvent*>( &aEvent );
int key = ke->GetKeyCode();
int mods = decodeModifiers<wxKeyEvent>( ke );
if( type == wxEVT_KEY_UP )
{
if( key == WXK_ESCAPE ) // ESC is the special key for cancelling tools
evt = TOOL_EVENT( TC_COMMAND, TA_CANCEL_TOOL );
else
evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_UP, key | mods );
}
else
{
evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_DOWN, key | mods );
}
}
if( evt )
m_toolMgr->ProcessEvent( *evt );
// pass the event to the GUI, it might still be interested in it
aEvent.Skip();
}
void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent )
{
bool activateTool = false;
std::string toolName;
// fixme: use TOOL_ACTIONs here
switch( aEvent.GetId() )
{
case ID_PNS_ROUTER_TOOL:
toolName = "pcbnew.InteractiveRouter";
activateTool = true;
break;
case ID_SELECTION_TOOL:
toolName = "pcbnew.InteractiveSelection";
activateTool = true;
break;
}
// do nothing if the legacy view is active
if( activateTool && m_editFrame->IsGalCanvasActive() )
m_toolMgr->InvokeTool( toolName );
}

162
common/tool/tool_event.cpp Normal file
View File

@ -0,0 +1,162 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <cstring>
#include <string>
#include <tool/tool_event.h>
#include <tool/tool_action.h>
#include <tool/tool_manager.h>
#include <boost/foreach.hpp>
using namespace std;
struct FlagString
{
int flag;
std::string str;
};
static const std::string flag2string( int aFlag, const FlagString* aExps )
{
std::string rv;
for( int i = 0; aExps[i].str.length(); i++ )
{
if( aExps[i].flag & aFlag )
rv += aExps[i].str + " ";
}
return rv;
}
bool TOOL_EVENT::IsAction( const TOOL_ACTION* aAction ) const
{
return Matches( aAction->MakeEvent() );
}
const std::string TOOL_EVENT::Format() const
{
std::string ev;
const FlagString categories[] =
{
{ TC_MOUSE, "mouse" },
{ TC_KEYBOARD, "keyboard" },
{ TC_COMMAND, "command" },
{ TC_MESSAGE, "message" },
{ TC_VIEW, "view" },
{ 0, "" }
};
const FlagString actions[] =
{
{ TA_MOUSE_CLICK, "click" },
{ TA_MOUSE_UP, "button-up" },
{ TA_MOUSE_DOWN, "button-down" },
{ TA_MOUSE_DRAG, "drag" },
{ TA_MOUSE_MOTION, "motion" },
{ TA_MOUSE_WHEEL, "wheel" },
{ TA_KEY_UP, "key-up" },
{ TA_KEY_DOWN, "key-down" },
{ TA_VIEW_REFRESH, "view-refresh" },
{ TA_VIEW_ZOOM, "view-zoom" },
{ TA_VIEW_PAN, "view-pan" },
{ TA_VIEW_DIRTY, "view-dirty" },
{ TA_CHANGE_LAYER, "change-layer" },
{ TA_CANCEL_TOOL, "cancel-tool" },
{ TA_CONTEXT_MENU_UPDATE, "context-menu-update" },
{ TA_CONTEXT_MENU_CHOICE, "context-menu-choice" },
{ TA_ACTION, "action" },
{ 0, "" }
};
const FlagString buttons[] =
{
{ BUT_NONE, "none" },
{ BUT_LEFT, "left" },
{ BUT_RIGHT, "right" },
{ BUT_MIDDLE, "middle" },
{ 0, "" }
};
const FlagString modifiers[] =
{
{ MD_SHIFT, "shift" },
{ MD_CTRL, "ctrl" },
{ MD_ALT, "alt" },
{ 0, "" }
};
ev = "category: ";
ev += flag2string( m_category, categories );
ev += " action: ";
ev += flag2string( m_actions, actions );
if( m_actions & TA_MOUSE )
{
ev += " btns: ";
ev += flag2string( m_mouseButtons, buttons );
}
if( m_actions & TA_KEYBOARD )
{
char tmp[128];
sprintf( tmp, "key: %d", m_keyCode );
ev += tmp;
}
if( m_actions & ( TA_MOUSE | TA_KEYBOARD ) )
{
ev += " mods: ";
ev += flag2string( m_modifiers, modifiers );
}
if( m_commandId )
{
char tmp[128];
sprintf( tmp, "cmd-id: %d", *m_commandId );
ev += tmp;
}
if( m_commandStr )
ev += "cmd-str: " + ( *m_commandStr );
return ev;
}
const std::string TOOL_EVENT_LIST::Format() const
{
string s;
BOOST_FOREACH( TOOL_EVENT e, m_events )
s += e.Format() + " ";
return s;
}

View File

@ -0,0 +1,65 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <string>
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
#include <tool/tool_interactive.h>
#include <tool/context_menu.h>
TOOL_INTERACTIVE::TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName ) :
TOOL_BASE( INTERACTIVE, aId, aName )
{
}
TOOL_INTERACTIVE::TOOL_INTERACTIVE( const std::string& aName ) :
TOOL_BASE( INTERACTIVE, TOOL_MANAGER::MakeToolId( aName ), aName )
{
}
TOOL_INTERACTIVE::~TOOL_INTERACTIVE()
{
}
OPT_TOOL_EVENT TOOL_INTERACTIVE::Wait( const TOOL_EVENT_LIST& aEventList )
{
return m_toolMgr->ScheduleWait( this, aEventList );
}
void TOOL_INTERACTIVE::goInternal( TOOL_STATE_FUNC& aState, const TOOL_EVENT_LIST& aConditions )
{
m_toolMgr->ScheduleNextState( this, aState, aConditions );
}
void TOOL_INTERACTIVE::SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger )
{
aMenu->setTool( this );
m_toolMgr->ScheduleContextMenu( this, aMenu, aTrigger );
}

View File

@ -0,0 +1,513 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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
*/
#include <map>
#include <deque>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/range/adaptor/map.hpp>
#include <wx/event.h>
#include <view/view.h>
#include <tool/tool_base.h>
#include <tool/tool_interactive.h>
#include <tool/tool_manager.h>
#include <tool/context_menu.h>
#include <tool/coroutine.h>
#include <tool/action_manager.h>
#include <wxPcbStruct.h>
#include <class_drawpanel_gal.h>
using boost::optional;
using namespace std;
/// Struct describing the current execution state of a TOOL
struct TOOL_MANAGER::TOOL_STATE
{
/// The tool itself
TOOL_BASE* theTool;
/// Is the tool active (pending execution) or disabled at the moment
bool idle;
/// Flag defining if the tool is waiting for any event (i.e. if it
/// issued a Wait() call).
bool pendingWait;
/// Is there a context menu being displayed
bool pendingContextMenu;
/// Context menu currently used by the tool
CONTEXT_MENU* contextMenu;
/// Defines when the context menu is opened
CONTEXT_MENU_TRIGGER contextMenuTrigger;
/// Tool execution context
COROUTINE<int, TOOL_EVENT&>* cofunc;
/// The event that triggered the execution/wakeup of the tool after Wait() call
TOOL_EVENT wakeupEvent;
/// List of events the tool is currently waiting for
TOOL_EVENT_LIST waitEvents;
/// List of possible transitions (ie. association of events and state handlers that are executed
/// upon the event reception
std::vector<TRANSITION> transitions;
bool operator==( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
{
return aRhs.theTool == this->theTool;
}
bool operator!=( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
{
return aRhs.theTool != this->theTool;
}
};
TOOL_MANAGER::TOOL_MANAGER() :
m_model( NULL ), m_view( NULL )
{
m_actionMgr = new ACTION_MANAGER( this );
}
TOOL_MANAGER::~TOOL_MANAGER()
{
std::map<TOOL_BASE*, TOOL_STATE*>::iterator it, it_end;
for( it = m_toolState.begin(), it_end = m_toolState.end(); it != it_end; ++it )
{
delete it->second->cofunc; // delete cofunction
delete it->second; // delete TOOL_STATE
delete it->first; // delete the tool itself
}
delete m_actionMgr;
}
void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool )
{
TOOL_STATE* st = new TOOL_STATE;
st->theTool = aTool;
st->idle = true;
st->pendingWait = false;
st->pendingContextMenu = false;
st->cofunc = NULL;
st->contextMenuTrigger = CMENU_OFF;
m_toolState[aTool] = st;
m_toolNameIndex[aTool->GetName()] = st;
m_toolIdIndex[aTool->GetId()] = st;
aTool->m_toolMgr = this;
if( aTool->GetType() == INTERACTIVE )
{
bool initState = static_cast<TOOL_INTERACTIVE*>( aTool )->Init();
if( !initState )
{
wxLogError( wxT( "Initialization of the %s tool failed" ), aTool->GetName().c_str() );
// Unregister the tool
m_toolState.erase( aTool );
m_toolNameIndex.erase( aTool->GetName() );
m_toolIdIndex.erase( aTool->GetId() );
delete st;
delete aTool;
}
}
}
bool TOOL_MANAGER::InvokeTool( TOOL_ID aToolId )
{
TOOL_BASE* tool = FindTool( aToolId );
if( tool && tool->GetType() == INTERACTIVE )
return invokeTool( tool );
return false; // there is no tool with the given id
}
bool TOOL_MANAGER::InvokeTool( const std::string& aToolName )
{
TOOL_BASE* tool = FindTool( aToolName );
if( tool && tool->GetType() == INTERACTIVE )
return invokeTool( tool );
return false; // there is no tool with the given name
}
void TOOL_MANAGER::RegisterAction( TOOL_ACTION* aAction )
{
m_actionMgr->RegisterAction( aAction );
}
void TOOL_MANAGER::UnregisterAction( TOOL_ACTION* aAction )
{
m_actionMgr->UnregisterAction( aAction );
}
bool TOOL_MANAGER::invokeTool( TOOL_BASE* aTool )
{
wxASSERT( aTool != NULL );
TOOL_EVENT evt( TC_COMMAND, TA_ACTION, aTool->GetName() );
ProcessEvent( evt );
return true;
}
bool TOOL_MANAGER::runTool( TOOL_ID aToolId )
{
TOOL_BASE* tool = FindTool( aToolId );
if( tool && tool->GetType() == INTERACTIVE )
return runTool( tool );
return false; // there is no tool with the given id
}
bool TOOL_MANAGER::runTool( const std::string& aToolName )
{
TOOL_BASE* tool = FindTool( aToolName );
if( tool && tool->GetType() == INTERACTIVE )
return runTool( tool );
return false; // there is no tool with the given name
}
bool TOOL_MANAGER::runTool( TOOL_BASE* aTool )
{
wxASSERT( aTool != NULL );
if( !isRegistered( aTool ) )
return false;
TOOL_STATE* state = m_toolState[aTool];
// If the tool is already active, do not invoke it again
if( state->idle == false )
return false;
state->idle = false;
static_cast<TOOL_INTERACTIVE*>( aTool )->Reset();
// Add the tool on the front of the processing queue (it gets events first)
m_activeTools.push_front( aTool->GetId() );
return true;
}
TOOL_BASE* TOOL_MANAGER::FindTool( int aId ) const
{
std::map<TOOL_ID, TOOL_STATE*>::const_iterator it = m_toolIdIndex.find( aId );
if( it != m_toolIdIndex.end() )
return it->second->theTool;
return NULL;
}
TOOL_BASE* TOOL_MANAGER::FindTool( const std::string& aName ) const
{
std::map<std::string, TOOL_STATE*>::const_iterator it = m_toolNameIndex.find( aName );
if( it != m_toolNameIndex.end() )
return it->second->theTool;
return NULL;
}
void TOOL_MANAGER::ScheduleNextState( TOOL_BASE* aTool, TOOL_STATE_FUNC& aHandler,
const TOOL_EVENT_LIST& aConditions )
{
TOOL_STATE* st = m_toolState[aTool];
st->transitions.push_back( TRANSITION( aConditions, aHandler ) );
}
optional<TOOL_EVENT> TOOL_MANAGER::ScheduleWait( TOOL_BASE* aTool,
const TOOL_EVENT_LIST& aConditions )
{
TOOL_STATE* st = m_toolState[aTool];
// indicate to the manager that we are going to sleep and we shall be
// woken up when an event matching aConditions arrive
st->pendingWait = true;
st->waitEvents = aConditions;
// switch context back to event dispatcher loop
st->cofunc->Yield();
return st->wakeupEvent;
}
void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
{
// iterate over all registered tools
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{
TOOL_STATE* st = m_toolIdIndex[toolId];
// the tool state handler is waiting for events (i.e. called Wait() method)
if( st->pendingWait )
{
if( st->waitEvents.Matches( aEvent ) )
{
// By default, already processed events are not passed further
m_passEvent = false;
// got matching event? clear wait list and wake up the coroutine
st->wakeupEvent = aEvent;
st->pendingWait = false;
st->waitEvents.clear();
if( st->cofunc && !st->cofunc->Resume() )
finishTool( st ); // The couroutine has finished
// If the tool did not request to propagate
// the event to other tools, we should stop it now
if( !m_passEvent )
break;
}
}
}
BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values )
{
// the tool scheduled next state(s) by calling Go()
if( !st->pendingWait )
{
// no state handler in progress - check if there are any transitions (defined by
// Go() method that match the event.
if( st->transitions.size() )
{
BOOST_FOREACH( TRANSITION tr, st->transitions )
{
if( tr.first.Matches( aEvent ) )
{
st->transitions.clear();
// no tool context allocated yet? Create one.
if( !st->cofunc )
st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second );
else
st->cofunc->SetEntry( tr.second );
// got match? Run the handler.
st->cofunc->Call( aEvent );
if( !st->cofunc->Running() )
finishTool( st ); // The couroutine has finished immediately?
}
}
}
}
}
}
bool TOOL_MANAGER::dispatchStandardEvents( TOOL_EVENT& aEvent )
{
if( aEvent.Action() == TA_KEY_UP )
{
// Check if there is a hotkey associated
if( m_actionMgr->RunHotKey( aEvent.Modifier() | aEvent.KeyCode() ) )
return false; // hotkey event was handled so it does not go any further
}
else if( aEvent.Category() == TC_COMMAND ) // it may be a tool activation event
{
dispatchActivation( aEvent );
// do not return false, as the event has to go on to the destined tool
}
return true;
}
bool TOOL_MANAGER::dispatchActivation( TOOL_EVENT& aEvent )
{
// Look for the tool that has the same name as parameter in the processed command TOOL_EVENT
BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values )
{
if( st->theTool->GetName() == aEvent.m_commandStr )
{
runTool( st->theTool );
return true;
}
}
return false;
}
void TOOL_MANAGER::finishTool( TOOL_STATE* aState )
{
// Find the tool to be deactivated
std::deque<TOOL_ID>::iterator it, it_end;
for( it = m_activeTools.begin(), it_end = m_activeTools.end(); it != it_end; ++it )
{
if( aState == m_toolIdIndex[*it] )
break;
}
if( it != m_activeTools.end() )
m_activeTools.erase( it );
else
wxLogWarning( wxT( "Tried to finish inactive tool" ) );
aState->idle = true;
delete aState->cofunc;
aState->cofunc = NULL;
}
bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent )
{
// wxLogDebug( "event: %s", aEvent.Format().c_str() );
// Early dispatch of events destined for the TOOL_MANAGER
if( !dispatchStandardEvents( aEvent ) )
return false;
dispatchInternal( aEvent );
// popup menu handling
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{
TOOL_STATE* st = m_toolIdIndex[toolId];
// the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
// or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
if( st->contextMenuTrigger != CMENU_OFF )
{
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( BUT_RIGHT ) )
break;
st->pendingWait = true;
st->waitEvents = TOOL_EVENT( TC_ANY, TA_ANY );
if( st->contextMenuTrigger == CMENU_NOW )
st->contextMenuTrigger = CMENU_OFF;
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
GetEditFrame()->PopupMenu( menu->GetMenu() );
//
TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CHOICE );
dispatchInternal( evt );
break;
}
}
if( m_view->IsDirty() )
{
PCB_EDIT_FRAME* f = static_cast<PCB_EDIT_FRAME*>( GetEditFrame() );
f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER.
}
return false;
}
void TOOL_MANAGER::ScheduleContextMenu( TOOL_BASE* aTool, CONTEXT_MENU* aMenu,
CONTEXT_MENU_TRIGGER aTrigger )
{
TOOL_STATE* st = m_toolState[aTool];
st->contextMenu = aMenu;
st->contextMenuTrigger = aTrigger;
// the tool wants the menu immediately? Preempt it and do so :)
if( aTrigger == CMENU_NOW )
st->cofunc->Yield();
}
TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
{
static int currentId;
return currentId++;
}
void TOOL_MANAGER::SetEnvironment( EDA_ITEM* aModel, KIGFX::VIEW* aView,
KIGFX::VIEW_CONTROLS* aViewControls, wxWindow* aFrame )
{
m_model = aModel;
m_view = aView;
m_viewControls = aViewControls;
m_editFrame = aFrame;
// Reset state of the registered tools
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{
TOOL_BASE* tool = m_toolIdIndex[toolId]->theTool;
if( tool->GetType() == INTERACTIVE )
static_cast<TOOL_INTERACTIVE*>( tool )->Reset();
}
}
bool TOOL_MANAGER::isActive( TOOL_BASE* aTool )
{
if( !isRegistered( aTool ) )
return false;
return !m_toolState[aTool]->idle;
}

1009
common/view/view.cpp Normal file

File diff suppressed because it is too large Load Diff

162
common/view/view_group.cpp Normal file
View File

@ -0,0 +1,162 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 view_group.cpp
* @brief VIEW_GROUP extends VIEW_ITEM by possibility of grouping items into a single object.
* VIEW_GROUP does not take over ownership of the held items. The main purpose of this class is
* to group items and draw them on a single layer (in particular the overlay).
*/
#include <set>
#include <algorithm>
#include <view/view_group.h>
#include <view/view.h>
#include <painter.h>
#include <gal/graphics_abstraction_layer.h>
#include <boost/foreach.hpp>
#include <layers_id_colors_and_visibility.h>
using namespace KIGFX;
VIEW_GROUP::VIEW_GROUP( VIEW* aView ) :
m_layer( ITEM_GAL_LAYER( GP_OVERLAY ) )
{
m_view = aView;
}
VIEW_GROUP::~VIEW_GROUP()
{
}
void VIEW_GROUP::Add( VIEW_ITEM* aItem )
{
m_items.insert( aItem );
}
void VIEW_GROUP::Remove( VIEW_ITEM* aItem )
{
m_items.erase( aItem );
}
void VIEW_GROUP::Clear()
{
m_items.clear();
}
unsigned int VIEW_GROUP::GetSize() const
{
return m_items.size();
}
const BOX2I VIEW_GROUP::ViewBBox() const
{
BOX2I maxBox;
maxBox.SetMaximum();
return maxBox;
}
void VIEW_GROUP::ViewDraw( int aLayer, GAL* aGal ) const
{
PAINTER* painter = m_view->GetPainter();
// Draw all items immediately (without caching)
BOOST_FOREACH( VIEW_ITEM* item, m_items )
{
aGal->PushDepth();
int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
item->ViewGetLayers( layers, layers_count );
m_view->SortLayers( layers, layers_count );
for( int i = 0; i < layers_count; i++ )
{
if( m_view->IsCached( layers[i] ) && m_view->IsLayerVisible( layers[i] ) )
{
aGal->AdvanceDepth();
if( !painter->Draw( item, layers[i] ) )
item->ViewDraw( layers[i], aGal ); // Alternative drawing method
}
}
aGal->PopDepth();
}
}
void VIEW_GROUP::ViewGetLayers( int aLayers[], int& aCount ) const
{
// Everything is displayed on a single layer
aLayers[0] = m_layer;
aCount = 1;
}
void VIEW_GROUP::FreeItems()
{
BOOST_FOREACH( VIEW_ITEM* item, m_items )
{
delete item;
}
m_items.clear();
}
void VIEW_GROUP::ItemsSetVisibility( bool aVisible )
{
std::set<VIEW_ITEM*>::const_iterator it, it_end;
for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
(*it)->ViewSetVisible( aVisible );
}
void VIEW_GROUP::ItemsViewUpdate( VIEW_ITEM::VIEW_UPDATE_FLAGS aFlags )
{
std::set<VIEW_ITEM*>::const_iterator it, it_end;
for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
(*it)->ViewUpdate( aFlags );
}
void VIEW_GROUP::updateBbox()
{
// Save the used VIEW, as it used nulled during Remove()
VIEW* view = m_view;
// Reinsert the group, so the bounding box can be updated
view->Remove( this );
view->Add( this );
}

139
common/view/view_item.cpp Normal file
View File

@ -0,0 +1,139 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <gal/definitions.h>
#include <view/view_item.h>
#include <view/view.h>
using namespace KIGFX;
void VIEW_ITEM::ViewSetVisible( bool aIsVisible )
{
bool update = false;
if( m_visible != aIsVisible )
{
update = true;
}
m_visible = aIsVisible;
// update only if the visibility has really changed
if( update )
{
ViewUpdate( APPEARANCE );
}
}
void VIEW_ITEM::ViewUpdate( int aUpdateFlags )
{
if( !m_view )
return;
m_view->invalidateItem( this, aUpdateFlags );
}
void VIEW_ITEM::ViewRelease()
{
if( m_view && m_view->IsDynamic() )
{
m_view->Remove( this );
}
}
void VIEW_ITEM::getLayers( int* aLayers, int& aCount ) const
{
int* layersPtr = aLayers;
for( unsigned int i = 0; i < m_layers.size(); ++i )
{
if( m_layers[i] )
*layersPtr++ = i;
}
aCount = m_layers.count();
}
int VIEW_ITEM::getGroup( int aLayer ) const
{
for( int i = 0; i < m_groupsSize; ++i )
{
if( m_groups[i].first == aLayer )
return m_groups[i].second;
}
return -1;
}
std::vector<int> VIEW_ITEM::getAllGroups() const
{
std::vector<int> groups( m_groupsSize );
for( int i = 0; i < m_groupsSize; ++i )
{
groups[i] = m_groups[i].second;
}
return groups;
}
void VIEW_ITEM::setGroup( int aLayer, int aId )
{
// Look if there is already an entry for the layer
for( int i = 0; i < m_groupsSize; ++i )
{
if( m_groups[i].first == aLayer )
{
m_groups[i].second = aId;
return;
}
}
// If there was no entry for the given layer - create one
GroupPair* newGroups = new GroupPair[m_groupsSize + 1];
if( m_groupsSize > 0 )
{
std::copy( m_groups, m_groups + m_groupsSize, newGroups );
delete[] m_groups;
}
m_groups = newGroups;
newGroups[m_groupsSize++] = GroupPair( aLayer, aId );
}
void VIEW_ITEM::deleteGroups()
{
delete[] m_groups;
m_groups = NULL;
m_groupsSize = 0;
}

View File

@ -0,0 +1,311 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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
*/
#include <wx/wx.h>
#include <view/view.h>
#include <view/wx_view_controls.h>
#include <gal/graphics_abstraction_layer.h>
#include <tool/tool_dispatcher.h>
using namespace KIGFX;
const wxEventType WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE = wxNewEventType();
WX_VIEW_CONTROLS::WX_VIEW_CONTROLS( VIEW* aView, wxWindow* aParentPanel ) :
VIEW_CONTROLS( aView ),
m_state( IDLE ),
m_parentPanel( aParentPanel )
{
m_parentPanel->Connect( wxEVT_MOTION,
wxMouseEventHandler( WX_VIEW_CONTROLS::onMotion ), NULL, this );
m_parentPanel->Connect( wxEVT_MOUSEWHEEL,
wxMouseEventHandler( WX_VIEW_CONTROLS::onWheel ), NULL, this );
m_parentPanel->Connect( wxEVT_MIDDLE_UP,
wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
m_parentPanel->Connect( wxEVT_MIDDLE_DOWN,
wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
m_parentPanel->Connect( wxEVT_LEFT_UP,
wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
m_parentPanel->Connect( wxEVT_LEFT_DOWN,
wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
#if defined _WIN32 || defined _WIN64
m_parentPanel->Connect( wxEVT_ENTER_WINDOW,
wxMouseEventHandler( WX_VIEW_CONTROLS::onEnter ), NULL, this );
#endif
m_panTimer.SetOwner( this );
this->Connect( wxEVT_TIMER,
wxTimerEventHandler( WX_VIEW_CONTROLS::onTimer ), NULL, this );
}
void VIEW_CONTROLS::ShowCursor( bool aEnabled )
{
m_view->GetGAL()->SetCursorEnabled( aEnabled );
}
void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
{
m_mousePosition.x = aEvent.GetX();
m_mousePosition.y = aEvent.GetY();
if( m_forceCursorPosition )
m_cursorPosition = m_view->ToScreen( m_forcedPosition );
else if( m_snappingEnabled )
m_cursorPosition = m_view->GetGAL()->GetGridPoint( m_mousePosition );
else
m_cursorPosition = m_mousePosition;
bool isAutoPanning = false;
if( m_autoPanEnabled )
{
isAutoPanning = handleAutoPanning( aEvent );
}
if( !isAutoPanning && aEvent.Dragging() )
{
if( m_state == DRAG_PANNING )
{
VECTOR2D d = m_dragStartPoint - m_mousePosition;
VECTOR2D delta = m_view->ToWorld( d, false );
m_view->SetCenter( m_lookStartPoint + delta );
aEvent.StopPropagation();
}
else
{
aEvent.Skip();
}
}
}
void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent )
{
const double wheelPanSpeed = 0.001;
if( aEvent.ControlDown() || aEvent.ShiftDown() )
{
// Scrolling
VECTOR2D scrollVec = m_view->ToWorld( m_view->GetScreenPixelSize() *
( (double) aEvent.GetWheelRotation() * wheelPanSpeed ), false );
double scrollSpeed;
if( abs( scrollVec.x ) > abs( scrollVec.y ) )
scrollSpeed = scrollVec.x;
else
scrollSpeed = scrollVec.y;
VECTOR2D delta( aEvent.ControlDown() ? -scrollSpeed : 0.0,
aEvent.ShiftDown() ? -scrollSpeed : 0.0 );
m_view->SetCenter( m_view->GetCenter() + delta );
}
else
{
// Zooming
wxLongLong timeStamp = wxGetLocalTimeMillis();
double timeDiff = timeStamp.ToDouble() - m_timeStamp.ToDouble();
m_timeStamp = timeStamp;
double zoomScale;
// Set scaling speed depending on scroll wheel event interval
if( timeDiff < 500 && timeDiff > 0 )
{
zoomScale = ( aEvent.GetWheelRotation() > 0.0 ) ? 2.05 - timeDiff / 500 :
1.0 / ( 2.05 - timeDiff / 500 );
}
else
{
zoomScale = ( aEvent.GetWheelRotation() > 0.0 ) ? 1.05 : 0.95;
}
VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) );
m_view->SetScale( m_view->GetScale() * zoomScale, anchor );
}
aEvent.Skip();
}
void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
{
switch( m_state )
{
case IDLE:
case AUTO_PANNING:
if( aEvent.MiddleDown() )
{
m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
m_lookStartPoint = m_view->GetCenter();
m_state = DRAG_PANNING;
}
if( aEvent.LeftUp() )
{
m_state = IDLE; // Stop autopanning when user release left mouse button
}
break;
case DRAG_PANNING:
if( aEvent.MiddleUp() )
{
m_state = IDLE;
}
break;
}
aEvent.Skip();
}
void WX_VIEW_CONTROLS::onEnter( wxMouseEvent& aEvent )
{
m_parentPanel->SetFocus();
}
void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent )
{
switch( m_state )
{
case AUTO_PANNING:
{
double borderSize = std::min( m_autoPanMargin * m_view->GetScreenPixelSize().x,
m_autoPanMargin * m_view->GetScreenPixelSize().y );
VECTOR2D dir( m_panDirection );
if( dir.EuclideanNorm() > borderSize )
dir = dir.Resize( borderSize );
dir = m_view->ToWorld( dir, false );
m_view->SetCenter( m_view->GetCenter() + dir * m_autoPanSpeed );
// Notify tools that the cursor position has changed in the world coordinates
wxCommandEvent moveEvent( EVT_REFRESH_MOUSE );
wxPostEvent( m_parentPanel, moveEvent );
}
break;
case IDLE: // Just remove unnecessary warnings
case DRAG_PANNING:
break;
}
}
void WX_VIEW_CONTROLS::SetGrabMouse( bool aEnabled )
{
m_grabMouse = aEnabled;
if( aEnabled )
m_parentPanel->CaptureMouse();
else
m_parentPanel->ReleaseMouse();
}
const VECTOR2D WX_VIEW_CONTROLS::GetMousePosition() const
{
wxPoint msp = wxGetMousePosition();
wxPoint winp = m_parentPanel->GetScreenPosition();
return VECTOR2D( msp.x - winp.x, msp.y - winp.y );
}
const VECTOR2D WX_VIEW_CONTROLS::GetCursorPosition() const
{
if( m_snappingEnabled )
return m_view->GetGAL()->GetGridPoint( GetMousePosition() );
else
return GetMousePosition();
}
bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent )
{
VECTOR2D p( aEvent.GetX(), aEvent.GetY() );
// Compute areas where autopanning is active
double borderStart = std::min( m_autoPanMargin * m_view->GetScreenPixelSize().x,
m_autoPanMargin * m_view->GetScreenPixelSize().y );
double borderEndX = m_view->GetScreenPixelSize().x - borderStart;
double borderEndY = m_view->GetScreenPixelSize().y - borderStart;
m_panDirection = VECTOR2D();
if( p.x < borderStart )
m_panDirection.x = -( borderStart - p.x );
else if( p.x > borderEndX )
m_panDirection.x = ( p.x - borderEndX );
if( p.y < borderStart )
m_panDirection.y = -( borderStart - p.y );
else if( p.y > borderEndY )
m_panDirection.y = ( p.y - borderEndY );
bool borderHit = ( m_panDirection.x != 0 || m_panDirection.y != 0 );
switch( m_state )
{
case AUTO_PANNING:
if( !borderHit )
{
m_panTimer.Stop();
m_state = IDLE;
return false;
}
return true;
break;
case IDLE:
if( borderHit )
{
m_state = AUTO_PANNING;
m_panTimer.Start( (int) ( 1000.0 / 60.0 ) );
return true;
}
return false;
break;
case DRAG_PANNING:
return false;
}
wxASSERT_MSG( false, wxT( "This line should never be reached" ) );
return false; // Should not be reached, just avoid the compiler warnings..
}

View File

@ -101,7 +101,7 @@ void EDA_DRAW_FRAME::DrawWorkSheet( wxDC* aDC, BASE_SCREEN* aScreen, int aLineWi
} }
wxString EDA_DRAW_FRAME::GetScreenDesc() wxString EDA_DRAW_FRAME::GetScreenDesc() const
{ {
// Virtual function. In basic class, returns // Virtual function. In basic class, returns
// an empty string. // an empty string.

View File

@ -0,0 +1,204 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 worksheet_viewitem.cpp
* @brief Class that handles properties and drawing of worksheet layout.
*/
#include <worksheet_viewitem.h>
#include <worksheet_shape_builder.h>
#include <gal/graphics_abstraction_layer.h>
#include <painter.h>
#include <layers_id_colors_and_visibility.h>
#include <boost/foreach.hpp>
using namespace KIGFX;
WORKSHEET_VIEWITEM::WORKSHEET_VIEWITEM( const std::string& aFileName, const std::string& aSheetName,
const PAGE_INFO* aPageInfo, const TITLE_BLOCK* aTitleBlock ) :
EDA_ITEM( NOT_USED ), // this item is never added to a BOARD so it needs no type
m_fileName( aFileName ), m_sheetName( aSheetName ),
m_titleBlock( aTitleBlock ), m_pageInfo( aPageInfo ), m_sheetNumber( 1 ), m_sheetCount( 1 ) {}
void WORKSHEET_VIEWITEM::SetPageInfo( const PAGE_INFO* aPageInfo )
{
m_pageInfo = aPageInfo;
ViewUpdate( GEOMETRY );
}
void WORKSHEET_VIEWITEM::SetTitleBlock( const TITLE_BLOCK* aTitleBlock )
{
m_titleBlock = aTitleBlock;
ViewUpdate( GEOMETRY );
}
const BOX2I WORKSHEET_VIEWITEM::ViewBBox() const
{
BOX2I bbox;
if( m_pageInfo != NULL )
{
bbox.SetOrigin( VECTOR2I( 0, 0 ) );
bbox.SetEnd( VECTOR2I( m_pageInfo->GetWidthMils() * 25400,
m_pageInfo->GetHeightMils() * 25400 ) );
}
else
{
bbox.SetMaximum();
}
return bbox;
}
void WORKSHEET_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const
{
RENDER_SETTINGS* settings = m_view->GetPainter()->GetSettings();
wxString fileName( m_fileName.c_str(), wxConvUTF8 );
wxString sheetName( m_sheetName.c_str(), wxConvUTF8 );
WS_DRAW_ITEM_LIST drawList;
drawList.SetPenSize( settings->GetWorksheetLineWidth() );
// Sorry, but I don't get this multi #ifdef from include/convert_to_biu.h, so here goes a magic
// number. IU_PER_MILS should be 25400 (as in a different compilation unit), but somehow
// it equals 1 in this case..
drawList.SetMilsToIUfactor( 25400 /* IU_PER_MILS */ );
drawList.SetSheetNumber( m_sheetNumber );
drawList.SetSheetCount( m_sheetCount );
drawList.SetFileName( fileName );
drawList.SetSheetName( sheetName );
COLOR4D color = settings->GetColor( this, aLayer );
EDA_COLOR_T edaColor = ColorFindNearest( color.r * 255, color.g * 255, color.b * 255 );
drawList.BuildWorkSheetGraphicList( *m_pageInfo, *m_titleBlock, edaColor, edaColor );
// Draw all the components that make the page layout
WS_DRAW_ITEM_BASE* item = drawList.GetFirst();
while( item )
{
switch( item->GetType() )
{
case WS_DRAW_ITEM_BASE::wsg_line:
draw( static_cast<const WS_DRAW_ITEM_LINE*>( item ), aGal );
break;
case WS_DRAW_ITEM_BASE::wsg_rect:
draw( static_cast<const WS_DRAW_ITEM_RECT*>( item ), aGal );
break;
case WS_DRAW_ITEM_BASE::wsg_poly:
draw( static_cast<const WS_DRAW_ITEM_POLYGON*>( item ), aGal );
break;
case WS_DRAW_ITEM_BASE::wsg_text:
draw( static_cast<const WS_DRAW_ITEM_TEXT*>( item ), aGal );
break;
}
item = drawList.GetNext();
}
// Draw gray line that outlines the sheet size
drawBorder( aGal );
}
void WORKSHEET_VIEWITEM::ViewGetLayers( int aLayers[], int& aCount ) const
{
aCount = 1;
aLayers[0] = ITEM_GAL_LAYER( WORKSHEET );
}
void WORKSHEET_VIEWITEM::draw( const WS_DRAW_ITEM_LINE* aItem, GAL* aGal ) const
{
aGal->SetIsStroke( true );
aGal->SetIsFill( false );
aGal->SetStrokeColor( COLOR4D( aItem->GetColor() ) );
aGal->SetLineWidth( aItem->GetPenWidth() );
aGal->DrawLine( VECTOR2D( aItem->GetStart() ), VECTOR2D( aItem->GetEnd() ) );
}
void WORKSHEET_VIEWITEM::draw( const WS_DRAW_ITEM_RECT* aItem, GAL* aGal ) const
{
aGal->SetIsStroke( true );
aGal->SetIsFill( false );
aGal->SetStrokeColor( COLOR4D( aItem->GetColor() ) );
aGal->SetLineWidth( aItem->GetPenWidth() );
aGal->DrawRectangle( VECTOR2D( aItem->GetStart() ), VECTOR2D( aItem->GetEnd() ) );
}
void WORKSHEET_VIEWITEM::draw( const WS_DRAW_ITEM_POLYGON* aItem, GAL* aGal ) const
{
std::deque<VECTOR2D> corners;
BOOST_FOREACH( wxPoint point, aItem->m_Corners )
{
corners.push_back( VECTOR2D( point ) );
}
if( aItem->IsFilled() )
{
aGal->SetFillColor( COLOR4D( aItem->GetColor() ) );
aGal->SetIsFill( true );
aGal->SetIsStroke( false );
aGal->DrawPolygon( corners );
}
else
{
aGal->SetStrokeColor( COLOR4D( aItem->GetColor() ) );
aGal->SetIsFill( false );
aGal->SetIsStroke( true );
aGal->SetLineWidth( aItem->GetPenWidth() );
aGal->DrawPolyline( corners );
}
}
void WORKSHEET_VIEWITEM::draw( const WS_DRAW_ITEM_TEXT* aItem, GAL* aGal ) const
{
VECTOR2D position( aItem->GetTextPosition().x, aItem->GetTextPosition().y );
aGal->SetStrokeColor( COLOR4D( aItem->GetColor() ) );
aGal->SetLineWidth( aItem->GetThickness() );
aGal->SetTextAttributes( aItem );
aGal->StrokeText( std::string( aItem->GetText().mb_str() ), position, 0.0 );
}
void WORKSHEET_VIEWITEM::drawBorder( GAL* aGal ) const
{
VECTOR2D origin = VECTOR2D( 0.0, 0.0 );
VECTOR2D end = VECTOR2D( m_pageInfo->GetWidthMils() * 25400,
m_pageInfo->GetHeightMils() * 25400 );
aGal->SetIsStroke( true );
aGal->SetIsFill( false );
aGal->DrawRectangle( origin, end );
}

View File

@ -33,6 +33,9 @@
#include <fctsys.h> #include <fctsys.h>
#include <id.h> #include <id.h>
#include <class_drawpanel.h> #include <class_drawpanel.h>
#include <class_drawpanel_gal.h>
#include <gal/graphics_abstraction_layer.h>
#include <view/view.h>
#include <class_base_screen.h> #include <class_base_screen.h>
#include <wxstruct.h> #include <wxstruct.h>
#include <kicad_device_context.h> #include <kicad_device_context.h>
@ -41,7 +44,6 @@
#include <base_units.h> #include <base_units.h>
void EDA_DRAW_FRAME::RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointer ) void EDA_DRAW_FRAME::RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointer )
{ {
AdjustScrollBars( aCenterPoint ); AdjustScrollBars( aCenterPoint );
@ -82,7 +84,8 @@ void EDA_DRAW_FRAME::Zoom_Automatique( bool aWarpPointer )
if( screen->m_FirstRedraw ) if( screen->m_FirstRedraw )
SetCrossHairPosition( GetScrollCenterPosition() ); SetCrossHairPosition( GetScrollCenterPosition() );
RedrawScreen( GetScrollCenterPosition(), aWarpPointer ); if( !m_galCanvasActive )
RedrawScreen( GetScrollCenterPosition(), aWarpPointer );
} }
@ -191,6 +194,20 @@ void EDA_DRAW_FRAME::OnZoom( wxCommandEvent& event )
RedrawScreen( center, true ); RedrawScreen( center, true );
} }
if( m_galCanvasActive )
{
// Apply computed view settings to GAL
KIGFX::VIEW* view = m_galCanvas->GetView();
KIGFX::GAL* gal = m_galCanvas->GetGAL();
double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor();
double zoom = 1.0 / ( zoomFactor * GetZoom() );
view->SetScale( zoom );
view->SetCenter( VECTOR2D( center ) );
m_galCanvas->Refresh();
}
UpdateStatusBar(); UpdateStatusBar();
} }

View File

@ -101,11 +101,27 @@ target_link_libraries( cvpcb
common common
bitmaps bitmaps
polygon polygon
gal
${wxWidgets_LIBRARIES} ${wxWidgets_LIBRARIES}
${OPENGL_LIBRARIES} ${OPENGL_LIBRARIES}
${GDI_PLUS_LIBRARIES} ${GDI_PLUS_LIBRARIES}
${GLEW_LIBRARIES}
${CAIRO_LIBRARIES}
) )
# Only for win32 cross compilation using MXE
if(WIN32 AND MSYS)
target_link_libraries(cvpcb
opengl32
glu32
pixman-1
fontconfig
freetype
bz2
)
endif(WIN32 AND MSYS)
if( BUILD_GITHUB_PLUGIN ) if( BUILD_GITHUB_PLUGIN )
target_link_libraries( cvpcb github_plugin ) target_link_libraries( cvpcb github_plugin )
endif() endif()

View File

@ -31,6 +31,7 @@
#include <appl_wxstruct.h> #include <appl_wxstruct.h>
#include <common.h> #include <common.h>
#include <class_drawpanel.h> #include <class_drawpanel.h>
#include <class_drawpanel_gal.h>
#include <confirm.h> #include <confirm.h>
#include <macros.h> #include <macros.h>
#include <bitmaps.h> #include <bitmaps.h>
@ -121,7 +122,7 @@ DISPLAY_FOOTPRINTS_FRAME::DISPLAY_FOOTPRINTS_FRAME( CVPCB_MAINFRAME* parent,
EDA_PANEINFO mesg; EDA_PANEINFO mesg;
mesg.MessageToolbarPane(); mesg.MessageToolbarPane();
m_galCanvas->Hide();
m_auimgr.AddPane( m_mainToolBar, m_auimgr.AddPane( m_mainToolBar,
wxAuiPaneInfo( horiz ).Name( wxT( "m_mainToolBar" ) ).Top(). Row( 0 ) ); wxAuiPaneInfo( horiz ).Name( wxT( "m_mainToolBar" ) ).Top(). Row( 0 ) );

View File

@ -281,7 +281,7 @@ int CVPCB_MAINFRAME::SaveCmpLinkFile( const wxString& aFullFileName )
fpLibFileName.SetName( FP_LIB_TABLE::GetFileName() ); fpLibFileName.SetName( FP_LIB_TABLE::GetFileName() );
if( fpLibFileName.FileExists() if( fpLibFileName.FileExists()
&& IsOK( this, _( "A footprint library table already exsist in this path.\n\nDo " && IsOK( this, _( "A footprint library table already exists in this path.\n\nDo "
"you want to overwrite it?" ) ) ) "you want to overwrite it?" ) ) )
{ {
try try
@ -292,7 +292,7 @@ int CVPCB_MAINFRAME::SaveCmpLinkFile( const wxString& aFullFileName )
{ {
DisplayError( this, DisplayError( this,
wxString::Format( _( "An error occurred attempting to save the " wxString::Format( _( "An error occurred attempting to save the "
"footpirnt library table <%s>\n\n%s" ), "footprint library table <%s>\n\n%s" ),
GetChars( fpLibFileName.GetFullPath() ), GetChars( fpLibFileName.GetFullPath() ),
GetChars( ioe.errorText ) ) ); GetChars( ioe.errorText ) ) );
} }

View File

@ -190,7 +190,7 @@ DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::DIALOG_EDIT_COMPONENT_IN_SCHEMATIC( wxWindow
void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnListItemDeselected( wxListEvent& event ) void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnListItemDeselected( wxListEvent& event )
{ {
D( printf( "OnListItemDeselected()\n" ); ) DBG( printf( "OnListItemDeselected()\n" ); )
if( !m_skipCopyFromPanel ) if( !m_skipCopyFromPanel )
{ {
@ -202,7 +202,7 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnListItemDeselected( wxListEvent& even
void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnListItemSelected( wxListEvent& event ) void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnListItemSelected( wxListEvent& event )
{ {
D( printf( "OnListItemSelected()\n" ); ) DBG( printf( "OnListItemSelected()\n" ); )
// remember the selected row, statically // remember the selected row, statically
s_SelectedRow = event.GetIndex(); s_SelectedRow = event.GetIndex();
@ -460,7 +460,7 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::moveUpButtonHandler( wxCommandEvent& ev
// and in the fieldListCtrl // and in the fieldListCtrl
SCH_FIELD tmp = m_FieldsBuf[fieldNdx - 1]; SCH_FIELD tmp = m_FieldsBuf[fieldNdx - 1];
D( printf( "tmp.m_Text=\"%s\" tmp.m_Name=\"%s\"\n", DBG( printf( "tmp.m_Text=\"%s\" tmp.m_Name=\"%s\"\n",
TO_UTF8( tmp.GetText() ), TO_UTF8( tmp.GetName( false ) ) ); ) TO_UTF8( tmp.GetText() ), TO_UTF8( tmp.GetName( false ) ) ); )
m_FieldsBuf[fieldNdx - 1] = m_FieldsBuf[fieldNdx]; m_FieldsBuf[fieldNdx - 1] = m_FieldsBuf[fieldNdx];
@ -880,12 +880,12 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copyOptionsToPanel()
if( mirror == CMP_MIRROR_X ) if( mirror == CMP_MIRROR_X )
{ {
mirrorRadioBox->SetSelection( 1 ); mirrorRadioBox->SetSelection( 1 );
D( printf( "mirror=X,1\n" ); ) DBG( printf( "mirror=X,1\n" ); )
} }
else if( mirror == CMP_MIRROR_Y ) else if( mirror == CMP_MIRROR_Y )
{ {
mirrorRadioBox->SetSelection( 2 ); mirrorRadioBox->SetSelection( 2 );
D( printf( "mirror=Y,2\n" ); ) DBG( printf( "mirror=Y,2\n" ); )
} }
else else
mirrorRadioBox->SetSelection( 0 ); mirrorRadioBox->SetSelection( 0 );
@ -905,7 +905,7 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copyOptionsToPanel()
// Show the "Parts Locked" option? // Show the "Parts Locked" option?
if( !m_LibEntry || !m_LibEntry->UnitsLocked() ) if( !m_LibEntry || !m_LibEntry->UnitsLocked() )
{ {
D( printf( "partsAreLocked->false\n" ); ) DBG( printf( "partsAreLocked->false\n" ); )
partsAreLockedLabel->Show( false ); partsAreLockedLabel->Show( false );
} }

View File

@ -480,7 +480,7 @@ void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::initBuffers()
// fixed fields: // fixed fields:
for( int i=0; i<MANDATORY_FIELDS; ++i ) for( int i=0; i<MANDATORY_FIELDS; ++i )
{ {
D( printf( "add fixed:%s\n", TO_UTF8( cmpFields[i].GetName() ) ); ) DBG( printf( "add fixed:%s\n", TO_UTF8( cmpFields[i].GetName() ) ); )
m_FieldsBuf.push_back( cmpFields[i] ); m_FieldsBuf.push_back( cmpFields[i] );
} }
@ -505,7 +505,7 @@ void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::initBuffers()
// values from the component will be set. // values from the component will be set.
if( !libField ) if( !libField )
{ {
D( printf( "add template:%s\n", TO_UTF8( it->m_Name ) ); ) DBG( printf( "add template:%s\n", TO_UTF8( it->m_Name ) ); )
fld.SetName( it->m_Name ); fld.SetName( it->m_Name );
fld.SetText( it->m_Value ); // empty? ok too. fld.SetText( it->m_Value ); // empty? ok too.
@ -517,7 +517,7 @@ void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::initBuffers()
} }
else else
{ {
D( printf( "match template:%s\n", TO_UTF8( libField->GetName() ) ); ) DBG( printf( "match template:%s\n", TO_UTF8( libField->GetName() ) ); )
fld = *libField; // copy values from component, m_Name too fld = *libField; // copy values from component, m_Name too
} }
@ -533,7 +533,7 @@ void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::initBuffers()
if( !buf ) if( !buf )
{ {
D( printf( "add cmp:%s\n", TO_UTF8( cmp->GetName() ) ); ) DBG( printf( "add cmp:%s\n", TO_UTF8( cmp->GetName() ) ); )
m_FieldsBuf.push_back( *cmp ); m_FieldsBuf.push_back( *cmp );
} }
} }
@ -731,11 +731,11 @@ bool DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::copyPanelToSelectedField()
if( field.GetId() >= MANDATORY_FIELDS ) if( field.GetId() >= MANDATORY_FIELDS )
{ {
wxString name = fieldNameTextCtrl->GetValue(); wxString name = fieldNameTextCtrl->GetValue();
D( printf("name:%s\n", TO_UTF8( name ) ); ) DBG( printf("name:%s\n", TO_UTF8( name ) ); )
field.SetName( name ); field.SetName( name );
} }
D( printf("setname:%s\n", TO_UTF8( field.GetName() ) ); ) DBG( printf("setname:%s\n", TO_UTF8( field.GetName() ) ); )
setRowItem( fieldNdx, field ); // update fieldListCtrl setRowItem( fieldNdx, field ); // update fieldListCtrl

View File

@ -48,7 +48,7 @@
*/ */
enum SchematicFindReplaceFlags enum SchematicFindReplaceFlags
{ {
// The last wxFindReplaceFlag enum is wxFR_MATCHCASE. // The last wxFindReplaceFlag enum is wxFR_MATCHCASE = 0x4.
/// Search the current sheet only. /// Search the current sheet only.
FR_CURRENT_SHEET_ONLY = wxFR_MATCHCASE << 1, FR_CURRENT_SHEET_ONLY = wxFR_MATCHCASE << 1,

View File

@ -292,7 +292,7 @@ void SCH_EDIT_FRAME::OnSetOptions( wxCommandEvent& event )
for( unsigned i=0; i<tfnames.size(); ++i ) for( unsigned i=0; i<tfnames.size(); ++i )
{ {
D(printf("dlg.SetFieldName(%d, '%s')\n", i, TO_UTF8( tfnames[i].m_Name) );) DBG(printf("dlg.SetFieldName(%d, '%s')\n", i, TO_UTF8( tfnames[i].m_Name) );)
dlg.SetFieldName( i, tfnames[i].m_Name ); dlg.SetFieldName( i, tfnames[i].m_Name );
} }
@ -680,7 +680,7 @@ void SCH_EDIT_FRAME::LoadSettings()
catch( IO_ERROR& e ) catch( IO_ERROR& e )
{ {
// @todo show error msg // @todo show error msg
D( printf( "templatefieldnames parsing error: '%s'\n", DBG( printf( "templatefieldnames parsing error: '%s'\n",
TO_UTF8( e.errorText ) ); ) TO_UTF8( e.errorText ) ); )
} }
} }
@ -751,7 +751,7 @@ void SCH_EDIT_FRAME::SaveSettings()
m_TemplateFieldNames.Format( &sf, 0 ); m_TemplateFieldNames.Format( &sf, 0 );
D(printf("saving formatted template fieldnames:'%s'\n", sf.GetString().c_str() );) DBG(printf("saving formatted template fieldnames:'%s'\n", sf.GetString().c_str() );)
wxString record = FROM_UTF8( sf.GetString().c_str() ); wxString record = FROM_UTF8( sf.GetString().c_str() );
record.Replace( wxT("\n"), wxT(""), true ); // strip all newlines record.Replace( wxT("\n"), wxT(""), true ); // strip all newlines

View File

@ -288,12 +288,11 @@ SCH_ITEM* SCH_EDIT_FRAME::FindComponentAndItem( const wxString& aReference,
void SCH_EDIT_FRAME::OnFindSchematicItem( wxFindDialogEvent& aEvent ) void SCH_EDIT_FRAME::OnFindSchematicItem( wxFindDialogEvent& aEvent )
{ {
static wxPoint itemPosition; // the actual position of the matched item. static wxPoint itemPosition; // the actual position of the matched item.
SCH_SHEET_LIST schematic; SCH_SHEET_LIST schematic;
wxString msg; wxString msg;
SCH_FIND_REPLACE_DATA searchCriteria; SCH_FIND_REPLACE_DATA searchCriteria;
bool warpCursor = !( aEvent.GetFlags() & FR_NO_WARP_CURSOR );
SCH_FIND_COLLECTOR_DATA data; SCH_FIND_COLLECTOR_DATA data;
searchCriteria.SetFlags( aEvent.GetFlags() ); searchCriteria.SetFlags( aEvent.GetFlags() );
@ -326,6 +325,88 @@ void SCH_EDIT_FRAME::OnFindSchematicItem( wxFindDialogEvent& aEvent )
m_foundItems.UpdateIndex(); m_foundItems.UpdateIndex();
} }
updateFindReplaceView( aEvent );
}
void SCH_EDIT_FRAME::OnFindReplace( wxFindDialogEvent& aEvent )
{
SCH_ITEM* item;
SCH_SHEET_PATH* sheet;
SCH_SHEET_LIST schematic;
SCH_FIND_COLLECTOR_DATA data;
if( aEvent.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL )
{
while( ( item = (SCH_ITEM*) m_foundItems.GetItem( data ) ) != NULL )
{
SCH_ITEM* undoItem = data.GetParent();
// Don't save child items in undo list.
if( undoItem == NULL )
undoItem = item;
SetUndoItem( undoItem );
sheet = schematic.GetSheet( data.GetSheetPath() );
wxCHECK_RET( sheet != NULL, wxT( "Could not find sheet path " ) + data.GetSheetPath() );
if( m_foundItems.ReplaceItem( sheet ) )
{
OnModify();
SaveUndoItemInUndoList( undoItem );
updateFindReplaceView( aEvent );
}
m_foundItems.IncrementIndex();
if( m_foundItems.PassedEnd() )
break;
}
}
else
{
SCH_ITEM* item = (SCH_ITEM*) m_foundItems.GetItem( data );
wxCHECK_RET( item != NULL, wxT( "Invalid replace item in find collector list." ) );
SCH_ITEM* undoItem = data.GetParent();
if( undoItem == NULL )
undoItem = item;
SetUndoItem( undoItem );
sheet = schematic.GetSheet( data.GetSheetPath() );
wxCHECK_RET( sheet != NULL, wxT( "Could not find sheet path " ) + data.GetSheetPath() );
if( m_foundItems.ReplaceItem( sheet ) )
{
OnModify();
SaveUndoItemInUndoList( undoItem );
updateFindReplaceView( aEvent );
}
m_foundItems.IncrementIndex();
}
// End the replace if we are at the end if the list. This prevents an infinite loop if
// wrap search is selected and all of the items have been replaced with a value that
// still satisfies the search criteria.
if( m_foundItems.PassedEnd() )
aEvent.SetFlags( aEvent.GetFlags() & ~FR_REPLACE_ITEM_FOUND );
}
void SCH_EDIT_FRAME::updateFindReplaceView( wxFindDialogEvent& aEvent )
{
wxString msg;
SCH_SHEET_LIST schematic;
SCH_FIND_COLLECTOR_DATA data;
bool warpCursor = !( aEvent.GetFlags() & FR_NO_WARP_CURSOR );
if( m_foundItems.GetItem( data ) != NULL ) if( m_foundItems.GetItem( data ) != NULL )
{ {
wxLogTrace( traceFindReplace, wxT( "Found " ) + m_foundItems.GetText() ); wxLogTrace( traceFindReplace, wxT( "Found " ) + m_foundItems.GetText() );
@ -335,13 +416,15 @@ void SCH_EDIT_FRAME::OnFindSchematicItem( wxFindDialogEvent& aEvent )
wxCHECK_RET( sheet != NULL, wxT( "Could not find sheet path " ) + wxCHECK_RET( sheet != NULL, wxT( "Could not find sheet path " ) +
data.GetSheetPath() ); data.GetSheetPath() );
SCH_ITEM* item = (SCH_ITEM*)m_foundItems.GetItem( data );
// Make the item temporarily visible just in case it's hide flag is set. This // Make the item temporarily visible just in case it's hide flag is set. This
// has no effect on objects that don't support hiding. If this is a close find // has no effect on objects that don't support hiding. If this is a close find
// dialog event, clear the temporary visibility flag. // dialog event, clear the temporary visibility flag.
if( aEvent.GetEventType() == wxEVT_COMMAND_FIND_CLOSE ) if( aEvent.GetEventType() == wxEVT_COMMAND_FIND_CLOSE )
m_foundItems.GetItem( data )->SetForceVisible( false ); item->SetForceVisible( false );
else else if( item->Type() == SCH_FIELD_T && !( (SCH_FIELD*) item )->IsVisible() )
m_foundItems.GetItem( data )->SetForceVisible( true ); item->SetForceVisible( true );
if( sheet->PathHumanReadable() != m_CurrentSheet->PathHumanReadable() ) if( sheet->PathHumanReadable() != m_CurrentSheet->PathHumanReadable() )
{ {
@ -371,61 +454,3 @@ void SCH_EDIT_FRAME::OnFindSchematicItem( wxFindDialogEvent& aEvent )
SetStatusText( msg ); SetStatusText( msg );
} }
void SCH_EDIT_FRAME::OnFindReplace( wxFindDialogEvent& aEvent )
{
SCH_FIND_COLLECTOR_DATA data;
bool warpCursor = !( aEvent.GetFlags() & FR_NO_WARP_CURSOR );
SCH_ITEM* item = (SCH_ITEM*) m_foundItems.GetItem( data );
wxCHECK_RET( item != NULL, wxT( "Invalid replace item in find collector list." ) );
wxLogTrace( traceFindReplace, wxT( "Replacing %s with %s in item %s" ),
GetChars( aEvent.GetFindString() ), GetChars( aEvent.GetReplaceString() ),
GetChars( m_foundItems.GetText() ) );
SCH_ITEM* undoItem = data.GetParent();
if( undoItem == NULL )
undoItem = item;
SetUndoItem( undoItem );
if( m_foundItems.ReplaceItem() )
{
OnModify();
SaveUndoItemInUndoList( undoItem );
RedrawScreen( data.GetPosition(), warpCursor );
}
OnFindSchematicItem( aEvent );
if( aEvent.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL )
{
while( ( item = (SCH_ITEM*) m_foundItems.GetItem( data ) ) != NULL )
{
wxLogTrace( traceFindReplace, wxT( "Replacing %s with %s in item %s" ),
GetChars( aEvent.GetFindString() ), GetChars( aEvent.GetReplaceString() ),
GetChars( m_foundItems.GetText() ) );
SCH_ITEM* undoItem = data.GetParent();
// Don't save child items in undo list.
if( undoItem == NULL )
undoItem = item;
SetUndoItem( undoItem );
if( m_foundItems.ReplaceItem() )
{
OnModify();
SaveUndoItemInUndoList( undoItem );
RedrawScreen( data.GetPosition(), warpCursor );
}
OnFindSchematicItem( aEvent );
}
}
}

View File

@ -640,7 +640,7 @@ void LIB_FIELD::SetName( const wxString& aName )
// Besides, m_id is a relic that is untrustworthy now. // Besides, m_id is a relic that is untrustworthy now.
if( m_id >=0 && m_id < MANDATORY_FIELDS ) if( m_id >=0 && m_id < MANDATORY_FIELDS )
{ {
D(printf( "trying to set a MANDATORY_FIELD's name\n" );) DBG(printf( "trying to set a MANDATORY_FIELD's name\n" );)
return; return;
} }

View File

@ -424,7 +424,7 @@ bool SCH_EDIT_FRAME::WriteNetListFile( NETLIST_OBJECT_LIST * aConnectedItemsList
wxFileName tmpFile = aFullFileName; wxFileName tmpFile = aFullFileName;
tmpFile.SetExt( INTERMEDIATE_NETLIST_EXT ); tmpFile.SetExt( INTERMEDIATE_NETLIST_EXT );
D(printf("tmpFile:'%s'\n", TO_UTF8( tmpFile.GetFullPath() ) );) DBG(printf("tmpFile:'%s'\n", TO_UTF8( tmpFile.GetFullPath() ) );)
ret = helper.WriteGENERICNetList( tmpFile.GetFullPath() ); ret = helper.WriteGENERICNetList( tmpFile.GetFullPath() );
if( !ret ) if( !ret )
@ -442,7 +442,7 @@ bool SCH_EDIT_FRAME::WriteNetListFile( NETLIST_OBJECT_LIST * aConnectedItemsList
tmpFile.GetFullPath(), tmpFile.GetFullPath(),
aFullFileName ); aFullFileName );
D(printf("commandLine:'%s'\n", TO_UTF8( commandLine ) );) DBG(printf("commandLine:'%s'\n", TO_UTF8( commandLine ) );)
ProcessExecute( commandLine, wxEXEC_SYNC ); ProcessExecute( commandLine, wxEXEC_SYNC );
} }

View File

@ -347,7 +347,7 @@ bool SCH_FIND_COLLECTOR::PassedEnd() const
if( GetCount() == 0 ) if( GetCount() == 0 )
return true; return true;
if( !(flags & FR_SEARCH_WRAP) ) if( !(flags & FR_SEARCH_WRAP) || (flags & FR_SEARCH_REPLACE) )
{ {
if( flags & wxFR_DOWN ) if( flags & wxFR_DOWN )
{ {
@ -454,7 +454,7 @@ EDA_ITEM* SCH_FIND_COLLECTOR::GetItem( SCH_FIND_COLLECTOR_DATA& aData )
} }
bool SCH_FIND_COLLECTOR::ReplaceItem() bool SCH_FIND_COLLECTOR::ReplaceItem( SCH_SHEET_PATH* aSheetPath )
{ {
if( PassedEnd() ) if( PassedEnd() )
return false; return false;
@ -464,15 +464,10 @@ bool SCH_FIND_COLLECTOR::ReplaceItem()
EDA_ITEM* item = m_List[ m_foundIndex ]; EDA_ITEM* item = m_List[ m_foundIndex ];
bool replaced = item->Replace( m_findReplaceData ); bool replaced = item->Replace( m_findReplaceData, aSheetPath );
// If the replace was successful, remove the item from the find list to prevent
// iterating back over it again.
if( replaced ) if( replaced )
{ m_forceSearch = true;
Remove( m_foundIndex );
m_data.erase( m_data.begin() + m_foundIndex );
}
return replaced; return replaced;
} }

View File

@ -237,15 +237,6 @@ class SCH_FIND_COLLECTOR : public COLLECTOR
/// performed even if the search criteria hasn't changed. /// performed even if the search criteria hasn't changed.
bool m_forceSearch; bool m_forceSearch;
/**
* Function PassedEnd
* tests if #m_foundIndex is beyond the end of the list give the current
* find/replace criterial in #m_findReplaceData.
*
* @return True if #m_foundIndex has crossed the end of the found item list.
*/
bool PassedEnd() const;
/** /**
* Function dump * Function dump
* is a helper to dump the items in the find list for debugging purposes. * is a helper to dump the items in the find list for debugging purposes.
@ -266,8 +257,24 @@ public:
m_forceSearch = false; m_forceSearch = false;
} }
void Empty()
{
m_foundIndex = 0;
COLLECTOR::Empty();
m_data.clear();
}
void SetForceSearch() { m_forceSearch = true; } void SetForceSearch() { m_forceSearch = true; }
/**
* Function PassedEnd
* tests if #m_foundIndex is beyond the end of the list give the current
* find/replace criterial in #m_findReplaceData.
*
* @return True if #m_foundIndex has crossed the end of the found item list.
*/
bool PassedEnd() const;
/** /**
* Function UpdateIndex * Function UpdateIndex
* updates the list index according to the current find and replace criteria. * updates the list index according to the current find and replace criteria.
@ -326,7 +333,7 @@ public:
* *
* @return True if the text replace occurred otherwise false. * @return True if the text replace occurred otherwise false.
*/ */
bool ReplaceItem(); bool ReplaceItem( SCH_SHEET_PATH* aSheetPath = NULL );
SEARCH_RESULT Inspect( EDA_ITEM* aItem, const void* aTestData = NULL ); SEARCH_RESULT Inspect( EDA_ITEM* aItem, const void* aTestData = NULL );
@ -340,6 +347,8 @@ public:
* value searches the entire schematic hierarchy. * value searches the entire schematic hierarchy.
*/ */
void Collect( SCH_FIND_REPLACE_DATA& aFindReplaceData, SCH_SHEET_PATH* aSheetPath = NULL ); void Collect( SCH_FIND_REPLACE_DATA& aFindReplaceData, SCH_SHEET_PATH* aSheetPath = NULL );
void IncrementIndex() { m_foundIndex += 1; }
}; };

View File

@ -431,8 +431,11 @@ bool SCH_FIELD::Replace( wxFindReplaceData& aSearchData, void* aAuxData )
bool isReplaced; bool isReplaced;
wxString text = GetFullyQualifiedText(); wxString text = GetFullyQualifiedText();
if( m_id == REFERENCE && aAuxData != NULL ) if( m_id == REFERENCE )
{ {
wxCHECK_MSG( aAuxData != NULL, false,
wxT( "Cannot replace reference designator without valid sheet path." ) );
wxCHECK_MSG( aSearchData.GetFlags() & FR_REPLACE_REFERENCES, false, wxCHECK_MSG( aSearchData.GetFlags() & FR_REPLACE_REFERENCES, false,
wxT( "Invalid replace component reference field call." ) ) ; wxT( "Invalid replace component reference field call." ) ) ;
@ -443,8 +446,8 @@ bool SCH_FIELD::Replace( wxFindReplaceData& aSearchData, void* aAuxData )
text = component->GetRef( (SCH_SHEET_PATH*) aAuxData ); text = component->GetRef( (SCH_SHEET_PATH*) aAuxData );
if( component->GetPartCount() > 1 ) // if( component->GetPartCount() > 1 )
text << LIB_COMPONENT::ReturnSubReference( component->GetUnit() ); // text << LIB_COMPONENT::ReturnSubReference( component->GetUnit() );
isReplaced = EDA_ITEM::Replace( aSearchData, text ); isReplaced = EDA_ITEM::Replace( aSearchData, text );

View File

@ -438,6 +438,7 @@ SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet )
m_index = 0; m_index = 0;
m_count = 0; m_count = 0;
m_List = NULL; m_List = NULL;
m_isRootSheet = false;
if( aSheet == NULL ) if( aSheet == NULL )
aSheet = g_RootSheet; aSheet = g_RootSheet;
@ -518,6 +519,9 @@ SCH_SHEET_PATH* SCH_SHEET_LIST::GetSheet( const wxString aPath, bool aHumanReada
void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet ) void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet )
{ {
if( aSheet == g_RootSheet )
m_isRootSheet = true;
if( m_List == NULL ) if( m_List == NULL )
{ {
int count = aSheet->CountSheets(); int count = aSheet->CountSheets();
@ -702,3 +706,25 @@ bool SCH_SHEET_LIST::SetComponentFootprint( const wxString& aReference,
return found; return found;
} }
bool SCH_SHEET_LIST::IsComplexHierarchy()
{
wxString fileName;
for( int i = 0; i < GetCount(); i++ )
{
fileName = GetSheet( i )->Last()->GetFileName();
for( int j = 0; j < GetCount(); j++ )
{
if( i == j )
continue;
if( fileName == GetSheet( j )->Last()->GetFileName() )
return true;
}
}
return false;
}

View File

@ -292,6 +292,7 @@ private:
* returning the next item in m_List. Also used for * returning the next item in m_List. Also used for
* internal calculations in BuildSheetList() * internal calculations in BuildSheetList()
*/ */
bool m_isRootSheet;
SCH_SHEET_PATH m_currList; SCH_SHEET_PATH m_currList;
public: public:
@ -442,6 +443,15 @@ public:
bool SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint, bool SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint,
bool aSetVisible ); bool aSetVisible );
/**
* Function IsComplexHierarchy
* searches all of the sheets for duplicate files names which indicates a complex
* hierarchy.
*
* @return true if the #SCH_SHEET_LIST is a complex hierarchy.
*/
bool IsComplexHierarchy();
private: private:
/** /**

View File

@ -351,7 +351,7 @@ SCH_SCREEN* SCH_EDIT_FRAME::GetScreen() const
} }
wxString SCH_EDIT_FRAME::GetScreenDesc() wxString SCH_EDIT_FRAME::GetScreenDesc() const
{ {
wxString s = m_CurrentSheet->PathHumanReadable(); wxString s = m_CurrentSheet->PathHumanReadable();

View File

@ -151,7 +151,7 @@ int TEMPLATES::AddTemplateFieldName( const TEMPLATE_FIELDNAME& aFieldName )
{ {
if( m_Fields[i].m_Name == aFieldName.m_Name ) if( m_Fields[i].m_Name == aFieldName.m_Name )
{ {
D( printf( "inserting template fieldname:'%s' at %d\n", DBG( printf( "inserting template fieldname:'%s' at %d\n",
TO_UTF8( aFieldName.m_Name ), i ); ) TO_UTF8( aFieldName.m_Name ), i ); )
m_Fields[i] = aFieldName; m_Fields[i] = aFieldName;
@ -159,7 +159,7 @@ int TEMPLATES::AddTemplateFieldName( const TEMPLATE_FIELDNAME& aFieldName )
} }
} }
// D(printf("appending template fieldname:'%s'\n", aFieldName.m_Name.utf8_str() );) // DBG(printf("appending template fieldname:'%s'\n", aFieldName.m_Name.utf8_str() );)
// the name is legal and not previously added to the config container, append // the name is legal and not previously added to the config container, append
// it and return its index within the container. // it and return its index within the container.

View File

@ -409,7 +409,7 @@ void AM_PRIMITIVE::DrawBasicShape( GERBER_DRAW_ITEM* aParent,
case AMP_UNKNOWN: case AMP_UNKNOWN:
default: default:
D( printf( "AM_PRIMITIVE::DrawBasicShape() err: unknown prim id %d\n",primitive_id) ); DBG( printf( "AM_PRIMITIVE::DrawBasicShape() err: unknown prim id %d\n",primitive_id) );
break; break;
} }
} }

View File

@ -167,7 +167,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
if( m_GerbMetric ) if( m_GerbMetric )
conv_scale /= 25.4; conv_scale /= 25.4;
// D( printf( "%22s: Command <%c%c>\n", __func__, (command >> 8) & 0xFF, command & 0xFF ); ) // DBG( printf( "%22s: Command <%c%c>\n", __func__, (command >> 8) & 0xFF, command & 0xFF ); )
switch( command ) switch( command )
{ {
@ -521,7 +521,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
m_ImageNegative = true; m_ImageNegative = true;
else else
m_ImageNegative = false; m_ImageNegative = false;
D( printf( "%22s: IMAGE_POLARITY m_ImageNegative=%s\n", __func__, DBG( printf( "%22s: IMAGE_POLARITY m_ImageNegative=%s\n", __func__,
m_ImageNegative ? "true" : "false" ); ) m_ImageNegative ? "true" : "false" ); )
break; break;
@ -531,7 +531,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command,
else else
GetLayerParams().m_LayerNegative = false; GetLayerParams().m_LayerNegative = false;
D( printf( "%22s: LAYER_POLARITY m_LayerNegative=%s\n", __func__, DBG( printf( "%22s: LAYER_POLARITY m_LayerNegative=%s\n", __func__,
GetLayerParams().m_LayerNegative ? "true" : "false" ); ) GetLayerParams().m_LayerNegative ? "true" : "false" ); )
break; break;

View File

@ -35,6 +35,7 @@
#include <colors.h> #include <colors.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <richio.h> #include <richio.h>
#include <view/view_item.h>
#include <boost/ptr_container/ptr_vector.hpp> #include <boost/ptr_container/ptr_vector.hpp>
@ -46,102 +47,8 @@ extern std::ostream& operator <<( std::ostream& out, const wxPoint& pt );
#endif #endif
/** /// Flag to enable find and replace tracing using the WXTRACE environment variable.
* Enum KICAD_T extern const wxString traceFindReplace;
* is the set of class identification values, stored in EDA_ITEM::m_StructType
*/
enum KICAD_T {
NOT_USED = -1, ///< the 3d code uses this value
EOT = 0, ///< search types array terminator (End Of Types)
TYPE_NOT_INIT = 0,
PCB_T,
SCREEN_T, ///< not really an item, used to identify a screen
// Items in pcb
PCB_MODULE_T, ///< class MODULE, a footprint
PCB_PAD_T, ///< class D_PAD, a pad in a footprint
PCB_LINE_T, ///< class DRAWSEGMENT, a segment not on copper layers
PCB_TEXT_T, ///< class TEXTE_PCB, text on a layer
PCB_MODULE_TEXT_T, ///< class TEXTE_MODULE, text in a footprint
PCB_MODULE_EDGE_T, ///< class EDGE_MODULE, a footprint edge
PCB_TRACE_T, ///< class TRACKE, a track segment (segment on a copper layer)
PCB_VIA_T, ///< class SEGVIA, a via (like a track segment on a copper layer)
PCB_ZONE_T, ///< class SEGZONE, a segment used to fill a zone area (segment on a
///< copper layer)
PCB_MARKER_T, ///< class MARKER_PCB, a marker used to show something
PCB_DIMENSION_T, ///< class DIMENSION, a dimension (graphic item)
PCB_TARGET_T, ///< class PCB_TARGET, a target (graphic item)
PCB_ZONE_AREA_T, ///< class ZONE_CONTAINER, a zone area
PCB_ITEM_LIST_T, ///< class BOARD_ITEM_LIST, a list of board items
// Schematic draw Items. The order of these items effects the sort order.
// It is currently ordered to mimic the old Eeschema locate behavior where
// the smallest item is the selected item.
SCH_MARKER_T,
SCH_JUNCTION_T,
SCH_NO_CONNECT_T,
SCH_BUS_WIRE_ENTRY_T,
SCH_BUS_BUS_ENTRY_T,
SCH_LINE_T,
SCH_BITMAP_T,
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_FIELD_T,
SCH_COMPONENT_T,
SCH_SHEET_PIN_T,
SCH_SHEET_T,
// Be prudent with these 3 types:
// they should be used only to locate a specific field type
// among SCH_FIELD_T items types
SCH_FIELD_LOCATE_REFERENCE_T,
SCH_FIELD_LOCATE_VALUE_T,
SCH_FIELD_LOCATE_FOOTPRINT_T,
// General
SCH_SCREEN_T,
/*
* Draw items in library component.
*
* The order of these items effects the sort order for items inside the
* "DRAW/ENDDRAW" section of the component definition in a library file.
* If you add a new draw item, type, please make sure you add it so the
* sort order is logical.
*/
LIB_COMPONENT_T,
LIB_ALIAS_T,
LIB_ARC_T,
LIB_CIRCLE_T,
LIB_TEXT_T,
LIB_RECTANGLE_T,
LIB_POLYLINE_T,
LIB_BEZIER_T,
LIB_PIN_T,
/*
* Fields are not saved inside the "DRAW/ENDDRAW". Add new draw item
* types before this line.
*/
LIB_FIELD_T,
/*
* For GerbView: items type:
*/
TYPE_GERBER_DRAW_ITEM,
/*
* for Pl_Editor, in undo/redo commands
*/
TYPE_PL_EDITOR_LAYOUT,
// End value
MAX_STRUCT_TYPE_ID
};
/** /**
@ -400,6 +307,9 @@ public:
#define END_ONPAD (1 << 23) ///< Pcbnew: flag set for track segment ending on a pad #define END_ONPAD (1 << 23) ///< Pcbnew: flag set for track segment ending on a pad
#define BUSY (1 << 24) ///< Pcbnew: flag indicating that the structure has #define BUSY (1 << 24) ///< Pcbnew: flag indicating that the structure has
///< already been edited, in some functions ///< already been edited, in some functions
#define HIGHLIGHTED (1 << 25) ///< item is drawn in normal colors, when the rest is darkened
#define BRIGHTENED (1 << 26) ///< item is drawn with a bright contour
#define EDA_ITEM_ALL_FLAGS -1 #define EDA_ITEM_ALL_FLAGS -1
typedef unsigned STATUS_FLAGS; typedef unsigned STATUS_FLAGS;
@ -409,7 +319,7 @@ typedef unsigned STATUS_FLAGS;
* is a base class for most all the KiCad significant classes, used in * is a base class for most all the KiCad significant classes, used in
* schematics and boards. * schematics and boards.
*/ */
class EDA_ITEM class EDA_ITEM : public KIGFX::VIEW_ITEM
{ {
private: private:
@ -450,12 +360,7 @@ public:
EDA_ITEM( const EDA_ITEM& base ); EDA_ITEM( const EDA_ITEM& base );
virtual ~EDA_ITEM() { }; virtual ~EDA_ITEM() { };
/** /// @copydoc VIEW_ITEM::Type()
* Function Type
* returns the type of object. This attribute should never be changed
* after a constructor sets it, so there is no public "setter" method.
* @return KICAD_T - the type of object.
*/
KICAD_T Type() const { return m_StructType; } KICAD_T Type() const { return m_StructType; }
void SetTimeStamp( time_t aNewTimeStamp ) { m_TimeStamp = aNewTimeStamp; } void SetTimeStamp( time_t aNewTimeStamp ) { m_TimeStamp = aNewTimeStamp; }
@ -479,6 +384,16 @@ public:
inline bool IsDragging() const { return m_Flags & IS_DRAGGED; } inline bool IsDragging() const { return m_Flags & IS_DRAGGED; }
inline bool IsSelected() const { return m_Flags & SELECTED; } inline bool IsSelected() const { return m_Flags & SELECTED; }
inline bool IsResized() const { return m_Flags & IS_RESIZED; } inline bool IsResized() const { return m_Flags & IS_RESIZED; }
inline bool IsHighlighted() const { return m_Flags & HIGHLIGHTED; }
inline bool IsBrightened() const { return m_Flags & BRIGHTENED; }
inline void SetSelected() { SetFlags( SELECTED ); ViewUpdate( COLOR ); }
inline void SetHighlighted() { SetFlags( HIGHLIGHTED ); ViewUpdate( COLOR ); }
inline void SetBrightened() { SetFlags( BRIGHTENED ); }
inline void ClearSelected() { ClearFlags( SELECTED ); ViewUpdate( COLOR ); }
inline void ClearHighlighted() { ClearFlags( HIGHLIGHTED ); ViewUpdate( COLOR ); }
inline void ClearBrightened() { ClearFlags( BRIGHTENED ); }
void SetModified(); void SetModified();
@ -748,6 +663,12 @@ public:
*/ */
virtual EDA_ITEM& operator=( const EDA_ITEM& aItem ); virtual EDA_ITEM& operator=( const EDA_ITEM& aItem );
/// @copydoc VIEW_ITEM::ViewBBox()
virtual const BOX2I ViewBBox() const;
/// @copydoc VIEW_ITEM::ViewGetLayers()
virtual void ViewGetLayers( int aLayers[], int& aCount ) const;
#if defined(DEBUG) #if defined(DEBUG)
/** /**

View File

@ -90,6 +90,10 @@ public:
// Do not create a copy constructor. The one generated by the compiler is adequate. // Do not create a copy constructor. The one generated by the compiler is adequate.
virtual const wxPoint& GetPosition() const = 0;
virtual void SetPosition( const wxPoint& aPos ) = 0;
/** /**
* A value of wxPoint(0,0) which can be passed to the Draw() functions. * A value of wxPoint(0,0) which can be passed to the Draw() functions.
*/ */
@ -269,6 +273,9 @@ public:
static std::string FormatInternalUnits( const wxPoint& aPoint ); static std::string FormatInternalUnits( const wxPoint& aPoint );
static std::string FormatInternalUnits( const wxSize& aSize ); static std::string FormatInternalUnits( const wxSize& aSize );
/// @copydoc VIEW_ITEM::ViewGetLayers()
virtual void ViewGetLayers( int aLayers[], int& aCount ) const;
}; };
#endif /* BOARD_ITEM_STRUCT_H */ #endif /* BOARD_ITEM_STRUCT_H */

View File

@ -317,6 +317,9 @@ public:
*/ */
void RefreshDrawingRect( const EDA_RECT& aRect, bool aEraseBackground = true ); void RefreshDrawingRect( const EDA_RECT& aRect, bool aEraseBackground = true );
/// @copydoc wxWindow::Refresh()
virtual void Refresh( bool eraseBackground = true, const wxRect* rect = NULL );
/** /**
* Function GetScreenCenterLogicalPosition * Function GetScreenCenterLogicalPosition
* @return The current screen center position in logical (drawing) units. * @return The current screen center position in logical (drawing) units.

View File

@ -0,0 +1,138 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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 class_drawpanel_gal.h:
* @brief EDA_DRAW_PANEL_GAL class definition.
*/
#ifndef PANELGAL_WXSTRUCT_H
#define PANELGAL_WXSTRUCT_H
#include <wx/wx.h>
#include <wx/window.h>
#include <math/vector2d.h>
class BOARD;
class TOOL_DISPATCHER;
namespace KIGFX
{
class GAL;
class VIEW;
class WX_VIEW_CONTROLS;
class VIEW_CONTROLS;
class PAINTER;
};
class EDA_DRAW_PANEL_GAL : public wxWindow
{
public:
enum GalType {
GAL_TYPE_NONE, ///< Not used
GAL_TYPE_OPENGL, ///< OpenGL implementation
GAL_TYPE_CAIRO, ///< Cairo implementation
};
EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWindowId, const wxPoint& aPosition,
const wxSize& aSize, GalType aGalType = GAL_TYPE_OPENGL );
~EDA_DRAW_PANEL_GAL();
/**
* Function SwitchBackend
* Switches method of rendering graphics.
* @param aGalType is a type of rendering engine that you want to use.
*/
void SwitchBackend( GalType aGalType );
/**
* Function GetGAL()
* Returns a pointer to the GAL instance used in the panel.
* @return The instance of GAL.
*/
KIGFX::GAL* GetGAL() const
{
return m_gal;
}
/**
* Function GetView()
* Returns a pointer to the VIEW instance used in the panel.
* @return The instance of VIEW.
*/
KIGFX::VIEW* GetView() const
{
return m_view;
}
/**
* Function GetViewControls()
* Returns a pointer to the VIEW_CONTROLS instance used in the panel.
* @return The instance of VIEW_CONTROLS.
*/
KIGFX::VIEW_CONTROLS* GetViewControls() const
{
return (KIGFX::VIEW_CONTROLS*)( m_viewControls );
}
/// @copydoc wxWindow::Refresh()
virtual void Refresh( bool eraseBackground = true, const wxRect* rect = NULL );
/**
* Function SetEventDispatcher()
* Sets a dispatcher that processes events and forwards them to tools.
* @param aEventDispatcher is the object that will be used for dispatching events.
*/
void SetEventDispatcher( TOOL_DISPATCHER* aEventDispatcher )
{
m_eventDispatcher = aEventDispatcher;
}
protected:
void onPaint( wxPaintEvent& WXUNUSED( aEvent ) );
void onSize( wxSizeEvent& aEvent );
void onEvent( wxEvent& aEvent );
void onEnter( wxEvent& aEvent );
void onRefreshTimer ( wxTimerEvent& aEvent );
void skipEvent( wxEvent& aEvent );
static const int MinRefreshPeriod = 17; ///< 60 FPS.
wxLongLong m_lastRefresh; ///< Last time the panel was refreshed
bool m_pendingRefresh;
wxTimer m_refreshTimer;
KIGFX::GAL* m_gal; ///< Interface for drawing objects on a 2D-surface
KIGFX::VIEW* m_view; ///< Stores view settings (scale, center, etc.)
///< and items to be drawn
KIGFX::PAINTER* m_painter; ///< Contains information about how to draw items
///< using GAL
KIGFX::WX_VIEW_CONTROLS* m_viewControls; ///< Control for VIEW (moving, zooming, etc.)
GalType m_currentGal; ///< Currently used GAL
TOOL_DISPATCHER* m_eventDispatcher; ///< Processes and forwards events to tools
};
#endif

View File

@ -6,7 +6,7 @@
#ifndef CLASS_WORKSHEET_DATA_ITEM_H #ifndef CLASS_WORKSHEET_DATA_ITEM_H
#define CLASS_WORKSHEET_DATA_ITEM_H #define CLASS_WORKSHEET_DATA_ITEM_H
#include <vector2d.h> #include <math/vector2d.h>
#include <eda_text.h> #include <eda_text.h>
#include <class_bitmap_base.h> #include <class_bitmap_base.h>

View File

@ -139,6 +139,14 @@ EDA_COLOR_T ColorByName( const wxChar *aName );
/// Find the nearest color match /// Find the nearest color match
EDA_COLOR_T ColorFindNearest( const wxColour &aColor ); EDA_COLOR_T ColorFindNearest( const wxColour &aColor );
/**
* Find the nearest color match
* @param aR is the red component of the color to be matched (in range 0-255)
* @param aG is the green component of the color to be matched (in range 0-255)
* @param aG is the blue component of the color to be matched (in range 0-255)
*/
EDA_COLOR_T ColorFindNearest( int aR, int aG, int aB );
/** /**
* Check if a color is light i.e. if black would be more readable than * Check if a color is light i.e. if black would be more readable than
* white on it * white on it

View File

@ -236,6 +236,8 @@ public:
* for single line text, aLine is unused * for single line text, aLine is unused
* If aLine == -1, the full area (considering all lines) is returned * If aLine == -1, the full area (considering all lines) is returned
* @param aThickness Overrides the current thickness when greater than 0. * @param aThickness Overrides the current thickness when greater than 0.
* this is needed when the current m_Thickness is 0 and a default line thickness
* is used
* @param aInvertY Invert the Y axis when calculating bounding box. * @param aInvertY Invert the Y axis when calculating bounding box.
*/ */
EDA_RECT GetTextBox( int aLine = -1, int aThickness = -1, bool aInvertY = false ) const; EDA_RECT GetTextBox( int aLine = -1, int aThickness = -1, bool aInvertY = false ) const;
@ -244,11 +246,11 @@ public:
* Function GetInterline * Function GetInterline
* return the distance between 2 text lines * return the distance between 2 text lines
* has meaning only for multiline texts * has meaning only for multiline texts
* @param aTextThickness Overrides the current thickness when greater than 0.
* this is needed when the current m_Thickness is 0 and a default line thickness
* is used
*/ */
int GetInterline() const int GetInterline( int aTextThickness = -1 ) const;
{
return (( m_Size.y * 14 ) / 10) + m_Thickness;
}
/** /**
* Function GetTextStyleName * Function GetTextStyleName
@ -286,15 +288,13 @@ private:
* @param aColor = text color * @param aColor = text color
* @param aDrawMode = GR_OR, GR_XOR.., -1 to use the current mode. * @param aDrawMode = GR_OR, GR_XOR.., -1 to use the current mode.
* @param aFillMode = LINE, FILLED or SKETCH * @param aFillMode = LINE, FILLED or SKETCH
* @param aAnchor_color = anchor color ( UNSPECIFIED_COLOR = do not draw anchor ).
* @param aText = the single line of text to draw. * @param aText = the single line of text to draw.
* @param aPos = the position of this line ). * @param aPos = the position of this line ).
*/ */
void drawOneLineOfText( EDA_RECT* aClipBox, wxDC* aDC, void drawOneLineOfText( EDA_RECT* aClipBox, wxDC* aDC,
const wxPoint& aOffset, EDA_COLOR_T aColor, const wxPoint& aOffset, EDA_COLOR_T aColor,
GR_DRAWMODE aDrawMode, EDA_DRAW_MODE_T aFillMode, GR_DRAWMODE aDrawMode, EDA_DRAW_MODE_T aFillMode,
EDA_COLOR_T aAnchor_color, wxString& aText, wxString& aText, wxPoint aPos );
wxPoint aPos );
}; };

View File

@ -21,9 +21,9 @@
#define WIN_STRING_DIR_SEP wxT( "\\" ) #define WIN_STRING_DIR_SEP wxT( "\\" )
#ifdef DEBUG #ifdef DEBUG
#define D(x) x #define DBG(x) x
#else #else
#define D(x) // nothing #define DBG(x) // nothing
#endif #endif
/** /**

View File

@ -0,0 +1,127 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 cairo_compositor.h
* @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
* later compositing into a single image (Cairo flavour).
*/
#ifndef CAIRO_COMPOSITOR_H_
#define CAIRO_COMPOSITOR_H_
#include <gal/compositor.h>
#include <cairo.h>
#include <boost/smart_ptr/shared_array.hpp>
#include <deque>
namespace KIGFX
{
class CAIRO_COMPOSITOR : public COMPOSITOR
{
public:
CAIRO_COMPOSITOR( cairo_t** aMainContext );
virtual ~CAIRO_COMPOSITOR();
/// @copydoc COMPOSITOR::Initialize()
virtual void Initialize();
/// @copydoc COMPOSITOR::Resize()
virtual void Resize( unsigned int aWidth, unsigned int aHeight );
/// @copydoc COMPOSITOR::CreateBuffer()
virtual unsigned int CreateBuffer();
/// @copydoc COMPOSITOR::GetBuffer()
inline virtual unsigned int GetBuffer() const
{
return m_current + 1;
}
/// @copydoc COMPOSITOR::SetBuffer()
virtual void SetBuffer( unsigned int aBufferHandle );
/// @copydoc COMPOSITOR::ClearBuffer()
virtual void ClearBuffer();
/// @copydoc COMPOSITOR::DrawBuffer()
virtual void DrawBuffer( unsigned int aBufferHandle );
/**
* Function SetMainContext()
* Sets a context to be treated as the main context (ie. as a target of buffers rendering and
* as a source of settings for newly created buffers).
*
* @param aMainContext is the context that should be treated as the main one.
*/
inline virtual void SetMainContext( cairo_t* aMainContext )
{
m_mainContext = aMainContext;
// Use the context's transformation matrix
cairo_get_matrix( m_mainContext, &m_matrix );
}
protected:
typedef boost::shared_array<unsigned int> BitmapPtr;
typedef struct
{
cairo_t* context; ///< Main texture handle
cairo_surface_t* surface; ///< Point to which an image from texture is attached
BitmapPtr bitmap; ///< Pixel storage
} CAIRO_BUFFER;
unsigned int m_current; ///< Currently used buffer handle
typedef std::deque<CAIRO_BUFFER> CAIRO_BUFFERS;
/// Pointer to the current context, so it can be changed
cairo_t** m_currentContext;
/// Rendering target used for compositing (the main display)
cairo_t* m_mainContext;
/// Transformation matrix
cairo_matrix_t m_matrix;
/// Stores information about initialized buffers
CAIRO_BUFFERS m_buffers;
unsigned int m_stride; ///< Stride to use given the desired format and width
unsigned int m_bufferSize; ///< Amount of memory needed to store a buffer
/**
* Function clean()
* performs freeing of resources.
*/
void clean();
/// Returns number of currently used buffers
unsigned int usedBuffers()
{
return m_buffers.size();
}
};
} // namespace KIGFX
#endif /* COMPOSITOR_H_ */

View File

@ -0,0 +1,392 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* CairoGal - Graphics Abstraction Layer for Cairo
*
* 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
*/
#ifndef CAIROGAL_H_
#define CAIROGAL_H_
#include <map>
#include <iterator>
#include <cairo.h>
#include <gal/graphics_abstraction_layer.h>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <wx/dcbuffer.h>
#if defined(__WXMSW__)
#define SCREEN_DEPTH 24
#else
#if wxCHECK_VERSION( 2, 9, 0 )
#define SCREEN_DEPTH wxBITMAP_SCREEN_DEPTH
#else
#define SCREEN_DEPTH 32
#endif
#endif
/**
* @brief Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
*
* Quote from Wikipedia:
* " Cairo is a software library used to provide a vector graphics-based, device-independent
* API for software developers. It is designed to provide primitives for 2-dimensional
* drawing across a number of different backends. "
* <br>
* Cairo offers also backends for Postscript and PDF surfaces. So it can be used for printing
* of KiCad graphics surfaces as well.
*
*/
namespace KIGFX
{
class CAIRO_COMPOSITOR;
class CAIRO_GAL : public GAL, public wxWindow
{
public:
/**
* Constructor CAIRO_GAL
*
* @param aParent is the wxWidgets immediate wxWindow parent of this object.
*
* @param aMouseListener is the wxEvtHandler that should receive the mouse events,
* this can be can be any wxWindow, but is often a wxFrame container.
*
* @param aPaintListener is the wxEvtHandler that should receive the paint
* event. This can be any wxWindow, but is often a derived instance
* of this class or a containing wxFrame. The "paint event" here is
* a wxCommandEvent holding EVT_GAL_REDRAW, as sent by PostPaint().
*
* @param aName is the name of this window for use by wxWindow::FindWindowByName()
*/
CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener = NULL,
wxEvtHandler* aPaintListener = NULL, const wxString& aName = wxT( "CairoCanvas" ) );
virtual ~CAIRO_GAL();
// ---------------
// Drawing methods
// ---------------
/// @copydoc GAL::BeginDrawing()
virtual void BeginDrawing();
/// @copydoc GAL::EndDrawing()
virtual void EndDrawing();
/// @copydoc GAL::DrawLine()
virtual void DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
/// @copydoc GAL::DrawSegment()
virtual void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth );
/// @copydoc GAL::DrawCircle()
virtual void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius );
/// @copydoc GAL::DrawArc()
virtual void DrawArc( const VECTOR2D& aCenterPoint, double aRadius,
double aStartAngle, double aEndAngle );
/// @copydoc GAL::DrawRectangle()
virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
/// @copydoc GAL::DrawPolyline()
virtual void DrawPolyline( std::deque<VECTOR2D>& aPointList );
/// @copydoc GAL::DrawPolygon()
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList );
/// @copydoc GAL::DrawCurve()
virtual void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
const VECTOR2D& controlPointB, const VECTOR2D& endPoint );
// --------------
// Screen methods
// --------------
/// @brief Resizes the canvas.
virtual void ResizeScreen( int aWidth, int aHeight );
/// @brief Shows/hides the GAL canvas
virtual bool Show( bool aShow );
/// @copydoc GAL::Flush()
virtual void Flush();
/// @copydoc GAL::ClearScreen()
virtual void ClearScreen();
// -----------------
// Attribute setting
// -----------------
/// @copydoc GAL::SetIsFill()
virtual void SetIsFill( bool aIsFillEnabled );
/// @copydoc GAL::SetIsStroke()
virtual void SetIsStroke( bool aIsStrokeEnabled );
/// @copydoc GAL::SetStrokeColor()
virtual void SetStrokeColor( const COLOR4D& aColor );
/// @copydoc GAL::SetFillColor()
virtual void SetFillColor( const COLOR4D& aColor );
/// @copydoc GAL::SetLineWidth()
virtual void SetLineWidth( double aLineWidth );
/// @copydoc GAL::SetLayerDepth()
virtual void SetLayerDepth( double aLayerDepth );
// --------------
// Transformation
// --------------
/// @copydoc GAL::Transform()
virtual void Transform( MATRIX3x3D aTransformation );
/// @copydoc GAL::Rotate()
virtual void Rotate( double aAngle );
/// @copydoc GAL::Translate()
virtual void Translate( const VECTOR2D& aTranslation );
/// @copydoc GAL::Scale()
virtual void Scale( const VECTOR2D& aScale );
/// @copydoc GAL::Save()
virtual void Save();
/// @copydoc GAL::Restore()
virtual void Restore();
// --------------------------------------------
// Group methods
// ---------------------------------------------
/// @copydoc GAL::BeginGroup()
virtual int BeginGroup();
/// @copydoc GAL::EndGroup()
virtual void EndGroup();
/// @copydoc GAL::DrawGroup()
virtual void DrawGroup( int aGroupNumber );
/// @copydoc GAL::ChangeGroupColor()
virtual void ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor );
/// @copydoc GAL::ChangeGroupDepth()
virtual void ChangeGroupDepth( int aGroupNumber, int aDepth );
/// @copydoc GAL::DeleteGroup()
virtual void DeleteGroup( int aGroupNumber );
/// @copydoc GAL::ClearCache()
virtual void ClearCache();
// --------------------------------------------------------
// Handling the world <-> screen transformation
// --------------------------------------------------------
/// @copydoc GAL::SaveScreen()
virtual void SaveScreen();
/// @copydoc GAL::RestoreScreen()
virtual void RestoreScreen();
/// @copydoc GAL::SetTarget()
virtual void SetTarget( RENDER_TARGET aTarget );
/// @copydoc GAL::GetTarget()
virtual RENDER_TARGET GetTarget() const;
/// @copydoc GAL::ClearTarget()
virtual void ClearTarget( RENDER_TARGET aTarget );
// -------
// Cursor
// -------
/// @copydoc GAL::DrawCursor()
virtual void DrawCursor( const VECTOR2D& aCursorPosition );
/**
* Function PostPaint
* posts an event to m_paint_listener. A post is used so that the actual drawing
* function can use a device context type that is not specific to the wxEVT_PAINT event.
*/
void PostPaint()
{
if( paintListener )
{
wxPaintEvent redrawEvent;
wxPostEvent( paintListener, redrawEvent );
}
}
void SetMouseListener( wxEvtHandler* aMouseListener )
{
mouseListener = aMouseListener;
}
void SetPaintListener( wxEvtHandler* aPaintListener )
{
paintListener = aPaintListener;
}
protected:
virtual void drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
private:
/// Super class definition
typedef GAL super;
// Compositing variables
boost::shared_ptr<CAIRO_COMPOSITOR> compositor; ///< Object for layers compositing
unsigned int mainBuffer; ///< Handle to the main buffer
unsigned int overlayBuffer; ///< Handle to the overlay buffer
RENDER_TARGET currentTarget; ///< Current rendering target
bool validCompositor; ///< Compositor initialization flag
// Variables related to wxWidgets
wxWindow* parentWindow; ///< Parent window
wxEvtHandler* mouseListener; ///< Mouse listener
wxEvtHandler* paintListener; ///< Paint listener
unsigned int bufferSize; ///< Size of buffers cairoOutput, bitmapBuffers
unsigned char* wxOutput; ///< wxImage comaptible buffer
// Cursor variables
std::deque<wxColour> savedCursorPixels; ///< Saved pixels of the cursor
bool isDeleteSavedPixels; ///< True, if the saved pixels can be discarded
wxPoint savedCursorPosition; ///< The last cursor position
wxBitmap* cursorPixels; ///< Cursor pixels
wxBitmap* cursorPixelsSaved; ///< Saved cursor pixels
int cursorSize; ///< Cursor size
VECTOR2D cursorPosition; ///< Current cursor position
/// Maximum number of arguments for one command
static const int MAX_CAIRO_ARGUMENTS = 6;
/// Definitions for the command recorder
enum GRAPHICS_COMMAND
{
CMD_SET_FILL, ///< Enable/disable filling
CMD_SET_STROKE, ///< Enable/disable stroking
CMD_SET_FILLCOLOR, ///< Set the fill color
CMD_SET_STROKECOLOR, ///< Set the stroke color
CMD_SET_LINE_WIDTH, ///< Set the line width
CMD_STROKE_PATH, ///< Set the stroke path
CMD_FILL_PATH, ///< Set the fill path
CMD_TRANSFORM, ///< Transform the actual context
CMD_ROTATE, ///< Rotate the context
CMD_TRANSLATE, ///< Translate the context
CMD_SCALE, ///< Scale the context
CMD_SAVE, ///< Save the transformation matrix
CMD_RESTORE, ///< Restore the transformation matrix
CMD_CALL_GROUP ///< Call a group
};
/// Type definition for an graphics group element
typedef struct
{
GRAPHICS_COMMAND command; ///< Command to execute
double arguments[MAX_CAIRO_ARGUMENTS]; ///< Arguments for Cairo commands
bool boolArgument; ///< A bool argument
int intArgument; ///< An int argument
cairo_path_t* cairoPath; ///< Pointer to a Cairo path
} GROUP_ELEMENT;
// Variables for the grouping function
bool isGrouping; ///< Is grouping enabled ?
bool isElementAdded; ///< Was an graphic element added ?
typedef std::deque<GROUP_ELEMENT> GROUP; ///< A graphic group type definition
std::map<int, GROUP> groups; ///< List of graphic groups
unsigned int groupCounter; ///< Counter used for generating keys for groups
GROUP* currentGroup; ///< Currently used group
// Variables related to Cairo <-> wxWidgets
cairo_matrix_t cairoWorldScreenMatrix; ///< Cairo world to screen transformation matrix
cairo_t* currentContext; ///< Currently used Cairo context for drawing
cairo_t* context; ///< Cairo image
cairo_surface_t* surface; ///< Cairo surface
unsigned int* bitmapBuffer; ///< Storage of the cairo image
unsigned int* bitmapBufferBackup; ///< Backup storage of the cairo image
int stride; ///< Stride value for Cairo
bool isInitialized; ///< Are Cairo image & surface ready to use
// Methods
void storePath(); ///< Store the actual path
// Event handlers
/**
* @brief Paint event handler.
*
* @param aEvent is the paint event.
*/
void onPaint( wxPaintEvent& aEvent );
/**
* @brief Mouse event handler, forwards the event to the child.
*
* @param aEvent is the mouse event to be forwarded.
*/
void skipMouseEvent( wxMouseEvent& aEvent );
/// @copydoc GAL::initCursor()
virtual void initCursor( int aCursorSize );
/**
* @brief Blits cursor into the current screen.
*/
virtual void blitCursor( wxBufferedDC& clientDC );
/// Prepare Cairo surfaces for drawing
void initSurface();
/// Destroy Cairo surfaces when are not needed anymore
void deinitSurface();
/// Allocate the bitmaps for drawing
void allocateBitmaps();
/// Allocate the bitmaps for drawing
void deleteBitmaps();
/// Prepare the compositor
void setCompositor();
/**
* @brief Returns a valid key that can be used as a new group number.
*
* @return An unique group number that is not used by any other group.
*/
unsigned int getNewGroupNumber();
/// Format used to store pixels
static const cairo_format_t GAL_FORMAT = CAIRO_FORMAT_RGB24;
};
} // namespace KIGFX
#endif // CAIROGAL_H_

222
include/gal/color4d.h Normal file
View File

@ -0,0 +1,222 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* Color class
*
* 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
*/
#ifndef COLOR4D_H_
#define COLOR4D_H_
#include <colors.h>
#include <cassert>
namespace KIGFX
{
/**
* Class COLOR4D
* is the color representation with 4 components: red, green, blue, alpha.
*/
class COLOR4D
{
public:
// Constructor (creates the Color 0,0,0,0)
COLOR4D() :
r( 0 ), g( 0 ), b( 0 ), a( 1 )
{
}
/**
* @brief Constructor
*
* @param aRed is the red component [0.0 .. 1.0].
* @param aGreen is the green component [0.0 .. 1.0].
* @param aBlue is the blue component [0.0 .. 1.0].
* @param aAlpha is the alpha value [0.0 .. 1.0].
*/
COLOR4D( double aRed, double aGreen, double aBlue, double aAlpha ) :
r( aRed ), g( aGreen ), b( aBlue ), a( aAlpha )
{
assert( r >= 0.0 && r <= 1.0 );
assert( g >= 0.0 && g <= 1.0 );
assert( b >= 0.0 && b <= 1.0 );
assert( a >= 0.0 && a <= 1.0 );
}
/**
* @brief Constructor
*
* @param aColor is one of KiCad's palette colors.
* @see EDA_COLOR_T
*/
COLOR4D( EDA_COLOR_T aColor );
#ifdef WX_COMPATIBILITY
/**
* @brief Constructor
*
* @param aColor is the color type used by wxWidgets.
*/
COLOR4D( const wxColour& aColor );
#endif /* WX_COMPATIBLITY */
/**
* Function Brighten
* Makes the color brighter by a given factor.
* @param aFactor Specifies how bright the color should become (valid values: 0.0 .. 1.0).
* @return COLOR4D& Brightened color.
*/
COLOR4D& Brighten( double aFactor )
{
assert( aFactor >= 0.0 && aFactor <= 1.0 );
r = r * ( 1.0 - aFactor ) + aFactor;
g = g * ( 1.0 - aFactor ) + aFactor;
b = b * ( 1.0 - aFactor ) + aFactor;
return *this;
}
/**
* Function Darken
* Makes the color darker by a given factor.
* @param aFactor Specifies how dark the color should become (valid values: 0.0 .. 1.0).
* @return COLOR4D& Darkened color.
*/
COLOR4D& Darken( double aFactor )
{
assert( aFactor >= 0.0 && aFactor <= 1.0 );
r = r * ( 1.0 - aFactor );
g = g * ( 1.0 - aFactor );
b = b * ( 1.0 - aFactor );
return *this;
}
/**
* Function Invert
* Makes the color inverted, alpha remains the same.
* @return COLOR4D& Inverted color.
*/
COLOR4D& Invert()
{
r = ( 1.0 - r );
g = ( 1.0 - g );
b = ( 1.0 - b );
return *this;
}
/**
* Saturates the color to a given factor (in HSV model)
*/
COLOR4D& Saturate( double aFactor );
/**
* Function Brightened
* Returns a color that is brighter by a given factor, without modifying object.
* @param aFactor Specifies how bright the color should become (valid values: 0.0 .. 1.0).
* @return COLOR4D Highlightedd color.
*/
COLOR4D Brightened( double aFactor ) const
{
assert( aFactor >= 0.0 && aFactor <= 1.0 );
return COLOR4D( r * ( 1.0 - aFactor ) + aFactor,
g * ( 1.0 - aFactor ) + aFactor,
b * ( 1.0 - aFactor ) + aFactor,
a );
}
/**
* Function Darkened
* Returns a color that is darker by a given factor, without modifying object.
* @param aFactor Specifies how dark the color should become (valid values: 0.0 .. 1.0).
* @return COLOR4D Darkened color.
*/
COLOR4D Darkened( double aFactor ) const
{
assert( aFactor >= 0.0 && aFactor <= 1.0 );
return COLOR4D( r * ( 1.0 - aFactor ),
g * ( 1.0 - aFactor ),
b * ( 1.0 - aFactor ),
a );
}
/**
* Function Inverted
* Returns an inverted color, alpha remains the same.
* @return COLOR4D& Inverted color.
*/
COLOR4D Inverted() const
{
return COLOR4D( 1.0 - r, 1.0 - g, 1.0 - b, a );
}
/**
* Function GetBrightness
* Returns the brightness value of the color ranged from 0.0 to 1.0.
* @return The brightness value.
*/
double GetBrightness() const
{
// Weighted W3C formula
return r * 0.299 + g * 0.587 + b * 0.117;
}
/**
* Function ToHSV()
* Converts current color (stored in RGB) to HSV format.
*
* @param aOutH is conversion result for hue component.
* @param aOutS is conversion result for saturation component.
* @param aOutV is conversion result for value component.
*/
void ToHSV( double& aOutH, double& aOutS, double& aOutV ) const;
/**
* Function FromHSV()
* Changes currently used color to the one given by hue, saturation and value parameters.
*
* @param aOutH is hue component.
* @param aOutS is saturation component.
* @param aOutV is value component.
*/
void FromHSV( double aInH, double aInS, double aInV );
/// @brief Equality operator, are two colors equal
const bool operator==( const COLOR4D& aColor );
/// @brief Not equality operator, are two colors not equal
const bool operator!=( const COLOR4D& aColor );
// Color components: red, green, blue, alpha
double r; ///< Red component
double g; ///< Green component
double b; ///< Blue component
double a; ///< Alpha component
};
} // namespace KIGFX
#endif /* COLOR4D_H_ */

106
include/gal/compositor.h Normal file
View File

@ -0,0 +1,106 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 compositor.h
* @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
* later compositing into a single image.
*/
#ifndef COMPOSITOR_H_
#define COMPOSITOR_H_
namespace KIGFX
{
class COMPOSITOR
{
public:
virtual ~COMPOSITOR()
{
}
/**
* Function Reset()
* performs primary initialiation, necessary to use the object.
*/
virtual void Initialize() = 0;
/**
* Function Resize()
* clears the state of COMPOSITOR, so it has to be reinitialized again with the new dimensions.
*
* @param aWidth is the framebuffer width (in pixels).
* @param aHeight is the framebuffer height (in pixels).
*/
virtual void Resize( unsigned int aWidth, unsigned int aHeight ) = 0;
/**
* Function CreateBuffer()
* prepares a new buffer that may be used as a rendering target.
*
* @return is the handle of the buffer. In case of failure 0 (zero) is returned as the handle.
*/
virtual unsigned int CreateBuffer() = 0;
/**
* Function GetBuffer()
* returns currently used buffer handle.
*
* @return Currently used buffer handle.
*/
virtual unsigned int GetBuffer() const = 0;
/**
* Function SetBuffer()
* sets the selected buffer as the rendering target. All the following drawing functions are
* going to be rendered in the selected buffer.
*
* @param aBufferHandle is the handle of the buffer or 0 in case of rendering directly to the
* display.
*/
virtual void SetBuffer( unsigned int aBufferHandle ) = 0;
/**
* Function ClearBuffer()
* clears the selected buffer (set by the SetBuffer() function).
*/
virtual void ClearBuffer() = 0;
/**
* Function DrawBuffer()
* draws the selected buffer on the screen.
*
* @param aBufferHandle is the handle of the buffer to be drawn.
*/
virtual void DrawBuffer( unsigned int aBufferHandle ) = 0;
protected:
unsigned int m_width; ///< Width of the buffer (in pixels)
unsigned int m_height; ///< Height of the buffer (in pixels)
};
} // namespace KIGFX
#endif /* COMPOSITOR_H_ */

48
include/gal/definitions.h Normal file
View File

@ -0,0 +1,48 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* Macro definitions
*
* 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
*/
#ifndef DEFINITIONS_H_
#define DEFINITIONS_H_
/// Swap the variables if a condition is met.
#define SWAP( varA, condition, varB ) if( varA condition varB ) { double tmp = varA; varA = varB; \
varB = tmp; }
namespace KIGFX
{
/**
* RENDER_TARGET: Possible rendering targets
*/
enum RENDER_TARGET
{
TARGET_CACHED = 0, ///< Main rendering target (cached)
TARGET_NONCACHED, ///< Auxiliary rendering target (noncached)
TARGET_OVERLAY, ///< Items that may change while the view stays the same (noncached)
TARGETS_NUMBER ///< Number of available rendering targets
};
} // namespace KIGFX
#endif /* DEFINITIONS_H_ */

View File

@ -0,0 +1,896 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
*
* Graphics Abstraction Layer (GAL) - base class
*
* 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
*/
#ifndef GRAPHICSABSTRACTIONLAYER_H_
#define GRAPHICSABSTRACTIONLAYER_H_
#include <deque>
#include <stack>
#include <limits>
#include <wx/event.h>
#include <math/matrix3x3.h>
#include <gal/color4d.h>
#include <gal/definitions.h>
#include <gal/stroke_font.h>
#include <newstroke_font.h>
namespace KIGFX
{
/**
* GridStyle: Type definition of the grid style
*/
enum GRID_STYLE
{
GRID_STYLE_LINES, ///< Use lines for the grid
GRID_STYLE_DOTS ///< Use dots for the grid
};
/**
* @brief Class GAL is the abstract interface for drawing on a 2D-surface.
*
* The functions are optimized for drawing shapes of an EDA-program such as KiCad. Most methods
* are abstract and need to be implemented by a lower layer, for example by a cairo or OpenGL implementation.
* <br>
* Almost all methods use world coordinates as arguments. The board design is defined in world space units;
* for drawing purposes these are transformed to screen units with this layer. So zooming is handled here as well.
*
*/
class GAL
{
public:
// Constructor / Destructor
GAL();
virtual ~GAL();
// ---------------
// Drawing methods
// ---------------
/// @brief Begin the drawing, needs to be called for every new frame.
virtual void BeginDrawing() = 0;
/// @brief End the drawing, needs to be called for every new frame.
virtual void EndDrawing() = 0;
/**
* @brief Draw a line.
*
* Start and end points are defined as 2D-Vectors.
*
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
*/
virtual void DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) = 0;
/**
* @brief Draw a rounded segment.
*
* Start and end points are defined as 2D-Vectors.
*
* @param aStartPoint is the start point of the segment.
* @param aEndPoint is the end point of the segment.
* @param aWidth is a width of the segment
*/
virtual void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) = 0;
/**
* @brief Draw a polyline
*
* @param aPointList is a list of 2D-Vectors containing the polyline points.
*/
virtual void DrawPolyline( std::deque<VECTOR2D>& aPointList ) = 0;
/**
* @brief Draw a circle using world coordinates.
*
* @param aCenterPoint is the center point of the circle.
* @param aRadius is the radius of the circle.
*/
virtual void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) = 0;
/**
* @brief Draw an arc.
*
* @param aCenterPoint is the center point of the arc.
* @param aRadius is the arc radius.
* @param aStartAngle is the start angle of the arc.
* @param aEndAngle is the end angle of the arc.
*/
virtual void
DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle ) = 0;
/**
* @brief Draw a rectangle.
*
* @param aStartPoint is the start point of the rectangle.
* @param aEndPoint is the end point of the rectangle.
*/
virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) = 0;
/**
* @brief Draw a polygon.
*
* @param aPointList is the list of the polygon points.
*/
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList ) = 0;
/**
* @brief Draw a cubic bezier spline.
*
* @param startPoint is the start point of the spline.
* @param controlPointA is the first control point.
* @param controlPointB is the second control point.
* @param endPoint is the end point of the spline.
*/
virtual void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
const VECTOR2D& controlPointB, const VECTOR2D& endPoint ) = 0;
// --------------
// Screen methods
// --------------
/// @brief Resizes the canvas.
virtual void ResizeScreen( int aWidth, int aHeight ) = 0;
/// @brief Shows/hides the GAL canvas
virtual bool Show( bool aShow ) = 0;
/// @brief Returns GAL canvas size in pixels
VECTOR2D GetScreenPixelSize() const
{
return screenSize;
}
/// @brief Force all remaining objects to be drawn.
virtual void Flush() = 0;
/// @brief Clear the screen.
virtual void ClearScreen() = 0;
// -----------------
// Attribute setting
// -----------------
/**
* @brief Enable/disable fill.
*
* @param aIsFillEnabled is true, when the graphics objects should be filled, else false.
*/
inline virtual void SetIsFill( bool aIsFillEnabled )
{
isFillEnabled = aIsFillEnabled;
}
/**
* @brief Enable/disable stroked outlines.
*
* @param aIsStrokeEnabled is true, if the outline of an object should be stroked.
*/
inline virtual void SetIsStroke( bool aIsStrokeEnabled )
{
isStrokeEnabled = aIsStrokeEnabled;
}
/**
* @brief Set the fill color.
*
* @param aColor is the color for filling.
*/
inline virtual void SetFillColor( const COLOR4D& aColor )
{
fillColor = aColor;
}
/**
* @brief Set the stroke color.
*
* @param aColor is the color for stroking the outline.
*/
inline virtual void SetStrokeColor( const COLOR4D& aColor )
{
strokeColor = aColor;
}
/**
* @brief Get the stroke color.
*
* @return the color for stroking the outline.
*/
inline COLOR4D GetStrokeColor()
{
return strokeColor;
}
/**
* @brief Set the background color.
*
* @param aColor is the color for background filling.
*/
inline virtual void SetBackgroundColor( const COLOR4D& aColor )
{
backgroundColor = aColor;
}
/**
* @brief Set the line width.
*
* @param aLineWidth is the line width.
*/
inline virtual void SetLineWidth( double aLineWidth )
{
lineWidth = aLineWidth;
}
/**
* @brief Get the line width.
*
* @return the actual line width.
*/
inline double GetLineWidth()
{
return lineWidth;
}
/**
* @brief Set the depth of the layer (position on the z-axis)
*
* @param aLayerDepth the layer depth for the objects.
*/
inline virtual void SetLayerDepth( double aLayerDepth )
{
layerDepth = aLayerDepth;
}
// ----
// Text
// ----
/**
* @brief Draws a vector type text using preloaded Newstroke font.
*
* @param aText is the text to be drawn.
* @param aPosition is the text position in world coordinates.
* @param aRotationAngle is the text rotation angle.
*/
inline virtual void StrokeText( const std::string& aText, const VECTOR2D& aPosition,
double aRotationAngle )
{
strokeFont.Draw( aText, aPosition, aRotationAngle );
}
/**
* @brief Loads attributes of the given text (bold/italic/underline/mirrored and so on).
*
* @param aText is the text item.
*/
virtual void SetTextAttributes( const EDA_TEXT* aText );
/// @copydoc STROKE_FONT::SetGlyphSize()
inline void SetGlyphSize( const VECTOR2D aGlyphSize )
{
strokeFont.SetGlyphSize( aGlyphSize );
}
/// @copydoc STROKE_FONT::SetBold()
inline void SetBold( const bool aBold )
{
strokeFont.SetBold( aBold );
}
/// @copydoc STROKE_FONT::SetItalic()
inline void SetItalic( const bool aItalic )
{
strokeFont.SetItalic( aItalic );
}
/// @copydoc STROKE_FONT::SetMirrored()
inline void SetMirrored( const bool aMirrored )
{
strokeFont.SetMirrored( aMirrored );
}
/// @copydoc STROKE_FONT::SetHorizontalJustify()
inline void SetHorizontalJustify( const EDA_TEXT_HJUSTIFY_T aHorizontalJustify )
{
strokeFont.SetHorizontalJustify( aHorizontalJustify );
}
/// @copydoc STROKE_FONT::SetVerticalJustify()
inline void SetVerticalJustify( const EDA_TEXT_VJUSTIFY_T aVerticalJustify )
{
strokeFont.SetVerticalJustify( aVerticalJustify );
}
// --------------
// Transformation
// --------------
/**
* @brief Transform the context.
*
* @param aTransformation is the ransformation matrix.
*/
virtual void Transform( MATRIX3x3D aTransformation ) = 0;
/**
* @brief Rotate the context.
*
* @param aAngle is the rotation angle in radians.
*/
virtual void Rotate( double aAngle ) = 0;
/**
* @brief Translate the context.
*
* @param aTranslation is the translation vector.
*/
virtual void Translate( const VECTOR2D& aTranslation ) = 0;
/**
* @brief Scale the context.
*
* @param aScale is the scale factor for the x- and y-axis.
*/
virtual void Scale( const VECTOR2D& aScale ) = 0;
/// @brief Save the context.
virtual void Save() = 0;
/// @brief Restore the context.
virtual void Restore() = 0;
// --------------------------------------------
// Group methods
// ---------------------------------------------
/**
* @brief Begin a group.
*
* A group is a collection of graphic items.
* Hierarchical groups are possible, attributes and transformations can be used.
*
* @return the number of the group.
*/
virtual int BeginGroup() = 0;
/// @brief End the group.
virtual void EndGroup() = 0;
/**
* @brief Draw the stored group.
*
* @param aGroupNumber is the group number.
*/
virtual void DrawGroup( int aGroupNumber ) = 0;
/**
* @brief Changes the color used to draw the group.
*
* @param aGroupNumber is the group number.
* @param aNewColor is the new color.
*/
virtual void ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor ) = 0;
/**
* @brief Changes the depth (Z-axis position) of the group.
*
* @param aGroupNumber is the group number.
* @param aDepth is the new depth.
*/
virtual void ChangeGroupDepth( int aGroupNumber, int aDepth ) = 0;
/**
* @brief Delete the group from the memory.
*
* @param aGroupNumber is the group number.
*/
virtual void DeleteGroup( int aGroupNumber ) = 0;
/**
* @brief Delete all data created during caching of graphic items.
*/
virtual void ClearCache() = 0;
// --------------------------------------------------------
// Handling the world <-> screen transformation
// --------------------------------------------------------
/// @brief Compute the world <-> screen transformation matrix
virtual void ComputeWorldScreenMatrix();
/**
* @brief Get the world <-> screen transformation matrix.
*
* @return the transformation matrix.
*/
MATRIX3x3D GetWorldScreenMatrix()
{
return worldScreenMatrix;
}
/**
* @brief Set the world <-> screen transformation matrix.
*
* @param aMatrix is the 3x3 world <-> screen transformation matrix.
*/
inline void SetWorldScreenMatrix( const MATRIX3x3D& aMatrix )
{
worldScreenMatrix = aMatrix;
}
/**
* @brief Set the unit length.
*
* This defines the length [inch] per one integer. For instance a value 0.001 means
* that the coordinate [1000, 1000] corresponds with a point at (1 inch, 1 inch) or
* 1 mil resolution per integer.
*
* @param aWorldUnitLength is the world Unit length.
*/
inline void SetWorldUnitLength( double aWorldUnitLength )
{
worldUnitLength = aWorldUnitLength;
}
/**
* @brief Set the dots per inch of the screen.
*
* This value depends on the user screen, it should be configurable by the application.
* For instance a typical notebook with HD+ resolution (1600x900) has 106 DPI.
*
* @param aScreenDPI are the screen DPI.
*/
inline void SetScreenDPI( double aScreenDPI )
{
screenDPI = aScreenDPI;
}
/**
* @brief Set the Point in world space to look at.
*
* This point corresponds with the center of the actual drawing area.
*
* @param aPoint is the look at point (center of the actual drawing area).
*/
inline void SetLookAtPoint( const VECTOR2D& aPoint )
{
lookAtPoint = aPoint;
}
/**
* @brief Get the look at point.
*
* @return the look at point.
*/
inline VECTOR2D GetLookAtPoint()
{
return lookAtPoint;
}
/**
* @brief Set the zoom factor of the scene.
*
* @param aZoomFactor is the zoom factor.
*/
inline void SetZoomFactor( double aZoomFactor )
{
zoomFactor = aZoomFactor;
}
/**
* @brief Get the zoom factor
*
* @return the zoom factor.
*/
inline double GetZoomFactor()
{
return zoomFactor;
}
/**
* @brief Set the range of the layer depth.
*
* Usually required for the OpenGL implementation, any object outside this range is not drawn.
*
* @param aDepthRange is the depth range where component x is the near clipping plane and y
* is the far clipping plane.
*/
inline void SetDepthRange( const VECTOR2D& aDepthRange )
{
depthRange = aDepthRange;
}
/**
* @brief Returns the minimum depth in the currently used range (the top).
*/
inline double GetMinDepth()
{
return depthRange.x;
}
/**
* @brief Returns the maximum depth in the currently used range (the bottom).
*/
inline double GetMaxDepth()
{
return depthRange.y;
}
/**
* @brief Get the world scale.
*
* @return the actual world scale factor.
*/
inline double GetWorldScale()
{
return worldScale;
}
/**
* @brief Sets flipping of the screen.
*
* @param xAxis is the flip flag for the X axis.
* @param yAxis is the flip flag for the Y axis.
*/
inline void SetFlip( bool xAxis, bool yAxis )
{
if( xAxis )
flipX = -1.0; // flipped
else
flipX = 1.0; // regular
if( yAxis )
flipY = -1.0; // flipped
else
flipY = 1.0; // regular
}
// ---------------------------
// Buffer manipulation methods
// ---------------------------
/**
* @brief Save the screen contents.
*/
virtual void SaveScreen() = 0;
/**
* @brief Restore the screen contents.
*/
virtual void RestoreScreen() = 0;
/**
* @brief Sets the target for rendering.
*
* @param aTarget is the new target for rendering.
*/
virtual void SetTarget( RENDER_TARGET aTarget ) = 0;
/**
* @brief Gets the currently used target for rendering.
*
* @return The current rendering target.
*/
virtual RENDER_TARGET GetTarget() const = 0;
/**
* @brief Clears the target for rendering.
*
* @param aTarget is the target to be cleared.
*/
virtual void ClearTarget( RENDER_TARGET aTarget ) = 0;
// -------------
// Grid methods
// -------------
/**
* @brief Sets the visibility setting of the grid.
*
* @param aVisibility is the new visibility setting of the grid.
*/
inline void SetGridVisibility( bool aVisibility )
{
gridVisibility = aVisibility;
}
/**
* @brief Set the origin point for the grid.
*
* @param aGridOrigin is a vector containing the grid origin point, in world coordinates.
*/
inline void SetGridOrigin( const VECTOR2D& aGridOrigin )
{
gridOrigin = aGridOrigin;
}
/**
* @brief Sets the screen size of the grid origin marker
*
* @param aSize is the radius of the origin marker, in pixels.
*/
inline void SetGridOriginMarkerSize( int aSize )
{
gridOriginMarkerSize = aSize;
}
/**
* @brief Set the threshold for grid drawing.
*
* @param aThreshold is the minimum grid cell size (in pixels) for which the grid is drawn.
*/
inline void SetGridDrawThreshold( int aThreshold )
{
gridDrawThreshold = aThreshold;
}
/**
* @brief Set the grid size.
*
* @param aGridSize is a vector containing the grid size in x and y direction.
*/
inline void SetGridSize( const VECTOR2D& aGridSize )
{
gridSize = aGridSize;
}
/**
* @brief Returns the grid size.
*
* @return A vector containing the grid size in x and y direction.
*/
inline const VECTOR2D& GetGridSize() const
{
return gridSize;
}
/**
* @brief Set the grid color.
*
* @param aGridColor is the grid color, it should have a low alpha value for the best effect.
*/
inline void SetGridColor( const COLOR4D& aGridColor )
{
gridColor = aGridColor;
}
/**
* @brief Draw every tick line wider.
*
* @param aInterval increase the width of every aInterval line, if 0 do not use this feature.
*/
inline void SetCoarseGrid( int aInterval )
{
gridTick = aInterval;
}
/**
* @brief Get the grid line width.
*
* @return the grid line width
*/
inline double GetGridLineWidth()
{
return gridLineWidth;
}
/**
* @brief Set the grid line width.
*
* @param aGridLineWidth is the rid line width.
*/
inline void SetGridLineWidth( double aGridLineWidth )
{
gridLineWidth = aGridLineWidth;
}
/// @brief Draw the grid
void DrawGrid();
/**
* Function GetGridPoint()
* For a given point it returns the nearest point belonging to the grid.
*
* @param aPoint is the point for which the grid point is searched.
* @return The nearest grid point.
*/
VECTOR2D GetGridPoint( VECTOR2D aPoint ) const;
/**
* @brief Change the grid display style.
*
* @param aGridStyle is the new style for grid.
*/
inline virtual void SetGridStyle( GRID_STYLE aGridStyle )
{
gridStyle = aGridStyle;
}
/**
* @brief Compute the point position in world coordinates from given screen coordinates.
*
* @param aPoint the pointposition in screen coordinates.
* @return the point position in world coordinates.
*/
inline virtual VECTOR2D ToWorld( const VECTOR2D& aPoint ) const
{
return VECTOR2D( screenWorldMatrix * aPoint );
}
/**
* @brief Compute the point position in screen coordinates from given world coordinates.
*
* @param aPoint the pointposition in world coordinates.
* @return the point position in screen coordinates.
*/
inline virtual VECTOR2D ToScreen( const VECTOR2D& aPoint ) const
{
return VECTOR2D( worldScreenMatrix * aPoint );
}
/**
* @brief Enable/Disable cursor.
*
* @param aIsCursorEnabled is true if the cursor should be enabled, else false.
*/
inline void SetCursorEnabled( bool aCursorEnabled )
{
isCursorEnabled = aCursorEnabled;
}
/**
* @brief Set the cursor color.
*
* @param aCursorColor is the color of the cursor.
*/
inline void SetCursorColor( const COLOR4D& aCursorColor )
{
cursorColor = aCursorColor;
}
/**
* @brief Set the cursor size.
*
* @param aCursorSize is the size of the cursor.
*/
inline void SetCursorSize( unsigned int aCursorSize )
{
cursorSize = aCursorSize;
}
/**
* @brief Draw the cursor.
*
* @param aCursorPosition is the cursor position in screen coordinates.
*/
virtual void DrawCursor( const VECTOR2D& aCursorPosition ) = 0;
/**
* @brief Changes the current depth to deeper, so it is possible to draw objects right beneath
* other.
*/
inline void AdvanceDepth()
{
layerDepth -= 0.001;
}
/**
* @brief Stores current drawing depth on the depth stack.
*/
inline void PushDepth()
{
depthStack.push( layerDepth );
}
/**
* @brief Restores previously stored drawing depth for the depth stack.
*/
inline void PopDepth()
{
layerDepth = depthStack.top();
depthStack.pop();
}
/// Depth level on which the grid is drawn
static const int GRID_DEPTH = 1024;
protected:
std::stack<double> depthStack; ///< Stored depth values
VECTOR2D screenSize; ///< Screen size in screen coordinates
double worldUnitLength; ///< The unit length of the world coordinates [inch]
double screenDPI; ///< The dots per inch of the screen
VECTOR2D lookAtPoint; ///< Point to be looked at in world space
double zoomFactor; ///< The zoom factor
MATRIX3x3D worldScreenMatrix; ///< World transformation
MATRIX3x3D screenWorldMatrix; ///< Screen transformation
double worldScale; ///< The scale factor world->screen
double flipX; ///< Flag for X axis flipping
double flipY; ///< Flag for Y axis flipping
double lineWidth; ///< The line width
bool isFillEnabled; ///< Is filling of graphic objects enabled ?
bool isStrokeEnabled; ///< Are the outlines stroked ?
COLOR4D backgroundColor; ///< The background color
COLOR4D fillColor; ///< The fill color
COLOR4D strokeColor; ///< The color of the outlines
double layerDepth; ///< The actual layer depth
VECTOR2D depthRange; ///< Range of the depth
// Grid settings
bool gridVisibility; ///< Should the grid be shown
GRID_STYLE gridStyle; ///< Grid display style
VECTOR2D gridSize; ///< The grid size
VECTOR2D gridOrigin; ///< The grid origin
COLOR4D gridColor; ///< Color of the grid
int gridTick; ///< Every tick line gets the double width
double gridLineWidth; ///< Line width of the grid
int gridDrawThreshold; ///< Minimum screen size of the grid (pixels)
///< below which the grid is not drawn
int gridOriginMarkerSize; ///< Grid origin indicator size (pixels)
bool isCursorEnabled; ///< Is the cursor enabled?
COLOR4D cursorColor; ///< Cursor color
int cursorSize; ///< Size of the cursor in pixels
/// Instance of object that stores information about how to draw texts
STROKE_FONT strokeFont;
/// Compute the scaling factor for the world->screen matrix
inline void ComputeWorldScale()
{
worldScale = screenDPI * worldUnitLength * zoomFactor;
}
/**
* @brief Draw a grid line (usually a simplified line function).
*
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
*/
virtual void drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) = 0;
/**
* @brief Initialize the cursor.
*
* @param aCursorSize is the size of the cursor.
*/
virtual void initCursor( int aCursorSize ) = 0;
static const int MIN_DEPTH = -2048;
static const int MAX_DEPTH = 2047;
};
} // namespace KIGFX
#endif /* GRAPHICSABSTRACTIONLAYER_H_ */

View File

@ -0,0 +1,178 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 cached_container.h
* @brief Class to store instances of VERTEX with caching. It allows storing VERTEX objects and
* associates them with VERTEX_ITEMs. This leads to a possibility of caching vertices data in the
* GPU memory and a fast reuse of that data.
*/
#ifndef CACHED_CONTAINER_H_
#define CACHED_CONTAINER_H_
#include <gal/opengl/vertex_container.h>
#include <map>
#include <set>
// Debug messages verbosity level
// #define CACHED_CONTAINER_TEST 1
namespace KIGFX
{
class VERTEX_ITEM;
class SHADER;
class CACHED_CONTAINER : public VERTEX_CONTAINER
{
public:
CACHED_CONTAINER( unsigned int aSize = defaultInitSize );
///> @copydoc VERTEX_CONTAINER::SetItem()
virtual void SetItem( VERTEX_ITEM* aItem );
///> @copydoc VERTEX_CONTAINER::FinishItem()
virtual void FinishItem();
///> @copydoc VERTEX_CONTAINER::Allocate()
virtual VERTEX* Allocate( unsigned int aSize );
///> @copydoc VERTEX_CONTAINER::Delete()
virtual void Delete( VERTEX_ITEM* aItem );
///> @copydoc VERTEX_CONTAINER::Clear()
virtual void Clear();
/**
* Function GetVertices()
* returns the vertices stored by the specific item.
*
* @param aItem is the item.
*/
virtual VERTEX* GetVertices( const VERTEX_ITEM* aItem ) const;
protected:
///> Maps size of free memory chunks to their offsets
typedef std::pair<unsigned int, unsigned int> CHUNK;
typedef std::multimap<unsigned int, unsigned int> FREE_CHUNK_MAP;
/// List of all the stored items
typedef std::set<VERTEX_ITEM*> ITEMS;
///> Stores size & offset of free chunks.
FREE_CHUNK_MAP m_freeChunks;
///> Stored VERTEX_ITEMs
ITEMS m_items;
///> Currently modified item
VERTEX_ITEM* m_item;
///> Properties of currently modified chunk & item
unsigned int m_chunkSize;
unsigned int m_chunkOffset;
unsigned int m_itemSize;
/**
* Function reallocate()
* resizes the chunk that stores the current item to the given size.
*
* @param aSize is the number of vertices to be stored.
* @return offset of the new chunk.
*/
virtual unsigned int reallocate( unsigned int aSize );
/**
* Function defragment()
* removes empty spaces between chunks, so after that there is a long continous space
* for storing vertices at the and of the container.
*
* @param aTarget is the already allocated destination for defragmented data. It has to be
* at least of the same size as the current container. If left NULL, it will be allocated
* inside the defragment() function.
* @return false in case of failure (eg. memory shortage)
*/
virtual bool defragment( VERTEX* aTarget = NULL );
/**
* Function mergeFreeChunks()
* looks for consecutive free memory chunks and merges them, decreasing fragmentation of
* memory.
*/
virtual void mergeFreeChunks();
/**
* Function resizeContainer()
*
* prepares a bigger container of a given size.
* @param aNewSize is the new size of container, expressed in vertices
* @return false in case of failure (eg. memory shortage)
*/
virtual bool resizeContainer( unsigned int aNewSize );
/**
* Function getPowerOf2()
* returns the nearest power of 2, bigger than aNumber.
*
* @param aNumber is the number for which we look for a bigger power of 2.
*/
unsigned int getPowerOf2( unsigned int aNumber ) const;
private:
/**
* Function getChunkSize()
* returns size of the given chunk.
*
* @param aChunk is the chunk.
*/
inline int getChunkSize( const CHUNK& aChunk ) const
{
return aChunk.first;
}
/**
* Function getChunkOffset()
* returns offset of the chunk.
*
* @param aChunk is the chunk.
*/
inline unsigned int getChunkOffset( const CHUNK& aChunk ) const
{
return aChunk.second;
}
/// Debug & test functions
#if CACHED_CONTAINER_TEST > 0
void showFreeChunks();
void showReservedChunks();
void test();
#else
inline void showFreeChunks() {}
inline void showReservedChunks() {}
inline void test() {}
#endif /* CACHED_CONTAINER_TEST */
};
} // namespace KIGFX
#endif /* CACHED_CONTAINER_H_ */

View File

@ -0,0 +1,475 @@
///////////////////////////////////////////////////////////////////////////////////
/// OpenGL Mathematics (glm.g-truc.net)
///
/// Copyright (c) 2005 - 2012 G-Truc Creation (www.g-truc.net)
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
/// THE SOFTWARE.
///
/// @ref core
/// @file glm/core/_detail.hpp
/// @date 2008-07-24 / 2011-06-14
/// @author Christophe Riccio
///////////////////////////////////////////////////////////////////////////////////
#ifndef glm_core_detail
#define glm_core_detail
#include "setup.hpp"
#include <cassert>
#if(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
#include <cstdint>
#endif
namespace glm{
namespace detail
{
class half;
#if(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) // C99 detected, 64 bit types available
typedef int64_t sint64;
typedef uint64_t uint64;
#elif(GLM_COMPILER & GLM_COMPILER_VC)
typedef signed __int64 sint64;
typedef unsigned __int64 uint64;
#elif(GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_LLVM_GCC | GLM_COMPILER_CLANG))
__extension__ typedef signed long long sint64;
__extension__ typedef unsigned long long uint64;
#elif(GLM_COMPILER & GLM_COMPILER_BC)
typedef Int64 sint64;
typedef Uint64 uint64;
#else//unknown compiler
typedef signed long long sint64;
typedef unsigned long long uint64;
#endif//GLM_COMPILER
template<bool C>
struct If
{
template<typename F, typename T>
static GLM_FUNC_QUALIFIER T apply(F functor, const T& val)
{
return functor(val);
}
};
template<>
struct If<false>
{
template<typename F, typename T>
static GLM_FUNC_QUALIFIER T apply(F, const T& val)
{
return val;
}
};
//template <typename T>
//struct traits
//{
// static const bool is_signed = false;
// static const bool is_float = false;
// static const bool is_vector = false;
// static const bool is_matrix = false;
// static const bool is_genType = false;
// static const bool is_genIType = false;
// static const bool is_genUType = false;
//};
//template <>
//struct traits<half>
//{
// static const bool is_float = true;
// static const bool is_genType = true;
//};
//template <>
//struct traits<float>
//{
// static const bool is_float = true;
// static const bool is_genType = true;
//};
//template <>
//struct traits<double>
//{
// static const bool is_float = true;
// static const bool is_genType = true;
//};
//template <typename genType>
//struct desc
//{
// typedef genType type;
// typedef genType * pointer;
// typedef genType const* const_pointer;
// typedef genType const *const const_pointer_const;
// typedef genType *const pointer_const;
// typedef genType & reference;
// typedef genType const& const_reference;
// typedef genType const& param_type;
// typedef typename genType::value_type value_type;
// typedef typename genType::size_type size_type;
// static const typename size_type value_size;
//};
//template <typename genType>
//const typename desc<genType>::size_type desc<genType>::value_size = genType::value_size();
union uif32
{
GLM_FUNC_QUALIFIER uif32() :
i(0)
{}
GLM_FUNC_QUALIFIER uif32(float f) :
f(f)
{}
GLM_FUNC_QUALIFIER uif32(unsigned int i) :
i(i)
{}
float f;
unsigned int i;
};
union uif64
{
GLM_FUNC_QUALIFIER uif64() :
i(0)
{}
GLM_FUNC_QUALIFIER uif64(double f) :
f(f)
{}
GLM_FUNC_QUALIFIER uif64(uint64 i) :
i(i)
{}
double f;
uint64 i;
};
typedef uif32 uif;
//////////////////
// int
template <typename T>
struct is_int
{
enum is_int_enum
{
_YES = 0,
_NO = 1
};
};
#define GLM_DETAIL_IS_INT(T) \
template <> \
struct is_int<T> \
{ \
enum is_int_enum \
{ \
_YES = 1, \
_NO = 0 \
}; \
}
//////////////////
// uint
template <typename T>
struct is_uint
{
enum is_uint_enum
{
_YES = 0,
_NO = 1
};
};
#define GLM_DETAIL_IS_UINT(T) \
template <> \
struct is_uint<T> \
{ \
enum is_uint_enum \
{ \
_YES = 1, \
_NO = 0 \
}; \
}
//GLM_DETAIL_IS_UINT(unsigned long long)
//////////////////
// float
template <typename T>
struct is_float
{
enum is_float_enum
{
_YES = 0,
_NO = 1
};
};
#define GLM_DETAIL_IS_FLOAT(T) \
template <> \
struct is_float<T> \
{ \
enum is_float_enum \
{ \
_YES = 1, \
_NO = 0 \
}; \
}
GLM_DETAIL_IS_FLOAT(detail::half);
GLM_DETAIL_IS_FLOAT(float);
GLM_DETAIL_IS_FLOAT(double);
GLM_DETAIL_IS_FLOAT(long double);
//////////////////
// bool
template <typename T>
struct is_bool
{
enum is_bool_enum
{
_YES = 0,
_NO = 1
};
};
template <>
struct is_bool<bool>
{
enum is_bool_enum
{
_YES = 1,
_NO = 0
};
};
//////////////////
// vector
template <typename T>
struct is_vector
{
enum is_vector_enum
{
_YES = 0,
_NO = 1
};
};
# define GLM_DETAIL_IS_VECTOR(TYPE) \
template <typename T> \
struct is_vector<TYPE<T> > \
{ \
enum is_vector_enum \
{ \
_YES = 1, \
_NO = 0 \
}; \
}
//////////////////
// matrix
template <typename T>
struct is_matrix
{
enum is_matrix_enum
{
_YES = 0,
_NO = 1
};
};
#define GLM_DETAIL_IS_MATRIX(T) \
template <> \
struct is_matrix \
{ \
enum is_matrix_enum \
{ \
_YES = 1, \
_NO = 0 \
}; \
}
//////////////////
// type
template <typename T>
struct type
{
enum type_enum
{
is_float = is_float<T>::_YES,
is_int = is_int<T>::_YES,
is_uint = is_uint<T>::_YES,
is_bool = is_bool<T>::_YES
};
};
//////////////////
// type
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef detail::sint64 int64;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef detail::uint64 uint64;
typedef detail::half float16;
typedef float float32;
typedef double float64;
//////////////////
// float_or_int_trait
struct float_or_int_value
{
enum
{
GLM_ERROR,
GLM_FLOAT,
GLM_INT
};
};
template <typename T>
struct float_or_int_trait
{
enum{ID = float_or_int_value::GLM_ERROR};
};
template <>
struct float_or_int_trait<int8>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<int16>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<int32>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<int64>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<uint8>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<uint16>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<uint32>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<uint64>
{
enum{ID = float_or_int_value::GLM_INT};
};
template <>
struct float_or_int_trait<float16>
{
enum{ID = float_or_int_value::GLM_FLOAT};
};
template <>
struct float_or_int_trait<float32>
{
enum{ID = float_or_int_value::GLM_FLOAT};
};
template <>
struct float_or_int_trait<float64>
{
enum{ID = float_or_int_value::GLM_FLOAT};
};
}//namespace detail
}//namespace glm
#if((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC2005))
# define GLM_DEPRECATED __declspec(deprecated)
# define GLM_ALIGN(x) __declspec(align(x))
# define GLM_ALIGNED_STRUCT(x) __declspec(align(x)) struct
# define GLM_RESTRICT __declspec(restrict)
# define GLM_RESTRICT_VAR __restrict
# define GLM_CONSTEXPR
#elif((GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_LLVM_GCC)) && (GLM_COMPILER >= GLM_COMPILER_GCC31))
# define GLM_DEPRECATED __attribute__((__deprecated__))
# define GLM_ALIGN(x) __attribute__((aligned(x)))
# define GLM_ALIGNED_STRUCT(x) struct __attribute__((aligned(x)))
# if(GLM_COMPILER >= GLM_COMPILER_GCC33)
# define GLM_RESTRICT __restrict__
# define GLM_RESTRICT_VAR __restrict__
# else
# define GLM_RESTRICT
# define GLM_RESTRICT_VAR
# endif
# define GLM_RESTRICT __restrict__
# define GLM_RESTRICT_VAR __restrict__
# if((GLM_COMPILER >= GLM_COMPILER_GCC47) && ((GLM_LANG & GLM_LANG_CXX0X) == GLM_LANG_CXX0X))
# define GLM_CONSTEXPR constexpr
# else
# define GLM_CONSTEXPR
# endif
#else
# define GLM_DEPRECATED
# define GLM_ALIGN
# define GLM_ALIGNED_STRUCT(x)
# define GLM_RESTRICT
# define GLM_RESTRICT_VAR
# define GLM_CONSTEXPR
#endif//GLM_COMPILER
#endif//glm_core_detail

Some files were not shown because too many files have changed in this diff Show More