Import Geant4 11.0.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2021-06-25 16:12:29 +02:00
parent c968e26a39
commit 6399a014b6
4200 changed files with 207479 additions and 237366 deletions
+12 -2
View File
@@ -17,9 +17,21 @@ if(NOT GEANT4_USE_SYSTEM_ZLIB)
add_subdirectory(zlib)
endif()
# - G4tools always built
add_subdirectory(g4tools)
# PTL requires additional pre and post inclusion steps as it's a true subproject
if(NOT GEANT4_USE_SYSTEM_PTL)
set(CMAKE_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}-${${PROJECT_NAME}_VERSION}/PTL)
set(PTL_USE_TBB ${GEANT4_USE_TBB})
if(NOT (GEANT4_BUILD_SANITIZER STREQUAL "none"))
set(PTL_USE_SANITIZER ON)
set(PTL_SANITIZER_TYPE ${GEANT4_BUILD_SANITIZER})
endif()
set(PTL_USE_LOCKS ${GEANT4_USE_PTL_LOCKS})
add_subdirectory(ptl)
# Needs to be in defined category list for static/shared to be linked correctly.
set_property(GLOBAL APPEND PROPERTY GEANT4_DEFINED_CATEGORIES G4ptl)
@@ -30,7 +42,6 @@ endif()
#
if(TARGET ptl-shared)
add_library(G4ptl INTERFACE)
add_library(PTL::ptl-shared ALIAS ptl-shared)
target_link_libraries(G4ptl INTERFACE PTL::ptl-shared)
install(TARGETS G4ptl
EXPORT Geant4LibraryDepends
@@ -43,7 +54,6 @@ endif()
if(TARGET ptl-static)
add_library(G4ptl-static INTERFACE)
add_library(PTL::ptl-static ALIAS ptl-static)
target_link_libraries(G4ptl-static INTERFACE PTL::ptl-static)
install(TARGETS G4ptl-static
EXPORT Geant4LibraryDepends
+3 -3
View File
@@ -1,6 +1,6 @@
# -----------------------------------------------------------------------
# GNUmakefile for Geant4 external packages
# Gunter Folger 26-April-2011
# Gunter Folger 26-April-2011
# -----------------------------------------------------------------------
MAKEFLAGS= --no-print-directory
@@ -13,8 +13,8 @@ endif
include $(G4INSTALL)/config/architecture.gmk
SUBDIRS :=
SUBLIBS :=
SUBDIRS := g4tools
SUBLIBS := G4tools
ifdef G4LIB_USE_PTL
SUBDIRS += ptl
+17 -2
View File
@@ -16,10 +16,25 @@ committal in the CVS repository !
* Reverse chronological order (last date on top), please *
----------------------------------------------------------
06 May 2021 - G.Cosmo (externals-V10-06-07)
03 June 2021, B. Morgan (externals-V10-07-05)
- PTL: Hide PTL_... options from clients building Geant4
- Forward relevant Geant4 options to PTL: TBB, sanitizer, locks
11 May 2021, J. Allison (externals-V10-07-04)
- g4tools-V10-07-03: Rename g4tools/include/tools/sg/gL_manager to GL_manager.
07 May 2021 - G.Cosmo (externals-V10-07-03)
- CLHEP: Updated values in SystemOfUnits.h and PhysicalConstants.h:
o Added units: minute, hour, day, year and millielectronvolt.
o Added constants: Bohr_magneton and nuclear_magneton.
06 May 2021 - G.Cosmo (externals-V10-07-02)
- CLHEP: Fixed trivial compilation warnings on gcc-11 in Random headers.
8 December 2020 - B.Morgan (externals-V10-06-06)
18 February 2021 - B.Morgan (externals-V10-07-01)
- Move g4tools from analysis to externals category
8 December 2020 - B.Morgan (externals-V10-07-00)
- Force PTL to install its CMake configuration files within the directory
where Geant4 installs its own.
- Force PTL to install its headers under CMAKE_INSTALL_INCLUDEDIR/Geant4
+7 -2
View File
@@ -16,12 +16,17 @@ committal in the CVS repository !
* Reverse chronological order (last date on top), please *
----------------------------------------------------------
07 May 2021 - G.Cosmo
- Units (M.Maire)
o Added in SystemOfUnits.h: minute, hour, day, year and millielectronvolt.
o Added in PhysicalConstants.h: Bohr_magneton and nuclear_magneton.
06 May 2021 - G.Cosmo
- Fixed trivial compilation warnings on gcc-11 in Random headers.
11 November 2020 - G.Cosmo
- Synchronised with CLHEP-2.4.4.0:
* Vector (G.Amadio <amadio@cern.ch>)
* Vector (G.Amadio)
o Removed obsolete #pragma interface/implementation
These pragmas are obsolete since GCC 2.7.2.
https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Interface.html.
@@ -34,7 +39,7 @@ committal in the CVS repository !
This is in preparation to change the data layout of Hep3Vector
by replacing the private dx/dy/dz members with a vector, data[3],
to allow us to remove the inefficient switch from operator[]().
* Vector, Random (V.Vassilev <v.g.vassilev@gmail.com>)
* Vector, Random (V.Vassilev)
o Added missing includes for translation unit encapsulation.
17 July 2020 - G.Cosmo
@@ -32,9 +32,10 @@
// 23.02.96 Created
// 26.03.96 Added constants for standard conditions of temperature
// and pressure; also added Gas threshold.
// 29.04.08 use PDG 2006 values
// 03.11.08 use PDG 2008 values
// 17.07.20 use PDG 2019 values
// 29.04.08 Use PDG 2006 values
// 03.11.08 Use PDG 2008 values
// 17.07.20 Use PDG 2019 values
// 06.05.21 Added Bohr_magneton and nuclear_magneton constants
#ifndef HEP_PHYSICAL_CONSTANTS_H
#define HEP_PHYSICAL_CONSTANTS_H
@@ -105,6 +106,10 @@ static constexpr double alpha_rcl2 = fine_structure_const
static constexpr double twopi_mc2_rcl2 = twopi*electron_mass_c2
*classic_electr_radius
*classic_electr_radius;
static constexpr double Bohr_magneton = (eplus*hbarc*c_light)/(2*electron_mass_c2);
static constexpr double nuclear_magneton = (eplus*hbarc*c_light)/(2*proton_mass_c2);
//
//
//
+8 -1
View File
@@ -42,6 +42,7 @@
// 19.08.15 added liter and its sub units (mma)
// 12.01.16 added symbols for microsecond (us) and picosecond (ps) (mma)
// 17.07.20 use PDG 2019 value of e_SI
// 06.05.21 added minute, hour, day, year and millielectronvolt (mma)
#ifndef HEP_SYSTEM_OF_UNITS_H
#define HEP_SYSTEM_OF_UNITS_H
@@ -138,7 +139,12 @@ namespace CLHEP {
static constexpr double second = 1.e+9 *nanosecond;
static constexpr double millisecond = 1.e-3 *second;
static constexpr double microsecond = 1.e-6 *second;
static constexpr double picosecond = 1.e-12*second;
static constexpr double picosecond = 1.e-12*second;
static constexpr double minute = 60*second;
static constexpr double hour = 60*minute;
static constexpr double day = 24*hour;
static constexpr double year = 365*day;
static constexpr double hertz = 1./second;
static constexpr double kilohertz = 1.e+3*hertz;
@@ -167,6 +173,7 @@ namespace CLHEP {
static constexpr double gigaelectronvolt = 1.e+3*megaelectronvolt;
static constexpr double teraelectronvolt = 1.e+6*megaelectronvolt;
static constexpr double petaelectronvolt = 1.e+9*megaelectronvolt;
static constexpr double millielectronvolt = 1.e-9*megaelectronvolt;
static constexpr double joule = electronvolt/e_SI;// joule = 6.24150 e+12 * MeV
+22
View File
@@ -0,0 +1,22 @@
# - Build for G4tools as an "external"
# It can be built as a standard module, but we don't declare the headers
# so that their nested structure can be retained on install
geant4_add_module(G4tools SOURCES csz_inflate.cc)
geant4_add_category(G4tools MODULES G4tools)
#-----------------------------------------------------------------------
# Custom install of (nested) headers and license
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
COMPONENT Development
)
install(FILES tools.license DESTINATION ${CMAKE_INSTALL_DATADIR})
#-----------------------------------------------------------------------
# Install fonts
#
if(GEANT4_USE_FREETYPE)
install(DIRECTORY fonts/ DESTINATION ${CMAKE_INSTALL_DATADIR}/fonts)
endif()
+13
View File
@@ -0,0 +1,13 @@
# --------------------------------------------------------------------
# GNUmakefile for analysis/g4tools sub-library.
# --------------------------------------------------------------------
name := G4tools
ifndef G4INSTALL
G4INSTALL = ../../..
endif
include $(G4INSTALL)/config/architecture.gmk
include $(G4INSTALL)/config/common.gmk
+26
View File
@@ -0,0 +1,26 @@
# g4tools Category History
# - It is NOT a substitute for good git commit messages!
# - All entries must be in reverse time order (most recent data on top)!
25th May 2021, B. Morgan (g4tools-V10-07-05)
- Move fonts from analysis category to tools to assist cross-category use
18th May 2021, G. Barrand (g4tools-V10-07-04)
- tools/zb/polygon: in scan() : initialize ET,AET,SLLBlock, before calling
CreateETandAET, to quiet g++-11 -Wmaybe-uninitialized warnings.
5th May 2021, J. Allison (g4tools-V10-07-03)
- Rename g4tools/include/tools/sg/gL_manager to GL_manager.
16th April 2021, I. Hrivnacova (g4tools-V10-07-02)
- Updated to g4tools 5.4.0 (Guy Barrand):
“Windowing” code update needed for the new “ToolsSG” vis drivers.
See History_tools for the complete list of modifications.
04th March 2021, I. Hrivnacova (g4tools-V10-07-01)
- Updated to g4tools 5.3.1 (Guy Barrand):
"Windowing" code needed for G4/vis/tools_sg
See History_tools for the complete list of modifications.
18th February 2021, B. Morgan (g4tools-V10-07-00)
- Move g4tools from g4analysis to externals category
File diff suppressed because it is too large Load Diff
Binary file not shown.
+94
View File
@@ -0,0 +1,94 @@
Copyright (c) 2010-2015, Łukasz Dziedzic (dziedzic@typoland.com),
with Reserved Font Name Lato.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+72
View File
@@ -0,0 +1,72 @@
Lato font family (Desktop version)
==================================
Version 2.015; Latin+Cyrillic+Greek+IPA opensource
Created by: tyPoland Lukasz Dziedzic
Creation year: 2015
Copyright (c) 2010-2015 by tyPoland Lukasz Dziedzic with Reserved Font Name "Lato". Licensed under the SIL Open Font License, Version 1.1.
Lato is a trademark of tyPoland Lukasz Dziedzic.
Source URL: http://www.latofonts.com/
License URL: http://scripts.sil.org/OFL
================
Lato is a sanserif typeface family designed in the Summer 2010 and extended in the Summer 2013 by Warsaw-based designer Lukasz Dziedzic ("Lato" means "Summer" in Polish). It tries to carefully balance some potentially conflicting priorities: it should seem quite "transparent" when used in body text but would display some original traits when used in larger sizes. The classical proportions, particularly visible in the uppercase, give the letterforms familiar harmony and elegance. At the same time, its sleek sanserif look makes evident the fact that Lato was designed in the 2010s, even though it does not follow any current trend. The semi-rounded details of the letters give Lato a feeling of warmth, while the strong structure provides stability and seriousness. In 2013-2014, the family was greatly extended (with the help of Adam Twardoch and Botio Nikoltchev) to cover 3000+ glyphs over nine weights with italics. It now supports 100+ Latin-based languages, 50+ Cyrillic-based languages as well as Greek and IPA phonetics. The Lato fonts are available free of charge under the SIL Open Font License from http://www.latofonts.com/
================
CONTENTS:
This folder contains 18 font files in OpenType TT (.ttf) format. You can install these fonts on your computer and use in any desktop applications (such as Word, InDesign, Illustrator, Photoshop, Keynote or Pages).
================
REVISION LOG:
# Version 2.015 (2015-08-06)
Initial implementation of mark positioning (should work for most glyphs)
Autohinted using ttfautohint 1.3.
# Version 2.010 (2014-09-01)
Improved some contour bugs and diacritics positioning.
Improved outline quality.
Revised OTL features so that they work in browsers (ot-sanitise).
Autohinted using ttfautohint 1.1.
Interpolated the Medium weight differently so it provides more visual difference from Regular.
# Version 2.007 (2014-02-27)
Greatly expanded character set, revised metrics, four additional weights.
# Version 1.104 (2011-11-08)
Merged the distribution again
Autohinted with updated ttfautohint 0.4 (which no longer causes Adobe and iOS problems)
except the Hai and Lig weights which are hinted in FLS 5.1.
# Version 1.102 (2011-10-28)
Added OpenType Layout features
Ssplit between desktop and web versions
Desktop version: all weights autohinted with FontLab Studio
Web version autohinted with ttfautohint 0.4 except the Hai and Lig weights
# Version 1.101 (2011-09-30)
Fixed OS/2 table Unicode and codepage entries
# Version 1.100 (2011-09-12)
Added Polish diacritics to the character set
Weights Hai and Lig autohinted with FontLab Studio
Other weights autohinted with ttfautohint 0.3
# Version 1.011 (2010-12-29)
Added the soft hyphen glyph
# Version 1.010 (2010-12-13)
Initial version released under SIL Open Font License
Western character set
================
Binary file not shown.
+215
View File
@@ -0,0 +1,215 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Cocoa_session_hm
#define tools_Cocoa_session_hm
#include <Cocoa/Cocoa.h>
namespace tools {
namespace Cocoa {
class isession {
public:
virtual ~isession(){}
public:
virtual void terminate() = 0;
};
}}
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
@interface tools_Cocoa_session_app_delegate : NSObject {
#else
@interface tools_Cocoa_session_app_delegate : NSObject<NSApplicationDelegate> {
#endif
NSApplication* m_app;
tools::Cocoa::isession* m_session;
}
- (id)init:(NSApplication*)a_app;
- (void)dealloc;
- (void)applicationDidFinishLaunching:(NSNotification*)a_notification;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)a_app;
- (void)set_session:(tools::Cocoa::isession*)a_session;
@end
@implementation tools_Cocoa_session_app_delegate
- (id)init:(NSApplication*)a_app {
if(self = [super init]) {}
m_app = a_app;
m_session = 0;
return self;
}
- (void)dealloc {[super dealloc];}
- (void)applicationDidFinishLaunching:(NSNotification*)a_notification {
[m_app activateIgnoringOtherApps:YES];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)a_app {
if(m_session) m_session->terminate();
return NSTerminateNow;
}
- (void)set_session:(tools::Cocoa::isession*)a_session {
m_session = a_session;
}
@end
#include <ostream>
namespace tools {
namespace Cocoa {
class session : public virtual isession {
typedef isession parent;
public:
virtual void terminate() {}
public:
session(std::ostream& a_out)
:m_out(a_out),m_pool(0),m_app(0),m_to_exit(false)
{
m_pool = [[NSAutoreleasePool alloc] init];
m_app = [NSApplication sharedApplication];
tools_Cocoa_session_app_delegate* app_del = [[tools_Cocoa_session_app_delegate alloc] init:m_app];
[m_app setDelegate:app_del];
[app_del set_session:this];
[m_app setActivationPolicy:NSApplicationActivationPolicyRegular]; //so that change of NSCursor works.
//[m_app activateIgnoringOtherApps:YES]; //done in the app_delegate, so that menu works at startup.
{id menubar = [[NSMenu new] autorelease];
id appMenuItem = [[NSMenuItem new] autorelease];
[menubar addItem:appMenuItem];
id appMenu = [[NSMenu new] autorelease];
id appName = [[NSProcessInfo processInfo] processName];
id quitTitle = [@"Quit " stringByAppendingString:appName];
id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
[m_app setMainMenu:menubar];}
}
virtual ~session() {
[m_pool release];
}
protected:
session(const session& a_from):parent(a_from),m_out(a_from.m_out),m_pool(0),m_app(0),m_to_exit(false) {}
session& operator=(const session&){return *this;}
public:
std::ostream& out() const {return m_out;}
bool is_valid() const {return true;}
bool steer() {
if(!m_app) return false;
m_to_exit = false;
NSDate* date = [NSDate distantFuture]; //it will permit to block on the below.
while(!m_to_exit) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1060 //macarts.
NSEvent* event = [m_app nextEventMatchingMask:NSAnyEventMask
#else
NSEvent* event = [m_app nextEventMatchingMask:NSEventMaskAny
#endif
untilDate:date inMode:NSDefaultRunLoopMode dequeue:YES];
if(event) {
[m_app sendEvent:event];
[m_app updateWindows];
}
[pool release];
}
return true;
}
bool sync() {
if(!m_app) return false;
NSDate* date = [NSDate distantPast]; //not blocking.
//NSDate* date = [NSDate distantFuture]; //blocking.
while(true) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1060 //macarts.
NSEvent* event = [m_app nextEventMatchingMask:NSAnyEventMask
#else
NSEvent* event = [m_app nextEventMatchingMask:NSEventMaskAny
#endif
untilDate:date inMode:NSDefaultRunLoopMode dequeue:YES];
if(event) {
[m_app sendEvent:event];
[m_app updateWindows];
}
[pool release];
if(!event) break;
}
return true;
}
public:
NSWindow* create_window(const char* a_title,int a_x,int a_y,unsigned int a_width,unsigned int a_height) {
if(!m_app) return 0L;
NSScreen* screen = 0;
{unsigned int monitor = 0;
NSArray* scrs = [NSScreen screens];
int number = [scrs count];
if(int(monitor)<number) {
screen = (NSScreen*)[scrs objectAtIndex:monitor];
}}
NSRect screen_rect = [screen frame];
// origin = bottom, left.
NSRect rect;
rect.origin.x = a_x;
rect.origin.y = screen_rect.size.height-(a_y+a_height),
rect.size.width = a_width;
rect.size.height = a_height;
//if(args.is_arg("-no_decos")) {
// rect.origin.y -= 23; //size of APPLE menubar.
//}
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1060 //macarts.
unsigned int mask = NSTitledWindowMask;
mask |= NSResizableWindowMask;
mask |= NSClosableWindowMask;
mask |= NSMiniaturizableWindowMask;
#else
unsigned int mask = NSWindowStyleMaskTitled;
mask |= NSWindowStyleMaskResizable;
mask |= NSWindowStyleMaskClosable;
mask |= NSWindowStyleMaskMiniaturizable;
#endif
//if(args.is_arg("-no_decos")) mask = 0;
NSWindow* window = [[NSWindow alloc] initWithContentRect:rect styleMask:mask backing:NSBackingStoreBuffered
defer:NO /*we are the owner.*/ screen:screen];
NSString* title = [NSString stringWithUTF8String:a_title];
[window setTitle:title];
[window setShowsResizeIndicator:YES];
[window setAcceptsMouseMovedEvents:YES];
return window;
}
void delete_window(NSWindow* a_window) const {
if(!m_app) return;
if([a_window isReleasedWhenClosed]==YES) {
[a_window close];
} else {
[a_window close];
[a_window release];
}
}
void show_window(NSWindow* a_window){
if(!m_app) return;
[a_window makeKeyAndOrderFront:m_app];
[m_app finishLaunching];
}
public: //not in SWIG.
void set_to_exit() {m_to_exit = true;}
bool to_exit() const {return m_to_exit;}
protected:
std::ostream& m_out;
NSAutoreleasePool* m_pool;
NSApplication* m_app;
bool m_to_exit;
};
}}
#endif
@@ -0,0 +1,163 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Cocoa_sg_viewer_hm
#define tools_Cocoa_sg_viewer_hm
#include "../sg/GL_viewer"
#include "session.hm"
@interface tools_Cocoa_sg_viewer_GLView : NSOpenGLView {
tools::sg::GL_viewer* m_viewer;
}
- (id)init:(NSRect)rect viewer:(tools::sg::GL_viewer*)a_viewer;
- (void)dealloc;
- (void)drawRect:(NSRect)a_rect;
@end
@implementation tools_Cocoa_sg_viewer_GLView
- (id)init:(NSRect)a_rect viewer:(tools::sg::GL_viewer*)a_viewer {
NSOpenGLPixelFormatAttribute att[32];
int i = 0;
att[i++] = NSOpenGLPFADoubleBuffer;
att[i++] = NSOpenGLPFAAccelerated;
att[i++] = NSOpenGLPFAAccumSize;
att[i++] = (NSOpenGLPixelFormatAttribute)32;
att[i++] = NSOpenGLPFAColorSize;
att[i++] = (NSOpenGLPixelFormatAttribute)32;
att[i++] = NSOpenGLPFADepthSize;
att[i++] = (NSOpenGLPixelFormatAttribute)32;
// Antialiasing :
att[i++] = NSOpenGLPFASampleBuffers;
att[i++] = 1;
att[i++] = NSOpenGLPFASamples;
att[i++] = 2;
att[i++] = NSOpenGLPFANoRecovery;
att[i] = (NSOpenGLPixelFormatAttribute)0;
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:att];
if(self = [super initWithFrame:a_rect pixelFormat:pixelFormat]) {
// flush buffer only during the vertical retrace of the monitor
const GLint vals[1] = {1};
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1014
[[self openGLContext] setValues:vals forParameter:NSOpenGLCPSwapInterval];
#else
[[self openGLContext] setValues:vals forParameter:NSOpenGLContextParameterSwapInterval];
#endif
}
[pixelFormat release];
m_viewer = a_viewer;
return self;
}
- (void)dealloc {[super dealloc];}
- (void)drawRect:(NSRect)a_rect {
if(!m_viewer) return;
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101500
int w = a_rect.size.width;
int h = a_rect.size.height;
#else
NSRect backing_rect = [self convertRectToBacking:a_rect];
int w = (int)(backing_rect.size.width);
int h = (int)(backing_rect.size.height);
#endif
m_viewer->set_size(w,h);
[[self openGLContext] makeCurrentContext];
m_viewer->render();
[[self openGLContext] flushBuffer];
}
@end
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
@interface tools_Cocoa_sg_viewer_win_delegate : NSObject {
#else
@interface tools_Cocoa_sg_viewer_win_delegate : NSObject<NSWindowDelegate> {
#endif
tools::Cocoa::session* m_session;
}
- (id)init:(tools::Cocoa::session*)a_session;
- (void)dealloc;
- (void)windowWillClose:(NSNotification*)a_not;
@end
@implementation tools_Cocoa_sg_viewer_win_delegate
- (id)init:(tools::Cocoa::session*)a_session {
if(self = [super init]) {}
m_session = a_session;
return self;
}
- (void)dealloc {[super dealloc];}
- (void)windowWillClose:(NSNotification*)a_not {
m_session->set_to_exit();
}
@end
namespace tools {
namespace Cocoa {
class sg_viewer : public sg::GL_viewer {
TOOLS_HEADER(sg_viewer,tools::Cocoa::sg_viewer,sg::GL_viewer)
public:
sg_viewer(session& a_session,
int a_x = 0,int a_y = 0,
unsigned int a_width = 500,unsigned int a_height = 500,
const std::string& a_win_title = "")
:parent(a_session.out(),a_width,a_height)
,m_session(a_session)
,m_win(0),m_GLView(0)
{
m_win = m_session.create_window(a_win_title.c_str(),a_x,a_y,a_width,a_height);
if(!m_win) return; //throw
tools_Cocoa_sg_viewer_win_delegate* _win_delegate = [[tools_Cocoa_sg_viewer_win_delegate alloc] init:&a_session];
[m_win setDelegate:_win_delegate];
NSRect rect;
rect = [m_win frame];
rect = [m_win contentRectForFrameRect:rect]; //window content true size.
m_GLView = [[tools_Cocoa_sg_viewer_GLView alloc] init:rect viewer:this];
[m_win setContentView:m_GLView];
[m_GLView release];
}
virtual ~sg_viewer() {
if(m_win) {
m_session.delete_window(m_win);
//m_session.sync();
}
}
protected:
sg_viewer(const sg_viewer& a_from)
:parent(a_from)
,m_session(a_from.m_session)
,m_win(0),m_GLView(0)
{}
sg_viewer& operator=(const sg_viewer& a_from) {
parent::operator=(a_from);
return *this;
}
public:
bool has_window() const {return m_win?true:false;}
bool show() {
if(!m_win) return false;
m_session.show_window(m_win);
return true;
}
void win_render() {
[[m_GLView openGLContext] makeCurrentContext];
render();
[[m_GLView openGLContext] flushBuffer];
}
protected:
session& m_session;
NSWindow* m_win;
tools_Cocoa_sg_viewer_GLView* m_GLView;
};
}}
#endif
+43
View File
@@ -0,0 +1,43 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_HEADER
#define tools_HEADER
#include "S_STRING"
#include "scast"
#define TOOLS_HEADER(a__class,a__sclass,a__parent)\
private:\
typedef a__parent parent;\
public:\
TOOLS_SCLASS(a__sclass)\
/*public:\
static bool is_a(const std::string& a_class) {\
if(!rcmp(a_class,s_class())) return true;\
return parent::is_a(a_class);\
}*/\
public:\
virtual void* cast(const std::string& a_class) const {\
if(void* p = tools::cmp_cast<a__class>(this,a_class)) return p;\
return parent::cast(a_class);\
}\
virtual const std::string& s_cls() const {return s_class();}
#define TOOLS_HEADER_COPY(a__class,a__sclass,a__parent,a__to)\
TOOLS_HEADER(a__class,a__sclass,a__parent)\
virtual a__to* copy() const {return new a__class(*this);}
#define TOOLS_T_HEADER(a__T,a__class,a__sclass,a__parent)\
private:\
typedef a__parent parent;\
public:\
TOOLS_T_SCLASS(a__T,a__sclass)\
public:\
virtual void* cast(const std::string& a_class) const {\
if(void* p = tools::cmp_cast<a__class>(this,a_class)) return p;\
return parent::cast(a_class);\
}\
virtual const std::string& s_cls() const {return s_class();}
#endif
+37
View File
@@ -0,0 +1,37 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_OpenGL
#define tools_OpenGL
#ifdef TOOLS_TOOLS_GL
#include "inlib_OpenGL"
#else //!TOOLS_TOOLS_GL
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if TARGET_OS_IPHONE
#include <OpenGLES/ES1/gl.h>
#elif defined(ANDROID)
#include <GLES/gl.h>
#elif _WIN32
#include <windows.h>
#include <GL/gl.h>
#elif __APPLE__
#ifdef TOOLS_USE_GL_GL_H
#include <GL/gl.h> //Macports X11 GL.
#else
#include <OpenGL/gl.h> //Apple/OpenGL.
#endif
#else
#include <GL/gl.h>
#endif
#endif //TOOLS_TOOLS_GL
#endif
+97
View File
@@ -0,0 +1,97 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Qt_glarea
#define tools_Qt_glarea
#include "../sg/GL_viewer"
#include <QtOpenGL/qgl.h>
#include <QtGui/qevent.h>
#include <tools/sg/device_interactor>
namespace tools {
namespace Qt {
class glarea : public QGLWidget {
typedef QGLWidget parent;
public:
virtual void initialieGL() {}
virtual void resizeGL(int a_w,int a_h){
//::printf("debug : resize : %d %d\n",a_w,a_h);
#if QT_VERSION < 0x050000
#else
m_width = a_w;
m_height = a_h;
#endif
}
//virtual void paintGL();
virtual void paintGL() {
#if QT_VERSION < 0x050000
//::printf("debug : tools::Qt::glarea::paintGL %d %d\n",width(),height());
m_viewer.set_size(width(),height());
#else
//::printf("debug : tools::Qt::glarea::paintGL %d %d\n",m_width,m_height);
m_viewer.set_size(m_width,m_height);
#endif
m_viewer.render();
}
virtual void keyPressEvent(QKeyEvent* a_event) {
if(!m_interactor) return;
tools::sg::key_down_event event(convert(a_event->key()));
m_interactor->key_press(event);
}
virtual void keyReleaseEvent(QKeyEvent* a_event) {
if(!m_interactor) return;
tools::sg::key_up_event event(convert(a_event->key()));
m_interactor->key_release(event);
}
virtual void mousePressEvent(QMouseEvent* a_event) {
if(!m_interactor) return;
tools::sg::mouse_down_event event(a_event->x(),a_event->y());
m_interactor->mouse_press(event);
}
virtual void mouseReleaseEvent(QMouseEvent* a_event) {
if(!m_interactor) return;
tools::sg::mouse_up_event event(a_event->x(),a_event->y());
m_interactor->mouse_release(event);
}
virtual void mouseMoveEvent(QMouseEvent* a_event) {
if(!m_interactor) return;
tools::sg::mouse_move_event event(a_event->x(),a_event->y(),0,0,false);
m_interactor->mouse_move(event);
}
//virtual void mouseDoubleClickEvent(QMouseEvent* a_event) {
// if(!m_interactor) return;
// tools::sg::mouse_double_click_event event(a_event->x(),a_event->y());
// m_interactor->mouse_double_click(event);
//}
virtual void wheelEvent(QWheelEvent* a_event) {
if(!m_interactor) return;
tools::sg::wheel_rotate_event event(a_event->angleDelta().y());
m_interactor->wheel_rotate(event);
}
public:
glarea(QWidget* a_parent,tools::sg::GL_viewer& a_viewer):parent(a_parent),m_viewer(a_viewer),m_interactor(0){}
virtual ~glarea(){}
public:
void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
protected:
tools::key_code convert(/*Qt::Key*/int a_key) {return a_key;}
protected:
tools::sg::GL_viewer& m_viewer;
#if QT_VERSION < 0x050000
#else
protected:
int m_width;
int m_height;
#endif
tools::sg::device_interactor* m_interactor;
};
}}
#endif
+54
View File
@@ -0,0 +1,54 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Qt_plots_glarea
#define tools_Qt_plots_glarea
#include <QtOpenGL/qgl.h>
#include "../sg/GL_plots_viewer"
namespace tools {
namespace Qt {
class plots_glarea : public QGLWidget {
typedef QGLWidget parent;
public:
virtual void initialieGL() {}
virtual void resizeGL(int a_w,int a_h){
//::printf("debug : resize : %d %d\n",a_w,a_h);
#if QT_VERSION < 0x050000
#else
m_width = a_w;
m_height = a_h;
#endif
}
//virtual void paintGL();
virtual void paintGL() {
#if QT_VERSION < 0x050000
//::printf("debug : tools::Qt::plots_glarea::paintGL %d %d\n",width(),height());
m_viewer.set_size(width(),height());
#else
//::printf("debug : tools::Qt::plots_glarea::paintGL %d %d\n",m_width,m_height);
m_viewer.set_size(m_width,m_height);
#endif
m_viewer.render();
}
public:
plots_glarea(QWidget* a_parent,tools::sg::GL_plots_viewer& a_viewer):parent(a_parent),m_viewer(a_viewer){}
virtual ~plots_glarea(){}
protected:
tools::sg::GL_plots_viewer& m_viewer;
#if QT_VERSION < 0x050000
#else
protected:
int m_width;
int m_height;
#endif
};
}}
#endif
+109
View File
@@ -0,0 +1,109 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Qt_session
#define tools_Qt_session
// pure Qt code, no GL.
#include <ostream>
#include <vector>
#include <QtCore/qglobal.h> //For QT_VERSION.
#include <QtCore/qnamespace.h>
#if QT_VERSION < 0x050000
#include <QtGui/qapplication.h>
#include <QtGui/qwidget.h>
#else
#include <QtWidgets/qapplication.h>
#include <QtWidgets/qwidget.h>
#endif
namespace tools {
namespace Qt {
class session {
public:
session(std::ostream& a_out,int& a_argc,char** a_argv)
:m_out(a_out)
,m_qapp(0)
,m_own_qapp(false)
{
if(qApp) {
m_qapp = qApp;
m_own_qapp = false;
} else {
m_qapp = new QApplication(a_argc,a_argv);
m_own_qapp = true;
}
}
virtual ~session() {
if(m_own_qapp && m_qapp) delete m_qapp;
m_qapp = 0;
m_own_qapp = false;
}
protected:
session(const session& a_from)
:m_out(a_from.m_out)
,m_qapp(0)
,m_own_qapp(false)
{}
session& operator=(const session& a_from){
if(&a_from==this) return *this;
return *this;
}
public:
std::ostream& out() const {return m_out;}
bool is_valid() const {return m_qapp?true:false;}
bool steer() {
if(!m_qapp) return false;
m_qapp->exec();
return true;
}
bool sync() {
if(!m_qapp) return false;
//m_qapp->exec();
return true;
}
public:
QApplication* qapp() const {return m_qapp;}
QWidget* create_window(const char* a_title,int a_x,int a_y,unsigned int a_width,unsigned int a_height) {
if(!m_qapp) return 0;
#ifdef _MSC_VER
if(a_y<=0) a_y = 60;
#endif
QWidget* top = new QWidget();
top->setWindowFlags(::Qt::CustomizeWindowHint
| ::Qt::WindowTitleHint
| ::Qt::WindowMinMaxButtonsHint
// | ::Qt::WindowSystemMenuHint
// | ::Qt::WindowFullscreenButtonHint
);
top->setGeometry(a_x,a_y,a_width,a_height);
top->setWindowTitle(s2q(a_title));
//top->setAttribute(Qt::WA_DeleteOnClose,false);
return top;
}
void delete_window(QWidget* a_window) const {
if(!m_qapp) return;
delete a_window;
}
protected:
QString s2q(const std::string& a_s) {
#if QT_VERSION < 0x050000
return QString::fromAscii(a_s.c_str());
#else
return QString::fromLatin1(a_s.c_str());
#endif
}
protected:
std::ostream& m_out;
QApplication* m_qapp;
bool m_own_qapp;
};
}}
#endif
+102
View File
@@ -0,0 +1,102 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Qt_sg_viewer
#define tools_Qt_sg_viewer
#include "glarea"
#include "session"
#include <QtCore/qglobal.h> //For QT_VERSION.
#if QT_VERSION < 0x050000
#include <QtGui/qpushbutton.h>
#include <QtGui/qboxlayout.h>
#else
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qboxlayout.h>
#endif
namespace tools {
namespace Qt {
class sg_viewer : public sg::GL_viewer {
typedef sg::GL_viewer parent;
public:
sg_viewer(session& a_session,
int a_x = 0,int a_y = 0,
unsigned int a_width = 500,unsigned int a_height = 500,
const std::string& a_win_title = "")
:parent(a_session.out(),a_width,a_height)
,m_session(a_session)
,m_shell(0)
,m_own_shell(false)
,m_glarea(0)
{
if(!m_session.is_valid()) return; //throw
m_shell = m_session.create_window(a_win_title.c_str(),a_x,a_y,a_width,a_height);
if(!m_shell) return; //throw
m_own_shell = true;
m_glarea = new Qt::glarea(0,*this);
QVBoxLayout* layout = new QVBoxLayout;
layout->setContentsMargins(0,0,0,0);
layout->addWidget(m_glarea);
m_shell->setLayout(layout);
}
virtual ~sg_viewer() {
if(m_shell && m_own_shell) {
m_session.delete_window(m_shell);
//m_session.sync();
}
}
protected:
sg_viewer(const sg_viewer& a_from)
:parent(a_from)
,m_session(a_from.m_session)
,m_shell(0)
,m_own_shell(false)
,m_glarea(0)
{}
sg_viewer& operator=(const sg_viewer& a_from){
parent::operator=(a_from);
return *this;
}
public:
bool has_window() const {return m_shell?true:false;} //for SWIG
bool show() {
if(!m_shell) return false;
m_shell->show();
return true;
}
void win_render() {
if(!m_glarea) return;
m_glarea->update();
}
public:
QWidget* shell() {return m_shell;}
void set_own_shell(bool a_value) {m_own_shell = a_value;}
Qt::glarea* glarea() {return m_glarea;}
void set_device_interactor(tools::sg::device_interactor* a_interactor) { //we do not have ownership.
if(!m_glarea) return;
m_glarea->set_device_interactor(a_interactor);
}
void enable_keyboard_focus() {
if(!m_glarea) return;
m_glarea->setFocusPolicy(::Qt::StrongFocus);
}
protected:
session& m_session;
QWidget* m_shell;
bool m_own_shell;
Qt::glarea* m_glarea;
};
}}
#endif
+76
View File
@@ -0,0 +1,76 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_S_STRING
#define tools_S_STRING
// a few place in which a cpp macro help the readability.
#include <string>
#define TOOLS_CLASS_STRING(a_name)\
static const std::string& s_##a_name() {\
static const std::string s_v(#a_name);\
return s_v;\
}
#define TOOLS_CLASS_STRING_VALUE(a_name,a_value)\
static const std::string& s_##a_name() {\
static const std::string s_v(#a_value);\
return s_v;\
}
#define TOOLS_CLASS_STRING_SVALUE(a_name,a_value)\
static const std::string& s_##a_name() {\
static const std::string s_v(a_value);\
return s_v;\
}
#define TOOLS_GLOBAL_STRING(a_name)\
inline const std::string& s_##a_name() {\
static const std::string s_v(#a_name);\
return s_v;\
}
#define TOOLS_GLOBAL_STRING_VALUE(a_name,a_value)\
inline const std::string& s_##a_name() {\
static const std::string s_v(#a_value);\
return s_v;\
}
#define TOOLS_SCLASS(a_name)\
static const std::string& s_class() {\
static const std::string s_v(#a_name);\
return s_v;\
}\
static void check_class_name() {a_name::s_class();}
#define TOOLS_T_SCLASS(a_T,a_name)\
static const std::string& s_class() {\
static const std::string s_v(#a_name);\
return s_v;\
}\
static void check_class_name() {a_name<a_T>::s_class();}
#define TOOLS_T2_SCLASS(a_T1,a_T2,a_name)\
static const std::string& s_class() {\
static const std::string s_v(#a_name);\
return s_v;\
}\
static void check_class_name() {a_name<a_T1,a_T2>::s_class();}
#define TOOLS_T3_SCLASS(a_T1,a_T2,a_T3,a_name)\
static const std::string& s_class() {\
static const std::string s_v(#a_name);\
return s_v;\
}\
static void check_class_name() {a_name<a_T1,a_T2,a_T3>::s_class();}
// to transform the value of a cpp macro to a string :
#define TOOLS_CPP_TO__STRING(a_cpp) #a_cpp
#define TOOLS_CPP_TO_STRING(a_cpp) std::string(TOOLS_CPP_TO__STRING(a_cpp))
// for example :
// #define FOO foo
// std::cout << TOOLS_CPP_TO_STRING(FOO) << std::endl;
#endif
+810
View File
@@ -0,0 +1,810 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Windows_WinTk
#define tools_Windows_WinTk
#include "../Windows/tools" //and not "tools", because this fancy VisualC++ will not find the file!
#include <tools/touplow>
#include <tools/words>
#ifdef TOOLS_MEM
#include <tools/mem>
#endif
#include <vector>
namespace tools {
namespace WinTk {
class Component;
class CallbackData {
public:
CallbackData():x(0),y(0),wparam(0),lparam(0){}
public:
std::string value;
int x;
int y;
WPARAM wparam;
LPARAM lparam;
};
typedef void (*Callback)(Component&,CallbackData&,void*);
class Component {
typedef std::vector< std::pair<Callback,void*> > Callbacks;
typedef std::pair<std::string,Callbacks> NamedCallbacks;
#ifdef TOOLS_MEM
TOOLS_SCLASS(tools::WinTk::Component)
#endif
public:
Component(const std::string& aType):fType(aType),fWindow(0),fParent(0){
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
Component(const std::string& aType,Component& aParent):fType(aType),fWindow(0),fParent(&aParent) {
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
virtual ~Component() {
#ifdef TOOLS_MEM
tools::mem::decrement(s_class().c_str());
#endif
}
protected:
Component(Component&) {
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
Component& operator=(Component&) {return *this;}
public:
std::string name() const {return fName;}
void setName(const std::string& aName) {fName = aName;}
const std::string& type() const {return fType;}
HWND nativeWindow() {return fWindow;}
Component* parent() const {return fParent;}
virtual void show() {
//if(!fWindow) return;
//::ShowWindow(fWindow,SW_SHOWDEFAULT);
}
void hide() {
if(!fWindow) return;
::ShowWindow(fWindow,SW_HIDE);
}
virtual bool size(unsigned int& aWidth,unsigned int& aHeight) {
aWidth = 0;
aHeight = 0;
if(!fWindow) return false;
RECT rect;
::GetClientRect(fWindow,&rect);
aWidth = rect.right-rect.left;
aHeight = rect.bottom-rect.top;
return true;
}
virtual bool position(int& aX,int& aY) {
aX = 0;
aY = 0;
if(!fWindow) return false;
RECT rect;
::GetClientRect(fWindow,&rect);
aX = rect.left;
aY = rect.top;
return true;
}
Component* findFather(const std::string& aType) {
if(aType==type()) return this;
Component* parent = fParent;
while(parent) {
if(aType==parent->type()) return parent;
parent = parent->fParent;
}
return 0;
}
bool setBackground(double aR,double aG,double aB){
if(!fWindow) return false;
int r = int(aR*255.0);
if((r<0)||(r>255)) return false;
int g = int(aG*255.0);
if((g<0)||(g>255)) return false;
int b = int(aB*255.0);
if((b<0)||(b>255)) return false;
/*
//COLORREF cr = RGB(r,g,b);
HBRUSH brush = ::CreateSolidBrush(RGB(r,g,b));
::printf("debug : WinTk::Component::setBackground : brush %lu\n",brush);
HBRUSH prev = (HBRUSH)::GetClassLongPtr(fWindow,GCLP_HBRBACKGROUND);
::printf("debug : WinTk::Component::setBackground : prev brush %lu\n",prev);
{WNDCLASSEX wc;
::GetClassInfoEx(::GetModuleHandle(NULL),WC_STATIC,&wc);
::printf("debug : prev brush xxx %lu\n",wc.hbrBackground);}
ULONG_PTR stat =
::SetClassLongPtr(fWindow,GCLP_HBRBACKGROUND,(LONG_PTR)brush);
if(prev && !stat) {
::printf("debug : WinTk::Component::setBackground : SetClassLongPtr failed.\n");
return false;
}
{ULONG_PTR stat =
::SetClassLongPtr(fWindow,GCLP_HBRBACKGROUND,(LONG_PTR)brush);
::printf("debug : WinTk::Component::setBackground : SetClassLongPtr failed.yyy %lu.\n",stat);}
{WNDCLASSEX wc;
::GetClassInfoEx(::GetModuleHandle(NULL),WC_STATIC,&wc);
::printf("debug : prev brush yyy %lu\n",wc.hbrBackground);}
if(!::InvalidateRect(fWindow,NULL,TRUE)) {
::printf("debug : WinTk::Component::setBackground : InvalidateRect failed.\n");
return false;
}
//::DeleteObject(brush);
return true;
*/
return false;
}
public:
void addCallback(const std::string& aName,Callback aFunction,void* aTag) {
NamedCallbacks* cbks = 0;
std::vector<NamedCallbacks>::iterator it;
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
if(aName==(*it).first) {
cbks = &(*it);
break;
}
}
if(!cbks) {
fCallbacks.push_back(std::pair<std::string,Callbacks>(aName,Callbacks()));
cbks = &(fCallbacks.back());
}
cbks->second.push_back(std::pair<Callback,void*>(aFunction,aTag));
}
void removeCallback(const std::string& aName,Callback aFunction,void* aTag) {
NamedCallbacks* cbks = 0;
std::vector<NamedCallbacks>::iterator it;
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
if(aName==(*it).first) {
cbks = &(*it);
break;
}
}
if(cbks) {
Callbacks::iterator it;
for(it=cbks->second.begin();it!=cbks->second.end();++it) {
if( (aFunction==(*it).first) && (aTag==(*it).second) ) {
cbks->second.erase(it);
return;
}
}
}
}
bool executeCallbacks(const std::string& aName,CallbackData& aData) {
std::vector<NamedCallbacks>::const_iterator it;
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
if(aName==(*it).first) {
const Callbacks& cbks = (*it).second;
Callbacks::const_iterator it2;
for(it2=cbks.begin();it2!=cbks.end();++it2) {
Callback cbk = (*it2).first;
if(cbk) {
HWND back_fWindow = fWindow;
cbk(*this,aData,(*it2).second);
// The callback may have destroyed the Component and
// the native HWND. The below checks that.
// In a proc, it is better to not use the HWND
// (or the Component) after calling executeCallbacks.
if(back_fWindow && !::GetWindowLongPtr(back_fWindow,GWLP_USERDATA)) {
//::printf("WinTk::Component::executeCallbacks : WARNING : A callback destroyed the native HWND window !\n");
return false;
}
}
}
return true;
}
}
return false;
}
bool hasCallbacks(const std::string& aName) const {
std::vector<NamedCallbacks>::const_iterator it;
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
if(aName==(*it).first) return true;
}
return false;
}
protected:
static void wm__destroy(HWND aWindow) {
Component* This = (Component*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) { //How to be sure that we have a Component* ???
if(This->fWindow!=aWindow) {
::printf("WinTk::Component::wm_destroy : HWND mismatch !\n");
}
if(This->hasCallbacks("WM_DESTROY")) {
CallbackData data;
This->executeCallbacks("WM_DESTROY",data);
}
This->fWindow = 0;
}
::SetWindowLongPtr(aWindow,GWLP_USERDATA,LONG_PTR(NULL));
}
protected:
// WM_PARENTNOTIFY is sent within the CreateWindow of the child.
// When received by the parent, the parent Post (not Send) to itself
// a WM_TK_CHILDCREATED in order to be notify of the child creation
// out of any CreateWindow.
#define WM_TK_CHILDCREATED ((WM_USER)+888)
#define WM_TK_CHILDDELETED ((WM_USER)+889)
#define TK_KEY 127 // To be sure that it is a message of our own.
static LRESULT CALLBACK containerProc(HWND aWindow,UINT aMessage,WPARAM aWParam,LPARAM aLParam) {
//////////////////////////////////////////////////////////////////////////////
// Some child send notification message to their parent (instead of sending
// the message to themselves !). This procedure is used by containers
// to forward these messages to the child.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
switch(aMessage) {
case WM_PARENTNOTIFY:{
if(aWParam==WM_CREATE) {
::PostMessage(aWindow,WM_TK_CHILDCREATED,TK_KEY,0);
return 0;
} else if(aWParam==WM_DESTROY) {
::PostMessage(aWindow,WM_TK_CHILDDELETED,TK_KEY,0);
return 0;
}
}break;
case WM_TK_CHILDCREATED:{
if(aWParam==TK_KEY) {
RECT rect;
::GetClientRect(aWindow,&rect);
LPARAM size = MAKELPARAM(rect.right-rect.left,rect.bottom-rect.top);
::SendMessage(aWindow,WM_SIZE,(WPARAM)0,size);
return 0;
}
}break;
case WM_TK_CHILDDELETED:{
if(aWParam==TK_KEY) {
}
}break;
case WM_NOTIFY:{ //Coming from a child (combobox, scrollbar, toolbar).
NMHDR* nmhdr = (NMHDR*)aLParam;
HWND from_win = nmhdr->hwndFrom;
if(from_win!=aWindow) {
::SendMessage(from_win,aMessage,aWParam,aLParam);
}
}return 0;
case WM_COMMAND:
case WM_VSCROLL:
case WM_HSCROLL:{
::SendMessage((HWND)aLParam,aMessage,aWParam,(LPARAM)0);
}return 0;
}
return TRUE; //Not handled.
}
#undef WM_TK_CHILDCREATED
#undef WM_TK_CHILDDELETED
#undef TK_KEY
protected:
void destroy() {
if(hasCallbacks("delete")) {
CallbackData data;
executeCallbacks("delete",data);
}
if(fWindow) {
::SetWindowLongPtr(fWindow,GWLP_USERDATA,LONG_PTR(NULL));
::DestroyWindow(fWindow);
fWindow = 0;
}
}
void rubberDrawLine(POINT& aBegin,POINT& aEnd) {
if(!fWindow) return;
HPEN pen = ::CreatePen(PS_SOLID,5,RGB(0,0,0));
HDC hdc = ::GetWindowDC(fWindow);
HPEN oldPen = SelectPen(hdc,pen);
int oldROP = ::SetROP2(hdc,R2_NOT);
POINT pt;
::MoveToEx(hdc,aBegin.x,aBegin.y,&pt);
::LineTo(hdc,aEnd.x,aEnd.y);
::SetROP2(hdc,oldROP);
SelectPen(hdc,oldPen);
::ReleaseDC(fWindow,hdc);
::DeletePen(pen);
}
void rubberDrawRect(POINT& aBegin,POINT& aEnd) {
if(!fWindow) return;
HPEN pen = ::CreatePen(PS_SOLID,0,RGB(0,0,0));
HDC hdc = ::GetWindowDC(fWindow);
HPEN oldPen = SelectPen(hdc,pen);
int oldROP = ::SetROP2(hdc,R2_NOT);
POINT pt;
::MoveToEx(hdc,aBegin.x,aBegin.y,&pt);
::LineTo(hdc,aBegin.x,aEnd.y);
::LineTo(hdc,aEnd.x,aEnd.y);
::LineTo(hdc,aEnd.x,aBegin.y);
::LineTo(hdc,aBegin.x,aBegin.y);
::SetROP2(hdc,oldROP);
SelectPen(hdc,oldPen);
::ReleaseDC(fWindow,hdc);
::DeletePen(pen);
}
private:
std::string fType;
protected:
HWND fWindow;
Component* fParent;
std::vector<NamedCallbacks> fCallbacks;
std::string fName;
};
class Shell;
typedef void(*SetFocusCallback)(Shell*,void*);
class Shell : public Component {
public:
Shell(unsigned int aMask)
:Component("Shell")
,fFocusWindow(0)
,fSetFocusCallback(0)
,fSetFocusTag(0)
,fAcceleratorTable(0)
{
static char sWindowClassName[] = "WinTk::Shell";
static bool done = false;
if(!done) {
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)Shell::proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ::GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
wc.lpszMenuName = sWindowClassName;
wc.lpszClassName = sWindowClassName;
::RegisterClass(&wc);
done = true;
}
fWindow = ::CreateWindow(sWindowClassName,
NULL,
aMask, //WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
400,400,
NULL,NULL,
::GetModuleHandle(NULL),
NULL);
if(!fWindow) return;
::SetWindowLongPtr(fWindow,GWLP_USERDATA,LONG_PTR(this));
}
virtual ~Shell() {
if(fAcceleratorTable) {
::DestroyAcceleratorTable(fAcceleratorTable);
fAcceleratorTable = 0;
}
destroy();
}
protected:
Shell(Shell& a_from):Component(a_from) {}
Shell& operator=(Shell&) {return *this;}
public:
virtual void show() {
if(!fWindow) return;
::SetForegroundWindow(fWindow);
::ShowWindow(fWindow,SW_SHOWDEFAULT);
::UpdateWindow(fWindow);
::DrawMenuBar(fWindow);
}
void setTitle(const std::string& aString) {
if(!fWindow) return;
::SetWindowText(fWindow,aString.c_str());
}
void setGeometry(int aX,int aY,unsigned int aWidth,unsigned int aHeight) {
//////////////////////////////////////////////////////////////////////////////
// Given width, height is the desired client area.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
if(!fWindow) return;
int hborder = ::GetSystemMetrics(SM_CYCAPTION);
if(::GetWindowLongPtr(fWindow,GWLP_ID)) // Has a menubar.
hborder += ::GetSystemMetrics(SM_CYMENU);
::MoveWindow(fWindow,aX,aY,aWidth,hborder + aHeight,TRUE);
}
void setSize(unsigned int aWidth,unsigned int aHeight) {
//////////////////////////////////////////////////////////////////////////////
// Given width, height is the desired client area.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
if(!fWindow) return;
int hborder = ::GetSystemMetrics(SM_CYCAPTION);
RECT rect;
::GetWindowRect(fWindow,&rect);
::MoveWindow(fWindow,rect.left,rect.top,aWidth,hborder + aHeight,TRUE);
}
void setFocusWindow(HWND aWindow) {fFocusWindow = aWindow;}
HWND focusWindow() {return fFocusWindow;}
void setSetFocusCallback(SetFocusCallback aCallback,void* aTag) {
fSetFocusCallback = aCallback;
fSetFocusTag = aTag;
}
void callSetFocusCallback() {
if(!fSetFocusCallback) return;
fSetFocusCallback(this,fSetFocusTag);
}
HACCEL nativeAcceleratorTable() {return fAcceleratorTable;}
bool addAccelerator(const std::string& aString,int aID) {
//printf("debug : accel : %s %d\n",aString.c_str(),aID);
// aString should be of the form : "a" or "Ctrl+a".
ACCEL acc;
//acc.fVirt : FALT, FCONTROL, FNOINVERT, FSHIFT, FVIRTKEY
{acc.cmd = aID;
std::vector<std::string> words;
std::string s(aString);
tools::touppercase(s);
tools::words(s,"+",false,words);
if(words.size()==1) {
acc.fVirt = FVIRTKEY;
if(!string_to_VK(words[0],acc.key)) return false;
} else if((words.size()==2)&&(words[1].size())) {
if(words[0]=="CTRL") {
acc.fVirt = FCONTROL;
} else if(words[0]=="ALT") {
acc.fVirt = FALT;
} else if(words[0]=="SHIFT") {
acc.fVirt = FSHIFT;
} else {
return false;
}
acc.fVirt |= FVIRTKEY;
if(!string_to_VK(words[1],acc.key)) return false;
} else {
return false;
}}
if(!fAcceleratorTable) {
fAcceleratorTable = ::CreateAcceleratorTable(&acc,1);
} else {
int n = ::CopyAcceleratorTable(fAcceleratorTable,NULL,0);
ACCEL* tbl = new ACCEL[n+1];
::CopyAcceleratorTable(fAcceleratorTable,tbl,n);
ACCEL& tacc = tbl[n];
tacc.fVirt = acc.fVirt;
tacc.key = acc.key;
tacc.cmd = acc.cmd;
::DestroyAcceleratorTable(fAcceleratorTable);
fAcceleratorTable = ::CreateAcceleratorTable(tbl,n+1);
delete [] tbl;
}
return true;
}
private:
static bool string_to_VK(const std::string& aString,WORD& a_VK) {
//VK_xxx are defined in WinUser.h
if(aString.size()==1) { a_VK = aString[0];return true;} //WM_W is 'W'
#define S_VK(aWhat) \
if(!::strcmp(aString.c_str(),#aWhat)) { a_VK = VK_##aWhat;return true;}
S_VK(BACK)
S_VK(TAB)
S_VK(CLEAR)
S_VK(RETURN)
S_VK(ESCAPE)
S_VK(SPACE)
S_VK(UP)
S_VK(DOWN)
S_VK(LEFT)
S_VK(RIGHT)
S_VK(F1)
S_VK(F2)
S_VK(F3)
S_VK(F4)
S_VK(F5)
S_VK(F6)
S_VK(F7)
S_VK(F8)
S_VK(F9)
S_VK(F10)
S_VK(F11)
S_VK(F12)
S_VK(F13)
S_VK(F14)
S_VK(F15)
S_VK(F16)
S_VK(F17)
S_VK(F18)
S_VK(F19)
S_VK(F20)
S_VK(F21)
S_VK(F22)
S_VK(F23)
S_VK(F24)
//FIXME : handle other keys ? NUMPAD[0-9]
#undef S_VK
return false;
}
static LRESULT CALLBACK proc(HWND aWindow,UINT aMessage,WPARAM aWParam,LPARAM aLParam) {
switch (aMessage) {
// Same logic as containerProc :
case WM_NOTIFY:{ //Coming from a child (combobox, scrollbar, toolbar).
NMHDR* nmhdr = (NMHDR*)aLParam;
HWND from_win = nmhdr->hwndFrom;
if(from_win!=aWindow) {
::SendMessage(from_win,aMessage,aWParam,aLParam);
}
}return 0;
// Else :
case WM_SIZE:{ // Assume one child window ! FIXME : have a message if not.
int width = LOWORD(aLParam);
int height = HIWORD(aLParam);
HWND hwnd = GetFirstChild(aWindow);
if(hwnd) {
//FIXME : have to treat the case of TOOLBAR not being the first.
if(GetClassName(hwnd)==std::string(TOOLBARCLASSNAME)) {
HWND next = GetNextSibling(hwnd);
// Share area between toolbar and second child :
RECT rect;
::GetWindowRect(hwnd,&rect);
int htb = rect.bottom-rect.top;
SetGeometry(next,0,htb,width,height-htb);
} else {
SetGeometry(hwnd,0,0,width,height);
}
}
}return 0;
case WM_SETFOCUS:{
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
This->callSetFocusCallback();
HWND win = This->focusWindow();
if(win) ::SetFocus(win);
}
}return 0;
case WM_INITMENUPOPUP:{ //0x0117
//aWParam is the HMENU (from CreatePopupMenu)
//aLParam is the MenuItemCount
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
CallbackData data;
data.wparam = aWParam;
This->executeCallbacks("cascading",data);
}
} return 0;
case WM_COMMAND:{ //Coming from a menu item, a toolbar !
if(aLParam) {
// From a toolbar ; send it back to it :
::SendMessage((HWND)aLParam,aMessage,aWParam,0);
} else {
//if(HIWORD(aWParam)==1) { //From an accelerator.
//}
// From a menu item :
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
CallbackData data;
data.wparam = LOWORD(aWParam);
This->executeCallbacks("activate",data);
}
}
}return 0;
case WM_CLOSE:{
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
if(This->hasCallbacks("close")) {
CallbackData data;
This->executeCallbacks("close",data);
}
}
}break; //NOTE : can't be return 0.
case WM_DESTROY:wm__destroy(aWindow);return 0;
}
return (DefWindowProc(aWindow,aMessage,aWParam,aLParam));
}
private:
HWND fFocusWindow;
SetFocusCallback fSetFocusCallback;
void* fSetFocusTag;
HACCEL fAcceleratorTable;
};
class OpenGLArea : public Component {
public:
OpenGLArea(Component& aParent)
:Component("OpenGLArea",aParent)
,fContext(0)
,fHDC(0)
{
if(!fParent || !fParent->nativeWindow()) return;
HWND parent = fParent->nativeWindow();
static char sOpenGLAreaClassName[] = "WinTk::OpenGLArea";
static bool done = false;
if(!done) {
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)OpenGLArea::proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetWindowInstance(parent),
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
wc.lpszMenuName = sOpenGLAreaClassName;
wc.lpszClassName = sOpenGLAreaClassName;
::RegisterClass(&wc);
done = true;
}
// The WS_BORDER is needed. Else probleme of size at startup.
RECT rect;
::GetClientRect(parent,&rect);
fWindow = ::CreateWindow(sOpenGLAreaClassName,
NULL,
WS_CHILD | WS_VISIBLE,
0,0,
rect.right-rect.left,
rect.bottom-rect.top,
parent,NULL,
GetWindowInstance(parent),
NULL);
if(!fWindow) return;
::SetWindowLongPtr(fWindow,GWLP_USERDATA,LONG_PTR(this));
// initialize OpenGL rendering :
fHDC = ::GetDC(fWindow);
if( fHDC && SetWindowPixelFormat(fHDC) ) {
fContext = ::wglCreateContext(fHDC);
}
}
virtual ~OpenGLArea() {
if(wglGetCurrentContext()!=NULL) wglMakeCurrent(NULL,NULL);
if(fContext) {
wglDeleteContext(fContext);
fContext = 0;
}
destroy();
}
protected:
OpenGLArea(OpenGLArea& a_from):Component(a_from) {}
OpenGLArea& operator=(OpenGLArea&) {return *this;}
public:
bool write_gl2ps(const std::string&,const std::string&);
private:
static LRESULT CALLBACK proc(HWND aWindow,UINT aMessage,WPARAM aWParam,LPARAM aLParam) {
switch (aMessage) {
case WM_PAINT:{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(aWindow,&ps);
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
HDC hdc = This->fHDC;
HGLRC context = This->fContext;
if(hdc && context) {
::wglMakeCurrent(hdc,context);
// User OpenGL paint code :
CallbackData data;
data.wparam = aWParam;
data.lparam = aLParam;
This->executeCallbacks("paint",data);
::SwapBuffers(hdc);
}
}
EndPaint(aWindow,&ps);
}return 0;
case WM_LBUTTONDOWN:{
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
CallbackData data;
data.wparam = aWParam;
data.lparam = aLParam;
data.value = "ButtonPress";
data.x = LOWORD(aLParam);
data.y = HIWORD(aLParam);
This->executeCallbacks("event",data);
}
}return 0;
case WM_LBUTTONUP:{
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
CallbackData data;
data.wparam = aWParam;
data.lparam = aLParam;
data.value = "ButtonRelease";
data.x = LOWORD(aLParam);
data.y = HIWORD(aLParam);
This->executeCallbacks("event",data);
}
} return 0;
case WM_MOUSEMOVE:{
unsigned int state = aWParam;
if((state & MK_LBUTTON)==MK_LBUTTON) {
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
if(This) {
CallbackData data;
data.wparam = aWParam;
data.lparam = aLParam;
data.value = "MotionNotify";
data.x = LOWORD(aLParam);
data.y = HIWORD(aLParam);
This->executeCallbacks("event",data);
}
}
}return 0;
case WM_DESTROY:wm__destroy(aWindow);return 0;
}
return (DefWindowProc(aWindow,aMessage,aWParam,aLParam));
}
static bool SetWindowPixelFormat(HDC aHdc) {
PIXELFORMATDESCRIPTOR pfd;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags =
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_STEREO_DONTCARE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cRedBits = 8;
pfd.cRedShift = 16;
pfd.cGreenBits = 8;
pfd.cGreenShift = 8;
pfd.cBlueBits = 8;
pfd.cBlueShift = 0;
pfd.cAlphaBits = 0;
pfd.cAlphaShift = 0;
pfd.cAccumBits = 64;
pfd.cAccumRedBits = 16;
pfd.cAccumGreenBits = 16;
pfd.cAccumBlueBits = 16;
pfd.cAccumAlphaBits = 0;
pfd.cDepthBits = 32;
pfd.cStencilBits = 8;
pfd.cAuxBuffers = 0;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.bReserved = 0;
pfd.dwLayerMask = 0;
pfd.dwVisibleMask = 0;
pfd.dwDamageMask = 0;
int pixelIndex = ::ChoosePixelFormat(aHdc,&pfd);
if (pixelIndex==0) {
// Let's choose a default index.
pixelIndex = 1;
if (::DescribePixelFormat(aHdc,
pixelIndex,
sizeof(PIXELFORMATDESCRIPTOR),
&pfd)==0) {
return false;
}
}
if (::SetPixelFormat(aHdc,pixelIndex,&pfd)==FALSE) return false;
return true;
}
private:
HGLRC fContext;
HDC fHDC;
};
}}
#endif
+418
View File
@@ -0,0 +1,418 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Windows_glarea
#define tools_Windows_glarea
#include <windows.h>
#include <windowsx.h>
#include <wingdi.h>
#include <tools/sg/device_interactor>
#include <tools/sg/keys>
//#include <tools/log_file>
#include <string>
#if defined(_MSC_VER) && _MSC_VER < 1900
#else
#define TOOLS_WINDOWS_TOUCH
#endif
namespace tools {
namespace Windows {
#ifdef TOOLS_WINDOWS_TOUCH
inline bool is_message_touch_event() {
// from https://stackoverflow.com/questions/29857587/detect-if-wm-mousemove-is-caused-by-touch-pen.
static const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00;
static const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700;
LONG_PTR extraInfo = ::GetMessageExtraInfo();
return ( ( extraInfo & c_SIGNATURE_MASK ) == c_MOUSEEVENTF_FROMTOUCH );
}
#endif
class glarea {
static const std::string& s_class() {
static const std::string s_v("tools::Windows::glarea");
return s_v;
}
static void register_class(){
static bool s_done = false; //not const, then not thread safe.
if(!s_done) {
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ::GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
wc.lpszMenuName = s_class().c_str();
wc.lpszClassName = s_class().c_str();
::RegisterClass(&wc);
s_done = true;
}
}
public:
virtual void resize(unsigned int,unsigned int){}
virtual void paint(unsigned int a_w,unsigned int a_h) {}
virtual void close(){}
virtual void left_button_up(unsigned int a_x,unsigned int a_y) {}
virtual void left_button_down(unsigned int a_x,unsigned int a_y) {}
virtual void mouse_move(unsigned int a_x,unsigned int a_y,bool) {}
public:
glarea(HWND a_parent)
:m_parent(a_parent)
,m_hwnd(0)
,m_context(0)
,m_HDC(0)
,m_touch_available(false)
,m_interactor(0)
{
register_class();
// The WS_BORDER is needed. Else probleme of size at startup.
RECT rect;
::GetClientRect(m_parent,&rect);
//printf("debug : glarea : ca : %d %d\n",rect.right-rect.left,rect.bottom-rect.top);
//inlib::log_file::get().writef("debug : glarea : ca : %d %d\n",rect.right-rect.left,rect.bottom-rect.top);
m_hwnd = ::CreateWindow(s_class().c_str(),
NULL,
WS_CHILD | WS_VISIBLE,
0,0,
rect.right-rect.left,
rect.bottom-rect.top,
m_parent,NULL,
GetWindowInstance(m_parent),
NULL);
if(!m_hwnd) return;
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
// initialize OpenGL rendering :
m_HDC = ::GetDC(m_hwnd);
if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
m_context = ::wglCreateContext(m_HDC);
}
#ifdef TOOLS_WINDOWS_TOUCH
{BYTE digitizer_status = (BYTE)::GetSystemMetrics(SM_DIGITIZER);
if((digitizer_status & (0x80 + 0x40)) == 0) {
m_touch_available = false;
} else {
//BYTE nInputs = (BYTE)::GetSystemMetrics(SM_MAXIMUMTOUCHES);
m_touch_available = true;
if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
}}
#endif
}
virtual ~glarea(){
if(::wglGetCurrentContext()!=NULL) ::wglMakeCurrent(NULL,NULL);
if(m_context) {
::wglDeleteContext(m_context);
m_context = 0;
}
if(m_HDC && m_hwnd) ::ReleaseDC(m_hwnd,m_HDC);
if(m_hwnd) {
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
::DestroyWindow(m_hwnd);
m_hwnd = 0;
}
}
protected:
glarea(const glarea& a_from)
:m_parent(a_from.m_parent)
,m_hwnd(0)
,m_context(0)
,m_HDC(0)
,m_touch_available(a_from.m_touch_available)
,m_interactor(0)
{
if(!m_parent) return;
register_class();
RECT rect;
::GetClientRect(m_parent,&rect);
m_hwnd = ::CreateWindow(s_class().c_str(),
NULL,
WS_CHILD | WS_VISIBLE,
0,0,
rect.right-rect.left,
rect.bottom-rect.top,
m_parent,NULL,
GetWindowInstance(m_parent),
NULL);
if(!m_hwnd) return;
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
// initialize OpenGL rendering :
m_HDC = ::GetDC(m_hwnd);
if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
m_context = ::wglCreateContext(m_HDC);
}
#ifdef TOOLS_WINDOWS_TOUCH
if(a_from.m_touch_available) {
if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
}
#endif
}
protected:
glarea& operator=(const glarea&){return *this;}
public:
void set_client_area_size(unsigned int a_w,unsigned int a_h) {
RECT rect;
::GetClientRect(m_hwnd,&rect);
::MoveWindow(m_hwnd,rect.left,rect.top,a_w,a_h,TRUE);
}
HWND hwnd() const {return m_hwnd;}
void post_WM_PAINT() const {
::PostMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
}
void send_WM_PAINT() const {
::SendMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
}
void wm_paint() {
PAINTSTRUCT ps;
//HDC hDC =
BeginPaint(m_hwnd,&ps);
if(m_HDC && m_context) {
::wglMakeCurrent(m_HDC,m_context);
RECT rect;
::GetClientRect(m_hwnd,&rect);
unsigned int w = rect.right-rect.left;
unsigned int h = rect.bottom-rect.top;
//printf("debug : glarea : paint : %d %d\n",w,h);
//inlib::log_file::get().writef("debug : glarea : paint : %d %d\n",w,h);
paint(w,h);
::SwapBuffers(m_HDC);
::wglMakeCurrent(m_HDC,0);
}
EndPaint(m_hwnd,&ps);
}
public:
void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
protected:
bool is_touch_event() {
#ifdef TOOLS_WINDOWS_TOUCH
if(!m_touch_available) return false;
return is_message_touch_event();
#else
return false;
#endif
}
protected:
static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
switch (a_msg) {
case WM_SIZE:{
int width = LOWORD(a_lparam);
int height = HIWORD(a_lparam);
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
_this->resize(width,height);
} else {
// CreateWindow send a WM_SIZE but GWLP_USERDATA not yet set.
}
}return 0;
case WM_PAINT:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->wm_paint();
}return 0;
case WM_KEYDOWN:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
if(_this->m_interactor) {
tools::sg::key_down_event event(_this->convert(a_wparam));
_this->m_interactor->key_press(event);
}
}
} return 0;
case WM_KEYUP:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
if(_this->m_interactor) {
tools::sg::key_up_event event(_this->convert(a_wparam));
_this->m_interactor->key_release(event);
}
}
} return 0;
case WM_LBUTTONDOWN:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
if(_this->m_interactor) {
tools::sg::mouse_down_event event(LOWORD(a_lparam),HIWORD(a_lparam));
_this->m_interactor->mouse_press(event);
} else {
RECT rect;
::GetClientRect(a_hwnd,&rect);
unsigned int h = rect.bottom-rect.top;
if(!_this->is_touch_event()) _this->left_button_down(LOWORD(a_lparam),h-HIWORD(a_lparam));
}
}
}return 0;
case WM_LBUTTONUP:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
if(_this->m_interactor) {
tools::sg::mouse_up_event event(LOWORD(a_lparam),HIWORD(a_lparam));
_this->m_interactor->mouse_release(event);
} else {
RECT rect;
::GetClientRect(a_hwnd,&rect);
unsigned int h = rect.bottom-rect.top;
if(!_this->is_touch_event()) _this->left_button_up(LOWORD(a_lparam),h-HIWORD(a_lparam));
}
}
} return 0;
case WM_MOUSEMOVE:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
if(_this->m_interactor) {
tools::sg::mouse_move_event event(LOWORD(a_lparam),HIWORD(a_lparam),0,0,false);
_this->m_interactor->mouse_move(event);
} else {
WPARAM state = a_wparam;
bool ldown = ((state & MK_LBUTTON)==MK_LBUTTON)?true:false;
RECT rect;
::GetClientRect(a_hwnd,&rect);
unsigned int h = rect.bottom-rect.top;
if(!_this->is_touch_event()) _this->mouse_move(LOWORD(a_lparam),h-HIWORD(a_lparam),ldown);
}
}
}return 0;
case WM_MOUSEWHEEL:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
if(_this->m_interactor) {
tools::sg::wheel_rotate_event event(GET_WHEEL_DELTA_WPARAM(a_wparam));
_this->m_interactor->wheel_rotate(event);
}
}
} return 0;
#ifdef TOOLS_WINDOWS_TOUCH
case WM_TOUCH:{
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this && _this->m_touch_available) {
RECT rect;
//::GetWindowRect(hwnd,&rect); ???
::GetClientRect(a_hwnd,&rect);
unsigned int h = rect.bottom-rect.top;
unsigned int num_inputs = (int)a_wparam;
//::printf("debug : WM_TOUCH : 001 : %d\n",num_inputs);
TOUCHINPUT* ti = new TOUCHINPUT[num_inputs];
POINT p;
if(::GetTouchInputInfo((HTOUCHINPUT)a_lparam,num_inputs,ti,sizeof(TOUCHINPUT))) {
for(unsigned int i=0;i<num_inputs; ++i) {
p.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
p.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
if(!::ScreenToClient(a_hwnd,&p)) {}
if(ti[i].dwFlags & TOUCHEVENTF_DOWN) {
//::printf("debug : TOUCHEVENTF_DOWN %lu %lu\n",p.x,p.y);
_this->left_button_down(p.x,h-p.y);
} else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
//::printf("debug : TOUCHEVENTF_UP %lu %lu\n",p.x,p.y);
_this->left_button_up(p.x,h-p.y);
} else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
bool ldown = true; //we assume that a TOUCHEVENT_DOWN had been done.
//::printf("debug : TOUCHEVENTF_MOVE %lu %lu\n",p.x,p.y);
_this->mouse_move(p.x,h-p.y,ldown);
}
}
}
::CloseTouchInputHandle((HTOUCHINPUT)a_lparam);
delete [] ti;
}
}return 0;
#endif //TOOLS_WINDOWS_TOUCH
case WM_DESTROY:wm__destroy(a_hwnd);return 0;
}
return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam));
}
static bool SetWindowPixelFormat(HDC a_HDC){
PIXELFORMATDESCRIPTOR pfd;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags =
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_STEREO_DONTCARE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cRedBits = 8;
pfd.cRedShift = 16;
pfd.cGreenBits = 8;
pfd.cGreenShift = 8;
pfd.cBlueBits = 8;
pfd.cBlueShift = 0;
pfd.cAlphaBits = 0;
pfd.cAlphaShift = 0;
pfd.cAccumBits = 64;
pfd.cAccumRedBits = 16;
pfd.cAccumGreenBits = 16;
pfd.cAccumBlueBits = 16;
pfd.cAccumAlphaBits = 0;
pfd.cDepthBits = 32;
pfd.cStencilBits = 8;
pfd.cAuxBuffers = 0;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.bReserved = 0;
pfd.dwLayerMask = 0;
pfd.dwVisibleMask = 0;
pfd.dwDamageMask = 0;
int pixelIndex = ::ChoosePixelFormat(a_HDC,&pfd);
if (pixelIndex==0) {
// Let's choose a default index.
pixelIndex = 1;
if (::DescribePixelFormat(a_HDC,
pixelIndex,
sizeof(PIXELFORMATDESCRIPTOR),
&pfd)==0) {
return false;
}
}
if (::SetPixelFormat(a_HDC,pixelIndex,&pfd)==FALSE) return false;
return true;
}
static void wm__destroy(HWND a_hwnd) {
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) { //How to be sure that we have a glarea* ???
_this->close();
if(_this->m_hwnd!=a_hwnd) {
//::printf("WinTk::Component::wm_destroy : HWND mismatch !\n");
}
_this->m_hwnd = 0;
}
::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
}
protected:
tools::key_code convert(WPARAM a_key) {
if(a_key==VK_SHIFT) return tools::sg::key_shift();
return (tools::key_code)a_key;
}
protected:
HWND m_parent;
HWND m_hwnd;
HGLRC m_context;
HDC m_HDC;
bool m_touch_available;
tools::sg::device_interactor* m_interactor;
};
}}
#endif
+73
View File
@@ -0,0 +1,73 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Windows_session
#define tools_Windows_session
#include <windows.h>
#include <windowsx.h>
#include <ostream>
namespace tools {
namespace Windows {
class session {
public:
session(std::ostream& a_out):m_out(a_out){}
virtual ~session() {}
protected:
session(const session& a_from):m_out(a_from.m_out){}
session& operator=(const session&){return *this;}
public:
std::ostream& out() const {return m_out;}
bool is_valid() const {return true;}
bool steer() {
while(true) {
MSG event;
BOOL status = ::GetMessage(&event,NULL,0,0);
if(status == -1) { // This may happen (dixit Microsoft doc).
break;
} else if(status == 0) { //WM_QUIT
break;
} else {
::TranslateMessage(&event);
::DispatchMessage (&event);
}
}
return true;
}
bool sync() {
MSG event;
while(::PeekMessage(&event,NULL,0,0,PM_REMOVE)) {
if(event.message==WM_QUIT) return false;
::TranslateMessage(&event);
::DispatchMessage(&event);
}
return true;
}
void show_window(HWND a_hwnd){
::SetForegroundWindow(a_hwnd);
::ShowWindow(a_hwnd,SW_SHOWDEFAULT);
::UpdateWindow(a_hwnd);
::DrawMenuBar(a_hwnd);
}
void set_size(HWND a_hwnd,unsigned int a_width,unsigned int a_height) {
::MoveWindow(a_hwnd,0,0,a_width,a_height,TRUE);
}
//void post(HWND a_hwnd,LPARAM a_msg){
// ::PostMessage(a_hwnd,WM_USER,(WPARAM)0,a_msg);
//}
protected:
std::ostream& m_out;
};
}}
#endif
@@ -0,0 +1,90 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Windows_sg_viewer
#define tools_Windows_sg_viewer
#include "session"
#include "window"
#include "glarea"
#include "../sg/GL_viewer"
// disable the warning about the usage of "this" in the constructor.
#pragma warning(disable:4355)
namespace tools {
namespace Windows {
class sg_viewer : public window, public sg::GL_viewer {
typedef window parent_window;
typedef sg::GL_viewer parent_viewer;
public:
virtual void close() {}
public:
sg_viewer(session& a_session,
int a_x = 0,int a_y = 0,
unsigned int a_width = 500,unsigned int a_height = 500,
const std::string& a_title = "")
:parent_window(a_title.c_str(),a_x,a_y,a_width,a_height)
,parent_viewer(a_session.out(),a_width,a_height)
,m_session(a_session)
,m_glarea(m_hwnd,*this)
{
parent_window::set_focus_hwnd(m_glarea.hwnd());
}
virtual ~sg_viewer() {}
protected:
sg_viewer(const sg_viewer& a_from)
:parent_window(a_from)
,parent_viewer(a_from)
,m_session(a_from.m_session)
,m_glarea(a_from.m_glarea)
{}
sg_viewer& operator=(const sg_viewer& a_from){
parent_window::operator=(a_from);
return *this;
}
public:
bool has_window() const {return m_hwnd?true:false;} //for SWIG
HWND window() const {return m_hwnd;}
bool show() {
if(!m_hwnd) return false;
m_session.show_window(m_hwnd);
return true;
}
void win_render() {m_glarea.wm_paint();}
public:
void set_device_interactor(tools::sg::device_interactor* a_interactor) { //we do not have ownership.
m_glarea.set_device_interactor(a_interactor);
}
protected:
class _glarea : public glarea {
public:
virtual void paint(unsigned int a_w,unsigned int a_h) {
m_viewer.set_size(a_w,a_h);
m_viewer.render();
}
public:
_glarea(HWND a_parent,parent_viewer& a_viewer)
:glarea(a_parent)
,m_viewer(a_viewer)
{}
protected:
parent_viewer& m_viewer;
};
protected:
session& m_session;
_glarea m_glarea;
};
}}
#endif
+601
View File
@@ -0,0 +1,601 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Windows_tools
#define tools_Windows_tools
#include <windows.h>
#include <windowsx.h>
#include <string>
namespace tools {
namespace WinTk {
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
inline bool GetClassName(HWND aWindow,std::string& a_value) {
if(!aWindow) {a_value.clear();return false;}
char className[256];
::GetClassName(aWindow,className,128);
a_value = std::string(className);
return true;
}
inline HWND GetChildByClassName(HWND aWindow,const std::string& aClassName) {
// A CBS_SIMPLE has two children of class ComboLBox and Edit.
// At creation, a CBS_DROPDOWN has one child of class Edit.
if(!aWindow) return NULL;
HWND child = GetFirstChild(aWindow);
std::string ss;
while(child) {
GetClassName(child,ss);
if(ss==aClassName) return child;
child = GetNextSibling(child);
}
return NULL;
}
inline void SetGeometry(HWND aWindow,int aX,int aY,unsigned int aWidth,unsigned int aHeight) {
if(!aWindow) return;
std::string className;
GetClassName(aWindow,className);
if(className=="ComboBox") {
// For a Combo the height is the visible part + the height of the list !
// (A combo may have no edit control).
::MoveWindow(aWindow,aX,aY,aWidth,200,TRUE);
} else {
::MoveWindow(aWindow,aX,aY,aWidth,aHeight,TRUE);
}
}
inline void GetSize(HWND aWindow,int& aWidth,int& aHeight) {
RECT rect;
::GetWindowRect(aWindow,&rect);
aWidth = rect.right-rect.left;
aHeight = rect.bottom-rect.top;
}
inline unsigned int GetNumberOfChildren(HWND aWindow) {
unsigned int number = 0;
HWND child = GetFirstChild(aWindow);
while(child) {
number++;
child = GetNextSibling(child);
}
return number;
}
inline HWND GetLastChild(HWND aWindow) {
HWND child = GetFirstChild(aWindow);
while(child) {
HWND next = GetNextSibling(child);
if(!next) return child;
child = next;
}
return 0;
}
inline void GetText(HWND aWindow,std::string& a_value) {
int l = ::GetWindowTextLength(aWindow);
a_value.resize(l);
::GetWindowText(aWindow,(char*)a_value.c_str(),l+1);
}
/*
inline void PrintChildren(HWND aWindow) {
// A CBS_SIMPLE has two children of class ComboLBox and Edit.
// At creation, a CBS_DROPDOWN has one child of class Edit.
if(!aWindow) return;
HWND child = GetFirstChild(aWindow);
while(child) {
//printf("debug : window : %ld, child : %ld class \"%s\"\n",
// aWindow,child,ClassName(child).c_str());
child = GetNextSibling(child);
}
}
*/
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
inline bool IsStyle(HWND aWindow,LONG aStyle) {
LONG_PTR style = ::GetWindowLongPtr(aWindow,GWL_STYLE);
return ( ((style & aStyle ) == aStyle) ? true : false);
}
inline void ChangeStyle(HWND aWindow,LONG aStyle,bool aValue) {
LONG_PTR style = ::GetWindowLongPtr(aWindow,GWL_STYLE);
if(aValue) { //Enable style.
style = style | aStyle;
} else { //Disbale style.
style = style & ~aStyle;
}
::SetWindowLongPtr(aWindow,GWL_STYLE,style);
}
inline bool IsShell(HWND aWindow) {
if(IsStyle(aWindow,WS_OVERLAPPEDWINDOW)) return true;
if(IsStyle(aWindow,WS_POPUP)) return true;
return false;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
inline HWND GetShell(HWND aWindow) {
HWND window = aWindow;
if(IsShell(window)) return window;
while(true) {
HWND parent = GetParent(window);
if(!parent) return window;
if(IsShell(parent)) return parent;
window = parent;
}
return 0;
}
inline bool Show(HWND aWindow) {
HWND shell = GetShell(aWindow);
if(!shell) return false;
::SetForegroundWindow(shell);
::ShowWindow(shell,SW_SHOWDEFAULT);
::UpdateWindow(shell);
::DrawMenuBar(shell);
return true;
}
inline bool Hide(HWND aWindow) {
HWND shell = GetShell(aWindow);
if(!shell) return false;
::ShowWindow(shell,SW_HIDE);
return true;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
inline bool IsTabStop(HWND aWindow) {
LONG_PTR style = ::GetWindowLongPtr(aWindow,GWL_STYLE);
return ((style & WS_TABSTOP ) == WS_TABSTOP ? true : false);
}
inline HWND GetTabStopInTree(HWND aWindow,bool aForward) {
if(IsTabStop(aWindow)) return aWindow;
HWND child = aForward ? GetFirstChild(aWindow) : GetLastChild(aWindow);
while(child) {
HWND tabStop = GetTabStopInTree(child,aForward);
if(tabStop) return tabStop;
child = aForward ? GetNextSibling(child) : GetPrevSibling(child);
}
return NULL;
}
inline HWND GetTabStopInSibling(HWND aWindow,bool aForward) {
if(!aWindow) return NULL;
HWND child = aForward ? GetNextSibling(aWindow) : GetPrevSibling(aWindow);
while(child) {
HWND tabStop = GetTabStopInTree(child,aForward);
if(tabStop) return tabStop;
child = aForward ? GetNextSibling(child) : GetPrevSibling(child);
}
return NULL;
}
inline HWND GetTabStop(HWND aDialog,HWND aWindow,bool aForward = true) {
if(!aWindow) return NULL;
HWND window = aWindow;
while(window && (window!=aDialog) ) {
HWND tabStop = GetTabStopInSibling(window,aForward);
if(tabStop) return tabStop;
window = GetParent(window);
}
return GetTabStopInTree(aDialog,aForward);
}
inline HBITMAP CreateDIB(HDC aDC,int aWidth,int aHeight,int aBPP /*16||24||32*/,void** aBits) {
if((aBPP!=24) && (aBPP!=32)) return 0;
BITMAPINFO format;
BITMAPINFOHEADER* header = (BITMAPINFOHEADER*)&format;
header->biSize = sizeof(BITMAPINFOHEADER);
header->biWidth = aWidth;
header->biHeight = -aHeight;
header->biPlanes = 1;
header->biBitCount = aBPP;
header->biCompression = BI_RGB;
header->biSizeImage = 0;
header->biXPelsPerMeter = 0;
header->biYPelsPerMeter = 0;
header->biClrUsed = 0;
header->biClrImportant = 0;
UINT flag = DIB_RGB_COLORS;
HBITMAP bitmap = ::CreateDIBSection(aDC,&format,flag,(void**)aBits,NULL,0);
if(!(*aBits)) return 0;
return bitmap;
}
}}
#include <commctrl.h>
namespace tools {
namespace WinTk {
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
inline bool TreeGetItemLabel(HWND aWindow,HTREEITEM aItem,std::string& a_value) {
TCHAR text[256];
TV_ITEM item;
item.hItem = aItem;
item.mask = TVIF_TEXT;
item.pszText = text;
item.cchTextMax = 256;
if(!TreeView_GetItem(aWindow,&item)) {a_value.clear();return false;}
a_value = std::string(text);
return true;
}
inline bool TreeIsItemBranch(HWND aWindow,HTREEITEM aItem) {
TV_ITEM item;
item.hItem = aItem;
item.mask = TVIF_CHILDREN;
if(!TreeView_GetItem(aWindow,&item)) return 0;
return item.cChildren?true:false;
}
inline bool TreeIsItemExpanded(HWND aWindow,HTREEITEM aItem) {
TV_ITEM item;
item.hItem = aItem;
item.mask = TVIS_EXPANDED;
if(!TreeView_GetItem(aWindow,&item)) return 0;
return ((item.state & TVIS_EXPANDED)== TVIS_EXPANDED) ? true : false;
}
inline void TreeGetItemPath(HWND aWindow,HTREEITEM aItem,std::string& a_value) {
HTREEITEM item = aItem;
a_value.clear();
std::string ss;
while(item && (item!=TVI_ROOT)) {
TreeGetItemLabel(aWindow,item,ss);
std::string opath = a_value;
a_value = "\n";
a_value += ss;
a_value += opath;
item = TreeView_GetParent(aWindow,item);
}
// Remove the leading \n
if(a_value.size()) a_value = a_value.substr(1,a_value.size()-1);
}
inline void TreeGetItemXML(HWND aWindow,HTREEITEM aItem,std::string& a_value) {
//return a XML string representing this tree
std::string spaceItem = "";
std::string spaceRoot = "";
std::string ss;
a_value.clear();
do {
a_value += spaceRoot + "<treeItem>";
a_value += spaceItem + "<label>";
TreeGetItemLabel(aWindow,aItem,ss);
a_value.append(ss);
a_value += "</label>";
a_value += spaceItem + "<opened>";
if (TreeIsItemExpanded(aWindow,aItem)) a_value.append("true");
else a_value.append("false");
a_value += "</opened>";
if (TreeView_GetChild(aWindow,aItem)) {
TreeGetItemXML(aWindow,TreeView_GetChild(aWindow,aItem),ss);
a_value += ss;
}
a_value += spaceRoot + "</treeItem>";
aItem = TreeView_GetNextSibling(aWindow,aItem);
}
while (aItem);
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
inline int smanip_axtoi(const std::string& a_string) {
// convert from ASCII hex to int
// Exa : "FF" -> 256.
int x = 0;
size_t n = a_string.size();
// convert n nibbles
for (size_t i = 0; i < n; i++) {
char c = a_string[i];
// numbers 0 - 9
if ((c > 0x2F) && (c < 0x3A))
x += ((c - 0x30) << ((n - i - 1) * 4));
// capital letters A - F
if ((c > 0x40) && (c < 0x47))
x += ((c - 0x41 + 0x0A) << ((n - i - 1) * 4));
// lower case letters a - f
if ((c > 0x60) && (c < 0x67))
x += ((c - 0x61 + 0x0A) << ((n - i - 1) * 4));
}
return x;
}
}}
#include <tools/svalues>
namespace tools {
namespace WinTk {
inline HBITMAP ConvertXpmToDIB(HDC aDC,const std::vector<std::string>& aXPM,int& aWidth,int& aHeight) {
// Convert from xpm to DIB (demands hex colors).
// From CoinWin/widgets/SoWinBitmapButton.cpp.
aWidth = 0;
aHeight = 0;
if(!aXPM.size()) return 0;
std::vector<int> vals;
tools::values<int>(aXPM[0]," ",false,vals);
if(vals.size()!=4) return 0;
int width = vals[0];
int height = vals[1];
int numcol = vals[2];
int numchars = vals[3];
if(width<=0) return 0;
if(height<=0) return 0;
if(numcol<=0) return 0;
if(numchars<=0) return 0;
// Check consistency :
if((height+numcol)!=aXPM.size()-1) return 0;
size_t lcolor = 0;
int i;
for (i = 0; i < numcol; i++) {
std::string::size_type pos = aXPM[i+1].rfind("c #");
if(pos==std::string::npos) continue; // May be "c None"
lcolor = aXPM[i+1].size()-(pos+3);
break;
}
//printf("debug : xpm : numcol %d (%d)\n",numcol,lcolor);
if( (lcolor!=6) && (lcolor!=12) ) return 0;
// create color lookup table
char* charlookuptable = new char[numcol * numchars];
//long* colorlookuptable = new long[numcol];
int* rlookuptable = new int[numcol];
int* glookuptable = new int[numcol];
int* blookuptable = new int[numcol];
bool done = true;
// get colors
for (i = 0; i < numcol; i++) {
const std::string& line = aXPM[i+1];
// Check consistency :
if((int)line.size()<numchars) {
done = false;
break;
}
for (int j = 0; j < numchars; j ++) {
charlookuptable[(i * numchars) + j] = line[j];
}
// Find color by value :
std::string::size_type pos = line.find("c #",numchars);
if(pos!=std::string::npos) {
size_t lc = line.size()-(pos+3);
if(lc!=lcolor) {
done = false;
//printf("debug : xpm : error in \"%s\" %d %d\n",
//line.c_str(),lc,lcolor);
break;
}
if(lcolor==6) {
rlookuptable[i] = smanip_axtoi(line.substr(pos+3+0,2));
glookuptable[i] = smanip_axtoi(line.substr(pos+3+2,2));
blookuptable[i] = smanip_axtoi(line.substr(pos+3+4,2));
} else { //lcolor 12
rlookuptable[i] = smanip_axtoi(line.substr(pos+3+0,2));
glookuptable[i] = smanip_axtoi(line.substr(pos+3+4,2));
blookuptable[i] = smanip_axtoi(line.substr(pos+3+8,2));
}
//printf("debug : xpm : color %d : (%x,%x,%x)\n",
// i,rlookuptable[i],glookuptable[i],blookuptable[i]);
} else { // Could be "c None"
rlookuptable[i] = -1;
glookuptable[i] = -1;
blookuptable[i] = -1;
}
}
//printf("debug : xpm : read color %d\n",done);
//WARNING : pixelsize 3 does not work with button in a toolbar.
// unsigned char pixelsize = 3;
unsigned char pixelsize = 4;
if(!done) pixelsize = 0; // Will induce a clean exit.
// create bitmap
void* dest;
HBITMAP hbmp = CreateDIB(aDC,width,height,pixelsize * 8,&dest);
if(hbmp) {
int noneColor = ::GetSysColor(COLOR_3DFACE);
done = true;
// put pixels
for (i = 0; i < height; i++) {
const std::string& line = aXPM[i + 1 + numcol];
// Check consistency :
if((int)line.size()!=(numchars*width)) {
done = false;
break;
}
int y = i * width * pixelsize;
for (int j = 0; j < width; j++) {
int x = j * pixelsize;
// for every color
for (int k = 0; k < numcol; k++) {
bool found = true;
for (int l = 0; l < numchars; l++) {
if (charlookuptable[(k * numchars) + l]
!= line[(j * numchars) + l]) {
found = false;
break;
}
}
if(found) {
unsigned char r,g,b;
if (rlookuptable[k] == -1) {
r = (noneColor & 0x00FF0000)>>16;
g = (noneColor & 0x0000FF00)>>8;
b = noneColor & 0x000000FF;
} else {
r = rlookuptable[k];
g = glookuptable[k];
b = blookuptable[k];
}
if(pixelsize==4) {
((unsigned char*)dest)[y + x + 0] = b;
((unsigned char*)dest)[y + x + 1] = g;
((unsigned char*)dest)[y + x + 2] = r;
((unsigned char*)dest)[y + x + 3] = 0;
} else {
((unsigned char*)dest)[y + x + 0] = b;
((unsigned char*)dest)[y + x + 1] = g;
((unsigned char*)dest)[y + x + 2] = r;
}
// next pixel
break;
}
}
}
}
if(!done) {
//printf("debug : xpm : can'tread pixels.\n");
::DeleteObject(hbmp);
hbmp = 0;
}
}
// cleanup
delete [] charlookuptable;
delete [] rlookuptable;
delete [] glookuptable;
delete [] blookuptable;
if(hbmp) {
aWidth = width;
aHeight = height;
}
return hbmp;
}
}}
#include <tools/file>
namespace tools {
namespace WinTk {
inline HBITMAP Read_Xpm(HDC aDC,const std::string& aFileName,int& aWidth,int& aHeight) {
aWidth = 0;
aHeight = 0;
std::vector<std::string> text;
//std::string name;
//tools::file_name(aFileName,name);
if(!tools::file::read(aFileName,text)) return 0;
std::vector<std::string> xpm;
{for(size_t index=0;index<text.size();index++) {
if(text[index][0]!='"') continue;
std::string::size_type l = text[index].size();
std::string line = text[index].substr(1,l-1);
std::string::size_type pos = line.find("\"");
if(pos==std::string::npos) return 0;
xpm.push_back(line.substr(0,pos));
}}
if(!xpm.size()) return 0;
return ConvertXpmToDIB(aDC,xpm,aWidth,aHeight);
}
inline std::string TreeGetItemLabel(HWND aWindow,HTREEITEM aItem) {
std::string ss;
TreeGetItemLabel(aWindow,aItem,ss);
return ss;
}
inline std::string TreeGetItemPath(HWND aWindow,HTREEITEM aItem) {
std::string ss;
TreeGetItemPath(aWindow,aItem,ss);
return ss;
}
inline std::string TreeGetItemXML(HWND aWindow,HTREEITEM aItem) {
std::string ss;
TreeGetItemXML(aWindow,aItem,ss);
return ss;
}
inline std::string GetText(HWND aWindow) {
std::string ss;
GetText(aWindow,ss);
return ss;
}
inline std::string GetClassName(HWND aWindow) {
std::string ss;
GetClassName(aWindow,ss);
return ss;
}
}}
#include <tools/file_name>
namespace tools {
namespace WinTk {
inline HBITMAP ReadXpm(HDC aDC,const std::string& aFileName,int& aWidth,int& aHeight) {
std::string name;
tools::file_name(aFileName,name);
return Read_Xpm(aDC,name,aWidth,aHeight);
}
}}
#endif
+250
View File
@@ -0,0 +1,250 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Windows_window
#define tools_Windows_window
#include <windows.h>
#include <windowsx.h>
#include <string>
namespace tools {
namespace Windows {
class window {
static const std::string& s_class() {
static const std::string s_v("tools::Windows::window");
return s_v;
}
static void register_class(){
static bool s_done = false; //not const, then not thread safe.
if(!s_done) {
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ::GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
wc.lpszMenuName = s_class().c_str();
wc.lpszClassName = s_class().c_str();
::RegisterClass(&wc);
s_done = true;
}
}
public:
virtual void key_up(){}
virtual void key_down(){}
virtual void key_left(){}
virtual void key_right(){}
virtual void key_escape(){}
virtual void close(){
//if(m_hwnd) ::PostMessage(m_hwnd,WM_QUIT,0,0);
::PostQuitMessage(0);
}
public:
window(const char* a_title,int a_x,int a_y,unsigned int a_w,unsigned int a_h,unsigned int a_mask = WS_OVERLAPPEDWINDOW)
:m_hwnd(0)
,m_key_shift(false)
,m_key_ctrl(false)
,m_focus_hwnd(0)
{
// WARNING : given a_w,a_h may not be the client area because of various decorations.
// See set_client_area_size() method to enforce a client area size.
register_class();
m_hwnd = ::CreateWindow(s_class().c_str(),
NULL,
a_mask,
a_x,a_y,
a_w,a_h,
NULL,NULL,
::GetModuleHandle(NULL),
NULL);
if(!m_hwnd) return;
::SetWindowText(m_hwnd,a_title);
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
}
virtual ~window(){
if(m_hwnd) {
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
::DestroyWindow(m_hwnd);
m_hwnd = 0;
}
}
protected:
window(const window& a_from)
:m_hwnd(0)
,m_key_shift(a_from.m_key_shift)
,m_key_ctrl(a_from.m_key_ctrl)
,m_focus_hwnd(0)
{
/*
if(!a_from.m_hwnd) return;
int w,h;
get_size(a_from.m_hwnd,w,h);
register_class();
m_hwnd = ::CreateWindow(s_class().c_str(),
NULL,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
w,h,
NULL,NULL,
::GetModuleHandle(NULL),
NULL);
if(!m_hwnd) return;
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
*/
}
window& operator=(const window& a_from){
m_key_shift = a_from.m_key_shift;
m_key_ctrl = a_from.m_key_ctrl;
return *this;
}
public:
const window& get_me() const {return *this;}
window& get_me() {return *this;}
bool key_shift() const {return m_key_shift;}
HWND hwnd() const {return m_hwnd;}
void set_client_area_size(unsigned int a_w,unsigned int a_h) {
if(!m_hwnd) return;
RECT wrect;
::GetWindowRect(m_hwnd,&wrect);
unsigned int ww = wrect.right-wrect.left;
unsigned int wh = wrect.bottom-wrect.top;
RECT carect;
::GetClientRect(m_hwnd,&carect);
unsigned int cw = carect.right-carect.left;
unsigned int ch = carect.bottom-carect.top;
unsigned int woffset = ww-cw;
unsigned int hoffset = wh-ch;
::MoveWindow(m_hwnd,wrect.left,wrect.top,a_w+woffset,a_h+hoffset,TRUE);
}
void move(unsigned int a_x,unsigned int a_y) {
if(!m_hwnd) return;
RECT rect;
::GetWindowRect(m_hwnd,&rect);
unsigned int w = rect.right-rect.left;
unsigned int h = rect.bottom-rect.top;
::MoveWindow(m_hwnd,a_x,a_y,w,h,TRUE);
}
void set_focus_hwnd(HWND a_hwnd) {m_focus_hwnd = a_hwnd;}
HWND focus_hwnd() const {return m_focus_hwnd;}
protected:
static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
switch (a_msg) {
// Else :
case WM_SIZE:{ // Assume one child window ! FIXME : have a message if not.
int width = LOWORD(a_lparam);
int height = HIWORD(a_lparam);
HWND hwnd = GetFirstChild(a_hwnd);
if(hwnd) {
::MoveWindow(hwnd,0,0,width,height,TRUE);
}
}return 0;
case WM_SETFOCUS:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
HWND hwnd = _this->focus_hwnd();
if(hwnd) ::SetFocus(hwnd);
}
}return 0;
case WM_KEYDOWN:{
switch(a_wparam){
case VK_SHIFT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_shift = true;
return 0;
}
case VK_CONTROL:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_ctrl = true;
return 0;
}
case VK_UP:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_up();
return 0;
}
case VK_DOWN:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_down();
return 0;
}
case VK_LEFT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_left();
return 0;
}
case VK_RIGHT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_right();
return 0;
}
case VK_ESCAPE:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_escape();
return 0;
}
} //end switch(a_wparam)
break;
}
case WM_KEYUP:{
switch(a_wparam){
case VK_SHIFT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_shift = false;
return 0;
}
case VK_CONTROL:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_ctrl = false;
return 0;
}
} //end switch(a_wparam)
break;
}
case WM_CLOSE:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->close();
}break; //NOTE : can't be return 0.
case WM_DESTROY:wm__destroy(a_hwnd);return 0;
}
return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam));
}
static void wm__destroy(HWND a_hwnd) {
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) { //How to be sure that we have a window* ???
if(_this->m_hwnd!=a_hwnd) {
//::printf("WinTk::Component::wm_destroy : HWND mismatch !\n");
}
_this->m_hwnd = 0;
}
::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
}
protected:
void get_size(HWND a_hwnd,int& a_w,int& a_h){
RECT rect;
::GetWindowRect(a_hwnd,&rect);
a_w = rect.right-rect.left;
a_h = rect.bottom-rect.top;
}
protected:
HWND m_hwnd;
bool m_key_shift;
bool m_key_ctrl;
HWND m_focus_hwnd;
};
}}
#endif
+403
View File
@@ -0,0 +1,403 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_X11_base_session
#define tools_X11_base_session
// pure X11 code, no GL.
#include <ostream>
#include <vector>
#include "dispatcher"
#include <tools/forit>
#include <X11/Xatom.h> //XA_INTEGER
#include <X11/Xutil.h> //XVisualInfo
namespace tools {
namespace X11 {
class base_session {
public:
//virtual bool make_current(Window) const {
// if(!m_display) return false;
// return true;
//}
//virtual bool swap_buffers(Window) const {
// if(!m_display) return false;
// return true;
//}
public:
base_session(std::ostream& a_out,unsigned int a_monitor = 0)
:m_out(a_out)
,m_monitor(a_monitor)
,m_display(0)
,m_WM_DELETE_WINDOW_atom(None)
,m_SESSION_EXIT_STEER_atom(None)
{
//NOTE : macOS : XOpenDisplay leaks 128 bytes.
m_display = ::XOpenDisplay(NULL);
if(!m_display) {
m_out << "tools::X11::base_session::base_session : can't open display." << std::endl;
return;
}
int monitors = ::XScreenCount(m_display);
if(int(m_monitor)>=monitors) {
m_out << "tools::X11::base_session::base_session : bad monitor index "
<< m_monitor << ". (#monitors " << monitors << ")." << std::endl;
::XCloseDisplay(m_display);
m_display = 0;
return;
}
m_WM_DELETE_WINDOW_atom = ::XInternAtom(m_display,"WM_DELETE_WINDOW",False);
if(m_WM_DELETE_WINDOW_atom==None) {
m_out << "tools::X11::base_session::base_session : can't create WM_DELETE_WINDOW Atom." << std::endl;
::XCloseDisplay(m_display);
m_display = 0;
return;
}
m_SESSION_EXIT_STEER_atom = ::XInternAtom(m_display,"TOOLS_X11_SESSION_EXIT_STEER",False);
if(m_SESSION_EXIT_STEER_atom==None) {
m_out << "tools::X11::base_session::base_session :"
<< " can't create TOOLS_X11_SESSION_EXIT_STEER Atom." << std::endl;
::XCloseDisplay(m_display);
m_display = 0;
return;
}
}
virtual ~base_session() {
clear_dispatchers();
if(m_display) ::XCloseDisplay(m_display);
m_display = 0;
//std::cout << "debug : ~base_session" << std::endl;
}
protected:
base_session(const base_session& a_from)
:m_out(a_from.m_out)
,m_monitor(a_from.m_monitor)
,m_display(0)
,m_WM_DELETE_WINDOW_atom(None)
,m_SESSION_EXIT_STEER_atom(None)
{}
base_session& operator=(const base_session& a_from){
if(&a_from==this) return *this;
return *this;
}
public:
std::ostream& out() const {return m_out;}
Atom WM_DELETE_WINDOW_atom() const {return m_WM_DELETE_WINDOW_atom;}
Atom SESSION_EXIT_STEER_atom() const {return m_SESSION_EXIT_STEER_atom;}
bool is_valid() const {return m_display?true:false;}
Display* display() const {return m_display;}
bool steer() {
if(!m_display) return false;
while(true) {
XEvent xevent;
::XNextEvent(m_display,&xevent);
if(xevent.type==ClientMessage) {
if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) break;
}
dispatch(xevent);
}
return true;
}
bool sync() {
if(!m_display) return false;
//::glXWaitX();
::XSync(m_display,False);
while(true) {
XEvent xevent;
if(::XPending(m_display)) {
::XNextEvent(m_display,&xevent);
if(xevent.type==ClientMessage) {
if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) return false;
}
dispatch(xevent);
} else {
break;
}
}
return true;
}
bool event_pending(bool& a_is) {
if(!m_display) {a_is = false;return false;}
a_is = ::XPending(m_display)?true:false;
return true;
}
bool next_event(bool& a_to_exit) {
if(!m_display) {a_to_exit = false;return false;}
XEvent xevent;
::XNextEvent(m_display,&xevent);
if(xevent.type==ClientMessage) {
if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) {
a_to_exit = true;
return true;
}
}
dispatch(xevent);
a_to_exit = false;
return true;
}
bool flush() {
if(!m_display) return false;
::XFlush(m_display);
return true;
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
//////////////////////////////////////////////////
Window create_window(const char* a_title,int a_x,int a_y,unsigned int a_width,unsigned int a_height) {
if(!m_display) return 0L;
XSetWindowAttributes swa;
swa.event_mask = StructureNotifyMask | ExposureMask
| ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
| PointerMotionMask
| KeyPressMask;
swa.background_pixel = ::XWhitePixel(m_display,m_monitor);
Window window = ::XCreateWindow(m_display,
::XRootWindow(m_display,m_monitor),
a_x,a_y,a_width,a_height,
0,
(int)CopyFromParent,
InputOutput,
(Visual*)CopyFromParent,
CWEventMask|CWBackPixel,&swa);
if(window==0L) {
m_out << "tools::X11::base_session::create_window : can't create a X11 window." << std::endl;
return 0L;
}
XTextProperty tp;
::XStringListToTextProperty((char**)&a_title,1,&tp);
XSizeHints sh;
sh.flags = USPosition | USSize;
::XSetWMProperties(m_display,window,&tp,&tp,0,0,&sh,0,0);
::XFree(tp.value);
::XSetWMProtocols(m_display,window,&m_WM_DELETE_WINDOW_atom,1);
return window;
}
void map_raise_window(Window a_window) const {
if(!m_display) return;
::XMapWindow(m_display,a_window);
::XRaiseWindow(m_display,a_window);
}
void show_window(Window a_window) const {
if(!m_display) return;
// we should test if already mapped ! Else we are going to forever wait in the below XIfEvent.
::XMapWindow(m_display,a_window);
::XRaiseWindow(m_display,a_window);
{XEvent event;
::XIfEvent(m_display,&event,wait_map_notify,(char*)a_window);}
}
void hide_window(Window a_window) const {
if(!m_display) return;
::XUnmapWindow(m_display,a_window);
{XEvent event;
::XIfEvent(m_display,&event,wait_unmap_notify,(char*)a_window);}
}
void resize_window(Window a_window,unsigned int a_width,unsigned int a_height) const {
if(!m_display) return;
unsigned int mask = CWWidth | CWHeight | CWBorderWidth;
XWindowChanges changes;
changes.border_width = 0;
changes.width = a_width;
changes.height = a_height;
::XConfigureWindow(m_display,a_window,mask,&changes);
}
bool window_size(Window a_window,int& a_width,int& a_height) const {
if(!m_display) {a_width = 0;a_height = 0;return false;}
XWindowAttributes watbs;
if(!XGetWindowAttributes(m_display,a_window,&watbs)) {a_width = 0;a_height = 0;return false;}
a_width = watbs.width;
a_height = watbs.height;
return true;
}
void delete_window(Window a_window) const {
if(!m_display) return;
::XDestroyWindow(m_display,a_window);
}
void set_override_redirect(Window a_window) const {
//must be executed before window is mapped.
if(!m_display) return;
XSetWindowAttributes swa;
swa.override_redirect = True;
::XChangeWindowAttributes(m_display,a_window,CWOverrideRedirect,&swa);
}
void set_wm_no_decorations(Window a_window) const {
//must be executed before window is mapped.
if(!m_display) return;
// struct, mwm_hints_decorations taken from OpenMotif MwmUtils.h.
struct{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
} prop;
//unsigned long mwm_hints_functions = 1L << 0;
unsigned long mwm_hints_decorations = 1L << 1;
Atom atom = ::XInternAtom(m_display,"_MOTIF_WM_HINTS",False);
if(atom==None) {
m_out << "tools::X11::base_session::set_wm_no_decorations : can't create/get _MOTIF_WM_HINTS Atom." << std::endl;
return;
}
prop.flags = mwm_hints_decorations;
prop.functions = 0;
prop.decorations = 0;
::XChangeProperty(m_display,a_window,atom,atom,32,PropModeReplace,(unsigned char*)&prop,5);
}
bool post(Window a_win,
long a_0 = 0,long a_1 = 0,
long a_2 = 0,long a_3 = 0,
long a_4 = 0) const {
if(!m_display) return false;
XEvent event;
event.type = ClientMessage;
event.xclient.display = m_display;
event.xclient.window = a_win;
event.xclient.message_type = XA_INTEGER;
event.xclient.format = 8; /* put 8 because bug with 32 on VMCMS */
event.xclient.data.l[0] = a_0;
event.xclient.data.l[1] = a_1;
event.xclient.data.l[2] = a_2;
event.xclient.data.l[3] = a_3;
event.xclient.data.l[4] = a_4;
//lock();
Status stat = ::XSendEvent(m_display,a_win,False,0L,&event);
::XFlush(m_display);
//unlock();
return (stat==0?false:true);
}
bool post_EXIT_STEER(Window a_win) {
return post(a_win,SESSION_EXIT_STEER_atom());
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
//////////////////////////////////////////////////
void add_dispatcher(dispatcher* a_dispatcher) {
m_dispatchers.push_back(a_dispatcher); //take ownership.
}
void invalidate_dispatchers_with_window(Window a_win){
tools_vforit(dispatcher*,m_dispatchers,it) {
if((*it)->window()==a_win) (*it)->invalidate();
}
}
void remove_dispatchers_with_window(Window a_win){
tools_vforit_npp(dispatcher*,m_dispatchers,it) {
if((*it)->window()==a_win) {
dispatcher* obj = *it;
it = m_dispatchers.erase(it);
delete obj;
} else {
it++;
}
}
}
bool dispatch(XEvent& a_event) {
{tools_vforit_npp(dispatcher*,m_dispatchers,it) {
if(!(*it)->is_valid()) {
dispatcher* obj = *it;
it = m_dispatchers.erase(it);
delete obj;
} else {
it++;
}
}}
tools_vforit(dispatcher*,m_dispatchers,it) {
if((*it)->is_valid()) {
if((*it)->dispatch(a_event)) return true;
}
}
return false;
}
protected:
static Bool wait_map_notify(Display*,XEvent* a_event,char* a_arg){
return (a_event->type == MapNotify) && (a_event->xmap.window == (Window)a_arg);
}
static Bool wait_unmap_notify(Display*,XEvent* a_event,char* a_arg){
return (a_event->type == UnmapNotify) && (a_event->xmap.window == (Window)a_arg);
}
/*
void wait_xxx(Window a_window) {
if(!m_display) return;
{wait_what arg;
arg.m_event_type = ConfigureNotify;
arg.m_window = a_window;
XEvent event;
::XIfEvent(m_display,&event,wait_for,(char*)&arg);
dispatch(event);}
}
struct wait_what {
int m_event_type;
Window m_window;
};
static Bool wait_for(Display*,XEvent* a_event,char* a_arg){
wait_what* arg = (wait_what*)a_arg;
return (a_event->type == arg->m_event_type) &&
(a_event->xmap.window == arg->m_window);
}
*/
void clear_dispatchers() {
tools_vforit_npp(dispatcher*,m_dispatchers,it) {
dispatcher* obj = *it;
it = m_dispatchers.erase(it);
delete obj;
}
m_dispatchers.clear();
}
protected:
std::ostream& m_out;
unsigned int m_monitor;
Display* m_display;
Atom m_WM_DELETE_WINDOW_atom;
Atom m_SESSION_EXIT_STEER_atom;
std::vector<dispatcher*> m_dispatchers;
};
}}
#endif
+56
View File
@@ -0,0 +1,56 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_X11_dispatcher
#define tools_X11_dispatcher
#include <X11/Xlib.h>
#ifdef TOOLS_MEM
#include <tools/mem>
#endif
namespace tools {
namespace X11 {
class dispatcher {
protected:
#ifdef TOOLS_MEM
static const std::string& s_class() {
static const std::string s_v("tools::X11::dispatcher");
return s_v;
}
#endif
public:
virtual bool dispatch(XEvent&) = 0;
virtual Window window() const = 0;
virtual dispatcher* copy() const = 0;
public:
dispatcher():m_is_valid(true){
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
virtual ~dispatcher(){
#ifdef TOOLS_MEM
tools::mem::decrement(s_class().c_str());
#endif
}
public:
dispatcher(const dispatcher& a_from):m_is_valid(a_from.m_is_valid){
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
dispatcher& operator=(const dispatcher& a_from) { m_is_valid = a_from.m_is_valid;return *this;}
public:
bool is_valid() const {return m_is_valid;}
void invalidate() {m_is_valid = false;}
protected:
bool m_is_valid;
};
}}
#endif
+207
View File
@@ -0,0 +1,207 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_X11_session
#define tools_X11_session
#include "base_session"
#include <GL/glx.h>
namespace tools {
namespace X11 {
class session : public base_session {
typedef base_session parent;
public:
//virtual bool make_current(Window a_window) const {
// if(!m_display) return false;
// if(::glXMakeCurrent(m_display,a_window,m_ctx)==False) {
// m_out << "tools::X11::session::make_current : glXMakeCurrent failed." << std::endl;
// return false;
// }
// return true;
//}
//virtual bool swap_buffers(Window a_window) const {
// if(!m_display) return false;
// ::glXSwapBuffers(m_display,a_window);
// return true;
//}
public:
session(std::ostream& a_out,unsigned int a_monitor = 0)
:parent(a_out,a_monitor)
,m_vinfo(0)
,m_ctx(0)
,m_colormap(0)
{
if(!m_display) return;
{int glxMajor, glxMinor;
::glXQueryVersion(m_display,&glxMajor,&glxMinor);
if(glxMajor<=0) {
m_out << "tools::X11::session::session : bad GLX-Version " << glxMajor << "." << glxMinor << std::endl;
::XCloseDisplay(m_display);
m_display = 0;
m_vinfo = 0;
m_ctx = 0;
return;
}}
static const int atbs_alpha[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None};
//NOTE : macOS : glXChooseVisual leaks 640 bytes.
m_vinfo = ::glXChooseVisual(m_display,m_monitor,(int*)atbs_alpha);
if(!m_vinfo) {
//m_out << "tools::X11::session::initialize :"
// << " can't get a visual with alpha on screen " << m_monitor << ". Try without alpha..."
// << std::endl;
//m_out << "tools::X11::session::initialize :"
// << " DefaultScreen(m_display): " << DefaultScreen(m_display) << "."
// << std::endl;
static const int atbs[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None};
m_vinfo = ::glXChooseVisual(m_display,m_monitor,(int*)atbs);
if(!m_vinfo) {
m_out << "tools::X11::session::session :"
<< " can't choose a visual on screen " << m_monitor << "."
<< std::endl;
::XCloseDisplay(m_display);
m_display = 0;
m_vinfo = 0;
m_ctx = 0;
return;
}
}
m_ctx = ::glXCreateContext(m_display,m_vinfo,NULL,GL_TRUE);
if(!m_ctx) {
m_out << "tools::X11::session::session :"
<< " can't create a glX context with direct rendering."
<< std::endl;
m_ctx = ::glXCreateContext(m_display,m_vinfo,NULL,GL_FALSE);
if(!m_ctx) {
m_out << "tools::X11::session::session :"
<< " can't create a glX context."
<< std::endl;
::XCloseDisplay(m_display);
m_display = 0;
m_vinfo = 0;
m_ctx = 0;
return;
}
//} else {
//m_out << "tools::X11::session::session :"
// << " glX context with direct rendering created."
// << std::endl;
}
// It is better to create a colormap adapted to the visual.
m_colormap = ::XCreateColormap(m_display,::XRootWindow(m_display,m_monitor),m_vinfo->visual,AllocNone);
//m_colormap = ::XDefaultColormap(m_display,m_monitor);
if(m_colormap==0L) {
m_out << "tools::X11::session::session : XCreateColormap failed." << std::endl;
::XCloseDisplay(m_display);
m_display = 0;
m_vinfo = 0;
m_ctx = 0;
return;
}
}
virtual ~session() {
if(m_display) {
if(m_ctx) {
::glXDestroyContext(m_display,m_ctx);
m_ctx = 0;
}
if(m_colormap) {
::XFreeColormap(m_display,m_colormap);
m_colormap = 0;
}
::XCloseDisplay(m_display);
m_display = 0;
}
if(m_vinfo) {
::XFree(m_vinfo);
m_vinfo = 0;
}
//std::cout << "debug : ~session" << std::endl;
}
protected:
session(const session& a_from)
:parent(a_from)
,m_vinfo(0)
,m_ctx(0)
,m_colormap(0)
{}
session& operator=(const session& a_from){
if(&a_from==this) return *this;
parent::operator=(a_from);
return *this;
}
public:
GLXContext context() const {return m_ctx;}
Window create_window(const char* a_title,int a_x,int a_y,unsigned int a_width,unsigned int a_height) {
if(!m_display) return 0L;
XSetWindowAttributes swa;
swa.event_mask = StructureNotifyMask | ExposureMask
| ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
| PointerMotionMask
| KeyPressMask;
swa.colormap = m_colormap;
swa.border_pixel = 0L;
Window window = ::XCreateWindow(m_display,
::XRootWindow(m_display,m_monitor),
a_x,a_y,a_width,a_height,
0,
m_vinfo->depth,
InputOutput,
m_vinfo->visual,
CWBorderPixel|CWColormap|CWEventMask,&swa);
if(window==0L) {
m_out << "tools::X11::session::create_window :"
<< " can't create a X11 window."
<< std::endl;
return 0L;
}
XTextProperty tp;
::XStringListToTextProperty((char**)&a_title,1,&tp);
XSizeHints sh;
sh.flags = USPosition | USSize;
::XSetWMProperties(m_display,window,&tp,&tp,0,0,&sh,0,0);
::XFree(tp.value);
::XSetWMProtocols(m_display,window,&m_WM_DELETE_WINDOW_atom,1);
return window;
}
protected:
XVisualInfo* m_vinfo;
GLXContext m_ctx;
Colormap m_colormap;
};
}}
#endif
+113
View File
@@ -0,0 +1,113 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_X11_sg_viewer
#define tools_X11_sg_viewer
// not pure X11 version. The class inherits tools::sg::viewer that uses GL.
#include "session"
#include "../sg/GL_viewer"
#include "simple_dispatcher"
namespace tools{namespace sg{class device_interactor;}}
namespace tools {
namespace X11 {
class sg_viewer : public sg::GL_viewer {
typedef sg::GL_viewer parent;
private:
class dispatcher : public simple_dispatcher {
typedef simple_dispatcher parent;
public:
virtual void win_render() {m_sg_viewer.win_render();}
virtual void set_size(unsigned int a_width,unsigned int a_height) {m_sg_viewer.set_size(a_width,a_height);}
virtual dispatcher* copy() const {return new dispatcher(*this);}
public:
dispatcher(sg_viewer& a_sg_viewer)
:parent(a_sg_viewer.m_session,a_sg_viewer.m_win)
,m_sg_viewer(a_sg_viewer){}
virtual ~dispatcher(){}
protected:
dispatcher(const dispatcher& a_from)
:parent(a_from)
,m_sg_viewer(a_from.m_sg_viewer)
{}
dispatcher& operator=(const dispatcher& a_from) {
parent::operator=(a_from);
return *this;
}
protected:
sg_viewer& m_sg_viewer;
};
public:
sg_viewer(session& a_session,
int a_x = 0,int a_y = 0,
unsigned int a_width = 500,unsigned int a_height = 500,
const std::string& a_win_title = "")
:parent(a_session.out(),a_width,a_height)
,m_session(a_session)
,m_win(0)
{
if(!m_session.display()) return; //throw
m_win = m_session.create_window(a_win_title.c_str(),a_x,a_y,a_width,a_height);
if(!m_win) return; //throw
m_session.add_dispatcher(new dispatcher(*this));
}
virtual ~sg_viewer() {
if(m_win) {
m_session.remove_dispatchers_with_window(m_win);
m_session.delete_window(m_win);
m_session.sync();
}
}
public:
sg_viewer(const sg_viewer& a_from)
:parent(a_from)
,m_session(a_from.m_session)
,m_win(a_from.m_win)
{}
sg_viewer& operator=(const sg_viewer& a_from){
parent::operator=(a_from);
m_win = a_from.m_win;
return *this;
}
public:
bool has_window() const {return m_win?true:false;} //for SWIG
Window window() const {return m_win;}
bool show() {
if(!m_win) return false;
m_session.show_window(m_win);
return true;
}
void win_render() {
if(!m_win) return;
if(::glXMakeCurrent(m_session.display(),m_win,m_session.context())==False){
m_session.out() << "tools::X11::sg_viewer::win_render : glXMakeCurrent failed." << std::endl;
return;
}
render(); //viewer::render()
::glXSwapBuffers(m_session.display(),m_win);
if(::glXMakeCurrent(m_session.display(),None,NULL)==False){
m_session.out() << "tools::X11::sg_viewer::win_render : glXMakeCurrent(None,NULL) failed." << std::endl;
}
}
public:
void set_device_interactor(tools::sg::device_interactor*) {}
protected:
session& m_session;
Window m_win;
};
}}
#endif
@@ -0,0 +1,63 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_X11_simple_dispatcher
#define tools_X11_simple_dispatcher
#include "base_session"
#include <tools/saui>
namespace tools {
namespace X11 {
class simple_dispatcher : public dispatcher {
typedef dispatcher parent;
public:
virtual void win_render() = 0;
virtual void set_size(unsigned int a_width,unsigned int a_height) = 0;
public:
virtual bool dispatch(XEvent& a_event) {
if(!m_win) return false;
if(a_event.xany.window!=m_win) return false;
if( (a_event.type==Expose) || (a_event.type==ConfigureNotify) ){
int width,height;
m_session.window_size(m_win,width,height);
set_size(width,height); //viewer::set_size()
win_render();
return true;
} else if(a_event.type==ClientMessage) {
if(a_event.xclient.data.l[0]==(long)m_session.WM_DELETE_WINDOW_atom()) {
m_session.post(m_win,m_session.SESSION_EXIT_STEER_atom());
return true;
}
}
return false;
}
virtual Window window() const {return m_win;}
public:
simple_dispatcher(base_session& a_session,Window a_win)
:parent()
,m_session(a_session)
,m_win(a_win)
{}
virtual ~simple_dispatcher(){}
public:
simple_dispatcher(const simple_dispatcher& a_from)
:parent(a_from)
,m_session(a_from.m_session)
,m_win(a_from.m_win)
{}
simple_dispatcher& operator=(const simple_dispatcher& a_from) {
parent::operator=(a_from);
m_win = a_from.m_win;
return *this;
}
protected:
base_session& m_session;
Window m_win;
};
}}
#endif
+481
View File
@@ -0,0 +1,481 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Xt_OpenGLArea
#define tools_Xt_OpenGLArea
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>
#include <X11/StringDefs.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
namespace tools {
namespace Xt {
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
typedef struct _OpenGLAreaClassRec* OpenGLAreaWidgetClass;
typedef struct _OpenGLAreaRec* OpenGLAreaWidget;
typedef struct {
int reason;
XEvent* event;
} XoAnyCallbackStruct;
#define XoNdoubleBufferOn "doubleBufferOn"
#define XoNpaintCallback "paintCallback"
#define XoNeventCallback "eventCallback"
#define XoCR_PAINT 1
#define XoCR_EVENT 2
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
typedef struct {
void* extension;
} OpenGLAreaClassPart;
typedef struct _OpenGLAreaClassRec {
CoreClassPart core_class;
CompositeClassPart composite_class;
OpenGLAreaClassPart openGLArea_class;
} OpenGLAreaClassRec;
typedef struct {
Boolean doubleBufferOn;
XtCallbackList paintCallback;
XtCallbackList eventCallback;
Visual* visual;
Boolean installColormap;
GLXContext glContext;
} OpenGLAreaPart;
typedef struct _OpenGLAreaRec {
CorePart core;
CompositePart composite;
OpenGLAreaPart openGLArea;
} OpenGLAreaRec;
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
class OpenGLArea {
public:
static void paint(Widget a_this) {
if(!XtIsRealized(a_this)) return;
if(make_current(a_this)==1) {
XoAnyCallbackStruct value;
value.reason = XoCR_PAINT;
value.event = 0;
::XtCallCallbacks(a_this,XoNpaintCallback,(XtPointer)&value);
::glXSwapBuffers(XtDisplay(a_this),XtWindow(a_this));
::glXMakeCurrent(XtDisplay(a_this),None,NULL);
}
}
protected:
static void initialize_class(void) {}
static void initialize_widget(Widget a_request,Widget a_this,ArgList,Cardinal*) {
if(a_request->core.width<=0) a_this->core.width = 100;
if(a_request->core.height<=0) a_this->core.height = 100;
#ifdef OPENGLAREA_DEBUG
::printf ("debug : OpenGLArea : InitializeWidget : %s\n",::XtName(a_this));
#endif
OpenGLAreaPart& athis = _athis(a_this);
athis.visual = CopyFromParent;
athis.installColormap = False;
athis.glContext = NULL;
Display* display;
Screen* screen;
int iscreen;
XVisualInfo* vinfo;
display = XtDisplay(a_this);
screen = XtScreen(a_this);
iscreen = XScreenNumberOfScreen(screen);
{int error,event;
if(::glXQueryExtension(display,&error,&event)==0) {
CWarn ("X server does not have OpenGL extensions.\n");
}}
if(athis.doubleBufferOn==True) {
int atbs_1[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None
};
vinfo = ::glXChooseVisual (display,iscreen,atbs_1);
if(vinfo==NULL) { //GLX_ALPHA_SIZE : problem with Xming. Try without it.
int atbs_2[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None
};
vinfo = ::glXChooseVisual (display,iscreen,atbs_2);
}
} else {
int atbs_1[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None
};
vinfo = ::glXChooseVisual (display,iscreen,atbs_1);
if(vinfo==NULL) { //GLX_ALPHA_SIZE : problem with Xming. Try without it.
int atbs_2[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None
};
vinfo = ::glXChooseVisual (display,iscreen,atbs_2);
}
}
if(vinfo==NULL) {
CWarn ("Can't choose a visual.\n");
} else {
a_this->core.depth = vinfo->depth;
athis.visual = vinfo->visual;
if( (vinfo->depth ==DefaultDepth (display,iscreen)) &&
(vinfo->visual==DefaultVisual(display,iscreen)) ) {
a_this->core.colormap = XDefaultColormap (display,iscreen);
athis.installColormap = False;
} else {
a_this->core.colormap =
XCreateColormap (display,XRootWindow(display,iscreen),vinfo->visual, AllocNone);
athis.installColormap = True;
}
if(a_this->core.colormap==0L) {
CWarn ("Can't get/create a X colormap.\n");
}
athis.glContext = ::glXCreateContext (display,vinfo,NULL,GL_TRUE);
if(athis.glContext==NULL) {
athis.glContext = ::glXCreateContext (display,vinfo,NULL,GL_FALSE);
if(athis.glContext==NULL) {
CWarn ("Can't create a GLX context.\n");
}
}
::XFree(vinfo);
}
::XtAddEventHandler
(a_this,ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|KeyPressMask|KeyReleaseMask,0,event_handler,NULL);
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : InitializeWidget : end\n");
#endif
}
static void realize_widget(Widget a_this,XtValueMask* a_mask,XSetWindowAttributes* a_watbs) {
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : realize_widget : %s\n",XtName(a_this));
#endif
// Have to create window ourselves due to OpenGL that compells it's visual.
// In principle colormap is correctly set in a_watbsy.
OpenGLAreaPart& athis = _athis(a_this);
::XtCreateWindow(a_this,(unsigned int)InputOutput,athis.visual,*a_mask,a_watbs);
// Call the Realize procedure (XtInheritRealize) :
if(widget_class()->core_class.superclass->core_class.realize!=NULL)
(widget_class()->core_class.superclass->core_class.realize)(a_this, a_mask, a_watbs);
// If window is delete, all seems ok :
if(athis.installColormap==True) install_colormap(a_this);
//make_current(a_this);
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : realize_widget : end\n");
#endif
}
static void destroy_widget(Widget a_this) {
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : destroy_widget : begin\n");
#endif
OpenGLAreaPart& athis = _athis(a_this);
if(athis.installColormap==True) {
uninstall_colormap (a_this);
athis.installColormap = False;
::XFreeColormap(XtDisplay(a_this),a_this->core.colormap);
}
if(athis.glContext!=NULL) {
::glXMakeCurrent(XtDisplay(a_this),None,NULL);
::glXDestroyContext(XtDisplay(a_this),athis.glContext);
athis.glContext = NULL;
}
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : destroy_widget : end\n");
#endif
}
static Boolean set_values(Widget a_current,Widget,Widget a_this,ArgList,Cardinal*) {
OpenGLAreaPart& athis = _athis(a_this);
if(athis.doubleBufferOn != ((OpenGLAreaWidget)a_current)->openGLArea.doubleBufferOn) {
// Can't change buffering here if X window is created.
// With OpenGL, buffering fix parameter of the X window.
// Buffering must be choosen before the execution of the
// Realize method that create the window.
if(XtIsRealized(a_this) && (athis.installColormap==True)) {
CWarn("Can't change buffering after \"realization\" of the widget.\n");
athis.doubleBufferOn = ((OpenGLAreaWidget)a_current)->openGLArea.doubleBufferOn;
}
}
return False;
}
static void change_widget_size(Widget a_this) {
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : change_widget_size : %s\n",XtName(a_this));
#endif
// Call the Resize procedure (XtInheritResize) :
if(widget_class()->core_class.superclass->core_class.resize!=NULL)
(widget_class()->core_class.superclass->core_class.resize)(a_this);
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : change_widget_size : end\n");
#endif
}
static void draw_widget(Widget a_this,XEvent* a_event,Region a_region) {
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : draw_widget : %s\n",XtName(a_this));
#endif
if(widget_class()->core_class.superclass->core_class.expose!=NULL)
(widget_class()->core_class.superclass->core_class.expose)(a_this,a_event,a_region);
if(make_current(a_this)==1) {
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : draw_widget : %s : make_current ok : call paintCallback...\n",XtName(a_this));
#endif
XoAnyCallbackStruct value;
value.reason = XoCR_PAINT;
value.event = a_event;
::XtCallCallbacks(a_this,XoNpaintCallback,(XtPointer)&value);
::glXSwapBuffers(XtDisplay(a_this),XtWindow(a_this));
::glXMakeCurrent(XtDisplay(a_this),None,NULL);
}
#ifdef OPENGLAREA_DEBUG
printf("debug : OpenGLArea : draw_widget : end\n");
#endif
}
protected:
static OpenGLAreaPart& _athis(Widget a_this) {return *(&(((OpenGLAreaWidget)a_this)->openGLArea));}
static void CWarn(const char* a_msg) {
::printf("%s",a_msg);
}
static void CWarnF(const char* a_format,...) {
va_list args;
va_start(args,a_format);
::vprintf(a_format,args);
va_end(args);
}
static int make_current(Widget a_this) {
if(!XtIsRealized(a_this)) return 0;
OpenGLAreaPart& athis = _athis(a_this);
if(athis.glContext==NULL) return 0;
return (int)::glXMakeCurrent(XtDisplay(a_this),XtWindow(a_this),athis.glContext);
}
static void event_handler(Widget a_this,XtPointer,XEvent* a_event ,Boolean*) {
XoAnyCallbackStruct value;
value.reason = XoCR_EVENT;
value.event = a_event;
::XtCallCallbacks(a_this,XoNeventCallback,(XtPointer)&value);
}
static void install_colormap(Widget a_this) {
// From Mesa/widgets/GLwDrawingArea.c/post_colormap routine.
// Could use also XtSetWMColormapWindows.
if( !XtIsWidget(a_this) || !XtIsRealized(a_this) ) return;
Widget shell = get_shell(a_this);
if(shell==NULL) return;
Display* display = XtDisplay (a_this);
Window wthis = XtWindow (a_this);
Window wshell = XtWindow (shell);
Window* ws = NULL;
int wn = 0;
::XGetWMColormapWindows (display,wshell, &ws, &wn);
// Check if colormap of this is a colormap of a Window in list :
XWindowAttributes watbs;
XGetWindowAttributes (display,wthis,&watbs);
Colormap cmapthis = watbs.colormap;
int found = -1;
for(int count=0;count<wn;count++) {
Colormap cmap;
XGetWindowAttributes (display,ws[count],&watbs);
cmap = watbs.colormap;
if(cmap==cmapthis) {
::XFree (ws);
return;
}
if(ws[count]==wshell) {
found = count;
}
}
// Have to add window of this in list :
if(wn==0) {
if(ws!=NULL) ::XFree(ws);
ws = (Window*)::malloc( 2 * sizeof(Window));
} else {
ws = (Window*)::realloc(ws,(wn + 2) * sizeof(Window));
}
if(ws==NULL) return;
if(found==-1) {
// Window of shell not in list :
ws[wn] = wthis; wn++;
ws[wn] = wshell;wn++;
} else {
ws[found] = wthis;
ws[wn] = wshell; wn++; // Shell must be last.
}
if (::XSetWMColormapWindows(display,wshell, ws, wn)==0) {
CWarnF ("install_colormap: can't install colormap of %s in %s.\n",XtName(a_this),XtName(shell));
}
::free(ws);
}
static void uninstall_colormap(Widget a_this) {
if( !XtIsWidget(a_this) || !XtIsRealized(a_this) ) return;
Widget shell = get_shell (a_this);
if(shell==NULL) return;
Display* display = XtDisplay (a_this);
Window wthis = XtWindow (a_this);
Window wshell = XtWindow (shell);
Window* ws = NULL;
int wn = 0;
::XGetWMColormapWindows (display,wshell, &ws, &wn);
if( (wn==0) || (ws==NULL) ) return;
Window* nws = (Window*)::malloc( wn * sizeof(Window));
if(nws==NULL) {
::XFree (ws);
return;
}
int nwn = 0;
for(int count=0;count<wn;count++) {
if(ws[count]!=wthis) {
nws[nwn] = ws[count];
nwn++;
}
}
if(wn!=nwn) {
if (::XSetWMColormapWindows(display,wshell, nws, nwn)==0) {
CWarnF("uninstall_colormap: can't install colormap of %s in %s.\n",XtName(a_this),XtName(shell));
}
}
::XFree (ws);
::free (nws);
}
static Widget get_shell(Widget a_this) {
Widget widget = a_this;
while(1) {
if(widget==NULL) return NULL;
if(XtIsShell(widget)) return widget;
widget = XtParent(widget);
}
}
public:
static WidgetClass widget_class() {
static XtResource s_resources [] = {
{(String)XoNdoubleBufferOn,(String)"DoubleBufferOn",XtRBoolean,sizeof(Boolean),
XtOffset(OpenGLAreaWidget,openGLArea.doubleBufferOn),XtRImmediate,(XtPointer)True},
{(String)XoNpaintCallback,XtCCallback,XtRCallback,sizeof(XtCallbackList),
XtOffset(OpenGLAreaWidget,openGLArea.paintCallback),XtRImmediate,(XtPointer)NULL},
{(String)XoNeventCallback,XtCCallback,XtRCallback,sizeof(XtCallbackList),
XtOffset(OpenGLAreaWidget,openGLArea.eventCallback),XtRImmediate,(XtPointer)NULL}
};
static OpenGLAreaClassRec s_openGLAreaClassRec = {
// Core Class Part :
{
(WidgetClass) &compositeClassRec, // pointer to superclass ClassRec
(String)"OpenGLArea", // widget resource class name
sizeof(OpenGLAreaRec), // size in bytes of widget record
initialize_class, // class_initialize
NULL, // dynamic initialization
FALSE, // has class been initialized?
initialize_widget, // initialize
NULL, // notify that initialize called
realize_widget, // XCreateWindow for widget
NULL, // widget semantics name to proc mapWidget
0, // number of entries in actions
s_resources, // resources for subclass fields
XtNumber(s_resources), // number of entries in resources
NULLQUARK, // resource class quarkified
TRUE, // compress MotionNotify for widget
TRUE, // compress Expose events for widget
TRUE, // compress enter and leave events
TRUE, // select for VisibilityNotify
destroy_widget, // free data for subclass pointers
change_widget_size, // geom manager changed widget size
draw_widget, // rediplay window
set_values, // set subclass resource values
NULL, // notify that SetValues called
XtInheritSetValuesAlmost, // SetValues got "Almost" geo reply
NULL, // notify that get_values called
XtInheritAcceptFocus, // assign input focus to widget
XtVersion, // version of intrinsics used
NULL, // list of callback offsets
XtInheritTranslations, // translations
XtInheritQueryGeometry, // return preferred geometry
XtInheritDisplayAccelerator, // display your accelerator
NULL // pointer to extension record
},
// Composite Class Part :
{
XtInheritGeometryManager, // geometry manager for children
XtInheritChangeManaged, // change managed state of child
XtInheritInsertChild, // physically add child to parent
XtInheritDeleteChild, // physically remove child
NULL // pointer to extension record
},
// OpenGLArea :
{
NULL
}
};
return (WidgetClass)&s_openGLAreaClassRec;
}
};
}}
#endif
+531
View File
@@ -0,0 +1,531 @@
/*
#define DEBUG
*/
/*this*/
#include "OpenGLAreaP.h"
#include <X11/StringDefs.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C"{
#endif
static void InitializeClass(void);
static void InitializeWidget(Widget, Widget,ArgList,Cardinal*);
static void RealizeWidget(Widget, XtValueMask*, XSetWindowAttributes*);
static void DestroyWidget(Widget);
static void ChangeWidgetSize(Widget);
static void DrawWidget(Widget, XEvent*, Region);
static Boolean SetValues(Widget,Widget,Widget,ArgList,Cardinal *);
static void EventHandler(Widget,XtPointer,XEvent*,Boolean*);
static int MakeCurrent(Widget);
static void XWidgetInstallColormap(Widget);
static void XWidgetUninstallColormap(Widget);
static Widget XWidgetGetShell(Widget);
#ifdef __cplusplus
}
#endif
#define athis ((OpenGLAreaWidget)This)->openGLArea
#define acur ((OpenGLAreaWidget)a_current)->openGLArea
#define CWarn printf
#define CWarnF printf
static XtResource resources [] = {
{XoNdoubleBufferOn,"DoubleBufferOn",XtRBoolean,sizeof(Boolean),
XtOffset(OpenGLAreaWidget,openGLArea.doubleBufferOn),XtRImmediate,(XtPointer)True},
{XoNpaintCallback,XtCCallback,XtRCallback,sizeof(XtCallbackList),
XtOffset(OpenGLAreaWidget,openGLArea.paintCallback),XtRImmediate,(XtPointer)NULL},
{XoNeventCallback,XtCCallback,XtRCallback,sizeof(XtCallbackList),
XtOffset(OpenGLAreaWidget,openGLArea.eventCallback),XtRImmediate,(XtPointer)NULL}
};
OpenGLAreaClassRec openGLAreaClassRec = {
/* Core Class Part */
{
(WidgetClass) &compositeClassRec, /* pointer to superclass ClassRec */
"OpenGLArea", /* widget resource class name */
sizeof(OpenGLAreaRec), /* size in bytes of widget record */
InitializeClass, /* class_initialize */
NULL, /* dynamic initialization */
FALSE, /* has class been initialized? */
InitializeWidget, /* initialize */
NULL, /* notify that initialize called */
RealizeWidget, /* XCreateWindow for widget */
NULL, /* widget semantics name to proc mapWidget*/
0, /* number of entries in actions */
resources, /* resources for subclass fields */
XtNumber(resources), /* number of entries in resources */
NULLQUARK, /* resource class quarkified */
TRUE, /* compress MotionNotify for widget */
TRUE, /* compress Expose events for widget*/
TRUE, /* compress enter and leave events */
TRUE, /* select for VisibilityNotify */
DestroyWidget, /* free data for subclass pointers */
ChangeWidgetSize, /* geom manager changed widget size */
DrawWidget, /* rediplay window */
SetValues, /* set subclass resource values */
NULL, /* notify that SetValues called */
XtInheritSetValuesAlmost, /* SetValues got "Almost" geo reply*/
NULL, /* notify that get_values called */
XtInheritAcceptFocus, /* assign input focus to widget */
XtVersion, /* version of intrinsics used */
NULL, /* list of callback offsets */
XtInheritTranslations, /* translations */
XtInheritQueryGeometry, /* return preferred geometry */
XtInheritDisplayAccelerator, /* display your accelerator */
NULL /* pointer to extension record */
},
/* Composite Class Part */
{
XtInheritGeometryManager, /* geometry manager for children */
XtInheritChangeManaged, /* change managed state of child */
XtInheritInsertChild, /* physically add child to parent */
XtInheritDeleteChild, /* physically remove child */
NULL /* pointer to extension record */
},
/* OpenGLArea */
{
NULL
}
};
WidgetClass openGLAreaWidgetClass = (WidgetClass) &openGLAreaClassRec;
static void InitializeClass(void) {}
static void InitializeWidget(Widget a_request,Widget This,ArgList a_args,Cardinal* a_argn) {
if(a_request->core.width<=0) This->core.width = 100;
if(a_request->core.height<=0) This->core.height = 100;
#ifdef DEBUG
printf ("debug : OpenGLArea : InitializeWidget : %s\n",XtName(This));
#endif
athis.visual = CopyFromParent;
athis.installColormap = False;
athis.glContext = NULL;
{Display* display;
Screen* screen;
int iscreen;
XVisualInfo* vinfo;
display = XtDisplay(This);
screen = XtScreen(This);
iscreen = XScreenNumberOfScreen(screen);
{int error,event;
if(glXQueryExtension(display,&error,&event)==0) {
CWarn ("X server does not have OpenGL extensions.\n");
}}
if(athis.doubleBufferOn==True) {
int atbs[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None
};
vinfo = glXChooseVisual (display,iscreen,atbs);
if(vinfo==NULL) { /*GLX_ALPHA_SIZE : problem with Xming. Try without it.*/
int atbs[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None
};
vinfo = glXChooseVisual (display,iscreen,atbs);
}
} else {
int atbs[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None
};
vinfo = glXChooseVisual (display,iscreen,atbs);
if(vinfo==NULL) { /*GLX_ALPHA_SIZE : problem with Xming. Try without it.*/
int atbs[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None
};
vinfo = glXChooseVisual (display,iscreen,atbs);
}
}
if(vinfo==NULL) {
CWarn ("Can't choose a visual.\n");
} else {
This->core.depth = vinfo->depth;
athis.visual = vinfo->visual;
if( (vinfo->depth ==DefaultDepth (display,iscreen)) &&
(vinfo->visual==DefaultVisual(display,iscreen)) ) {
This->core.colormap = XDefaultColormap (display,iscreen);
athis.installColormap = False;
} else {
This->core.colormap =
XCreateColormap (display,XRootWindow(display,iscreen),vinfo->visual, AllocNone);
athis.installColormap = True;
}
if(This->core.colormap==0L) {
CWarn ("Can't get/create a X colormap.\n");
}
athis.glContext = glXCreateContext (display,vinfo,NULL,GL_FALSE);
if(athis.glContext==NULL) {
CWarn ("Can't create a GLX context.\n");
}
XFree(vinfo);
}}
XtAddEventHandler(This,ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,0,EventHandler,NULL);
#ifdef DEBUG
printf("debug : OpenGLArea : InitializeWidget : end\n");
#endif
/*avoid C++ warnings*/
a_request = NULL;
a_args = NULL;
a_argn = 0;
}
static void RealizeWidget(Widget This,XtValueMask* a_mask,XSetWindowAttributes* a_watbs) {
#ifdef DEBUG
printf("debug : OpenGLArea : RealizeWidget : %s\n",XtName(This));
#endif
/*Have to create window ourselves due to OpenGL that compells it's visual.*/
/*In principle colormap is correctly set in a_watbs.*/
XtCreateWindow(This,(unsigned int)InputOutput,athis.visual,*a_mask,a_watbs);
/* Call the Realize procedure (XtInheritRealize) */
if(openGLAreaWidgetClass->core_class.superclass->core_class.realize!=NULL)
(openGLAreaWidgetClass->core_class.superclass->core_class.realize)(This, a_mask, a_watbs);
/*If window is delete, all seems ok.*/
if(athis.installColormap==True) XWidgetInstallColormap(This);
/*MakeCurrent(This);*/
#ifdef DEBUG
printf("debug : OpenGLArea : RealizeWidget : end\n");
#endif
}
static void DestroyWidget(Widget This) {
if(athis.installColormap==True) {
XWidgetUninstallColormap (This);
athis.installColormap = False;
XFreeColormap(XtDisplay(This),This->core.colormap);
}
if(athis.glContext!=NULL) {
glXMakeCurrent(XtDisplay(This),None,NULL);
glXDestroyContext(XtDisplay(This),athis.glContext);
athis.glContext = NULL;
}
}
#define IFMOD(a_field) if(athis.a_field != acur.a_field)
static Boolean SetValues(Widget a_current,Widget a_request,Widget This,ArgList a_args,Cardinal* a_argn) {
IFMOD(doubleBufferOn) {
/* Can't change buffering here if X window is created.
With OpenGL, buffering fix parameter of the X window.
Buffering must be choosen before the execution of the
Realize method that create the window. */
if(XtIsRealized(This) && (athis.installColormap==True)) {
CWarn("Can't change buffering after \"realization\" of the widget.\n");
athis.doubleBufferOn = acur.doubleBufferOn;
}
}
/*avoid C++ warnings*/
a_request = NULL;
a_args = NULL;
a_argn = 0;
return False;
}
static void ChangeWidgetSize(Widget This) {
#ifdef DEBUG
printf("debug : OpenGLArea : ChangeWidgetSize : %s\n",XtName(This));
#endif
/* Call the Resize procedure (XtInheritResize) */
if(openGLAreaWidgetClass->core_class.superclass->core_class.resize!=NULL)
(openGLAreaWidgetClass->core_class.superclass->core_class.resize)(This);
#ifdef DEBUG
printf("debug : OpenGLArea : ChangeWidgetSize : end\n");
#endif
}
static void DrawWidget(Widget This,XEvent* a_event,Region a_region) {
#ifdef DEBUG
printf("debug : OpenGLArea : DrawWidget : %s\n",XtName(This));
#endif
if(openGLAreaWidgetClass->core_class.superclass->core_class.expose!=NULL)
(openGLAreaWidgetClass->core_class.superclass->core_class.expose)(This,a_event,a_region);
if(MakeCurrent(This)==1) {
#ifdef DEBUG
printf("debug : OpenGLArea : DrawWidget : %s : MakeCurrent ok : call paintCallback...\n",XtName(This));
#endif
XoAnyCallbackStruct value;
value.reason = XoCR_PAINT;
value.event = a_event;
XtCallCallbacks(This,XoNpaintCallback,(XtPointer)&value);
glXSwapBuffers(XtDisplay(This),XtWindow(This));
glXMakeCurrent(XtDisplay(This),None,NULL);
}
#ifdef DEBUG
printf("debug : OpenGLArea : DrawWidget : end\n");
#endif
/*avoid C++ warnings*/
a_event = NULL;
a_region = NULL;
}
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
void OpenGLAreaPaint(Widget This) {
if(!XtIsRealized(This)) return;
if(MakeCurrent(This)==1) {
XoAnyCallbackStruct value;
value.reason = XoCR_PAINT;
value.event = 0;
XtCallCallbacks(This,XoNpaintCallback,(XtPointer)&value);
glXSwapBuffers(XtDisplay(This),XtWindow(This));
glXMakeCurrent(XtDisplay(This),None,NULL);
}
}
#ifdef TOOLS_XT_OPENGLAREA_HAS_GL2PS
#include <tools/c_gl2ps.h>
int OpenGLAreaWrite_gl2ps(Widget This,const char* aFileName,const char* opts) {
FILE* file;
int options;
int sort;
inlib_GLint vp[4];
int bufsize = 0;
static inlib_gl2ps_gl_funcs_t s_OpenGL_funcs = {
glIsEnabled,
glBegin,
glEnd,
glGetFloatv,
glVertex3f,
glGetBooleanv,
glGetIntegerv,
glRenderMode,
glFeedbackBuffer,
glPassThrough
};
file = fopen(aFileName,"w");
if(!file) return 1;
inlib_c_gl2ps_set_gl_funcs(&s_OpenGL_funcs);
options = TOOLS_GL2PS_OCCLUSION_CULL
| TOOLS_GL2PS_BEST_ROOT
| TOOLS_GL2PS_SILENT
| TOOLS_GL2PS_DRAW_BACKGROUND;
sort = TOOLS_GL2PS_BSP_SORT;
//sort = TOOLS_GL2PS_SIMPLE_SORT;
vp[0] = 0;
vp[1] = 0;
vp[2] = This->core.width;
vp[3] = This->core.height;
inlib_c_gl2psBeginPage("title","exlib_Xt_OpenGLArea",
vp,TOOLS_GL2PS_EPS,sort,options,
TOOLS_GL_RGBA,0, NULL,0,0,0,bufsize,
file,aFileName);
{XoAnyCallbackStruct value;
value.reason = XoCR_PAINT;
value.event = 0;
XtCallCallbacks(This,XoNpaintCallback,(XtPointer)&value);}
inlib_c_gl2psEndPage();
inlib_c_gl2ps_reset_gl_funcs();
fclose(file);
return 0;
}
#else
#ifdef __cplusplus
int OpenGLAreaWrite_gl2ps(Widget,const char*,const char*) {return 1;}
#else
int OpenGLAreaWrite_gl2ps(Widget w,const char* f,const char* o) {return 1;}
#endif
#endif
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
static int MakeCurrent(Widget This) {
if(This==NULL) return 0;
if(!XtIsRealized(This)) return 0;
if(athis.glContext==NULL) return 0;
return (int)glXMakeCurrent(XtDisplay(This),XtWindow(This),athis.glContext);
}
static void EventHandler(Widget This,XtPointer a_tag,XEvent* a_event ,Boolean* a_continue) {
XoAnyCallbackStruct value;
value.reason = XoCR_EVENT;
value.event = a_event;
XtCallCallbacks(This,XoNeventCallback,(XtPointer)&value);
a_tag = NULL;
a_continue = NULL;
}
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
static void XWidgetInstallColormap(Widget This) {
/*
From Mesa/widgets/GLwDrawingArea.c/post_colormap routine.
Could use also XtSetWMColormapWindows.
*/
Display* display;
XWindowAttributes watbs;
Widget shell;
Window* ws = NULL;
int wn = 0,found,count;
Window wshell,wthis;
Colormap cmapthis;
/*.........................................................................*/
if(This==NULL) return;
if( !XtIsWidget(This) || !XtIsRealized(This) ) return;
shell = XWidgetGetShell (This);
if(shell==NULL) return;
display = XtDisplay (This);
wthis = XtWindow (This);
wshell = XtWindow (shell);
XGetWMColormapWindows (display,wshell, &ws, &wn);
/* Check if colormap of this is a colormap of a Window in list.*/
XGetWindowAttributes (display,wthis,&watbs);
cmapthis = watbs.colormap;
found = -1;
for(count=0;count<wn;count++) {
Colormap cmap;
XGetWindowAttributes (display,ws[count],&watbs);
cmap = watbs.colormap;
if(cmap==cmapthis) {
XFree (ws);
return; /*done*/
}
if(ws[count]==wshell) {
found = count;
}
}
/*Have to add window of this in list.*/
if(wn==0) {
if(ws!=NULL) XFree(ws);
ws = (Window*)malloc ( 2 * sizeof(Window));
} else {
ws = (Window*)realloc (ws,(wn + 2) * sizeof(Window));
}
if(ws==NULL) return;
if(found==-1) {
/*Window of shell not in list.*/
ws[wn] = wthis; wn++;
ws[wn] = wshell;wn++;
} else {
ws[found] = wthis;
ws[wn] = wshell; wn++; /*Shell must be last.*/
}
if (XSetWMColormapWindows(display,wshell, ws, wn)==0) {
CWarnF ("XWidgetInstallColormap: can't install colormap of %s in %s.\n",XtName(This),XtName(shell));
}
XFree (ws);
}
static void XWidgetUninstallColormap(Widget This) {
int count;
Widget shell;
Display* display;
Window wthis,wshell;
Window* ws = NULL;
int wn = 0;
Window* nws = NULL;
int nwn = 0;
/*.........................................................................*/
if(This==NULL) return;
if( !XtIsWidget(This) || !XtIsRealized(This) ) return;
shell = XWidgetGetShell (This);
if(shell==NULL) return;
display = XtDisplay (This);
wthis = XtWindow (This);
wshell = XtWindow (shell);
XGetWMColormapWindows (display,wshell, &ws, &wn);
if( (wn==0) || (ws==NULL) ) return;
nws = (Window*)malloc ( wn * sizeof(Window));
if(nws==NULL) {
XFree (ws);
return;
}
nwn = 0;
for(count=0;count<wn;count++) {
if(ws[count]!=wthis) {
nws[nwn] = ws[count];
nwn++;
}
}
if(wn!=nwn) {
if (XSetWMColormapWindows(display,wshell, nws, nwn)==0) {
CWarnF("XWidgetUninstallColormap: can't install colormap of %s in %s.\n",XtName(This),XtName(shell));
}
}
XFree (ws);
XFree (nws);
}
Widget XWidgetGetShell(Widget This) {
Widget widget;
if(This==NULL) return NULL;
widget = This;
while(1) {
if(widget==NULL) return NULL;
if(XtIsShell(widget)) return widget;
widget = XtParent(widget);
}
}
/*
exlib_build_use Xt inlib
*/
+37
View File
@@ -0,0 +1,37 @@
#ifndef tools_Xt_OpenGLArea_h
#define tools_Xt_OpenGLArea_h
#include <X11/Intrinsic.h>
typedef struct _OpenGLAreaClassRec* OpenGLAreaWidgetClass;
typedef struct _OpenGLAreaRec* OpenGLAreaWidget;
typedef struct {
int reason;
XEvent* event;
} XoAnyCallbackStruct;
/* OpenGLArea */
#define XoNdoubleBufferOn "doubleBufferOn"
#define XoNpaintCallback "paintCallback"
#define XoNeventCallback "eventCallback"
#define XoCR_PAINT 1
#define XoCR_EVENT 2
#ifdef __cplusplus
extern "C"{
#endif
extern WidgetClass openGLAreaWidgetClass;
void OpenGLAreaPaint(Widget);
int OpenGLAreaWrite_gl2ps(Widget,const char*,const char*);
#ifdef __cplusplus
}
#endif
#endif
/*
exlib_build_use Xt
*/
+54
View File
@@ -0,0 +1,54 @@
#ifndef tools_Xt_OpenGLAreaP_h
#define tools_Xt_OpenGLAreaP_h
#include "OpenGLArea.h"
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>
#include <GL/glx.h>
typedef struct
{
void* extension;
} OpenGLAreaClassPart;
typedef struct _OpenGLAreaClassRec
{
CoreClassPart core_class;
CompositeClassPart composite_class;
OpenGLAreaClassPart openGLArea_class;
} OpenGLAreaClassRec;
#ifdef __cplusplus
extern "C"{
#endif
extern OpenGLAreaClassRec openGLAreaClassRec;
#ifdef __cplusplus
}
#endif
typedef struct
{
/*Resources :*/
Boolean doubleBufferOn;
XtCallbackList paintCallback;
XtCallbackList eventCallback;
/**/
Visual* visual;
Boolean installColormap;
GLXContext glContext;
} OpenGLAreaPart;
typedef struct _OpenGLAreaRec
{
CorePart core;
CompositePart composite;
OpenGLAreaPart openGLArea;
} OpenGLAreaRec;
#endif
/*
exlib_build_use Xt
*/
+77
View File
@@ -0,0 +1,77 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Xt_session
#define tools_Xt_session
#include <ostream>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
namespace tools {
namespace Xt {
class session {
public:
session(std::ostream& a_out,int& a_argc,char** a_argv)
:m_out(a_out),m_app_context(0),m_app_widget(0)
{
//LookDSM_Problem();
Arg args[1];
XtSetArg(args[0],XtNgeometry,XtNewString("100x100"));
m_app_widget = ::XtAppInitialize(&m_app_context,"tools::Xt::session",NULL,(Cardinal)0,&a_argc,a_argv,NULL,args,1);
if(!m_app_context || !m_app_widget) {
m_app_context = 0;
m_app_widget = 0;
}
}
virtual ~session() {
if(m_app_widget) {::XtDestroyWidget(m_app_widget);m_app_widget = 0;}
if(m_app_context) {::XtDestroyApplicationContext(m_app_context);m_app_context = 0;}
}
protected:
session(const session& a_from)
:m_out(a_from.m_out),m_app_context(0),m_app_widget(0)
{}
session& operator=(const session&){return *this;}
public:
std::ostream& out() const {return m_out;}
bool is_valid() {return m_app_context && m_app_widget?true:false;}
bool steer() {
if(!m_app_context) return false;
while(true) {
XEvent event;
::XtAppNextEvent(m_app_context,&event);
::XtDispatchEvent(&event);
//if(m_exit) break;
}
return true;
}
bool sync() {
//if(!m_app_widget) return false;
//Display* display = XtDisplay(m_app_widget);
//::XSync(display,False);
if(!m_app_context) return false;
while(true) {
XtInputMask input = ::XtAppPending(m_app_context);
if(input==0) break;
XEvent event;
::XtAppNextEvent(m_app_context,&event);
::XtDispatchEvent(&event);
}
return true;
}
public:
Widget get_app_widget() {return m_app_widget;}
protected:
std::ostream& m_out;
bool m_app_owner;
XtAppContext m_app_context;
Widget m_app_widget;
};
}}
#endif
+183
View File
@@ -0,0 +1,183 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Xt_sg_viewer
#define tools_Xt_sg_viewer
#include "session"
#include "../sg/GL_viewer"
#include "OpenGLArea"
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <tools/num2s>
#include <tools/sg/device_interactor>
#include <tools/sg/keys>
namespace tools {
namespace Xt {
class sg_viewer : public sg::GL_viewer {
typedef sg::GL_viewer parent;
public:
sg_viewer(session& a_session,
int a_x = 0,int a_y = 0,
unsigned int a_width = 500,unsigned int a_height = 500,
const std::string& a_win_title = "")
:parent(a_session.out(),a_width,a_height)
,m_session(a_session)
,m_shell(0)
,m_glarea(0)
,m_interactor(0)
{
Widget app_widget = a_session.get_app_widget();
if(!app_widget) return;
std::string sgeom;
tools::numas(a_width,sgeom);
sgeom += "x";
tools::numas(a_height,sgeom);
sgeom += "+";
tools::numas(a_x,sgeom);
sgeom += "+";
tools::numas(a_y,sgeom);
Arg args[2];
XtSetArg(args[0],XtNgeometry,XtNewString(sgeom.c_str()));
XtSetArg(args[1],XtNborderWidth,0);
m_shell = ::XtAppCreateShell((char*)a_win_title.c_str(),
(char*)"sg_viewer_shell",
topLevelShellWidgetClass,XtDisplay(app_widget),args,2);
::XtSetMappedWhenManaged(m_shell,True);
m_glarea = ::XtCreateManagedWidget("glarea",OpenGLArea::widget_class(),m_shell,args,0);
::XtAddCallback(m_glarea,XoNpaintCallback,paint_cbk,(XtPointer)this);
::XtAddCallback(m_glarea,XoNeventCallback,event_cbk,(XtPointer)this);
::XtAddCallback(m_shell,XtNdestroyCallback,destroy_shell_callback,(XtPointer)this);
::XtRealizeWidget(m_shell);
//Atom WM_DELETE_WINDOW_atom = ::XInternAtom(XtDisplay(m_shell),"WM_DELETE_WINDOW",False);
//::XSetWMProtocols(XtDisplay(m_shell),XtWindow(m_shell),&WM_DELETE_WINDOW_atom,1);
}
virtual ~sg_viewer() {
if(m_shell) {
::XtRemoveCallback(m_glarea,XoNpaintCallback,paint_cbk,(XtPointer)this);
::XtRemoveCallback(m_shell,XtNdestroyCallback,destroy_shell_callback,(XtPointer)this);
::XtDestroyWidget(m_shell);
}
m_shell = 0;
m_glarea = 0;
}
protected:
sg_viewer(const sg_viewer& a_from)
:parent(a_from)
,m_session(a_from.m_session)
,m_shell(0)
,m_glarea(0)
,m_interactor(0)
{}
sg_viewer& operator=(const sg_viewer& a_from){
parent::operator=(a_from);
return *this;
}
public:
bool has_window() const {return m_glarea?true:false;}
bool show() {
if(!m_shell) return false;
::XtRealizeWidget(m_shell);
::XtMapWidget(m_shell);
// Raise window :
if(XtIsWidget(m_shell) && XtIsRealized(m_shell) ) {
Display* display = XtDisplay(m_shell);
Atom atom = ::XInternAtom(display,"WM_DELETE_WINDOW",False);
::XSetWMProtocols(display,XtWindow(m_shell),&atom,1);
::XRaiseWindow(display,XtWindow(m_shell));
}
return true;
}
void win_render() {
if(m_glarea) OpenGLArea::paint(m_glarea);
}
public:
void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
protected:
static void paint_cbk(Widget a_widget,XtPointer a_tag,XtPointer){
unsigned int width = a_widget->core.width;
unsigned int height = a_widget->core.height;
//::printf("debug : tools::Xt::sg_viewer::paint_cbk : %d %d\n",width,height);
sg_viewer* _this = (sg_viewer*)a_tag;
_this->set_size(width,height);
_this->render();
}
static void event_cbk(Widget,XtPointer a_tag,XtPointer a_data){
sg_viewer* _this = (sg_viewer*)a_tag;
if(!_this->m_interactor) return;
XoAnyCallbackStruct* data = (XoAnyCallbackStruct*)a_data;
XEvent* xevent = data->event;
switch( xevent->type ) {
case KeyPress:{
KeySym key_sym;
::XLookupString(&(xevent->xkey),NULL,0,&key_sym,NULL);
tools::sg::key_down_event event(_this->convert(key_sym));
_this->m_interactor->key_press(event);
}return;
case KeyRelease:{
KeySym key_sym;
::XLookupString(&(xevent->xkey),NULL,0,&key_sym,NULL);
tools::sg::key_up_event event(_this->convert(key_sym));
_this->m_interactor->key_release(event);
}return;
case ButtonPress:{
if(xevent->xbutton.button==Button4) { //4=wheel down, or move down double touch on trackpad = zoom in.
tools::sg::wheel_rotate_event event(8); //8=cooking.
_this->m_interactor->wheel_rotate(event);
} else if(xevent->xbutton.button==Button5) { //5=wheel up, or move up double touch on trackpad = zoom out.
tools::sg::wheel_rotate_event event(-8); //8=cooking.
_this->m_interactor->wheel_rotate(event);
} else {
tools::sg::mouse_down_event event(xevent->xbutton.x,xevent->xbutton.y);
_this->m_interactor->mouse_press(event);
}
}return;
case ButtonRelease:{
tools::sg::mouse_up_event event(xevent->xbutton.x,xevent->xbutton.y);
_this->m_interactor->mouse_release(event);
}return;
case MotionNotify:{
tools::sg::mouse_move_event event(xevent->xmotion.x,xevent->xmotion.y,0,0,false);
_this->m_interactor->mouse_move(event);
}return;
default:return;}
}
static void destroy_shell_callback(Widget,XtPointer a_tag,XtPointer) {
sg_viewer* _this = (sg_viewer*)a_tag;
_this->m_shell = 0;
_this->m_glarea = 0;
}
protected:
tools::key_code convert(KeySym a_key) {
if(a_key==XK_Shift_L) return tools::sg::key_shift();
if(a_key==XK_Shift_R) return tools::sg::key_shift();
return a_key;
}
protected:
session& m_session;
Widget m_shell;
Widget m_glarea;
tools::sg::device_interactor* m_interactor;
};
}}
#endif
+204
View File
@@ -0,0 +1,204 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_Xt_tools
#define tools_Xt_tools
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <string>
inline Widget XWidgetGetShell(Widget aWidget){
Widget widget = aWidget;
while(1) {
if(!widget) return 0;
if(XtIsShell(widget)) return widget;
widget = XtParent(widget);
}
}
inline Pixel XWidgetGetPixelResource(Widget aWidget,const std::string& aName){
Pixel pixel = 0L;
Arg args[1];
XtSetArg(args[0],(char*)aName.c_str(),&pixel);
XtGetValues(aWidget,args,1);
return pixel;
}
inline Pixel XWidgetConvertStringToPixel(Widget aWidget,const std::string& aString){
if(aString.empty()) return 0L;
if( (aString=="None") || (aString=="none") )
return XWidgetGetPixelResource(aWidget,std::string(XtNbackground));
XrmValue from,to;
from.size = aString.size()+1;
from.addr = (XPointer)aString.c_str();
XtConvert(aWidget,XtRString,&from,XtRPixel,&to);
if(to.addr==NULL) return 0L;
return (*((Pixel*)to.addr));
}
inline void XWidgetSetString(Widget aWidget,const std::string& aName,const std::string& aValue,bool aFreePrevious = false){
if(aFreePrevious) {
char* s = NULL;
Arg args[1];
XtSetArg(args[0],(char*)aName.c_str(),&s);
XtGetValues(aWidget,args,1);
if(s!=NULL) XtFree(s);
}
Arg args[1];
XtSetArg(args[0],(char*)aName.c_str(),XtNewString(aValue.c_str()));
XtSetValues(aWidget,args,1);
}
inline bool XWidgetGetString(Widget aWidget,const std::string& aName,std::string& a_value){
// XtNgeometry, XtNtitle.
char* s = NULL;
Arg args[1];
XtSetArg(args[0],(char*)aName.c_str(),&s);
XtGetValues(aWidget,args,1);
if(s==NULL) {a_value.clear();return false;}
a_value = std::string(s);
return true;
}
#include <X11/Xatom.h>
inline bool XWidgetSendMessage(Widget aWidget,long a_1,long a_2) {
XClientMessageEvent event;
if(!XtIsRealized(aWidget)) return 0;
event.type = ClientMessage;
event.display = XtDisplay(aWidget);
event.window = XtWindow(aWidget);
event.message_type = XA_INTEGER;
event.format = 8;
event.data.l[0] = a_1;
event.data.l[1] = a_2;
event.data.l[2] = 0L;
event.data.l[3] = 0L;
event.data.l[4] = 0L;
if(XSendEvent(event.display,event.window,False,0L,(XEvent*)&event)==0)
return false;
XFlush(event.display);
return true;
}
#include <X11/IntrinsicP.h>
inline void XClassGetName(WidgetClass aClass,std::string& a_value){
a_value = std::string((char*)aClass->core_class.class_name);
}
inline Boolean XClassIsSubclass(WidgetClass aClass,WidgetClass aParent){
for (WidgetClass wc = aClass; wc != NULL; wc = wc->core_class.superclass)
if (wc == aParent) return True;
return False;
}
inline Position XWidgetGetX(Widget aWidget){return aWidget->core.x;}
inline Position XWidgetGetY(Widget aWidget){return aWidget->core.y;}
inline Dimension XWidgetGetWidth(Widget aWidget){return aWidget->core.width;}
inline Dimension XWidgetGetHeight(Widget aWidget){return aWidget->core.height;}
inline void XWidgetGetClassName(Widget aWidget,std::string& a_value) {
WidgetClass wc = XtClass(aWidget);
a_value = std::string((char*)wc->core_class.class_name);
}
inline void XWidgetCompellResize(Widget aWidget){
if(aWidget->core.widget_class->core_class.resize==NULL) return;
(aWidget->core.widget_class->core_class.resize)(aWidget);
}
#include <X11/CompositeP.h>
inline int XWidgetGetChildrenNumber(Widget aWidget){
if(!XtIsComposite(aWidget)) return 0;
CompositePart* cwp = &(((CompositeWidget)aWidget)->composite);
return cwp->num_children;
}
inline Widget XWidgetGetChild(Widget aWidget,unsigned int aIndex){
if(!XtIsComposite(aWidget)) return 0;
CompositePart* cwp = &(((CompositeWidget)aWidget)->composite);
if(aIndex>=cwp->num_children) return 0;
return cwp->children[aIndex];
}
inline Widget XWidgetGetFirstChild(Widget aWidget){
if(!XtIsComposite(aWidget)) return 0;
CompositePart* cwp = &(((CompositeWidget)aWidget)->composite);
return (cwp->num_children?cwp->children[0]:0);
}
#include <vector>
inline void XWidgetGetChildren(Widget aWidget,std::vector<Widget>& aList){
aList.clear();
if(!XtIsComposite(aWidget)) return;
CompositePart* cwp = &(((CompositeWidget)aWidget)->composite);
for (unsigned int count=0;count<cwp->num_children;count++)
aList.push_back(cwp->children[count]);
}
inline void XWidgetGetPopupChildren(Widget aWidget,std::vector<Widget>& aList){
aList.clear();
if(!XtIsWidget(aWidget)) return;
for(int count=0;count<aWidget->core.num_popups;count++) {
aList.push_back(aWidget->core.popup_list[count]);
}
}
inline Widget XWidgetFindChild(Widget aWidget,const std::string& aName){
if(!XtIsComposite(aWidget)) return 0;
CompositePart* cwp = &(((CompositeWidget)aWidget)->composite);
for (unsigned int count=0;count<cwp->num_children;count++) {
if(aName==std::string(XtName(cwp->children[count])))
return cwp->children[count];
}
return 0;
}
#include <ostream>
inline void XWidgetPrintChildren(Widget aWidget,std::ostream& a_out){
int number = XWidgetGetChildrenNumber(aWidget);
a_out << "XWidgetPrintChildren :"
<< " " << (unsigned long)aWidget
<< " number " << number
<< std::endl;
std::string scls;
for(int index=0;index<number;index++) {
Widget child = XWidgetGetChild(aWidget,index);
XWidgetGetClassName(child,scls);
a_out << " index = " << index
<< ", child = " << (unsigned long)child
<< ", class = " << scls
<< std::endl;
}
}
inline void XWidgetDumpPopupChildren(Widget aWidget,std::ostream& a_out){
a_out << "XWidgetDumpPopupChildren :"
<< " " << std::string(XtName(aWidget))
<< std::endl;
if(!XtIsWidget(aWidget)) return;
a_out << " " << aWidget->core.num_popups << " popup children." << std::endl;
std::string scls;
for (unsigned int count=0;count<aWidget->core.num_popups;count++) {
Widget w = aWidget->core.popup_list[count];
XWidgetGetClassName(w,scls);
a_out << " " << count
<< " child class " << scls
<< " name " << std::string(XtName(w))
<< std::endl;
}
}
inline void XWidgetDumpChildren(Widget aWidget,std::ostream& a_out){
a_out << "XWidgetDumpChildren :"
<< " " << std::string(XtName(aWidget))
<< std::endl;
if(!XtIsComposite(aWidget)) return;
CompositePart* cwp = &(((CompositeWidget)aWidget)->composite);
a_out << " " << cwp->num_children << " children." << std::endl;
std::string scls;
for (unsigned int count=0;count<cwp->num_children;count++) {
Widget w = cwp->children[count];
XWidgetGetClassName(w,scls);
a_out << " " << count
<< " child class " << scls
<< " name " << std::string(XtName(w))
<< std::endl;
}
}
#endif
File diff suppressed because it is too large Load Diff
+191
View File
@@ -0,0 +1,191 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_app
#define tools_app
#include "path_env"
#include "sout"
#include "file"
#include "forit"
#include "sys/dir"
namespace tools {
#ifdef __APPLE__
inline bool is_mac_app(const std::string& a_arg0){
if(a_arg0.empty()) return false;
std::string bname = base_name(dir_name(a_arg0));
if(bname=="MacOS") return true;
return false;
}
#else
inline bool is_mac_app(const std::string&){return false;}
#endif
inline bool program_path(const std::string& a_arg0,std::string& a_path) {
if(a_arg0.empty()) {
a_path = "";
return false;
}
std::string path,name,suffix;
path_name_suffix(a_arg0,path,name,suffix);
if(path.empty()) {
std::string PATH;
if(get_env("PATH",PATH)) {
std::string program = a_arg0;
#ifdef _WIN32
if(program.find(".exe")==std::string::npos) program += ".exe";
#endif
std::vector<std::string> paths;
words(PATH,psep(),false,paths);
tools_vforit(std::string,paths,it) {
std::string dir = *it;
if(file::exists(dir+sep()+program)) {
path = dir;
break;
}
}
}
}
if(path.empty()) {
a_path = "";
return false;
}
if(!is_absolute_path(path)) {
std::string pwd;
if(!dir::pwd(pwd)) {
a_path = "";
return false;
}
path = pwd+sep()+path;
}
//printf("debug : path : %s\n",path.c_str());
a_path = path;
return true;
}
inline bool if_mouse_startup(const std::string& a_arg0,const std::string& a_env_HOME_DIR,const std::vector<std::string>& a_home_dirs,std::ostream& a_out){
std::string exe_dir = dir_name(a_arg0);
std::string bname = base_name(exe_dir);
if(bname=="MacOS") {
// cd in a_doc_dir :
if(!dir::cd_home()) {
a_out << "if_mouse_startup : can't go home." << std::endl;
return false;
}
tools_vforcit(std::string,a_home_dirs,it) {
if(!dir::mkcd(*it)) {
a_out << "if_mouse_startup :"
<< " can't mkcd " << sout(*it)
<< std::endl;
return false;
}
}
// set a_env_HOME_DIR from exe_dir :
std::string Contents_dir = dir_name(exe_dir);
if(!put_env(a_env_HOME_DIR,Contents_dir)) {
a_out << "if_mouse_startup :"
<< " can't putenv " << a_env_HOME_DIR
<< " to " << sout(Contents_dir)
<< "."
<< std::endl;
return false;
}
{std::vector<std::string> vals;
vals.push_back(Contents_dir+"/bin");
vals.push_back("."); // for on-the-fly compilation and loading :
if(!env_path_append("DYLD_LIBRARY_PATH",vals)) {
a_out << "if_mouse_startup :"
<< " can't putenv DYLD_LIBRARY_PATH."
//<< " to " << sout(DYLD_LIBRARY_PATH)
<< std::endl;
return false;
}}
// {std::string DYLD_LIBRARY_PATH;
// if(!get_env("DYLD_LIBRARY_PATH",DYLD_LIBRARY_PATH)) {}
// a_out << "debug : DYLD_LIBRARY_PATH = " << sout(DYLD_LIBRARY_PATH) << std::endl;}
if(!is_env("DISPLAY")) {
if(!put_env("DISPLAY",":0.0")) return false;
}
} else if(bname=="bin") {
//Linux, Windows : mouse startup ?
/* FIXME : do we want to treat the case of a terminal startup
whence the user did not <source setup> ???
If so if_mouse_startup should be renamed no_env_startup.
} else if(exe_dir=="") { //for exa when typing "osc-plot".
if(!program_path(a_arg0,exe_dir)) {
a_out << "if_mouse_startup :"
<< " program_path failed for " << sout(bname) << "."
<< std::endl;
return false;
}
a_out << "if_mouse_startup :"
<< " program_path is " << sout(exe_dir) << "."
<< std::endl;
#if defined(__APPLE__) || defined(Linux)
bool is_abs,is_win;
std::string drive;
std::vector<std::string> words;
path_words(exe_dir,words,is_abs,is_win,drive);
std::vector<std::string>::size_type n = words.size();
if( (n>=3) &&
(words[n-1]=="bin") &&
is_version(words[n-2]) &&
(words[n-3].substr(0,4)=="osc_")
){
std::string osc_vers_dir = dir_name(exe_dir);
printf("debug : auto env 000 \"%s\"\n",osc_vers_dir.c_str());
//if(a_env_HOME_DIR.size()) {
if(!put_env(a_env_HOME_DIR,osc_vers_dir)) {
a_out << "arg0_setenv :"
<< " can't putenv " << a_env_HOME_DIR
<< " to " << sout(osc_vers_dir)
<< "."
<< std::endl;
return false;
}
//}
#ifdef __APPLE__
{std::vector<std::string> vals;
vals.push_back(osc_vers_dir+"/bin");
vals.push_back(osc_vers_dir+"/lib");
vals.push_back("."); // for on-the-fly compilation and loading :
if(!env_path_append("DYLD_LIBRARY_PATH",vals)) return false;}
#else
#endif
if(!is_env("DISPLAY")) {
if(!put_env("DISPLAY",":0.0")) return false;
}
}
#endif
*/
}
return true;
}
inline void app_res_dir(const std::string& a_exe_path,std::string& a_res_dir) {
a_res_dir = a_exe_path+sep()+".."+sep()+"res";
}
}
#endif
+39
View File
@@ -0,0 +1,39 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_argcv
#define tools_argcv
#include <vector>
#include <string>
#include "cstr"
namespace tools {
inline void new_argcv(const std::vector<std::string>& a_args,int& a_argc,char**& a_argv){
// delete with delete_argcv
a_argc = (int)a_args.size();
if(a_argc<=0) {
a_argc = 0;
a_argv = 0;
return;
}
typedef char* cstring;
a_argv = new cstring[a_argc];
for(int index=0;index<a_argc;index++) {
const std::string& arg = a_args[index];
a_argv[index] = new char[arg.size()+1];
::strcpy(a_argv[index],arg.c_str());
}
}
inline void delete_argcv(int& a_argc,char**& a_argv) {
for(int index=0;index<a_argc;index++) delete [] a_argv[index];
delete [] a_argv;
a_argc = 0;
a_argv = 0;
}
}
#endif
+515
View File
@@ -0,0 +1,515 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_args
#define tools_args
#ifdef TOOLS_MEM
#include "mem"
#include "S_STRING"
#endif
#include "sout"
#include "strip"
#include "words"
#include "sto"
#include "forit"
#include "mnmx"
//#include "squote"
#include <ostream>
namespace tools {
class args {
#ifdef TOOLS_MEM
public:
TOOLS_SCLASS(tools::args)
#endif
public:
typedef std::pair<std::string,std::string> arg;
public:
args(){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
args(int a_argc,char* a_argv[]){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
for(int index=0;index<a_argc;index++) {
std::string s(a_argv[index]);
std::string::size_type pos = s.find('=');
if(pos==std::string::npos) {
m_args.push_back(arg(s,""));
} else {
std::string key = s.substr(0,pos);
pos++;
std::string value = s.substr(pos,s.size()-pos);
m_args.push_back(arg(key,value));
}
}
}
args(const std::vector<std::string>& a_args,bool a_strip = false){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
add(a_args,a_strip);
}
args(const std::vector<arg>& a_args):m_args(a_args){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
args(const std::string& a_args,const std::string& a_sep,bool a_strip){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
std::vector<std::string> _args;
words(a_args,a_sep,false,_args);
add(_args,a_strip);
}
virtual ~args(){
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
args(const args& a_from):m_args(a_from.m_args){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
args& operator=(const args& a_from){
m_args = a_from.m_args;
return *this;
}
public:
const std::vector<arg>& get_args() const {return m_args;}
//std::vector<arg>& get_args() {return m_args;}
bool is_arg(const std::string& a_string) const {
tools_vforcit(arg,m_args,it) {
if((*it).first==a_string) return true;
}
return false;
}
bool is_empty() const {return m_args.size()?false:true;}
size_t size() const {return m_args.size();}
size_t number() const {return m_args.size();} //back comp.
bool find(const std::string& a_key,std::string& a_value,const std::string& a_def = std::string()) const {
tools_vforcit(arg,m_args,it) {
if((*it).first==a_key) {
a_value = (*it).second;
return true;
}
}
a_value = a_def;
return false;
}
#ifdef TOOLS_DEPRECATED
std::vector<std::string> find(const std::string& a_key) const {
std::vector<std::string> vals;
tools_vforcit(arg,m_args,it) {
if((*it).first==a_key) vals.push_back((*it).second);
}
return vals;
}
#endif
void find(const std::string& a_key,std::vector<std::string>& a_vals,bool a_clear=true) const {
if(a_clear) a_vals.clear();
tools_vforcit(arg,m_args,it) {
if((*it).first==a_key) a_vals.push_back((*it).second);
}
}
bool find(const std::string& a_string,bool& a_value,const bool& a_def = false) const {
std::string s;
if(!find(a_string,s)) {a_value = a_def;return false;}
return to(s,a_value,a_def);
}
template <class aT>
bool find(const std::string& a_string,aT& a_value,const aT& a_def = aT()) const {
std::string _s;
if(!find(a_string,_s)) {a_value = a_def;return false;}
return to<aT>(_s,a_value,a_def);
}
#ifdef TOOLS_DEPRECATED
std::vector<std::string> tovector() const {
// Return a vector of string <name=value>
std::vector<std::string> vec;
tools_vforcit(arg,m_args,it) {
std::string s;
if((*it).second.empty()) {
s = (*it).first;
} else {
s = (*it).first;
s += "=";
s += (*it).second;
}
vec.push_back(s);
}
return vec;
}
#endif
void to_vector(std::vector<std::string>& a_vec) const {
// Return a vector of string <name=value>
a_vec.clear();
std::string s;
tools_vforcit(arg,m_args,it) {
s = (*it).first;
if((*it).second.size()) {
s += "=";
s += (*it).second;
}
a_vec.push_back(s);
}
}
bool add(const std::string& a_key,const std::string& a_value = std::string(),bool a_override = true){
if(a_override) {
tools_vforit(arg,m_args,it) {
if((*it).first==a_key) {
(*it).second = a_value;
return true;
}
}
}
if(a_key.empty()) return false;
m_args.push_back(arg(a_key,a_value));
return true;
}
bool insert_begin(const std::string& a_key,const std::string& a_value = std::string(),bool a_override = true){
if(a_override) {
tools_vforit(arg,m_args,it) {
if((*it).first==a_key) {
(*it).second = a_value;
return true;
}
}
}
if(a_key.empty()) return false;
m_args.insert(m_args.begin(),arg(a_key,a_value));
return true;
}
void add(const std::vector<std::string>& a_args,bool a_strip = false) {
tools_vforcit(std::string,a_args,it) {
const std::string& sarg = *it;
std::string::size_type pos = sarg.find('=');
if(pos==std::string::npos) {
if(a_strip) {
std::string left = sarg;
strip(left,both,' ');
m_args.push_back(arg(left,""));
} else {
m_args.push_back(arg(sarg,""));
}
} else {
std::string left = sarg.substr(0,pos);
std::string right = sarg.substr((pos+1),sarg.size()-(pos+1));
if(a_strip) {
strip(left,both,' ');
strip(right,both,' ');
}
m_args.push_back(arg(left,right));
}
}
}
void add_keyvals(const std::vector<std::string>& a_args,bool a_strip = false) {
//a_args must contain an even number of strings.
size_t sz_half = a_args.size()/2;
if((2*sz_half)!=a_args.size()) return;
for(std::vector<std::string>::const_iterator it = a_args.begin();it!=a_args.end();it+=2) {
if(a_strip) {
std::string key = *it;
strip(key,both,' ');
std::string val = *(it+1);
strip(val,both,' ');
m_args.push_back(arg(key,val));
} else {
m_args.push_back(arg(*it,*(it+1)));
}
}
}
void add(const std::vector<arg>& a_args){
tools_vforcit(arg,a_args,it) m_args.push_back(*it);
}
void add(const args& a_from){
tools_vforcit(arg,a_from.m_args,it) m_args.push_back(*it);
}
int remove(const std::string& a_key){
size_t nbeg = m_args.size();
for(std::vector<arg>::iterator it = m_args.begin();it!=m_args.end();) {
if(a_key==(*it).first) {
it = m_args.erase(it);
} else {
++it;
}
}
return int(nbeg) - int(m_args.size());
}
void remove_first(){if(m_args.size()) m_args.erase(m_args.begin());}
void remove_last(){if(m_args.size()) m_args.erase(m_args.end()-1);}
bool last(std::string& a_key,std::string& a_value) const {
a_key.clear();
a_value.clear();
if(m_args.empty()) return false;
a_key = m_args.back().first;
a_value = m_args.back().second;
return true;
}
bool prog_name(std::string& a_value) const {
if(m_args.empty()) {a_value.clear();return false;}
if(m_args[0].second.size()) {a_value.clear();return false;}
a_value = m_args[0].first;
return true;
}
bool file(std::string& a_file) const {
std::string slast;
std::string s;
if((m_args.size()>1) //first arg is the program name !
&& last(slast,s)
&& (slast.find('-')!=0)
&& (s.empty()) ) {
a_file = slast; //Last argument is not an option.
return true;
} else {
a_file.clear();
return false;
}
}
bool file(std::string& a_file,bool a_remove) {
std::string slast;
std::string s;
if((m_args.size()>1) //first arg is the program name !
&& last(slast,s)
&& (slast.find('-')!=0)
&& (s.empty()) ) {
a_file = slast; //Last argument is not an option.
if(a_remove) m_args.erase(m_args.end()-1);
return true;
} else {
a_file.clear();
return false;
}
}
void not_hyphens(std::vector<std::string>& a_not_hyphens,bool a_skip_first = false) const {
a_not_hyphens.clear();
// Get the serie of trailing args not beginning with '-'
// and without a value (not of the form [-]xxx=yyy).
// Note that an argument like that in between arguments
// is NOT taken into account.
if(m_args.empty()) return;
std::vector<arg>::const_iterator it = m_args.begin();
if(a_skip_first) it++;
for(;it!=m_args.end();++it) {
if( ((*it).first.find('-')==0) || (*it).second.size() ) {
a_not_hyphens.clear();
} else {
a_not_hyphens.push_back((*it).first);
}
}
}
void files(std::vector<std::string>& a_files,bool a_skip_first = true) const { //true and not false as in the upper.
return not_hyphens(a_files,a_skip_first);
}
bool first_not_hyphen(std::string& a_first,bool a_skip_first = false) const {
std::vector<std::string> _ss;
not_hyphens(_ss,a_skip_first);
if(_ss.empty()) {a_first.clear();return false;}
a_first = _ss[0];
return true;
}
//bool first_of_files(std::string& a_file,bool a_skip_first) const {return first_of_hyphen(a_file,a_skip_first);}
bool argcv(int& a_argc,char**& a_argv) const {
// If using with :
// int argc;
// char** argv;
// args.argcv(argc,argv);
// you can delete with :
// args::delete_argcv(argc,argv);
if(m_args.empty()) {a_argc = 0;a_argv = 0;return true;}
typedef char* _cstr_t;
_cstr_t* av = new _cstr_t[m_args.size()+1];
if(!av) {a_argc = 0;a_argv = 0;return false;}
a_argv = av;
for(std::vector<arg>::const_iterator it = m_args.begin();it!=m_args.end();++it,av++) {
std::string::size_type lf = (*it).first.length();
std::string::size_type ls = (*it).second.length();
std::string::size_type sz = lf;
if(ls) sz += 1 + ls;
char* p = new char[sz+1];
if(!p) {a_argc = 0;a_argv = 0;return false;} //some delete are lacking.
*av = p;
{char* pf = (char*)(*it).first.c_str();
for(std::string::size_type i=0;i<lf;i++,p++,pf++) {*p = *pf;}
*p = 0;}
if(ls) {*p = '=';p++;}
{char* ps = (char*)(*it).second.c_str();
for(std::string::size_type i=0;i<ls;i++,p++,ps++) {*p = *ps;}
*p = 0;}
}
*(a_argv+m_args.size()) = 0;
a_argc = (int)m_args.size();
return true;
}
static void delete_argcv(int& a_argc,char**& a_argv) {
for(int index=0;index<a_argc;index++) delete [] a_argv[index];
delete [] a_argv;
a_argc = 0;
a_argv = 0;
}
bool known_options(const std::vector<std::string>& a_knowns) const {
tools_vforcit(arg,m_args,it) {
if((*it).first.find('-')==0) { //find '-' at first pos.
bool found = false;
tools_vforcit(std::string,a_knowns,it2) {
if((*it).first==(*it2)) {
found = true;
break;
}
}
if(!found) return false; //one option not in a_knowns.
}
}
return true; //all options are in a_knowns.
}
bool known_options(const std::string& a_known) const {
tools_vforcit(arg,m_args,it) {
if((*it).first.find('-')==0) { //find '-' at first pos.
if((*it).first!=a_known) return false; //one option not a_known.
}
}
return true; //all options are a_known.
}
//void remove_string_delimiters_in_keys() {
// tools_vforit(arg,m_args,it) {
// if(!rm_quotes((*it).first)) rm_double_quotes((*it).first);
// }
//}
//void remove_string_delimiters_in_values() {
// tools_vforit(arg,m_args,it) {
// if(!rm_quotes((*it).second)) rm_double_quotes((*it).second);
// }
//}
void files_at_end(bool a_skip_first = true) {
// reorder to have "file" arguments at end.
if(m_args.empty()) return;
std::vector<arg> _args;
if(a_skip_first) _args.push_back(*(m_args.begin()));
//first pass :
{std::vector<arg>::const_iterator it = m_args.begin();
if(a_skip_first) it++;
for(;it!=m_args.end();++it) {
if( ((*it).first.find('-')==0) || (*it).second.size() ) {
_args.push_back(*it);
}
}}
//second pass :
{std::vector<arg>::const_iterator it = m_args.begin();
if(a_skip_first) it++;
for(;it!=m_args.end();++it) {
if( ((*it).first.find('-')==0) || (*it).second.size() ) {
} else {
_args.push_back(*it);
}
}}
m_args = _args;
}
//NOTE : print is a Python keyword.
void dump(std::ostream& a_out,const std::string& a_comment = std::string(),const std::string& a_prefix = std::string()) const {
if(a_comment.size()) a_out << a_comment << std::endl;
tools_vforcit(arg,m_args,it) {
a_out << a_prefix << "key = " << sout((*it).first) << ", value = " << sout((*it).second) << std::endl;
}
}
public: //backcomp (for Panoramix).
bool isAnArgument(const std::string& a_key) const {return is_arg(a_key);}
protected:
std::vector<arg> m_args;
};
inline bool check_args(const std::vector<std::string>& a_args,unsigned int a_number,std::ostream& a_out){
if(a_args.size()==a_number) return true;
a_out << "bad argument number."
<< " Given " << (unsigned int)a_args.size()
<< " whilst " << a_number << " expected."
<< std::endl;
return false;
}
inline bool check_min(const std::vector<std::string>& a_args,unsigned int a_number,std::string& a_last,std::ostream& a_out){
if(a_args.size()>=a_number) {
if(a_number==0) {
if(a_args.empty()) {
a_last.clear();
} else {
a_last = a_args[0];
for(size_t index=1;index<a_args.size();index++) a_last += " " + a_args[index];
}
} else {
a_last = a_args[a_number-1];
for(size_t index=a_number;index<a_args.size();index++) a_last += " " + a_args[index];
}
return true;
}
a_out << "bad argument number."
<< " Given " << (unsigned int)a_args.size()
<< " whilst at least " << a_number << " expected."
<< std::endl;
return false;
}
inline bool check_min_args(const std::vector<std::string>& aArgs,unsigned int a_number,std::ostream& a_out){
if(aArgs.size()>=a_number) return true;
a_out << "bad argument number."
<< " Given " << (unsigned int)aArgs.size()
<< " whilst at least " << a_number << " expected."
<< std::endl;
return false;
}
inline bool check_or_args(const std::vector<std::string>& aArgs,unsigned int a_1,unsigned int a_2,std::ostream& a_out){
if((aArgs.size()==a_1)||(aArgs.size()==a_2)) return true;
a_out << "bad argument number."
<< " Given " << (unsigned int)aArgs.size()
<< " whilst " << a_1 << " or " << a_2 << " expected."
<< std::endl;
return false;
}
inline std::vector<std::string> to(int a_argc,char** a_argv) {
std::vector<std::string> v;
for(int index=0;index<a_argc;index++) v.push_back(a_argv[index]);
return v;
}
}
#endif
+625
View File
@@ -0,0 +1,625 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_array
#define tools_array
#ifdef TOOLS_MEM
#include "mem"
#endif
#include <vector>
#include <string>
namespace tools {
// array handles an hyperparallelepiped of cells of class T.
template <class T>
class array {
public:
static const std::string& s_class() {
static const std::string s_v("tools::array");
return s_v;
}
public:
typedef typename std::vector< std::pair<unsigned int,unsigned int> > cut_t;
typedef typename std::vector<unsigned int> uints_t;
typedef typename std::vector<T>::iterator vec_it_t;
typedef typename std::vector<T>::const_iterator cons_vec_it_t;
public:
array() {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
array(const uints_t& a_orders) {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
configure(a_orders);
}
array(unsigned int a_dimension,unsigned int a_order) {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
// A hypercube of dimension "a_dimension" and size "a_order".
uints_t _orders(a_dimension);
for(unsigned int index=0;index<a_dimension;index++)
_orders[index] = a_order;
configure(_orders);
}
virtual ~array() {
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
array(const array& a_from)
:m_orders(a_from.m_orders)
,m_offsets(a_from.m_offsets)
,m_vector(a_from.m_vector)
,m_is(a_from.m_is){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
array& operator=(const array& a_from) {
m_orders = a_from.m_orders;
m_offsets = a_from.m_offsets;
m_vector = a_from.m_vector;
m_is = a_from.m_is;
return *this;
}
public: //operators:
array& operator*=(const T& a_T) {multiply(a_T);return *this;}
bool operator==(const array& a_array) const {
return equal(a_array);
}
bool operator!=(const array& a_array) const {
return !operator==(a_array);
}
array operator*(const T& a_T) const {
array a(*this);
a.multiply(a_T);
return a;
}
// the below would need exception to do it properly.
//array operator+(const array& a_array) const {
// array a(*this);
// if(!a.add(a_array)) {} //throw
// return a;
//}
//array& operator+=(const array& a_array) {
// if(!add(a_array)) {} //throw
// return *this;
//}
public:
void copy(const array& a_from) {
m_orders = a_from.m_orders;
m_offsets = a_from.m_offsets;
m_vector = a_from.m_vector;
m_is = a_from.m_is;
}
void clear() {
m_orders.clear();
m_offsets.clear();
m_vector.clear();
m_is.clear();
}
bool configure(const uints_t& a_orders) {
m_orders = a_orders;
size_t dim = m_orders.size();
if(dim==0) {
clear();
return false;
}
unsigned int _size = 1;
for(size_t index=0;index<dim;index++) {
//if(m_orders[index]<0) {
//clear();
//return false;
//}
_size *= m_orders[index];
}
m_vector.resize(_size);
m_vector.assign(_size,zero());
m_offsets.resize(dim,0);
m_offsets[0] = 1;
for(size_t iaxis=1;iaxis<dim;iaxis++)
m_offsets[iaxis] = m_offsets[iaxis-1] * m_orders[iaxis-1];
m_is.resize(dim);
m_is.assign(dim,0);
return true;
}
size_t dimension() const { return m_orders.size();}
const uints_t& orders() const { return m_orders;}
size_t size() const {return m_vector.size();}
bool set_value(const uints_t& a_is,const T& a_value) {
unsigned int off = 0;
if(!offset(a_is,off)) return false;
m_vector[off] = a_value;
return true;
}
bool value(const uints_t& a_is,T& a_value) const {
unsigned int off = 0;
if(!offset(a_is,off)) {
a_value = 0;
return false;
}
a_value = m_vector[off];
return true;
}
T value_no_check(const uints_t& a_is) const { //TOUCHY
unsigned int off = 0;
if(!offset(a_is,off)) {}
return m_vector[off];
}
void reset() {
for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it) *it = 0;
}
const std::vector<T>& vector() const { return m_vector;}
std::vector<T>& vector() { return m_vector;}
bool fill(const std::vector<T>& a_values,cut_t* a_cut = 0) {
size_t dsize = a_values.size();
size_t di = 0;
unsigned int index = 0;
for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
if(di>=dsize) return false; //a_values exhausted too early
*it = a_values[di];
di++;
}
}
return true;
}
bool fill(unsigned int a_sz,const T* a_data,cut_t* a_cut = 0) {
unsigned int di = 0;
unsigned int index = 0;
for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
if(di>=a_sz) return false; //a_values exhausted too early
*it = a_data[di];
di++;
}
}
return true;
}
// Related to other array :
bool equal(const array& a_array) const {
if(m_orders!=a_array.m_orders) return false;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
if((*it)!=(*ait)) return false;
}
return true;
}
bool equal(const array& a_array,T aEpsilon) const {
if(m_orders!=a_array.m_orders) return false;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
T diff = (*it) - (*ait);
if(diff<0) diff *= -1;
if(diff>=aEpsilon) return false;
}
return true;
}
bool is_proportional(const array& a_array,T& a_factor) const {
// If true, then : a_array = a_factor * this.
a_factor = zero();
if(m_orders!=a_array.m_orders) return false;
bool first = true;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
if( ((*it)==zero()) && ((*ait)==zero())) {
continue;
} else if( ((*it)!=zero()) && ((*ait)==zero())) {
return false;
} else if( ((*it)==zero()) && ((*ait)!=zero())) {
return false;
} else {
if(first) {
a_factor = (*ait)/(*it);
first = false;
} else {
if((*ait)!=(*it)*a_factor) return false;
}
}
}
return true;
}
bool add(const array& a_array,cut_t* a_cut = 0) {
if(m_orders!=a_array.m_orders) return false;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
unsigned int index = 0;
for(;it!=m_vector.end();++it,++ait,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
(*it) += (*ait);
}
}
return true;
}
bool subtract(const array& a_array) {
if(m_orders!=a_array.m_orders) return false;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) (*it) -= (*ait);
return true;
}
bool multiply(const array& a_array) {
if(m_orders!=a_array.m_orders) return false;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) (*it) *= (*ait);
return true;
}
bool divide(const array& a_array) {
if(m_orders!=a_array.m_orders) return false;
bool status = true;
vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) {
if((*ait)==zero()) {
(*it) = zero(); //PAW convention.
status = false;
} else {
(*it) /= (*ait);
}
}
return status;
}
bool contract(const array& a_array,T& a_value) const {
a_value = zero();
if(m_orders!=a_array.m_orders) return false;
cons_vec_it_t it = m_vector.begin();
cons_vec_it_t ait = a_array.m_vector.begin();
for(;it!=m_vector.end();++it,++ait) a_value += (*it) * (*ait);
return true;
}
//Else:
void add(const T& a_T,cut_t* a_cut = 0) {
unsigned int index = 0;
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it,index++) {
if(!a_cut || (a_cut && accept(index,*a_cut)) ) {
(*it) += a_T;
}
}
}
void multiply(const T& a_T) {
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) *= a_T;
}
bool divide(const T& a_T) {
if(a_T==zero()) return false;
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) /= a_T;
return true;
}
bool invert() {
bool status = true;
T v_one = one();
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) {
if((*it)==zero()) {
(*it) = zero(); //PAW convention.
status = false;
} else {
T _value = (*it);
(*it) = v_one/_value;
}
}
return status;
}
bool offset(const uints_t& a_is,unsigned int& a_offset) const {
size_t dim = m_orders.size();
a_offset = 0;
if(a_is.size()!=dim) return false;
if(dim==0) return false;
for(size_t iaxis=0;iaxis<dim;iaxis++) {
unsigned int i = a_is[iaxis];
if(i>=m_orders[iaxis]) {
a_offset = 0;
return false;
}
a_offset += i * m_offsets[iaxis];
}
return true;
}
bool indices(unsigned int a_offset,uints_t& a_is) const {
if(a_offset>=m_vector.size()) return false;
size_t dim = m_orders.size();
unsigned int off = a_offset;
for(int iaxis=int(dim)-1;iaxis>=0;iaxis--) {
a_is[iaxis] = off/m_offsets[iaxis];
off -= a_is[iaxis] * m_offsets[iaxis];
}
return true;
}
bool accept(unsigned int a_index,const cut_t& a_cut) const {
size_t dim = m_orders.size();
if(a_cut.size()!=dim) return false;
if(!indices(a_index,const_cast<uints_t&>(m_is))) return false;
bool good = true;
for(size_t iaxis=0;iaxis<dim;iaxis++) {
if(m_is[iaxis]<a_cut[iaxis].first) {good = false;break;}
if(m_is[iaxis]>a_cut[iaxis].second) {good = false;break;}
}
return good;
}
void set_constant(const T& a_v) {
for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) = a_v;
}
void set_zero(){
set_constant(zero());
}
public:
static T zero() {
//return (T)0;
//return T(0);
return T();
}
static T one() {
//return (T)1;
return T(1);
}
static T minus_one() {
//return (T)-1;
return T(-1);
}
static T two() {
//return (T)2;
return T(2);
}
protected:
uints_t m_orders;
uints_t m_offsets;
std::vector<T> m_vector;
uints_t m_is;
};
}
#include <ostream>
// Helpers array<T> :
namespace tools {
template <class T>
inline bool contract(
const array<T>& aA
,unsigned int aIA
,const array<T>& aB
,unsigned int aIB
,array<T>& aR
){
// Contract a tensor (aA) with a vector (aB)
// on indice aIA of aA and aIB of aB.
// aA.dimension must be > 1.
// aB.dimension must be > 1.
if(&aR==&aA) return false;
if(&aR==&aB) return false;
if(aA.dimension()==0) return false;
if(aB.dimension()==0) return false;
if(aIA>=aA.dimension()) return false;
if(aIB>=aB.dimension()) return false;
if(aA.orders()[aIA]!=aB.orders()[aIB]) return false;
unsigned int rdima = aA.dimension()-1;
unsigned int rdimb = aB.dimension()-1;
if((rdima+rdimb)==0) {
std::vector<unsigned int> rorders(1);
rorders[0] = 1;
if(!aR.configure(rorders)) return false;
const std::vector<T>& vA = aA.vector();
const std::vector<T>& vB = aB.vector();
T value = array<T>::zero();
for(unsigned int index=0;index<vA.size();index++) {
value += vA[index]*vB[index];
}
aR.vector()[0] = value;
return true;
}
std::vector<unsigned int> rorders(rdima+rdimb);
unsigned int index;
for(index=0;index<aIA;index++)
rorders[index] = aA.orders()[index];
for(index=aIA;index<rdima;index++)
rorders[index] = aA.orders()[index+1];
for(index=0;index<aIB;index++)
rorders[rdima+index] = aB.orders()[index];
for(index=aIB;index<rdimb;index++)
rorders[rdima+index] = aB.orders()[index+1];
if(!aR.configure(rorders)) return false;
std::vector<unsigned int> ais(aA.dimension());
std::vector<unsigned int> bis(aB.dimension());
std::vector<unsigned int> ris(aR.dimension());
//FIXME : optimize the below.
unsigned int order = aA.orders()[aIA];
unsigned int rsize = aR.size();
std::vector<T>& rvec = aR.vector();
for(unsigned int roffset=0;roffset<rsize;roffset++) {
if(!aR.indices(roffset,ris)) return false;
for(index=0;index<aIA;index++) ais[index] = ris[index];
for(index=aIA;index<rdima;index++) ais[index+1] = ris[index];
for(index=0;index<aIB;index++) bis[index] = ris[rdima+index];
for(index=aIB;index<rdimb;index++) bis[index+1] = ris[rdima+index];
T value = 0;
for(index=0;index<order;index++) {
ais[aIA] = index;
T av;
if(!aA.value(ais,av)) return false;
bis[aIB] = index;
T bv;
if(!aB.value(bis,bv)) return false;
value += av * bv;
}
rvec[roffset] = value;
}
return true;
}
template <class T>
inline bool swap(
const array<T>& aV
,unsigned int aI1
,unsigned int aI2
,array<T>& aR
){
if(&aR==&aV) return false;
unsigned int dim = aV.dimension();
if(aI1>=dim) return false;
if(aI2>=dim) return false;
if(aI1==aI2) {
aR.copy(aV);
return true;
}
if(!aR.configure(aV.orders())) return false;
std::vector<unsigned int> vis(aV.dimension());
std::vector<unsigned int> ris(aV.dimension());
const std::vector<T>& vvec = aV.vector();
unsigned int size = aV.size();
for(unsigned int offset=0;offset<size;offset++) {
T value = vvec[offset];
if(!aV.indices(offset,vis)) return false;
unsigned int i = vis[aI1];
vis[aI1] = vis[aI2];
vis[aI2] = i;
if(!aR.set_value(vis,value)) return false;
}
return true;
}
//NOTE : print is a Python keyword.
template <class T>
inline void dump(std::ostream& a_out,const tools::array<T>& a_array,const std::string& a_title){
if(a_title.size()) a_out << a_title << std::endl;
const std::vector<T>& vec = a_array.vector();
typedef typename std::vector<T>::const_iterator cons_vec_it_t;
for(cons_vec_it_t it = vec.begin();it!=vec.end();++it) {
a_out << (*it) << std::endl;
}
}
template <class T>
inline void diff(std::ostream& a_out,const array<T>& aA,const array<T>& aB,T a_epsilon){
if(aA.orders()!=aB.orders()) {
a_out << "tools::arrays::diff : not same orders" << std::endl;
return;
}
bool header_done = false;
unsigned int dim = aA.dimension();
std::vector<unsigned int> is(dim);
unsigned int vsize = aA.vector().size();
for(unsigned int index=0;index<vsize;index++) {
T diff = aA.vector()[index]-aB.vector()[index];
if(diff<0) diff *= -1;
if(diff>=a_epsilon) {
aA.indices(index,is);
if(!header_done) {
a_out << "tools::arrays::diff :" << std::endl;
header_done = true;
}
for(unsigned int i=0;i<dim;i++) a_out << is[i] << " ";
a_out << aA.vector()[index] << " " << aB.vector()[index] << std::endl;
}
}
}
//////////////////////////////////////////////////////////////////////////////
/// common array /////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
template <class T>
class kronecker : public array<T> {
public:
kronecker(unsigned int a_order):array<T>(a_order,a_order){
// epsilon(i1,i2,....in) with n = a_order and i in [0,n[.
// Then an Array of a_order * a_order.
unsigned int index = 0;
typedef typename std::vector<unsigned int> _uints_t;
_uints_t is(a_order);
std::vector<T>& vec = array<T>::vector();
typedef typename std::vector<T>::iterator _vec_it_t;
_vec_it_t it = vec.begin();
for(;it!=vec.end();++it,index++) {
if(!array<T>::indices(index,is)) return; //FIXME throw.
bool good = true;
{for(unsigned int iaxis=0;iaxis<a_order;iaxis++) {
unsigned int ival = is[iaxis];
for(unsigned int iaxis2=iaxis+1;iaxis2<a_order;iaxis2++) {
if(is[iaxis2]==ival) {
good = false;
break;
}
}
if(!good) break;
}}
if(!good) continue;
// All indicies are different.
unsigned int n = 0;
for(unsigned int iaxis=0;iaxis<a_order;) {
unsigned int ival = is[iaxis];
if(ival!=iaxis) {
// Swap and add one permutation :
unsigned int old = is[ival];
is[ival] = ival;
is[iaxis] = old;
n +=1;
} else {
iaxis++;
}
}
{unsigned int n_2 = n/2;
if(2*n_2==n) (*it) = array<T>::one();
else (*it) = array<T>::minus_one();}
}
}
};
template <class T>
inline array<T> operator+(const array<T>& a1,const array<T>& a2) {
array<T> res(a1);
if(!res.add(a2)) {}
return res;
}
template <class T>
inline array<T> operator-(const array<T>& a1,const array<T>& a2) {
array<T> res(a1);
if(!res.subtract(a2)) {}
return res;
}
template <class T>
inline array<T> operator*(const T& a_fac,const array<T>& a_m) {
array<T> res(a_m);
res *= a_fac;
return res;
}
}
#endif
+43
View File
@@ -0,0 +1,43 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_b2s
#define tools_b2s
#include <string>
namespace tools {
inline void b2s(bool a_value,std::string& a_s){
a_s = a_value?"true":"false";
}
inline void bas(bool a_value,std::string& a_s){
a_s += (a_value?"true":"false");
}
}
#include <vector>
namespace tools {
inline void b2s(const std::vector<bool>& a_vals,std::string& a_s,const std::string& a_sep = "\n",bool a_sep_at_end = false) {
a_s.clear();
size_t number = a_vals.size();
if(number<=0) return;
number--;
std::string stmp;
for(size_t index=0;index<number;index++) {
b2s(a_vals[index],stmp);
a_s += stmp;
a_s += a_sep;
}
b2s(a_vals[number],stmp);
a_s += stmp;
if(a_sep_at_end) a_s += a_sep;
}
}
#endif
+142
View File
@@ -0,0 +1,142 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_buf2lines
#define tools_buf2lines
#include <vector>
#include <string>
namespace tools {
inline void buf2lines(char* a_buffer,std::vector<std::string>& a_lines) {
// WARNING : it is assumed that last char of a_buffer is 0.
// This function seeks '\n' and replaces them with '0'.
a_lines.clear();
char* pos = a_buffer;
char* beg = pos;
while(true) {
if((*pos=='\r')&&(*(pos+1)=='\n')) {
*pos = 0;
a_lines.push_back(beg);
pos += 2;
beg = pos;
} else if(*pos=='\n') {
*pos = 0;
a_lines.push_back(beg);
pos++;
beg = pos;
} else if(*pos==0) {
a_lines.push_back(beg);
return;
} else {
pos++;
}
}
}
inline void buf2lines(size_t a_size,const char* a_buffer,std::vector<std::string>& a_lines) {
a_lines.clear();
if(!a_size) return;
std::string line;
char* pos = (char*)a_buffer;
const char* end = a_buffer+a_size-1;
while(true) {
if(pos>end) {
if(line.size()) a_lines.push_back(line);
return;
}
if((*pos=='\r')&&((pos+1)<=end)&&(*(pos+1)=='\n')) {
a_lines.push_back(line);
line.clear();
pos += 2;
} else if(*pos=='\n') {
a_lines.push_back(line);
line.clear();
pos++;
} else {
line += *pos;
pos++;
}
}
}
}
#include <string.h> //memcpy
namespace tools {
// used in exlib/hdf5/T_tools,tools :
/*
inline bool strings2buf(size_t a_number,const char** a_strings,size_t& a_size,char*& a_buffer) {
// For {"aa","bbb"}, it produces "aa0bbb00".
// For {""}, it produces "00".
// For {}, it produces "0".
a_size = 0;
for(size_t index=0;index<a_number;index++) a_size += ::strlen(a_strings[index])+1;
a_size++;
a_buffer = new char[a_size];
if(!a_buffer) {a_size = 0;return false;}
char* pos = a_buffer;
size_t array_size;
for(size_t index=0;index<a_number;index++) {
const char* s = a_strings[index];
array_size = ::strlen(s)+1;
::memcpy(pos,s,array_size);
pos += array_size;
}
*pos = '\0';
return true;
}
*/
inline bool strings2buf(const std::vector<std::string>& a_strings,size_t& a_size,char*& a_buffer) {
// For {"aa","bbb"}, it produces "aa0bbb00".
// For {""}, it produces "00".
// For {}, it produces "0".
size_t number = a_strings.size();
a_size = 0;
for(size_t index=0;index<number;index++) a_size += a_strings[index].size()+1;
a_size++;
a_buffer = new char[a_size];
if(!a_buffer) {a_size = 0;return false;}
char* pos = a_buffer;
size_t array_size;
for(size_t index=0;index<number;index++) {
const std::string& s = a_strings[index];
array_size = s.size()+1;
::memcpy(pos,s.c_str(),array_size);
pos += array_size;
}
*pos = '\0';
return true;
}
inline bool buf2strings(size_t a_size,char* a_buffer,std::vector<std::string>& a_strings) {
if(a_size<=1) return false;
// We assume here a_size>=1
// Exa : if ab0cde00, then a_strings should contain two strings ab and cde.
a_strings.clear();
char* begin = a_buffer;
char* pos = a_buffer;
size_t number = a_size-1;
for(size_t index=0;index<number;index++) {
if((*pos)=='\0') {
size_t l = pos - begin;
std::string s(l,0);
char* data = (char*)s.c_str();
::memcpy(data,begin,l);
a_strings.push_back(s);
begin = pos+1;
}
pos++;
}
//pos++;
return true;
}
}
#endif
+144
View File
@@ -0,0 +1,144 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_carray
#define tools_carray
//fixed array manips
namespace tools {
template <class T>
inline void destroy(T*& a_v){
delete [] a_v;
a_v = 0;
}
template <class T,class I>
inline bool carray_copy(T*& a_v,I a_n,const T* a_from){
delete [] a_v;
a_v = 0;
if(a_n) {
a_v = new T[a_n];
if(!a_v) return false;
}
for(I i=0;i<a_n;i++) a_v[i] = a_from[i];
return true;
}
template <class T,class I>
inline bool copy(T*& a_v,I a_n,const T* a_from) {return carray_copy<T,I>(a_v,a_n,a_from);}
/*
template <class T>
inline T value(const T* a_v,
unsigned int a_q,
unsigned int a_i,unsigned int a_j){
// to get value in the case a x[p][q] is stored in a x[p*q].
// (used in hep/polyhedron_arb8)
// WARNING : no check is done on a_i, a_j
return a_v[a_i*a_q+a_j];
}
template <class I,class T,class I>
inline bool normalize(I a_n,T*& a_v,T(*a_sqrt)(T)){
T sz = T();
I i;
for(i=0;i<a_n;i++) sz += a_v[i]*a_v[i];
sz = a_sqrt(sz);
if(sz==T()) return false;
for(i=0;i<a_n;i++) a_v[i] /= sz;
return true;
}
template <class T>
inline T value(const T* a_v,
unsigned int a_q,
unsigned int a_i,unsigned int a_j){
// to get value x[i][j] in the case a x[p][q] is stored in a x[p*q].
// (used in hep/polyhedron_arb8)
// WARNING : no check is done on a_i, a_j
return a_v[a_i*a_q+a_j];
}
*/
}
#include "mnmx"
namespace tools {
template <class I,class T,class TO>
inline bool min_max(I a_n,const void* a_v,TO& a_mn,TO& a_mx){
if(a_n<=I(0)) {a_mn = TO(0);a_mx = TO(0);return false;}
T* pos = (T*)a_v;
a_mn = *pos;
a_mx = *pos;
for(I i=0;i<a_n;i++,pos++) {
a_mn = mn<TO>(a_mn,*pos);
a_mx = mx<TO>(a_mx,*pos);
}
return true;
}
template <class I,class T,class TO>
inline bool min_max_S_S2(I a_n,const void* a_v,TO& a_mn,TO& a_mx,TO& a_S,TO& a_S2){
if(a_n<=0) {a_mn = TO(0);a_mx = TO(0);a_S=TO(0);a_S2=TO(0);return false;}
T* pos = (T*)a_v;
a_mn = *pos;
a_mx = *pos;
a_S = TO(0);
a_S2 = TO(0);
for(I i=0;i<a_n;i++,pos++) {
a_mn = mn<TO>(a_mn,*pos);
a_mx = mx<TO>(a_mx,*pos);
a_S += TO(*pos);
a_S2 += TO(*pos) * TO(*pos);
}
return true;
}
template <class I,class T,class TO>
inline bool min_max_mean_rms(I a_n,const void* a_v,TO& a_mn,TO& a_mx,TO& a_mean,TO& a_rms,
TO(*a_sqrt)(TO),TO(*a_fabs)(TO)){
TO S = TO(0);
TO S2 = TO(0);
if(!min_max_S_S2<I,T,TO>(a_n,a_v,a_mn,a_mx,S,S2)) {
a_mn = TO(0);a_mx = TO(0);a_mean=TO(0);a_rms=TO(0);
return false;
}
a_mean = S/TO(a_n);
a_rms = a_sqrt(a_fabs(S2/TO(a_n) - a_mean * a_mean));
return true;
}
template <class I,class T,class HISTO>
inline bool h1_fill(I a_n,const void* a_v,HISTO& a_histo) {
a_histo.reset();
if(a_n<=0) return false;
typedef typename HISTO::coordinate_t TC;
T* pos = (T*)a_v;
for(I i=0;i<a_n;i++,pos++) a_histo.fill(TC(*pos));
return true;
}
template <class T,class I>
inline T* _4s_to_3s(const T* a_4s,const I& a_w,const I& a_h) {
T* _3s = new T[a_w*a_h*3];
if(!_3s) return 0;
T* pfrom = (T*)a_4s;
T* pto = _3s;
{I _sz = a_w*a_h*4;
for(I i=0;i<_sz;i+=4) {
*(pto+0) = *(pfrom+0);
*(pto+1) = *(pfrom+1);
*(pto+2) = *(pfrom+2);
pfrom += 4;
pto += 3;
}}
return _3s;
}
}
#endif
+668
View File
@@ -0,0 +1,668 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_ccontour
#define tools_ccontour
// G.Barrand : inline version of the one found in Lib of OSC 16.11.
// This code is not mine and I keep it "as it is".
// Contour.h: interface for the ccontour class.
//
// ccontour implements Contour plot algorithm descrided in
// IMPLEMENTATION OF
// AN IMPROVED CONTOUR
// PLOTTING ALGORITHM
// BY
//
// MICHAEL JOSEPH ARAMINI
//
// B.S., Stevens Institute of Technology, 1980
// See http://www.ultranet.com/~aramini/thesis.html
//
// Ported to C++ by Jonathan de Halleux.
//
// Using ccontour :
//
// ccontour is not directly usable. The user has to
// 1. derive the function ExportLine that is
// supposed to draw/store the segment of the contour
// 2. Set the function draw contour of. (using SetFieldFn
// The function must be declared as follows
// double (*myF)(double x , double y);
//
// History:
// 31-07-2002:
// - A lot of contribution from Chenggang Zhou (better strip compressions, merging, area, weight),
// - Got rid of ugly MFC lists for STL.
//////////////////////////////////////////////////////////////////////
//G.Barrand :
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#ifdef TOOLS_MEM
#include "mem"
#endif
#include "mnmx"
namespace tools {
class ccontour
{
#ifdef TOOLS_MEM
static const std::string& s_class() {
static const std::string s_v("tools::ccontour");
return s_v;
}
#endif
protected:
// plots a line from (x1,y1) to (x2,y2)
virtual void ExportLine(int iPlane,int x1,int y1,int x2,int y2) = 0;
public:
ccontour();
virtual ~ccontour(){
CleanMemory();
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
protected: //G.Barrand
ccontour(const ccontour&){}
private: //G.Barrand
ccontour& operator=(const ccontour&){return *this;}
public:
protected: //G.Barrand
// Initialize memory. Called in generate
virtual void InitMemory();
// Clean work arrays
virtual void CleanMemory();
// generates contour
// Before calling this functions you must
// 1. derive the function ExportLine that is
// supposed to draw/store the segment of the contour
// 2. Set the function draw contour of. (using SetFieldFn
// The function must be declared as follows
// double (*myF)(double x , double y);
public: //G.Barrand
virtual void generate();
// Set the dimension of the primary grid
void set_first_grid(int iCol, int iRow);
// Set the dimension of the base grid
void set_secondary_grid(int iCol, int iRow);
// Sets the region [left, right, bottom,top] to generate contour
void set_limits(double pLimits[4]);
// Sets the isocurve values
void set_planes(const std::vector<double>& vPlanes);
// Sets the pointer to the F(x,y) funtion
// G.Barrand : handle a user data pointer.
void set_field_fcn(double (*_pFieldFcn)(double, double,void*),void*);
size_t get_number_of_planes() const { return m_vPlanes.size();};
const std::vector<double>& get_planes() const { return m_vPlanes;};
double get_plane(unsigned int i) const;
// For an indexed point i on the sec. grid, returns x(i)
double get_xi(int i) const { return m_pLimits[0] + i%(m_iColSec+1)*(m_pLimits[1]-m_pLimits[0])/(double)( m_iColSec );};
// For an indexed point i on the fir. grid, returns y(i)
double get_yi(int i) const;
void get_limits(double pLimits[4]);
protected: //G.Barrand
// Retrieve dimension of grids, contouring region and isocurve
int GetColFir() const { return m_iColFir;};
int GetRowFir() const { return m_iRowFir;};
int GetColSec() const { return m_iColSec;};
int GetRowSec() const { return m_iRowSec;};
private:
// A structure used internally by ccontour
/*G.Barrand :
struct CFnStr {
double m_dFnVal;
short m_sLeftLen;
short m_sRightLen;
short m_sTopLen;
short m_sBotLen;
};
*/
class CFnStr {
#ifdef TOOLS_MEM
static const std::string& s_class() {
static const std::string s_v("tools::ccontour::CFnStr");
return s_v;
}
#endif
public:
CFnStr():m_dFnVal(0),m_sLeftLen(0),m_sRightLen(0),m_sTopLen(0),m_sBotLen(0){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
~CFnStr(){
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
protected:
CFnStr(const CFnStr&){}
CFnStr& operator=(const CFnStr&){return *this;}
public:
double m_dFnVal;
short m_sLeftLen;
short m_sRightLen;
short m_sTopLen;
short m_sBotLen;
};
protected:
// Accesibles variables
std::vector<double> m_vPlanes; // value of contour planes
double m_pLimits[4]; // left, right, bottom, top
int m_iColFir; // primary grid, number of columns
int m_iRowFir; // primary grid, number of rows
int m_iColSec; // secondary grid, number of columns
int m_iRowSec; // secondary grid, number of rows
void* m_pFieldFcnData; // G.Barrand : handle a user data pointer.
double (*m_pFieldFcn)(double x, double y,void*); // pointer to F(x,y) function
// Protected function
//virtual void ExportLine(int iPlane, int x1, int y1, int x2, int y2) = 0; // plots a line from (x1,y1) to (x2,y2)
// Work functions and variables
double m_dDx;
double m_dDy;
CFnStr** m_ppFnData; // pointer to mesh parts
CFnStr* FnctData(int i,int j) { return (m_ppFnData[i]+j);};
double Field(int x, int y); /* evaluate funct if we must, */
void Cntr1(int x1, int x2, int y1, int y2);
void Pass2(int x1, int x2, int y1, int y2); /* draws the contour lines */
private:
//G.Barrand : have the below in the class.
// A simple test function
static double ContourTestFunction(double x,double y,void*) {
return 0.5*(::cos(x+3.14/4)+::sin(y+3.14/4));
}
protected:
static void _ASSERT_(bool a_what,const char* a_where) {
if(!a_what) {
::printf("debug : Contour : assert failure in %s\n",a_where);
::exit(0);
}
}
static void _ASSERTP_(void* a_what,const char* a_where) {
if(!a_what) {
::printf("debug : Contour : assert failure in %s\n",a_where);
::exit(0);
}
}
};
// implementation :
//
// Code get on the web at :
// http://www.codeproject.com/cpp/contour.asp
//
// G.Barrand
//
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
inline ccontour::ccontour()
{
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
m_iColFir=m_iRowFir=32;
m_iColSec=m_iRowSec=256;
m_dDx=m_dDy=0;
m_pFieldFcnData = NULL;
m_pFieldFcn=NULL;
m_pLimits[0]=m_pLimits[2]=0;
m_pLimits[1]=m_pLimits[3]=5.;
m_ppFnData=NULL;
// temporary stuff
m_pFieldFcn=ContourTestFunction;
m_vPlanes.resize(20);
for (unsigned int i=0;i<m_vPlanes.size();i++)
{
m_vPlanes[i]=(i-m_vPlanes.size()/2.0)*0.1;
}
}
//G.Barrand : inline
inline void ccontour::InitMemory()
{
if (!m_ppFnData)
{
m_ppFnData=new CFnStr*[m_iColSec+1];
for (int i=0;i<m_iColSec+1;i++)
{
m_ppFnData[i]=NULL;
}
}
}
inline void ccontour::CleanMemory()
{
if (m_ppFnData)
{
int i;
for (i=0;i<m_iColSec+1;i++)
{
if (m_ppFnData[i])
delete[] (m_ppFnData[i]);
}
delete[] m_ppFnData;
m_ppFnData=NULL;
}
}
inline void ccontour::generate()
{
int i, j;
int x3, x4, y3, y4, x, y, oldx3, xlow;
const int cols=m_iColSec+1;
const int rows=m_iRowSec+1;
//double xoff,yoff;
// Initialize memroy if needed
InitMemory();
m_dDx = (m_pLimits[1]-m_pLimits[0])/(double)(m_iColSec);
//xoff = m_pLimits[0];
m_dDy = (m_pLimits[3]-m_pLimits[2])/(double)(m_iRowSec);
//yoff = m_pLimits[2];
xlow = 0;
oldx3 = 0;
x3 = (cols-1)/m_iRowFir;
x4 = ( 2*(cols-1) )/m_iRowFir;
for (x = oldx3; x <= x4; x++)
{ /* allocate new columns needed
*/
if (x >= cols)
break;
if (m_ppFnData[x]==NULL)
m_ppFnData[x] = new CFnStr[rows];
for (y = 0; y < rows; y++)
FnctData(x,y)->m_sTopLen = -1;
}
y4 = 0;
for (j = 0; j < m_iColFir; j++)
{
y3 = y4;
y4 = ((j+1)*(rows-1))/m_iColFir;
Cntr1(oldx3, x3, y3, y4);
}
for (i = 1; i < m_iRowFir; i++)
{
y4 = 0;
for (j = 0; j < m_iColFir; j++)
{
y3 = y4;
y4 = ((j+1)*(rows-1))/m_iColFir;
Cntr1(x3, x4, y3, y4);
}
y4 = 0;
for (j = 0; j < m_iColFir; j++)
{
y3 = y4;
y4 = ((j+1)*(rows-1))/m_iColFir;
Pass2(oldx3,x3,y3,y4);
}
if (i < (m_iRowFir-1))
{ /* re-use columns no longer needed */
oldx3 = x3;
x3 = x4;
x4 = ((i+2)*(cols-1))/m_iRowFir;
for (x = x3+1; x <= x4; x++)
{
if (xlow < oldx3)
{
if (m_ppFnData[x])
delete[] m_ppFnData[x];
m_ppFnData[x] = m_ppFnData[xlow];
m_ppFnData[ xlow++ ] = NULL;
}
else
if (m_ppFnData[x]==NULL)
m_ppFnData[x] = new CFnStr[rows];
for (y = 0; y < rows; y++)
FnctData(x,y)->m_sTopLen = -1;
}
}
}
y4 = 0;
for (j = 0; j < m_iColFir; j++)
{
y3 = y4;
y4 = ((j+1)*(rows-1))/m_iColFir;
Pass2(x3,x4,y3,y4);
}
}
inline void ccontour::Cntr1(int x1, int x2, int y1, int y2)
{
double f11, f12, f21, f22, f33;
int x3, y3, i, j;
if ((x1 == x2) || (y1 == y2)) /* if not a real cell, punt */
return;
f11 = Field(x1, y1);
f12 = Field(x1, y2);
f21 = Field(x2, y1);
f22 = Field(x2, y2);
if ((x2 > x1+1) || (y2 > y1+1)) { /* is cell divisible? */
x3 = (x1+x2)/2;
y3 = (y1+y2)/2;
f33 = Field(x3, y3);
i = j = 0;
if (f33 < f11) i++; else if (f33 > f11) j++;
if (f33 < f12) i++; else if (f33 > f12) j++;
if (f33 < f21) i++; else if (f33 > f21) j++;
if (f33 < f22) i++; else if (f33 > f22) j++;
if ((i > 2) || (j > 2)) /* should we divide cell? */
{
/* subdivide cell */
Cntr1(x1, x3, y1, y3);
Cntr1(x3, x2, y1, y3);
Cntr1(x1, x3, y3, y2);
Cntr1(x3, x2, y3, y2);
return;
}
}
/* install cell in array */
FnctData(x1,y2)->m_sBotLen = FnctData(x1,y1)->m_sTopLen = x2-x1;
FnctData(x2,y1)->m_sLeftLen = FnctData(x1,y1)->m_sRightLen = y2-y1;
}
inline void ccontour::Pass2(int x1, int x2, int y1, int y2)
{
int left = 0, right = 0, top = 0, bot = 0,old, iNew, i, j, x3, y3;
double yy0 = 0, yy1 = 0, xx0 = 0, xx1 = 0, xx3, yy3;
double v, f11, f12, f21, f22, f33, fold, fnew, f;
double xoff=m_pLimits[0];
double yoff=m_pLimits[2];
if ((x1 == x2) || (y1 == y2)) /* if not a real cell, punt */
return;
f11 = FnctData(x1,y1)->m_dFnVal;
f12 = FnctData(x1,y2)->m_dFnVal;
f21 = FnctData(x2,y1)->m_dFnVal;
f22 = FnctData(x2,y2)->m_dFnVal;
if ((x2 > x1+1) || (y2 > y1+1)) /* is cell divisible? */
{
x3 = (x1+x2)/2;
y3 = (y1+y2)/2;
f33 = FnctData(x3, y3)->m_dFnVal;
i = j = 0;
if (f33 < f11) i++; else if (f33 > f11) j++;
if (f33 < f12) i++; else if (f33 > f12) j++;
if (f33 < f21) i++; else if (f33 > f21) j++;
if (f33 < f22) i++; else if (f33 > f22) j++;
if ((i > 2) || (j > 2)) /* should we divide cell? */
{
/* subdivide cell */
Pass2(x1, x3, y1, y3);
Pass2(x3, x2, y1, y3);
Pass2(x1, x3, y3, y2);
Pass2(x3, x2, y3, y2);
return;
}
}
for (i = 0; i < (int)m_vPlanes.size(); i++)
{
v = m_vPlanes[i];
j = 0;
if (f21 > v) j++;
if (f11 > v) j |= 2;
if (f22 > v) j |= 4;
if (f12 > v) j |= 010;
if ((f11 > v) ^ (f12 > v))
{
if ((FnctData(x1,y1)->m_sLeftLen != 0) &&
(FnctData(x1,y1)->m_sLeftLen < FnctData(x1,y1)->m_sRightLen))
{
old = y1;
fold = f11;
while (1)
{
iNew = old+FnctData(x1,old)->m_sLeftLen;
fnew = FnctData(x1,iNew)->m_dFnVal;
if ((fnew > v) ^ (fold > v))
break;
old = iNew;
fold = fnew;
}
yy0 = ((old-y1)+(iNew-old)*(v-fold)/(fnew-fold))/(y2-y1);
}
else
yy0 = (v-f11)/(f12-f11);
left = (int)(y1+(y2-y1)*yy0+0.5);
}
if ((f21 > v) ^ (f22 > v))
{
if ((FnctData(x2,y1)->m_sRightLen != 0) &&
(FnctData(x2,y1)->m_sRightLen < FnctData(x2,y1)->m_sLeftLen))
{
old = y1;
fold = f21;
while (1)
{
iNew = old+FnctData(x2,old)->m_sRightLen;
fnew = FnctData(x2,iNew)->m_dFnVal;
if ((fnew > v) ^ (fold > v))
break;
old = iNew;
fold = fnew;
}
yy1 = ((old-y1)+(iNew-old)*(v-fold)/(fnew-fold))/(y2-y1);
}
else
yy1 = (v-f21)/(f22-f21);
right = (int)(y1+(y2-y1)*yy1+0.5);
}
if ((f21 > v) ^ (f11 > v))
{
if ((FnctData(x1,y1)->m_sBotLen != 0) &&
(FnctData(x1,y1)->m_sBotLen < FnctData(x1,y1)->m_sTopLen)) {
old = x1;
fold = f11;
while (1) {
iNew = old+FnctData(old,y1)->m_sBotLen;
fnew = FnctData(iNew,y1)->m_dFnVal;
if ((fnew > v) ^ (fold > v))
break;
old = iNew;
fold = fnew;
}
xx0 = ((old-x1)+(iNew-old)*(v-fold)/(fnew-fold))/(x2-x1);
}
else
xx0 = (v-f11)/(f21-f11);
bot = (int)(x1+(x2-x1)*xx0+0.5);
}
if ((f22 > v) ^ (f12 > v))
{
if ((FnctData(x1,y2)->m_sTopLen != 0) &&
(FnctData(x1,y2)->m_sTopLen < FnctData(x1,y2)->m_sBotLen)) {
old = x1;
fold = f12;
while (1) {
iNew = old+FnctData(old,y2)->m_sTopLen;
fnew = FnctData(iNew,y2)->m_dFnVal;
if ((fnew > v) ^ (fold > v))
break;
old = iNew;
fold = fnew;
}
xx1 = ((old-x1)+(iNew-old)*(v-fold)/(fnew-fold))/(x2-x1);
}
else
xx1 = (v-f12)/(f22-f12);
top = (int)(x1+(x2-x1)*xx1+0.5);
}
switch (j)
{
case 7:
case 010:
ExportLine(i,x1,left,top,y2);
break;
case 5:
case 012:
ExportLine(i,bot,y1,top,y2);
break;
case 2:
case 015:
ExportLine(i,x1,left,bot,y1);
break;
case 4:
case 013:
ExportLine(i,top,y2,x2,right);
break;
case 3:
case 014:
ExportLine(i,x1,left,x2,right);
break;
case 1:
case 016:
ExportLine(i,bot,y1,x2,right);
break;
case 0:
case 017:
break;
case 6:
case 011:
yy3 = (xx0*(yy1-yy0)+yy0)/(1.0-(xx1-xx0)*(yy1-yy0));
xx3 = yy3*(xx1-xx0)+xx0;
xx3 = x1+xx3*(x2-x1);
yy3 = y1+yy3*(y2-y1);
xx3 = xoff+xx3*m_dDx;
yy3 = yoff+yy3*m_dDy;
f = (*m_pFieldFcn)(xx3, yy3,m_pFieldFcnData);
if (f == v) {
ExportLine(i,bot,y1,top,y2);
ExportLine(i,x1,left,x2,right);
} else
if (((f > v) && (f22 > v)) || ((f < v) && (f22 < v))) {
ExportLine(i,x1,left,top,y2);
ExportLine(i,bot,y1,x2,right);
} else {
ExportLine(i,x1,left,bot,y1);
ExportLine(i,top,y2,x2,right);
}
}
}
}
inline double ccontour::Field(int x, int y) /* evaluate funct if we must,*/
{
double x1, y1;
if (FnctData(x,y)->m_sTopLen != -1) /* is it already in the array */
return(FnctData(x,y)->m_dFnVal);
/* not in the array, create new array element */
x1 = m_pLimits[0]+m_dDx*x;
y1 = m_pLimits[2]+m_dDy*y;
FnctData(x,y)->m_sTopLen = 0;
FnctData(x,y)->m_sBotLen = 0;
FnctData(x,y)->m_sRightLen = 0;
FnctData(x,y)->m_sLeftLen = 0;
return (FnctData(x,y)->m_dFnVal = (*m_pFieldFcn)(x1, y1,m_pFieldFcnData));
}
inline void ccontour::set_planes(const std::vector<double>& vPlanes)
{
// cleaning memory
CleanMemory();
m_vPlanes = vPlanes;
}
inline void ccontour::set_field_fcn(double (*_pFieldFcn)(double, double,void*),void* aData)
{
m_pFieldFcnData = aData;
m_pFieldFcn=_pFieldFcn;
}
inline void ccontour::set_first_grid(int iCol, int iRow)
{
m_iColFir=mx<int>(iCol,2);
m_iRowFir=mx<int>(iRow,2);
}
inline void ccontour::set_secondary_grid(int iCol, int iRow)
{
// cleaning work matrices if allocated
CleanMemory();
m_iColSec=mx<int>(iCol,2);
m_iRowSec=mx<int>(iRow,2);
}
inline void ccontour::set_limits(double pLimits[])
{
_ASSERT_(pLimits[0]<pLimits[1],"ccontour::set_limits");
_ASSERT_(pLimits[2]<pLimits[3],"ccontour::set_limits");
for (int i=0;i<4;i++)
{
m_pLimits[i]=pLimits[i];
}
}
inline void ccontour::get_limits(double pLimits[])
{
for (int i=0;i<4;i++)
{
pLimits[i]=m_pLimits[i];
}
}
//G.Barrand : from .h to .cxx to avoid _ASSERT_ in .h
inline double ccontour::get_plane(unsigned int i) const {
/*_ASSERT_(i>=0);*/
_ASSERT_(i<m_vPlanes.size(),"ccontour::get_plane");
return m_vPlanes[i];
}
inline double ccontour::get_yi(int i) const {
if(i<0) ::printf("ccontour::get_yi : %d\n",i);
_ASSERT_(i>=0,"ccontour::get_yi");
return m_pLimits[2] + i/(m_iColSec+1)*(m_pLimits[3]-m_pLimits[2])/(double)( m_iRowSec );
}
}
#endif
+152
View File
@@ -0,0 +1,152 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_charmanip
#define tools_charmanip
namespace tools {
// some char ASCII code :
// \0 : 0
// \n = LF : 10
// \r = CR : 13
// \t = HT : 9
// , : 44
inline bool is_upper(char a_char) {
// do it myself: due to problem with ctype.h and
// isxxx macros on different platforms.
switch(a_char) {
case 'A':return true;
case 'B':return true;
case 'C':return true;
case 'D':return true;
case 'E':return true;
case 'F':return true;
case 'G':return true;
case 'H':return true;
case 'I':return true;
case 'J':return true;
case 'K':return true;
case 'L':return true;
case 'M':return true;
case 'N':return true;
case 'O':return true;
case 'P':return true;
case 'Q':return true;
case 'R':return true;
case 'S':return true;
case 'T':return true;
case 'U':return true;
case 'V':return true;
case 'W':return true;
case 'X':return true;
case 'Y':return true;
case 'Z':return true;
default:return false;
}
return false;
}
inline bool is_lower(char a_char) {
switch(a_char) {
case 'a':return true;
case 'b':return true;
case 'c':return true;
case 'd':return true;
case 'e':return true;
case 'f':return true;
case 'g':return true;
case 'h':return true;
case 'i':return true;
case 'j':return true;
case 'k':return true;
case 'l':return true;
case 'm':return true;
case 'n':return true;
case 'o':return true;
case 'p':return true;
case 'q':return true;
case 'r':return true;
case 's':return true;
case 't':return true;
case 'u':return true;
case 'v':return true;
case 'w':return true;
case 'x':return true;
case 'y':return true;
case 'z':return true;
default:return false;
}
return false;
}
inline bool is_digit(char a_char) {
switch(a_char){
case '0':return true;
case '1':return true;
case '2':return true;
case '3':return true;
case '4':return true;
case '5':return true;
case '6':return true;
case '7':return true;
case '8':return true;
case '9':return true;
default:return false;
}
return false;
}
inline bool is_letter(char a_char) {
return (is_lower(a_char)||is_upper(a_char)) ? true : false;
}
//inline bool is_alpha(char a_char) {
// return (is_lower(a_char)||is_upper(a_char)||is_digit(a_char)) ? true : false;
//}
inline bool is_printable(char a_char) {
if(is_lower(a_char)||is_upper(a_char)||is_digit(a_char)) return true;
switch(a_char) {
case ' ':return true;
case '!':return true;
case '"':return true;
case '#':return true;
case '$':return true;
case '%':return true;
case '&':return true;
case '\'':return true;
case '(':return true;
case ')':return true;
case '*':return true;
case '+':return true;
case ',':return true;
case '-':return true;
case '.':return true;
case '/':return true;
case ':':return true;
case ';':return true;
case '<':return true;
case '=':return true;
case '>':return true;
case '?':return true;
case '@':return true;
case '[':return true;
case '\\':return true;
case ']':return true;
case '^':return true;
case '_':return true;
case '`':return true;
case '{':return true;
case '|':return true;
case '}':return true;
case '~':return true;
default:return false;
}
return false;
}
}
#endif
+34
View File
@@ -0,0 +1,34 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_charp_out
#define tools_charp_out
#include "snpf"
#include <string>
namespace tools {
class charp_out : public std::string {
typedef std::string parent;
public:
charp_out(const char* a_value) {
char s[512];
if(sizeof(unsigned long)==sizeof(char*)) { //majority of cases.
snpf(s,sizeof(s),"%lu",a_value);
parent::operator+=(s);
} else if(sizeof(unsigned long long)==sizeof(char*)) { //majority of cases.
snpf(s,sizeof(s),"%llu",a_value);
parent::operator+=(s);
} else {
parent::operator+=("charp_out_failed");
}
}
public:
charp_out(const charp_out& a_from):parent(a_from){}
charp_out& operator=(const charp_out& a_from){parent::operator=(a_from);return *this;}
};
}
#endif
+21
View File
@@ -0,0 +1,21 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_chars
#define tools_chars
namespace tools {
// some char ASCII code :
// \0 : 0
// \n = LF : 10
// \r = CR : 13
// \t = HT : 9
// , : 44
inline char LF() {return 10;}
inline char CR() {return 13;}
}
#endif
+13
View File
@@ -0,0 +1,13 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_cid
#define tools_cid
namespace tools {
typedef unsigned short cid;
}
#endif
+104
View File
@@ -0,0 +1,104 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_cids
#define tools_cids
#include "cid"
#include <string>
#include "typedefs" //byte
namespace tools {
inline cid _cid(byte) {return 1;}
inline cid _cid(char) {return 2;}
inline cid _cid(unsigned short) {return 3;}
inline cid _cid(short) {return 4;}
inline cid _cid(unsigned int) {return 5;}
inline cid _cid(int) {return 6;}
inline cid _cid(float) {return 7;}
inline cid _cid(double) {return 8;}
inline cid _cid(bool) {return 9;}
// not compiler types :
inline cid _cid(uint64) {return 10;}
inline cid _cid(int64) {return 11;}
inline cid _cid(const std::string&) {return 12;}
inline cid _cid(fits_bit) {return 13;}
inline cid _cid(csv_time) {return 14;}
//NOTE : avoid time_t which is defined in general as a long
// and is then ambiguous relative to int/int64.
//NOTE : if adding some, it must not exceed 20. Else, you have to change
// the below for std::vector.
}
#include <vector>
namespace tools {
// For rntuple and rroot::ntuple::column_element.
// The read::icolumn<T> needs a _cid(T) with T :
// std::vector< [basic_type, std::vector<basic_type>] >
template <class T>
inline cid _cid(const std::vector<T>&) {return 20+_cid(T());}
template <class T>
inline cid _cid_std_vector() {
static const T s_v = T(); //do that for T = std::string.
return 20+_cid(s_v);
}
// Then : cid for std::vector< std::vector<T> > is going to be :
// 20+_cid(std::vector<T>) = 2*20+_cid(T)
//WARNING : rroot/cids start at 100.
//WARNING : rroot/geo_cids start at 1000.
}
namespace tools {
inline bool cid2s(cid a_id,std::string& a_s) {
// NOTE : the returned string must not contain space.
if(a_id==_cid(char(0))) {a_s = "char";return true;}
else if(a_id==_cid(short(0))) {a_s = "short";return true;}
else if(a_id==_cid(int(0))) {a_s = "int";return true;}
else if(a_id==_cid(float(0))) {a_s = "float";return true;}
else if(a_id==_cid(double(0))) {a_s = "double";return true;}
else if(a_id==_cid(std::string())) {a_s = "string";return true;}
// NOTE : the below do not follow the AIDA convention.
else if(a_id==_cid((unsigned char)0)) {a_s = "uchar";return true;} //AIDA=byte
else if(a_id==_cid((unsigned short)0)) {a_s = "ushort";return true;} //AIDA not defined
else if(a_id==_cid((unsigned int)0)) {a_s = "uint";return true;} //AIDA not defined
else if(a_id==_cid(bool(true))) {a_s = "bool";return true;} //AIDA=boolean
else if(a_id==_cid(int64(0))) {a_s = "int64";return true;} //AIDA=long
else if(a_id==_cid(uint64(0))) {a_s = "uint64";return true;} //AIDA=not defined
else if(a_id==_cid_std_vector<char>()) {a_s = "char[]";return true;}
else if(a_id==_cid_std_vector<short>()) {a_s = "short[]";return true;}
else if(a_id==_cid_std_vector<int>()) {a_s = "int[]";return true;}
else if(a_id==_cid_std_vector<float>()) {a_s = "float[]";return true;}
else if(a_id==_cid_std_vector<double>()) {a_s = "double[]";return true;}
else if(a_id==_cid_std_vector<std::string>()) {a_s = "string[]";return true;}
else if(a_id==_cid_std_vector<unsigned char>()) {a_s = "uchar[]";return true;}
else if(a_id==_cid_std_vector<unsigned short>()) {a_s = "ushort[]";return true;}
else if(a_id==_cid_std_vector<unsigned int>()) {a_s = "uint[]";return true;}
else if(a_id==_cid_std_vector<bool>()) {a_s = "bool[]";return true;}
else if(a_id==_cid_std_vector<int64>()) {a_s = "int64[]";return true;}
else if(a_id==_cid_std_vector<uint64>()) {a_s = "uint64[]";return true;}
a_s.clear();
return false;
}
}
#endif
+893
View File
@@ -0,0 +1,893 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_clist_contour
#define tools_clist_contour
// G.Barrand : inline version of the one found in Lib of OSC 16.11.
// This code is not mine and I keep it "as it is".
// Inheritance :
#include "ccontour"
#include <list>
#include <ostream>
#include <iomanip> //std::setprecision
namespace tools {
// a list of point index referring to the secondary grid
// Let i the index of a point,
typedef std::list<unsigned int> cline_strip;
typedef std::list<cline_strip*> cline_strip_list;
typedef std::vector<cline_strip_list> cline_strip_list_vector;
class clist_contour : public ccontour
{
public: //ccontour
// Adding segment to line strips
// See ccontour::ExportLine for further details
virtual void ExportLine(int iPlane,int x1, int y1, int x2, int y2);
public:
clist_contour();
virtual ~clist_contour(){CleanMemory();}
protected: //G.Barrand
clist_contour(const clist_contour& a_from):ccontour(a_from){}
private: //G.Barrand
clist_contour& operator=(const clist_contour&){return *this;}
public:
// retreiving list of line strip for the i-th contour
cline_strip_list* get_lines(unsigned int iPlane);
// Basic algorithm to concatanate line strip. Not optimized at all !
bool compact_strips ();
// generate contour strips
virtual void generate();
protected: //G.Barrand
// Initializing memory
virtual void InitMemory();
// Cleaning memory and line strips
virtual void CleanMemory();
// Adding segment to line strips
// See ccontour::ExportLine for further details
//void ExportLine(int iPlane,int x1, int y1, int x2, int y2);
/// debuggin
void DumpPlane(unsigned int iPlane) const;
// Area given by this function can be positive or negative depending on the winding direction of the contour.
double Area(cline_strip* Line);
double EdgeWeight(cline_strip* pLine, double R);
//bool PrintContour(std::ostream& a_out);
protected:
// Merges pStrip1 with pStrip2 if they have a common end point
bool MergeStrips(cline_strip* pStrip1, cline_strip* pStrip2);
// Merges the two strips with a welding threshold.
bool ForceMerge(cline_strip* pStrip1, cline_strip* pStrip2,double);
// returns true if contour is touching boundary
bool OnBoundary(cline_strip* pStrip);
// L.Garnier : check specials case for CompactStrip
bool SpecialCompactStripCase(double,double,double,double,double);
private:
// array of line strips
cline_strip_list_vector m_vStripLists;
typedef unsigned int UINT;
private:
static const char* _TT(const char* what) {return what;}
static void _TRACE_(const char* /*a_fmt*/,...) {
//va_list args;
//va_start(args,a_fmt);
//::vprintf(s,a_fmt,args);
//va_end(args);
}
static void _PROBLEM_(const char* what) {::printf("%s",what);}
static bool _ASSERT_RET_(bool what,const char* cmt) {
if(!(what)) {
::printf("debug : ListContour : assert failure in %s\n",cmt);
return false;
}
return true;
}
static bool _ASSERT_MERGE_RET_(bool what,const char* cmt,cline_strip* pStrip2) {
if(!(what)) {
::printf("debug : ListContour : assert failure in %s\n",cmt);
pStrip2->clear();
return false;
}
return true;
}
};
// implementation :
inline clist_contour::clist_contour()
: ccontour()
{
}
inline void clist_contour::generate()
{
// generate line strips
ccontour::generate();
// compact strips
compact_strips ();
}
inline void clist_contour::InitMemory()
{
ccontour::InitMemory();
cline_strip_list::iterator pos;
cline_strip* pStrip;
if (!m_vStripLists.empty())
{
UINT i;
// reseting lists
_ASSERT_(m_vStripLists.size() == get_number_of_planes(),"clist_contour::InitMemory::0");
for (i=0;i<get_number_of_planes();i++)
{
for (pos = m_vStripLists[i].begin(); pos!=m_vStripLists[i].end() ; pos++)
{
pStrip=(*pos);
_ASSERTP_(pStrip,"clist_contour::InitMemory::1");
pStrip->clear();
delete pStrip;
}
m_vStripLists[i].clear();
}
}
else
m_vStripLists.resize(get_number_of_planes());
}
inline void clist_contour::CleanMemory()
{
ccontour::CleanMemory();
cline_strip_list::iterator pos;
cline_strip* pStrip;
UINT i;
// reseting lists
for (i=0;i<m_vStripLists.size();i++) //G.Barrand
{
for (pos=m_vStripLists[i].begin(); pos!=m_vStripLists[i].end();pos++)
{
pStrip=(*pos);
_ASSERTP_(pStrip,"clist_contour::CleanMemory");
pStrip->clear();
delete pStrip;
}
m_vStripLists[i].clear();
}
}
inline void clist_contour::ExportLine(int iPlane,int x1, int y1, int x2, int y2)
{
_ASSERT_(iPlane>=0,"clist_contour::ExportLine::0");
_ASSERT_(iPlane<(int)get_number_of_planes(),"clist_contour::ExportLine::1");
// check that the two points are not at the beginning or end of the some line strip
UINT i1=y1*(m_iColSec+1)+x1;
UINT i2=y2*(m_iColSec+1)+x2;
cline_strip* pStrip;
cline_strip_list::iterator pos;
bool added = false;
for(pos=m_vStripLists[iPlane].begin(); pos!=m_vStripLists[iPlane].end() && !added; pos++)
{
pStrip=(*pos);
_ASSERTP_(pStrip,"clist_contour::ExportLine::2");
// check if points are appendable to this strip
if (i1==pStrip->front())
{
pStrip->insert(pStrip->begin(),i2);
return;
}
if (i1==pStrip->back())
{
pStrip->insert(pStrip->end(),i2);
return;
}
if (i2==pStrip->front())
{
pStrip->insert(pStrip->begin(),i1);
return;
}
if (i2==pStrip->back())
{
pStrip->insert(pStrip->end(),i1);
return;
}
}
// segment was not part of any line strip, creating new one
pStrip=new cline_strip;
pStrip->insert(pStrip->begin(),i1);
pStrip->insert(pStrip->end(),i2);
m_vStripLists[iPlane].insert(m_vStripLists[iPlane].begin(),pStrip);
}
inline bool clist_contour::ForceMerge(cline_strip* pStrip1, cline_strip* pStrip2,double aHeight)
{
cline_strip::iterator pos;
cline_strip::reverse_iterator rpos;
if (pStrip2->empty())
return false;
double x[4], y[4], weldDist;
int index;
index = pStrip1->front();
x[0] = get_xi(index);
y[0] = get_yi(index);
index = pStrip1->back();
x[1] = get_xi(index);
y[1] = get_yi(index);
index = pStrip2->front();
x[2] = get_xi(index);
y[2] = get_yi(index);
index = pStrip2->back();
x[3] = get_xi(index);
y[3] = get_yi(index);
weldDist = 10*(m_dDx*m_dDx+m_dDy*m_dDy);
if (((x[1]-x[2])*(x[1]-x[2])+(y[1]-y[2])*(y[1]-y[2])< weldDist)
|| SpecialCompactStripCase(x[1],x[2],y[1],y[2],aHeight)) // L.Garnier
{
for (pos=pStrip2->begin(); pos!=pStrip2->end();pos++)
{
index=(*pos);
if(!_ASSERT_RET_(index>=0,"clist_contour::ForceMerge::0")) return false;
pStrip1->insert(pStrip1->end(),index);
}
pStrip2->clear();
return true;
}
if (((x[3]-x[0])*(x[3]-x[0])+(y[3]-y[0])*(y[3]-y[0])< weldDist)
|| SpecialCompactStripCase(x[3],x[0],y[3],y[0],aHeight)) // L.Garnier
{
for (rpos=pStrip2->rbegin(); rpos!=pStrip2->rend();rpos++)
{
index=(*rpos);
if(!_ASSERT_RET_(index>=0,"clist_contour::ForceMerge::1")) return false;
pStrip1->insert(pStrip1->begin(),index);
}
pStrip2->clear();
return true;
}
if (((x[1]-x[3])*(x[1]-x[3])+(y[1]-y[3])*(y[1]-y[3])< weldDist)
|| SpecialCompactStripCase(x[1],x[3],y[1],y[3],aHeight)) // L.Garnier
{
for (rpos=pStrip2->rbegin(); rpos!=pStrip2->rend();rpos++)
{
index=(*rpos);
if(!_ASSERT_RET_(index>=0,"clist_contour::ForceMerge::2")) return false;
pStrip1->insert(pStrip1->end(),index);
}
pStrip2->clear();
return true;
}
if (((x[0]-x[2])*(x[0]-x[2])+(y[0]-y[2])*(y[0]-y[2])< weldDist)
|| SpecialCompactStripCase(x[0],x[2],y[0],y[2],aHeight)) // L.Garnier
{
for (pos=pStrip2->begin(); pos!=pStrip2->end();pos++)
{
index=(*pos);
if(!_ASSERT_RET_(index>=0,"clist_contour::ForceMerge::3")) return false;
pStrip1->insert(pStrip1->begin(),index);
}
pStrip2->clear();
return true;
}
return false;
}
inline bool clist_contour::MergeStrips(cline_strip* pStrip1, cline_strip* pStrip2)
{
cline_strip::iterator pos;
cline_strip::reverse_iterator rpos;
if (pStrip2->empty())
return false;
int index;
// debugging stuff
if (pStrip2->front()==pStrip1->front())
{
// retreiving first element
pStrip2->pop_front();
// adding the rest to strip1
for (pos=pStrip2->begin(); pos!=pStrip2->end();pos++)
{
index=(*pos);
if(!_ASSERT_MERGE_RET_(index>=0,"clist_contour::MergeStrips::0",pStrip2)) return false;
pStrip1->insert(pStrip1->begin(),index);
}
pStrip2->clear();
return true;
}
if (pStrip2->front()==pStrip1->back())
{
pStrip2->pop_front();
// adding the rest to strip1
for (pos=pStrip2->begin(); pos!=pStrip2->end();pos++)
{
index=(*pos);
if(!_ASSERT_MERGE_RET_(index>=0,"clist_contour::MergeStrips::1",pStrip2)) return false;
pStrip1->insert(pStrip1->end(),index);
}
pStrip2->clear();
return true;
}
if (pStrip2->back()==pStrip1->front())
{
pStrip2->pop_back();
// adding the rest to strip1
for (rpos=pStrip2->rbegin(); rpos!=pStrip2->rend();rpos++)
{
index=(*rpos);
if(!_ASSERT_MERGE_RET_(index>=0,"clist_contour::MergeStrips::2",pStrip2)) return false;
pStrip1->insert(pStrip1->begin(),index);
}
pStrip2->clear();
return true;
}
if (pStrip2->back()==pStrip1->back())
{
pStrip2->pop_back();
// adding the rest to strip1
for (rpos=pStrip2->rbegin(); rpos!=pStrip2->rend();rpos++)
{
index=(*rpos);
if(!_ASSERT_MERGE_RET_(index>=0,"clist_contour::MergeStrips::3",pStrip2)) return false;
pStrip1->insert(pStrip1->end(),index);
}
pStrip2->clear();
return true;
}
return false;
}
inline bool clist_contour::compact_strips ()
{
cline_strip* pStrip;
cline_strip* pStripBase = 0;
UINT i;
cline_strip_list::iterator pos,pos2;
cline_strip_list newList;
bool again, changed;
const double weldDist = 10*(m_dDx*m_dDx+m_dDy*m_dDy);
if(!_ASSERT_RET_(m_vStripLists.size() == get_number_of_planes(),"clist_contour::compact_strips ::0")) return false;
for (i=0;i<get_number_of_planes();i++)
{
double planeHeight = get_plane(i);
again=true;
while(again)
{
// REPEAT COMPACT PROCESS UNTILL LAST PROCESS MAKES NO CHANGE
again=false;
// building compacted list
if(!_ASSERT_RET_(newList.empty(),"clist_contour::compact_strips ::1")) return false;
for (pos=m_vStripLists[i].begin(); pos!=m_vStripLists[i].end();pos++)
{
pStrip=(*pos);
for (pos2=newList.begin(); pos2!=newList.end();pos2++)
{
pStripBase=(*pos2);
changed=MergeStrips(pStripBase,pStrip);
if (changed)
again=true;
if (pStrip->empty())
break;
}
if (pStrip->empty())
delete pStrip;
else
newList.insert(newList.begin(),pStrip);
}
// deleting old list
m_vStripLists[i].clear();
cline_strip* pStrip2;
// Copying all
for (pos2=newList.begin(); pos2 != newList.end(); pos2++)
{
pStrip2=(*pos2);
cline_strip::iterator pos1 = pStrip2->begin(),pos3;
while (pos1!=pStrip2->end())
{
pos3 = pos1;
pos3++;
if (pos3==pStrip2->end()) break; //G.Barrand
if ( (*pos1) == (*pos3))
{
/*G.Barrand : we can't compare with pStrip2->end() content.
if ( (*pos3) != (*pStrip2->end()))
pStrip2->erase(pos3);
else
{
pStrip2->erase(pos3);
break;
}
*/
pStrip2->erase(pos3); //G.Barrand.
}
else
pos1++;
}
//if (!(pStrip2->front()==pStrip2->back() && pStrip2->size()==2))
if (pStrip2->size()!=1)
m_vStripLists[i].insert(m_vStripLists[i].begin(),pStrip2 );
else
delete pStrip2;
}
// emptying temp list
newList.clear();
} // OF WHILE(AGAIN) (LAST COMPACT PROCESS MADE NO CHANGES)
if (m_vStripLists[i].empty())
continue;
///////////////////////////////////////////////////////////////////////
// compact more
int index,count;
size_t Nstrip,j;
Nstrip = m_vStripLists[i].size();
std::vector<bool> closed(Nstrip);
double x,y;
// First let's find the open and closed lists in m_vStripLists
for(pos2 = m_vStripLists[i].begin(), j=0, count=0; pos2 != m_vStripLists[i].end(); pos2++, j++)
{
pStrip = (*pos2);
// is it open ?
if (pStrip->front() != pStrip->back())
{
index = pStrip->front();
x = get_xi(index); y = get_yi(index);
index = pStrip->back();
x -= get_xi(index); y -= get_yi(index);
// is it "almost closed" ?
if ((x*x+y*y < weldDist) ||
SpecialCompactStripCase(get_xi(pStrip->front()), // L.Garnier
get_xi(pStrip->back()),
get_yi(pStrip->front()),
get_yi(pStrip->back()),
planeHeight))
{
closed[j] = true;
// close it !!! Added by L.Garnier
pStrip->push_back(pStrip->front());
//
}
else
{
closed[j] = false;
// updating not closed counter...
count ++;
}
}
else
closed[j] = true;
}
// is there any open strip ?
if (count > 1)
{
// Merge the open strips into NewList
pos = m_vStripLists[i].begin();
for(j=0;j<Nstrip;j++)
{
if (closed[j] == false )
{
pStrip = (*pos);
newList.insert(newList.begin(),pStrip);
pos = m_vStripLists[i].erase(pos);
}
else
pos ++;
}
// are they open strips to process ?
while(newList.size()>1)
{
pStripBase = newList.front();
// merge the rest to pStripBase
again = true;
while (again)
{
again = false;
pos = newList.begin();
for(pos++; pos!=newList.end();)
{
pStrip = (*pos);
changed = ForceMerge(pStripBase,pStrip,planeHeight);
if (changed)
{
again = true;
delete pStrip;
pos = newList.erase(pos);
}
else
pos ++;
}
} // while(again)
index = pStripBase->front();
x = get_xi(index); y = get_yi(index);
index = pStripBase->back();
x -= get_xi(index); y -= get_yi(index);
// if pStripBase is closed or not
if ((x*x+y*y < weldDist) ||
SpecialCompactStripCase(get_xi(pStripBase->front()), // L.Garnier
get_xi(pStripBase->back()),
get_yi(pStripBase->front()),
get_yi(pStripBase->back()),
planeHeight))
{
// close it !!! Added by L.Garnier
if ((x!=0) || (y!=0)) {
pStripBase->push_back(pStripBase->front());
}
//
m_vStripLists[i].insert(m_vStripLists[i].begin(),pStripBase);
newList.pop_front();
}
else
{
if (OnBoundary(pStripBase))
{
_TRACE_(_TT("# open strip ends on boundary, continue.\n"));
m_vStripLists[i].insert(m_vStripLists[i].begin(),pStripBase);
newList.pop_front();
}
else
{
_PROBLEM_(_TT("unpaird open strip at 1!\n"));
//exit(0);
return false;
}
}
} // while(newList.size()>1);
if (newList.size() ==1)
{
pStripBase = newList.front();
index = pStripBase->front(); // L.Garnier
x = get_xi(index); y = get_yi(index); // L.Garnier
index = pStripBase->back(); // L.Garnier
x -= get_xi(index); y -= get_yi(index); // L.Garnier
// is it "almost closed", give last chance...5*weldDist
if (x*x+y*y < 3*weldDist) // L.Garnier
{
m_vStripLists[i].insert(m_vStripLists[i].begin(),pStripBase);
newList.pop_front();
}
else if (OnBoundary(pStripBase))
{
_TRACE_(_TT("# open strip ends on boundary, continue.\n"));
m_vStripLists[i].insert(m_vStripLists[i].begin(),pStripBase);
newList.pop_front();
}
else
{
_PROBLEM_(_TT("unpaird open strip at 2!\n"));
DumpPlane(i);
//exit(0);
return false;
}
}
newList.clear();
}
else if (count == 1)
{
pos = m_vStripLists[i].begin();
for(j=0;j<Nstrip;j++)
{
if (closed[j] == false )
{
pStripBase = (*pos);
break;
}
pos ++;
}
index = pStripBase->front(); // L.Garnier
x = get_xi(index); y = get_yi(index); // L.Garnier
index = pStripBase->back(); // L.Garnier
x -= get_xi(index); y -= get_yi(index); // L.Garnier
// is it "almost closed", give last chance...5*weldDist
if (x*x+y*y < 2*weldDist) // L.Garnier
{
//close it!!
pStripBase->push_back(pStripBase->front()); // L.Garnier
}
else if (OnBoundary(pStripBase))
{
_TRACE_(_TT("# open strip ends on boundary, continue.\n"));
pStripBase->push_back(pStripBase->front()); // L.Garnier
}
else
{
_TRACE_(_TT("unpaird open strip at 3!"));
DumpPlane(i);
return false; // L.Garnier
//exit(0);
}
newList.clear(); // L.Garnier
}
}
return true;
}
inline bool clist_contour::OnBoundary(cline_strip* pStrip)
{
bool e1,e2;
int index = pStrip->front();
double x = get_xi(index), y = get_yi(index);
if (x==m_pLimits[0] || x == m_pLimits[1] ||
y == m_pLimits[2] || y == m_pLimits[3])
e1 = true;
else
e1 = false;
index = pStrip->back();
x = get_xi(index); y = get_yi(index);
if (x==m_pLimits[0] || x == m_pLimits[1] ||
y == m_pLimits[2] || y == m_pLimits[3])
e2 = true;
else
e2 = false;
return (e1 && e2);
}
inline void clist_contour::DumpPlane(UINT iPlane) const
{
cline_strip_list::const_iterator pos;
UINT i;
cline_strip* pStrip;
/*_ASSERT_(iPlane>=0,"clist_contour::DumpPlane");*/
_ASSERT_(iPlane<get_number_of_planes(),"clist_contour::DumpPlane::0");
_TRACE_(_TT("Level : %d"),get_plane(iPlane));
_TRACE_(_TT("Number of strips : %d\r\n"),m_vStripLists[iPlane].size());
_TRACE_(_TT("i np start end xstart ystart xend yend\r\n"));
for (pos = m_vStripLists[iPlane].begin(), i=0; pos != m_vStripLists[iPlane].end(); pos++, i++)
{
pStrip=*pos;
_ASSERTP_(pStrip,"clist_contour::DumpPlane::1");
_TRACE_(_TT("%d %d %d %d %g %g %g %g\r\n"),i,pStrip->size(),pStrip->front(),pStrip->back(),
get_xi(pStrip->front()),get_yi(pStrip->front()),
get_xi(pStrip->back()),get_yi(pStrip->back()) );
}
}
inline double clist_contour::Area(cline_strip* Line)
{
// if Line is not closed, return 0;
double Ar = 0, x, y, x0,y0,x1, y1;
int index;
cline_strip::iterator pos;
pos = Line->begin();
index = (*pos);
x0 = x = get_xi(index);
y0 = y = get_yi(index);
pos ++;
for(;pos!=Line->end();pos++)
{
index = (*pos);
x1 = get_xi(index);
y1 = get_yi(index);
// Ar += (x1-x)*(y1+y);
Ar += (y1-y)*(x1+x)-(x1-x)*(y1+y);
x = x1;
y = y1;
}
//Ar += (x0-x)*(y0+y);
Ar += (y0-y)*(x0+x)-(x0-x)*(y0+y);
// if not closed curve, return 0;
if ((x0-x)*(x0-x) + (y0-y)*(y0-y)>20*(m_dDx*m_dDx+m_dDy*m_dDy))
{
Ar = 0;
_TRACE_(_TT("# open curve!\n"));
}
//else Ar /= -2;
else Ar/=4;
// result is \int ydex/2 alone the implicit direction.
return Ar;
}
inline double clist_contour:: EdgeWeight(cline_strip* pLine, double R)
{
cline_strip::iterator pos;
int count = 0,index;
double x,y;
for(pos = pLine->begin(); pos!=pLine->end(); pos++)
{
index = (*pos);
x = get_xi(index);
y = get_yi(index);
if (fabs(x) > R || fabs(y) > R)
count ++;
}
return (double)count/pLine->size();
}
/*
inline bool clist_contour::PrintContour(std::ostream& a_out)
{
std::streamsize old_prec = a_out.precision(3);
a_out << std::setprecision(10);
UINT i, index;
cline_strip* pStrip;
cline_strip::iterator pos2;
cline_strip_list::iterator pos;
for(i=0;i<get_number_of_planes();i++) {
for(pos = m_vStripLists[i].begin();pos!=m_vStripLists[i].end();pos++)
{
pStrip = (*pos);
for(pos2 = pStrip->begin();pos2!=pStrip->end();pos2++)
{
index = (*pos2);
a_out << get_xi(index)<<"\t"<<get_yi(index)<<"\n";
}
a_out<<"\n";
}
}
a_out.precision(old_prec);
return true;
}
*/
//G.Barrand : from .h to .cxx to avoid _ASSERT_ in .h
inline cline_strip_list* clist_contour::get_lines(unsigned int iPlane) {
/*_ASSERT_(iPlane>=0);*/
_ASSERT_(iPlane<get_number_of_planes(),"clist_contour::get_lines");
return &m_vStripLists[iPlane];
}
// Added by L.Garnier
inline bool clist_contour::SpecialCompactStripCase(double aXfront,double aXback,double aYfront,double aYback,double actualHeight)
{
// To solve the case of a list of strips
// which appeared to be open but should correspond to a closed
// contour.
// With the today generate() algorithm, it appears that we fall
// on this case when the begin and end points
// are on a horizontal or vertical line.
// (case where front()->x == back()->x or front()->y == back()->y).
// We try to detect in this method this situation and decide to close
// or not the line. To do that we check the heigth of intermediate
// points to see if there are on the same contour; if so we close
// the line (and return true), if not we do nothing (and return false).
// check if we could realy close it
float marge = 1; // *m_dDy or *m_dDx. 1 seems to be good and normal, but why
// not 2 in certain cases???
double distToNext =0;
// try to get the correct hight
if (get_plane(0)>= actualHeight) {
return false;
}
if (get_number_of_planes() >1){
distToNext = get_plane(1)-get_plane(0);
} else {
return false;
}
if ((aYback-aYfront) == 0) {
double temp;
double av;
double eg;
double ap;
if (aXfront==m_pLimits[0] && aXback == m_pLimits[1]) return false;
if (aXfront==m_pLimits[1] && aXback == m_pLimits[0]) return false;
if (aXfront > aXback ) {
temp = aXfront;
aXfront = aXback;
aXback = temp;
}
for(double check=aXfront+m_dDx;
check<aXback;
check+=m_dDx) {
av = ((*m_pFieldFcn)(check,aYback-marge*m_dDy,m_pFieldFcnData)-actualHeight);
eg = ((*m_pFieldFcn)(check,aYback,m_pFieldFcnData)-actualHeight);
ap = ((*m_pFieldFcn)(check,aYback+marge*m_dDy,m_pFieldFcnData)-actualHeight);
if ((av>distToNext) && (ap>distToNext) && (eg>distToNext)) {
return false;
} else if ((av<0) && (ap<0) && (eg<0)) {
return false;
}
}
return true;
} else if ((aXback-aXfront) == 0) {
double temp;
double av;
double eg;
double ap;
if (aYfront==m_pLimits[3] && aYback == m_pLimits[2]) return false;
if (aYfront==m_pLimits[2] && aYback == m_pLimits[3]) return false;
if (aYfront > aYback ) {
temp = aYfront;
aYfront = aYback;
aYback = temp;
}
for(double check=aYfront+m_dDy;
check<aYback;
check+=m_dDy) {
av = ((*m_pFieldFcn)(aXback-marge*m_dDx,check,m_pFieldFcnData)-actualHeight);
eg = ((*m_pFieldFcn)(aXback,check,m_pFieldFcnData)-actualHeight);
ap = ((*m_pFieldFcn)(aXback+marge*m_dDx,check,m_pFieldFcnData)-actualHeight);
if ((av>distToNext) && (ap>distToNext) && (eg>distToNext)) {
return false;
} else if ((av<0) && (ap<0) && (eg<0)) {
return false;
}
}
return true;
}
return false;
}
}
#endif
+51
View File
@@ -0,0 +1,51 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_cmemT
#define tools_cmemT
#include <cstdlib>
#ifdef TOOLS_MEM
#include "mem"
#endif
namespace tools {
template <class T>
inline void cmem_free(T*& a_p){
if(!a_p) return;
::free(a_p);
a_p = NULL;
#ifdef TOOLS_MEM
mem::decrement("cmem");
#endif
}
template <class T>
inline T* cmem_alloc(size_t a_num){
if(a_num<=0) return 0;
T* p = (T*)::malloc(a_num*sizeof(T));
if(!p) return 0;
#ifdef TOOLS_MEM
mem::increment("cmem");
#endif
return p;
}
template <class T>
inline T* cmem_alloc_copy(const T* a_from,size_t a_num){
if(a_num<=0) return 0;
T* p = (T*)::malloc(a_num*sizeof(T));
if(!p) return 0;
#ifdef TOOLS_MEM
mem::increment("cmem");
#endif
//::memcpy(p,a_from,a_num*sizeof(T));
for(size_t i=0;i<a_num;i++) p[i] = a_from[i];
return p;
}
}
#endif
+31
View File
@@ -0,0 +1,31 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_cmp
#define tools_cmp
#include <ostream>
namespace tools {
template <class T>
inline bool cmp(std::ostream& a_out,
const T& a_what,
const T& a_ref,const T& a_error = T()) {
if(a_what>a_ref) {
if((a_what-a_ref)>a_error) {
a_out << a_ref << " expected. Got " << a_what << std::endl;
return false;
}
} else {
if((a_ref-a_what)>a_error) {
a_out << a_ref << " expected. Got " << a_what << std::endl;
return false;
}
}
return true;
}
}
#endif
+166
View File
@@ -0,0 +1,166 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_colorf
#define tools_colorf
#include "lina/vec4f"
namespace tools {
class colorf : public vec4f {
typedef vec4f parent;
public: //for SWIG
typedef unsigned char uchar;
public:
TOOLS_SCLASS(tools::colorf) //for stype()
public:
colorf():parent(0,0,0,1){}
#ifdef TOOLS_MEM
colorf(float a_r,float a_g,float a_b,float a_a = 1,bool a_inc = true):parent(a_r,a_g,a_b,a_a,a_inc){}
#else
colorf(float a_r,float a_g,float a_b,float a_a = 1):parent(a_r,a_g,a_b,a_a){}
#endif
virtual ~colorf() {}
public:
colorf(const colorf& a_from):parent(a_from){}
colorf& operator=(const colorf& a_from){
parent::operator=(a_from);
return *this;
}
public:
float r() const {return v0();}
float g() const {return v1();}
float b() const {return v2();}
float a() const {return v3();}
void set_r(float a_v) {m_data[0] = a_v;}
void set_g(float a_v) {m_data[1] = a_v;}
void set_b(float a_v) {m_data[2] = a_v;}
void set_a(float a_v) {m_data[3] = a_v;}
uchar ruchar() const {return uchar(255.0f*m_data[0]);}
uchar guchar() const {return uchar(255.0f*m_data[1]);}
uchar buchar() const {return uchar(255.0f*m_data[2]);}
uchar auchar() const {return uchar(255.0f*m_data[3]);}
#ifdef tools_colorf
// deprecated, use the upper ones.
uchar rchar() const {return uchar(255.0f*m_data[0]);}
uchar gchar() const {return uchar(255.0f*m_data[1]);}
uchar bchar() const {return uchar(255.0f*m_data[2]);}
#endif
public:
//#define tools_stat_colorfs
#ifdef tools_stat_colorfs
//NOTE : the below are deprecated, use functions in inlib/colorfs.
// colorf::white() replaced by colorf_white()
// our forever 65 named colors taken long time ago from X11.
//NOTE : don't handle a static object because of mem balance.
//0-9
static colorf aquamarine() {return colorf(0.496101F,0.996109F,0.828138F);}
static colorf mediumaquamarine() {return colorf(0.398444F,0.800793F,0.664073F);}
static colorf black() {return colorf(0,0,0);}
static colorf blue() {return colorf(0,0,1);}
static colorf cadetblue() {return colorf(0.371099F,0.617197F,0.62501F);}
static colorf cornflowerblue() {return colorf(0.390631F,0.58204F,0.925795F);}
static colorf darkslateblue() {return colorf(0.281254F,0.238285F,0.542977F);}
static colorf lightblue() {return colorf(0.675792F,0.843763F,0.898451F);}
static colorf lightsteelblue() {return colorf(0.68751F,0.765637F,0.867201F);}
static colorf mediumblue() {return colorf(0,0,0.800793F);}
//10-19
static colorf mediumslateblue() {return colorf(0.480476F,0.406256F,0.929702F);}
static colorf midnightblue() {return colorf(0.0976577F,0.0976577F,0.437507F);}
static colorf navyblue() {return colorf(0,0,0.500008F);}
static colorf navy() {return colorf(0,0,0.500008F);}
static colorf skyblue() {return colorf(0.527352F,0.8047F,0.917983F);}
static colorf slateblue() {return colorf(0.414069F,0.351568F,0.800793F);}
static colorf steelblue() {return colorf(0.273442F,0.50782F,0.703136F);}
static colorf coral() {return colorf(0.996109F,0.496101F,0.312505F);}
static colorf cyan() {return colorf(0,1,1);}
static colorf firebrick() {return colorf(0.695323F,0.132815F,0.132815F);}
//20-29
static colorf brown() {return colorf(0.644541F,0.164065F,0.164065F);}
static colorf gold() {return colorf(0.996109F,0.839857F,0);}
static colorf goldenrod() {return colorf(0.851575F,0.644541F,0.125002F);}
static colorf green() {return colorf(0,1,0);}
static colorf darkgreen() {return colorf(0,0.390631F,0);}
static colorf darkolivegreen() {return colorf(0.332036F,0.417975F,0.183597F);}
static colorf forestgreen() {return colorf(0.132815F,0.542977F,0.132815F);}
static colorf limegreen() {return colorf(0.195315F,0.800793F,0.195315F);}
static colorf mediumseagreen() {return colorf(0.234379F,0.699229F,0.441413F);}
static colorf mediumspringgreen() {return colorf(0,0.976577F,0.601572F);}
//30-39
static colorf palegreen() {return colorf(0.593759F,0.980484F,0.593759F);}
static colorf seagreen() {return colorf(0.17969F,0.542977F,0.339849F);}
static colorf springgreen() {return colorf(0,0.996109F,0.496101F);}
static colorf yellowgreen() {return colorf(0.601572F,0.800793F,0.195315F);}
static colorf darkslategrey() {return colorf(0.183597F,0.308598F,0.308598F);}
static colorf dimgrey() {return colorf(0.410163F,0.410163F,0.410163F);}
static colorf lightgrey() {return colorf(0.824231F,0.824231F,0.824231F);}
static colorf grey() {return colorf(0.750011F,0.750011F,0.750011F);}
static colorf khaki() {return colorf(0.937514F,0.898451F,0.546883F);}
static colorf magenta() {return colorf(1,0,1);}
//40-49
static colorf maroon() {return colorf(0.68751F,0.187503F,0.375006F);}
static colorf orange() {return colorf(0.996109F,0.644541F,0);}
static colorf orchid() {return colorf(0.851575F,0.437507F,0.83595F);}
static colorf darkorchid() {return colorf(0.597665F,0.195315F,0.796887F);}
static colorf mediumorchid() {return colorf(0.726574F,0.332036F,0.824231F);}
static colorf pink() {return colorf(0.996109F,0.750011F,0.792981F);}
static colorf plum() {return colorf(0.863294F,0.62501F,0.863294F);}
static colorf red() {return colorf(1,0,0);}
static colorf indianred() {return colorf(0.800793F,0.35938F,0.35938F);}
static colorf mediumvioletred() {return colorf(0.777356F,0.0820325F,0.519539F);}
//50-59
static colorf orangered() {return colorf(0.996109F,0.269535F,0);}
static colorf violetred() {return colorf(0.812512F,0.125002F,0.562509F);}
static colorf salmon() {return colorf(0.976577F,0.500008F,0.445319F);}
static colorf sienna() {return colorf(0.62501F,0.320317F,0.175784F);}
static colorf tan() {return colorf(0.820325F,0.703136F,0.546883F);}
static colorf thistle() {return colorf(0.843763F,0.746105F,0.843763F);}
static colorf turquoise() {return colorf(0.250004F,0.875013F,0.812512F);}
static colorf darkturquoise() {return colorf(0,0.8047F,0.816419F);}
static colorf mediumturquoise() {return colorf(0.281254F,0.816419F,0.796887F);}
static colorf violet() {return colorf(0.929702F,0.50782F,0.929702F);}
//60-64
static colorf blueviolet() {return colorf(0.539071F,0.167971F,0.882826F);}
static colorf wheat() {return colorf(0.957046F,0.867201F,0.699229F);}
static colorf white() {return colorf(1,1,1);}
static colorf yellow() {return colorf(1,1,0);}
static colorf greenyellow() {return colorf(0.675792F,0.996109F,0.18359F);}
#endif
};
struct cmp_colorf {
bool operator()(const colorf& a_a,const colorf& a_b) const {
// x :
if(a_a.v0()<a_b.v0()) return true;
if(a_a.v0()>a_b.v0()) return false;
// y :
if(a_a.v1()<a_b.v1()) return true;
if(a_a.v1()>a_b.v1()) return false;
// z :
if(a_a.v2()<a_b.v2()) return true;
return false;
}
};
#if defined(TOOLS_MEM) && !defined(TOOLS_MEM_ATEXIT)
inline const colorf& colorf_default() {static const colorf s_v(0.8f,0.8f,0.8f,1,false);return s_v;}
#else
inline const colorf& colorf_default() {static const colorf s_v(0.8f,0.8f,0.8f,1);return s_v;}
#endif
}
#endif
+115
View File
@@ -0,0 +1,115 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_colorfs
#define tools_colorfs
#include "colors"
#include "colorf"
namespace tools {
#define TOOLS_COLORFS_STAT(a__name) \
inline const colorf& colorf_##a__name() {return get_color_##a__name<colorf>();}
//NOTE : false in the upper so that mem balance is ok at exit.
//0-9
TOOLS_COLORFS_STAT(aquamarine)
TOOLS_COLORFS_STAT(mediumaquamarine)
TOOLS_COLORFS_STAT(black)
TOOLS_COLORFS_STAT(blue)
TOOLS_COLORFS_STAT(cadetblue)
TOOLS_COLORFS_STAT(cornflowerblue)
TOOLS_COLORFS_STAT(darkslateblue)
TOOLS_COLORFS_STAT(lightblue)
TOOLS_COLORFS_STAT(lightsteelblue)
TOOLS_COLORFS_STAT(mediumblue)
//10-19
TOOLS_COLORFS_STAT(mediumslateblue)
TOOLS_COLORFS_STAT(midnightblue)
TOOLS_COLORFS_STAT(navyblue)
TOOLS_COLORFS_STAT(navy)
TOOLS_COLORFS_STAT(skyblue)
TOOLS_COLORFS_STAT(slateblue)
TOOLS_COLORFS_STAT(steelblue)
TOOLS_COLORFS_STAT(coral)
TOOLS_COLORFS_STAT(cyan)
TOOLS_COLORFS_STAT(firebrick)
//20-29
TOOLS_COLORFS_STAT(brown)
TOOLS_COLORFS_STAT(gold)
TOOLS_COLORFS_STAT(goldenrod)
TOOLS_COLORFS_STAT(green)
TOOLS_COLORFS_STAT(darkgreen)
TOOLS_COLORFS_STAT(darkolivegreen)
TOOLS_COLORFS_STAT(forestgreen)
TOOLS_COLORFS_STAT(limegreen)
TOOLS_COLORFS_STAT(mediumseagreen)
TOOLS_COLORFS_STAT(mediumspringgreen)
//30-39
TOOLS_COLORFS_STAT(palegreen)
TOOLS_COLORFS_STAT(seagreen)
TOOLS_COLORFS_STAT(springgreen)
TOOLS_COLORFS_STAT(yellowgreen)
TOOLS_COLORFS_STAT(darkslategrey)
TOOLS_COLORFS_STAT(dimgrey)
TOOLS_COLORFS_STAT(lightgrey)
TOOLS_COLORFS_STAT(grey)
TOOLS_COLORFS_STAT(khaki)
TOOLS_COLORFS_STAT(magenta)
//40-49
TOOLS_COLORFS_STAT(maroon)
TOOLS_COLORFS_STAT(orange)
TOOLS_COLORFS_STAT(orchid)
TOOLS_COLORFS_STAT(darkorchid)
TOOLS_COLORFS_STAT(mediumorchid)
TOOLS_COLORFS_STAT(pink)
TOOLS_COLORFS_STAT(plum)
TOOLS_COLORFS_STAT(red)
TOOLS_COLORFS_STAT(indianred)
TOOLS_COLORFS_STAT(mediumvioletred)
//50-59
TOOLS_COLORFS_STAT(orangered)
TOOLS_COLORFS_STAT(violetred)
TOOLS_COLORFS_STAT(salmon)
TOOLS_COLORFS_STAT(sienna)
TOOLS_COLORFS_STAT(tan)
TOOLS_COLORFS_STAT(thistle)
TOOLS_COLORFS_STAT(turquoise)
TOOLS_COLORFS_STAT(darkturquoise)
TOOLS_COLORFS_STAT(mediumturquoise)
TOOLS_COLORFS_STAT(violet)
//60-64
TOOLS_COLORFS_STAT(blueviolet)
TOOLS_COLORFS_STAT(wheat)
TOOLS_COLORFS_STAT(white)
TOOLS_COLORFS_STAT(yellow)
TOOLS_COLORFS_STAT(greenyellow)
////////////////////////////////////////////////////////
/// CERN-ROOT colors : /////////////////////////////////
////////////////////////////////////////////////////////
TOOLS_COLORFS_STAT(ROOT_Color8)
TOOLS_COLORFS_STAT(ROOT_Color9)
TOOLS_COLORFS_STAT(ROOT_grey12)
TOOLS_COLORFS_STAT(ROOT_grey13)
TOOLS_COLORFS_STAT(ROOT_grey14)
TOOLS_COLORFS_STAT(ROOT_grey15)
TOOLS_COLORFS_STAT(ROOT_grey16)
TOOLS_COLORFS_STAT(ROOT_grey17)
TOOLS_COLORFS_STAT(ROOT_grey18)
TOOLS_COLORFS_STAT(ROOT_grey19)
TOOLS_COLORFS_STAT(ROOT_Color50)
#undef TOOLS_COLORFS_STAT
}
#endif
+205
View File
@@ -0,0 +1,205 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_colors
#define tools_colors
// our forever 65 named colors taken long time ago from X11.
namespace tools {
#define TOOLS_COLORS_SET(a__name,a__r,a__g,a__b) \
template <class COLOR>\
inline void set_color_##a__name(COLOR& a_color) {a_color.set_value(a__r,a__g,a__b,1);}
//0-9
TOOLS_COLORS_SET(aquamarine,0.496101F,0.996109F,0.828138F)
TOOLS_COLORS_SET(mediumaquamarine,0.398444F,0.800793F,0.664073F)
TOOLS_COLORS_SET(black,0,0,0)
TOOLS_COLORS_SET(blue,0,0,1)
TOOLS_COLORS_SET(cadetblue,0.371099F,0.617197F,0.62501F)
TOOLS_COLORS_SET(cornflowerblue,0.390631F,0.58204F,0.925795F)
TOOLS_COLORS_SET(darkslateblue,0.281254F,0.238285F,0.542977F)
TOOLS_COLORS_SET(lightblue,0.675792F,0.843763F,0.898451F)
TOOLS_COLORS_SET(lightsteelblue,0.68751F,0.765637F,0.867201F)
TOOLS_COLORS_SET(mediumblue,0,0,0.800793F)
//10-19
TOOLS_COLORS_SET(mediumslateblue,0.480476F,0.406256F,0.929702F)
TOOLS_COLORS_SET(midnightblue,0.0976577F,0.0976577F,0.437507F)
TOOLS_COLORS_SET(navyblue,0,0,0.500008F)
TOOLS_COLORS_SET(navy,0,0,0.500008F)
TOOLS_COLORS_SET(skyblue,0.527352F,0.8047F,0.917983F)
TOOLS_COLORS_SET(slateblue,0.414069F,0.351568F,0.800793F)
TOOLS_COLORS_SET(steelblue,0.273442F,0.50782F,0.703136F)
TOOLS_COLORS_SET(coral,0.996109F,0.496101F,0.312505F)
TOOLS_COLORS_SET(cyan,0,1,1)
TOOLS_COLORS_SET(firebrick,0.695323F,0.132815F,0.132815F)
//20-29
TOOLS_COLORS_SET(brown,0.644541F,0.164065F,0.164065F)
TOOLS_COLORS_SET(gold,0.996109F,0.839857F,0)
TOOLS_COLORS_SET(goldenrod,0.851575F,0.644541F,0.125002F)
TOOLS_COLORS_SET(green,0,1,0)
TOOLS_COLORS_SET(darkgreen,0,0.390631F,0)
TOOLS_COLORS_SET(darkolivegreen,0.332036F,0.417975F,0.183597F)
TOOLS_COLORS_SET(forestgreen,0.132815F,0.542977F,0.132815F)
TOOLS_COLORS_SET(limegreen,0.195315F,0.800793F,0.195315F)
TOOLS_COLORS_SET(mediumseagreen,0.234379F,0.699229F,0.441413F)
TOOLS_COLORS_SET(mediumspringgreen,0,0.976577F,0.601572F)
//30-39
TOOLS_COLORS_SET(palegreen,0.593759F,0.980484F,0.593759F)
TOOLS_COLORS_SET(seagreen,0.17969F,0.542977F,0.339849F)
TOOLS_COLORS_SET(springgreen,0,0.996109F,0.496101F)
TOOLS_COLORS_SET(yellowgreen,0.601572F,0.800793F,0.195315F)
TOOLS_COLORS_SET(darkslategrey,0.183597F,0.308598F,0.308598F)
TOOLS_COLORS_SET(dimgrey,0.410163F,0.410163F,0.410163F)
TOOLS_COLORS_SET(lightgrey,0.824231F,0.824231F,0.824231F)
TOOLS_COLORS_SET(grey,0.750011F,0.750011F,0.750011F)
TOOLS_COLORS_SET(khaki,0.937514F,0.898451F,0.546883F)
TOOLS_COLORS_SET(magenta,1,0,1)
//40-49
TOOLS_COLORS_SET(maroon,0.68751F,0.187503F,0.375006F)
TOOLS_COLORS_SET(orange,0.996109F,0.644541F,0)
TOOLS_COLORS_SET(orchid,0.851575F,0.437507F,0.83595F)
TOOLS_COLORS_SET(darkorchid,0.597665F,0.195315F,0.796887F)
TOOLS_COLORS_SET(mediumorchid,0.726574F,0.332036F,0.824231F)
TOOLS_COLORS_SET(pink,0.996109F,0.750011F,0.792981F)
TOOLS_COLORS_SET(plum,0.863294F,0.62501F,0.863294F)
TOOLS_COLORS_SET(red,1,0,0)
TOOLS_COLORS_SET(indianred,0.800793F,0.35938F,0.35938F)
TOOLS_COLORS_SET(mediumvioletred,0.777356F,0.0820325F,0.519539F)
//50-59
TOOLS_COLORS_SET(orangered,0.996109F,0.269535F,0)
TOOLS_COLORS_SET(violetred,0.812512F,0.125002F,0.562509F)
TOOLS_COLORS_SET(salmon,0.976577F,0.500008F,0.445319F)
TOOLS_COLORS_SET(sienna,0.62501F,0.320317F,0.175784F)
TOOLS_COLORS_SET(tan,0.820325F,0.703136F,0.546883F)
TOOLS_COLORS_SET(thistle,0.843763F,0.746105F,0.843763F)
TOOLS_COLORS_SET(turquoise,0.250004F,0.875013F,0.812512F)
TOOLS_COLORS_SET(darkturquoise,0,0.8047F,0.816419F)
TOOLS_COLORS_SET(mediumturquoise,0.281254F,0.816419F,0.796887F)
TOOLS_COLORS_SET(violet,0.929702F,0.50782F,0.929702F)
//60-64
TOOLS_COLORS_SET(blueviolet,0.539071F,0.167971F,0.882826F)
TOOLS_COLORS_SET(wheat,0.957046F,0.867201F,0.699229F)
TOOLS_COLORS_SET(white,1,1,1)
TOOLS_COLORS_SET(yellow,1,1,0)
TOOLS_COLORS_SET(greenyellow,0.675792F,0.996109F,0.18359F)
#undef TOOLS_COLORS_SET
#if defined(TOOLS_MEM) && !defined(TOOLS_MEM_ATEXIT)
#define TOOLS_COLORS_STAT(a__name,a__r,a__g,a__b) \
template <class COLOR>\
inline const COLOR& get_color_##a__name() {static const COLOR s_v(a__r,a__g,a__b,1,false);return s_v;}
#else
#define TOOLS_COLORS_STAT(a__name,a__r,a__g,a__b) \
template <class COLOR>\
inline const COLOR& get_color_##a__name() {static const COLOR s_v(a__r,a__g,a__b,1);return s_v;}
#endif
//0-9
TOOLS_COLORS_STAT(aquamarine,0.496101F,0.996109F,0.828138F)
TOOLS_COLORS_STAT(mediumaquamarine,0.398444F,0.800793F,0.664073F)
TOOLS_COLORS_STAT(black,0,0,0)
TOOLS_COLORS_STAT(blue,0,0,1)
TOOLS_COLORS_STAT(cadetblue,0.371099F,0.617197F,0.62501F)
TOOLS_COLORS_STAT(cornflowerblue,0.390631F,0.58204F,0.925795F)
TOOLS_COLORS_STAT(darkslateblue,0.281254F,0.238285F,0.542977F)
TOOLS_COLORS_STAT(lightblue,0.675792F,0.843763F,0.898451F)
TOOLS_COLORS_STAT(lightsteelblue,0.68751F,0.765637F,0.867201F)
TOOLS_COLORS_STAT(mediumblue,0,0,0.800793F)
//10-19
TOOLS_COLORS_STAT(mediumslateblue,0.480476F,0.406256F,0.929702F)
TOOLS_COLORS_STAT(midnightblue,0.0976577F,0.0976577F,0.437507F)
TOOLS_COLORS_STAT(navyblue,0,0,0.500008F)
TOOLS_COLORS_STAT(navy,0,0,0.500008F)
TOOLS_COLORS_STAT(skyblue,0.527352F,0.8047F,0.917983F)
TOOLS_COLORS_STAT(slateblue,0.414069F,0.351568F,0.800793F)
TOOLS_COLORS_STAT(steelblue,0.273442F,0.50782F,0.703136F)
TOOLS_COLORS_STAT(coral,0.996109F,0.496101F,0.312505F)
TOOLS_COLORS_STAT(cyan,0,1,1)
TOOLS_COLORS_STAT(firebrick,0.695323F,0.132815F,0.132815F)
//20-29
TOOLS_COLORS_STAT(brown,0.644541F,0.164065F,0.164065F)
TOOLS_COLORS_STAT(gold,0.996109F,0.839857F,0)
TOOLS_COLORS_STAT(goldenrod,0.851575F,0.644541F,0.125002F)
TOOLS_COLORS_STAT(green,0,1,0)
TOOLS_COLORS_STAT(darkgreen,0,0.390631F,0)
TOOLS_COLORS_STAT(darkolivegreen,0.332036F,0.417975F,0.183597F)
TOOLS_COLORS_STAT(forestgreen,0.132815F,0.542977F,0.132815F)
TOOLS_COLORS_STAT(limegreen,0.195315F,0.800793F,0.195315F)
TOOLS_COLORS_STAT(mediumseagreen,0.234379F,0.699229F,0.441413F)
TOOLS_COLORS_STAT(mediumspringgreen,0,0.976577F,0.601572F)
//30-39
TOOLS_COLORS_STAT(palegreen,0.593759F,0.980484F,0.593759F)
TOOLS_COLORS_STAT(seagreen,0.17969F,0.542977F,0.339849F)
TOOLS_COLORS_STAT(springgreen,0,0.996109F,0.496101F)
TOOLS_COLORS_STAT(yellowgreen,0.601572F,0.800793F,0.195315F)
TOOLS_COLORS_STAT(darkslategrey,0.183597F,0.308598F,0.308598F)
TOOLS_COLORS_STAT(dimgrey,0.410163F,0.410163F,0.410163F)
TOOLS_COLORS_STAT(lightgrey,0.824231F,0.824231F,0.824231F)
TOOLS_COLORS_STAT(grey,0.750011F,0.750011F,0.750011F)
TOOLS_COLORS_STAT(khaki,0.937514F,0.898451F,0.546883F)
TOOLS_COLORS_STAT(magenta,1,0,1)
//40-49
TOOLS_COLORS_STAT(maroon,0.68751F,0.187503F,0.375006F)
TOOLS_COLORS_STAT(orange,0.996109F,0.644541F,0)
TOOLS_COLORS_STAT(orchid,0.851575F,0.437507F,0.83595F)
TOOLS_COLORS_STAT(darkorchid,0.597665F,0.195315F,0.796887F)
TOOLS_COLORS_STAT(mediumorchid,0.726574F,0.332036F,0.824231F)
TOOLS_COLORS_STAT(pink,0.996109F,0.750011F,0.792981F)
TOOLS_COLORS_STAT(plum,0.863294F,0.62501F,0.863294F)
TOOLS_COLORS_STAT(red,1,0,0)
TOOLS_COLORS_STAT(indianred,0.800793F,0.35938F,0.35938F)
TOOLS_COLORS_STAT(mediumvioletred,0.777356F,0.0820325F,0.519539F)
//50-59
TOOLS_COLORS_STAT(orangered,0.996109F,0.269535F,0)
TOOLS_COLORS_STAT(violetred,0.812512F,0.125002F,0.562509F)
TOOLS_COLORS_STAT(salmon,0.976577F,0.500008F,0.445319F)
TOOLS_COLORS_STAT(sienna,0.62501F,0.320317F,0.175784F)
TOOLS_COLORS_STAT(tan,0.820325F,0.703136F,0.546883F)
TOOLS_COLORS_STAT(thistle,0.843763F,0.746105F,0.843763F)
TOOLS_COLORS_STAT(turquoise,0.250004F,0.875013F,0.812512F)
TOOLS_COLORS_STAT(darkturquoise,0,0.8047F,0.816419F)
TOOLS_COLORS_STAT(mediumturquoise,0.281254F,0.816419F,0.796887F)
TOOLS_COLORS_STAT(violet,0.929702F,0.50782F,0.929702F)
//60-64
TOOLS_COLORS_STAT(blueviolet,0.539071F,0.167971F,0.882826F)
TOOLS_COLORS_STAT(wheat,0.957046F,0.867201F,0.699229F)
TOOLS_COLORS_STAT(white,1,1,1)
TOOLS_COLORS_STAT(yellow,1,1,0)
TOOLS_COLORS_STAT(greenyellow,0.675792F,0.996109F,0.18359F)
////////////////////////////////////////////////////////
/// CERN-ROOT colors : /////////////////////////////////
////////////////////////////////////////////////////////
TOOLS_COLORS_STAT(ROOT_Color8, 0.35F,0.83F,0.33F)
TOOLS_COLORS_STAT(ROOT_Color9, 0.35F,0.33F,0.85F)
TOOLS_COLORS_STAT(ROOT_grey12, 0.3F,0.3F,0.3F)
TOOLS_COLORS_STAT(ROOT_grey13, 0.4F,0.4F,0.4F)
TOOLS_COLORS_STAT(ROOT_grey14, 0.5F,0.5F,0.5F)
TOOLS_COLORS_STAT(ROOT_grey15, 0.6F,0.6F,0.6F)
TOOLS_COLORS_STAT(ROOT_grey16, 0.7F,0.7F,0.7F)
TOOLS_COLORS_STAT(ROOT_grey17, 0.8F,0.8F,0.8F)
TOOLS_COLORS_STAT(ROOT_grey18, 0.9F,0.9F,0.9F)
TOOLS_COLORS_STAT(ROOT_grey19 , 0.95F,0.95F,0.95F)
TOOLS_COLORS_STAT(ROOT_Color50, 0.83F,0.35F,0.33F)
#undef TOOLS_COLORS_STAT
}
#endif
+565
View File
@@ -0,0 +1,565 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_columns
#define tools_columns
#include "vmanip"
#include "forit"
#include "sout"
#include "schar"
#ifdef TOOLS_MEM
#include "mem"
#include "S_STRING"
#endif
namespace tools {
namespace columns {
class tree {
#ifdef TOOLS_MEM
TOOLS_SCLASS(tools::columns::tree)
#endif
public:
tree(tree* a_parent,const std::string& a_dcl):m_parent(a_parent),m_dcl(a_dcl){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
if(a_parent) a_parent->m_sub.push_back(this);
}
virtual ~tree(){
clear();
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
protected:
tree(const tree&) {}
tree& operator=(const tree&) {return *this;}
public:
void clear() {
m_dcl.clear();
safe_reverse_clear(m_sub);
}
void dump_tree(std::ostream& a_out,const std::string& a_margin) {
if(m_dcl.size()) a_out << a_margin << m_dcl << std::endl;
{tools_vforit(tree*,m_sub,it) {
(*it)->dump_tree(a_out,a_margin+" ");
}}
}
public:
tree* m_parent;
std::string m_dcl;
std::vector<tree*> m_sub;
};
}}
#include "strip"
namespace tools {
namespace columns {
class parser {
public:
parser():m_top(0,""){}
virtual ~parser(){m_top.clear();}
protected:
parser(const parser&):m_top(0,"") {}
parser& operator=(const parser&){return *this;}
public:
bool parse(const std::string& a_s){
m_top.clear();
tree* prev = &m_top;
{std::string s;
for(std::string::const_iterator it=a_s.begin();;++it) {
if(it==a_s.end()) {
if(s.size()) {
new tree(prev,s);
s.clear();
}
break;
} else {
const char& c = *it;
if(c==',') {
if(s.size()) {
new tree(prev,s);
s.clear();
}
} else if(c=='{') {
tree* _tree = new tree(prev,s);
s.clear();
prev = _tree;
} else if(c=='}') {
if(s.size()) {
new tree(prev,s);
s.clear();
}
prev = prev->m_parent;
if(!prev) return false; //should not happen.
} else {
s += c;
}
}
}}
return true;
}
void dump(std::ostream& a_out) {m_top.dump_tree(a_out,"");}
protected:
tree m_top;
};
}}
#include "words"
#include "value"
namespace tools {
namespace columns {
inline void delete_columns(std::vector<value>& a_vars) {
tools_vforit(value,a_vars,it) {
if((*it).type()==value::VOID_STAR) {
std::vector<value>* vars =
(std::vector<value>*)(*it).get_void_star();
delete_columns(*vars);
delete vars;
}
}
a_vars.clear();
}
inline void copy_columns(const std::vector<value>& a_from,std::vector<value>& a_to) {
std::vector<value>::const_iterator it;
for(it=a_from.begin();it!=a_from.end();++it) {
if((*it).type()==value::VOID_STAR) {
std::vector<value>* vars = new std::vector<value>();
value v((void*)vars);
v.set_label((*it).label());
a_to.push_back(v);
std::vector<value>* p =
(std::vector<value>*)(*it).get_void_star();
copy_columns(*p,*vars);
} else {
a_to.push_back(*it);
}
}
}
inline void dump_columns(std::ostream& a_out,const std::vector<value>& a_vars,const std::string& a_margin = "") {
std::vector<value>::const_iterator it;
for(it=a_vars.begin();it!=a_vars.end();++it) {
if((*it).type()==value::VOID_STAR) {
a_out << a_margin
<< "ITuple : " << (*it).label() << " : begin "
<< std::endl;
std::vector<value>* vars = (std::vector<value>*)(*it).get_void_star();
dump_columns(a_out,*vars,a_margin+" ");
//a_out << a_margin
// << "ITuple : " << (*it).label() << " : end "
// << std::endl;
} else {
std::string stype;
(*it).s_type(stype);
std::string sval;
(*it).tos(sval);
a_out << a_margin
<< stype << " : "
<< (*it).label() << " : "
<< sval
<< std::endl;
}
}
}
class finder : public columns::parser {
typedef columns::parser parent;
public:
finder(std::ostream& a_out,const std::string& a_script)
:m_out(a_out)
,m_script(a_script)
//,fSuccess(false)
,m_cur_type(value::NONE)
{}
virtual ~finder() {clear();}
protected:
finder(const finder& a_from):parent(a_from),m_out(a_from.m_out){}
finder& operator=(const finder&){return *this;}
public:
//void setScript(const std::string& a_string) { m_script = a_string;}
bool find_variables() {
clear();
if(m_script.empty()) return false; //keep old version logic.
if(!parse(m_script)) return false;
//dump(m_out);
//analyse m_top :
if(!analyse(m_top,m_stack)) {clear();return false;}
return true;
}
void result(std::vector<value>& a_vars) const {
a_vars.clear();
copy_columns(m_stack,a_vars);
}
void clear() {
m_top.clear();
delete_columns(m_stack);
m_cur_type = value::NONE;
}
/*
const std::string& script() const { return m_script;}
//bool isSuccess() const { return fSuccess;}
std::ostream& out() const {return m_out;}
*/
protected:
bool analyse(columns::tree& a_tree,std::vector<value>& a_stack) {
if(a_tree.m_dcl.empty()) { //top
//std::cout << "debug : dcl empty" << std::endl;
tools_vforit(columns::tree*,a_tree.m_sub,it) {
if(!analyse(*(*it),a_stack)) return false;
}
} else {
//std::cout << "debug : dcl not empty" << std::endl;
if(is_spaces(a_tree.m_dcl)) return true;
value* v = analyse_dcl(a_tree.m_dcl);
if(!v) return false;
//std::cout << "debug : dcl label " << v->label() << std::endl;
if(a_tree.m_sub.size()) {
if(v->type()!=value::VOID_STAR) {
m_out << "tools::columns::finder::analyse :"
<< " Expect a VOID_STAR."
<< std::endl;
delete v;
return false;
}
m_cur_type = value::NONE;
std::vector<value>* stk = new std::vector<value>();
tools_vforit(columns::tree*,a_tree.m_sub,it) {
if(!analyse(*(*it),*stk)) {
delete v;
return false;
}
}
v->set((void*)stk);
} else {
m_cur_type = v->type();
}
a_stack.push_back(*v);
delete v;
}
return true;
}
value* analyse_dcl(const std::string& a_s) {
std::vector<std::string> ws;
words(a_s,"=",false,ws);
if(ws.size()==2) { //<type> <name>=<value>
std::vector<std::string> swords;
words(ws[0]," ",false,swords);
if(swords.size()==2) {
strip(swords[0]);
strip(swords[1]);
if(swords[0]=="ITuple") {
//create a value::VOID_STAR :
value* v = new value((void*)0);
v->set_label(swords[1]);
return v;
} else {
value::e_type type;
if(!s2type(swords[0],type)){
m_out << "tools::columns::finder::analyse_dcl :"
<< " s2type failed for " << sout(swords[0]) << "."
<< std::endl;
return 0;
}
strip(ws[1]);
value* v = new_value(type,ws[1]);
if(!v) {
m_out << "tools::columns::finder::analyse_dcl :"
<< " syntax error in " << sout(a_s) << "."
<< " new_value() failed."
<< std::endl;
return 0;
}
v->set_label(swords[1]);
return v;
}
} else if(swords.size()==1) {
if(m_cur_type==value::NONE) {
m_out << "tools::columns::finder::analyse_dcl :"
<< " (1) current type is NONE."
<< std::endl;
return 0;
}
strip(ws[1]);
value* v = new_value(m_cur_type,ws[1]);
if(!v) {
m_out << "tools::columns::finder::analyse_dcl :"
<< " syntax error in " << sout(a_s) << "."
<< " Bad value " << sout(ws[1]) << "."
<< std::endl;
return 0;
}
v->set_label(swords[0]);
return v;
} else {
m_out << "tools::columns::finder::analyse_dcl :"
<< " syntax error in " << sout(a_s)
<< ". Case 1."
<< std::endl;
return 0;
}
} else if(ws.size()==1) {
//<type> <name>
//<type> <name>={
std::vector<std::string> swords;
words(ws[0]," ",false,swords);
if(swords.size()==2) {
strip(swords[0]);
strip(swords[1]);
if(swords[0]=="ITuple") {
//create a value::VOID_STAR :
value* v = new value((void*)0);
v->set_label(swords[1]);
return v;
} else {
value::e_type type;
if(!s2type(swords[0],type)){
m_out << "tools::columns::finder::analyse_dcl :"
<< " s2type failed for " << sout(swords[0]) << "."
<< std::endl;
return 0;
}
value* v = new_value(type,"");
if(!v) {
m_out << "tools::columns::finder::analyse_dcl :"
<< " (2) syntax error in " << sout(ws[0]) << "."
<< " Unknown type " << sout(swords[0]) << "."
<< std::endl;
return 0;
}
v->set_label(swords[1]);
return v;
}
} else if(swords.size()==1) {
if(m_cur_type==value::NONE) {
m_out << "tools::columns::finder::analyse_dcl :"
<< " (1) current type is NONE."
<< std::endl;
return 0;
}
value* v = new value();
v->set_type(m_cur_type);
v->set_label(swords[0]);
return v;
} else {
m_out << "tools::columns::finder::analyse_dcl :"
<< " syntax error in " << sout(a_s)
<< ". Case 2."
<< std::endl;
return 0;
}
} else {
m_out << "tools::columns::finder::analyse_dcl :"
<< " syntax error in " << sout(a_s)
<< ". Case 3."
<< std::endl;
return 0;
}
}
protected:
static bool s2type(const std::string& a_s,value::e_type& a_type){
if(a_s=="float") {
a_type = value::FLOAT;
} else if(a_s=="double") {
a_type = value::DOUBLE;
//} else if(a_s=="char") {
// a_type = value::CHAR;
} else if(a_s=="short") {
a_type = value::SHORT;
} else if(a_s=="int") {
a_type = value::INT;
} else if(a_s=="long") {
a_type = value::INT64;
} else if((a_s=="bool")||(a_s=="boolean")) {
a_type = value::BOOL;
} else if((a_s=="string")||(a_s=="java.lang.String")){
a_type = value::STRING;
//} else if(a_s=="byte") {
// a_type = value::UNSIGNED_CHAR;
} else if(a_s=="float[]") {
a_type = value::ARRAY_FLOAT;
} else if(a_s=="double[]") {
a_type = value::ARRAY_DOUBLE;
//} else if(a_s=="char[]") {
// a_type = value::ARRAY_CHAR;
//} else if(a_s=="byte[]") {
// a_type = value::ARRAY_UNSIGNED_CHAR;
} else if(a_s=="short[]") {
a_type = value::ARRAY_SHORT;
} else if(a_s=="int[]") {
a_type = value::ARRAY_INT;
} else if(a_s=="long[]") {
a_type = value::ARRAY_INT64;
} else if((a_s=="bool[]")||(a_s=="boolean[]")) {
a_type = value::ARRAY_BOOL;
} else if((a_s=="string[]")||(a_s=="java.lang.String[]")){
a_type = value::ARRAY_STRING;
// not AIDA :
//} else if(a_s=="uchar") {
// a_type = value::UNSIGNED_CHAR;
} else if(a_s=="ushort") {
a_type = value::UNSIGNED_SHORT;
} else if(a_s=="uint") {
a_type = value::UNSIGNED_INT;
} else if(a_s=="ulong") {
a_type = value::UNSIGNED_INT64;
} else {
return false;
}
return true;
}
static value* new_value(value::e_type a_type,const std::string& a_v) {
if(a_type==value::FLOAT) {
float v = 0;
if(a_v.size()) {if(!to<float>(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::DOUBLE) {
double v = 0;
if(a_v.size()) {if(!to<double>(a_v,v)) return 0;}
return new value(v);
//} else if(a_type==value::CHAR) {
// char v = 0;
// if(a_v.size()) {if(!to<char>(a_v,v)) return 0;}
// return new value(v);
} else if(a_type==value::SHORT) {
short v = 0;
if(a_v.size()) {if(!to<short>(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::INT) {
int v = 0;
if(a_v.size()) {if(!to<int>(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::INT64) {
int64 v = 0;
if(a_v.size()) {if(!to<int64>(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::BOOL) {
bool v = false;
if(a_v.size()) {if(!to(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::STRING) {
if( (a_v.size()>=2) && (a_v[0]=='"') && (a_v[a_v.size()-1]=='"') ){
return new value(a_v.substr(1,a_v.size()-2));
} else {
return new value(a_v);
}
//} else if(a_type==value::UNSIGNED_CHAR) {
// unsigned short v = 0;
// if(a_v.size()) {if(!to<unsigned short>(a_v,v)) return 0;}
// return new value((unsigned char)v);
} else if(a_type==value::UNSIGNED_SHORT) {
unsigned short v = 0;
if(a_v.size()) {if(!to<unsigned short>(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::UNSIGNED_INT) {
unsigned int v = 0;
if(a_v.size()) {if(!to<unsigned int>(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::UNSIGNED_INT64) {
uint64 v = 0;
if(a_v.size()) {if(!to<uint64>(a_v,v)) return 0;}
return new value(v);
} else if(a_type==value::ARRAY_FLOAT) {
if(a_v.size()) return 0;
value* v = new value();
v->set_type(value::ARRAY_FLOAT);
return v;
} else if(a_type==value::ARRAY_DOUBLE) {
if(a_v.size()) return 0;
value* v = new value();
v->set_type(value::ARRAY_DOUBLE);
return v;
//} else if(a_type==value::ARRAY_UNSIGNED_CHAR) {
// if(a_v.size()) return 0;
// value* v = new value();
// v->set_type(value::ARRAY_UNSIGNED_CHAR);
// return v;
//} else if(a_type==value::ARRAY_CHAR) {
// if(a_v.size()) return 0;
// value* v = new value();
// v->set_type(value::ARRAY_CHAR);
// return v;
} else if(a_type==value::ARRAY_SHORT) {
if(a_v.size()) return 0;
value* v = new value();
v->set_type(value::ARRAY_SHORT);
return v;
} else if(a_type==value::ARRAY_INT) {
if(a_v.size()) return 0;
value* v = new value();
v->set_type(value::ARRAY_INT);
return v;
} else if(a_type==value::ARRAY_INT64) {
if(a_v.size()) return 0;
value* v = new value();
v->set_type(value::ARRAY_INT64);
return v;
} else if(a_type==value::ARRAY_BOOL) {
if(a_v.size()) return 0;
value* v = new value();
v->set_type(value::ARRAY_BOOL);
return v;
} else if(a_type==value::ARRAY_STRING) {
if(a_v.size()) return 0;
value* v = new value();
v->set_type(value::ARRAY_STRING);
return v;
} else {
return 0;
}
}
public:
std::ostream& m_out;
std::string m_script;
std::vector<value> m_stack;
value::e_type m_cur_type;
//bool fSuccess;
};
}}
#endif
+352
View File
@@ -0,0 +1,352 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_cstr
#define tools_cstr
#include <cstring> // strcpy
#include <cstdlib> // malloc,free
#ifdef TOOLS_MEM
#include "mem"
//#define TOOLS_CSTR_DEBUG_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
#include <cstdio>
#endif
#endif
namespace tools {
// NOTE : have str_ to avoid clashes with various strxxx cpp macro
// that may come from C or system headers.
#ifdef TOOLS_MEM
inline const std::string& s_cstr() {
static const std::string s_v("tools::cstr");
return s_v;
}
#endif
inline char* str_dup(const char* a_cstr
#ifdef TOOLS_MEM
,bool a_inc = true
#endif
) {
#ifdef TOOLS_MEM
if(a_inc) {
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_dup \"%s\"\n",a_cstr);
#endif
mem::increment(s_cstr().c_str());
}
#endif
return ::strcpy((char*)::malloc(::strlen(a_cstr)+1),a_cstr);
}
inline char* str_from_buffer(const char* a_buffer,size_t a_len
#ifdef TOOLS_MEM
,bool a_inc = true
#endif
) {
#ifdef TOOLS_MEM
if(a_inc) {
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_from_buffer.\n");
#endif
mem::increment(s_cstr().c_str());
}
#endif
char* s = (char*)::malloc(a_len+1);
if(s==NULL) return NULL;
s = ::strncpy(s,a_buffer,a_len);
s[a_len] = 0;
return s;
}
inline void str_del(char*& a_cstr) {
if(a_cstr==NULL) return;
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_del \"%s\"\n",a_cstr);
#endif
mem::decrement(s_cstr().c_str());
#endif
::free(a_cstr);
a_cstr = NULL;
}
inline char* str_new(size_t a_l = 0,char a_char = ' ') {
char* s = (char*)::malloc((a_l+1)*sizeof(char));
if(s==NULL) return NULL;
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_new : len %lu\n",a_l);
#endif
mem::increment(s_cstr().c_str());
#endif
char* pos = s;
for(size_t c=0;c<a_l;c++,pos++) *pos = a_char;
*(s+a_l) = 0;
return s;
}
inline bool str_cat(char*& a_1,const char a_c) {
size_t l1 = ::strlen(a_1);
char* s = (char*)::malloc(l1+1+1);
if(!s) return false;
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_cat \"%s\", char %d\n",a_1,a_c);
#endif
mem::increment(s_cstr().c_str());
#endif
::memcpy(s,a_1,l1);
::memcpy(s+l1,&a_c,1);
*(s+l1+1) = 0;
::free(a_1);
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_cat : dec\n");
#endif
mem::decrement(s_cstr().c_str());
#endif
a_1 = s;
return true;
}
inline bool str_cat(char*& a_1,const char* a_2) {
size_t l1 = ::strlen(a_1);
size_t l2 = ::strlen(a_2);
char* s = (char*)::malloc(l1+l2+1);
if(!s) return false;
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_cat \"%s\" \"%s\"\n",a_1,a_2);
#endif
mem::increment(s_cstr().c_str());
#endif
::memcpy(s,a_1,l1);
::memcpy(s+l1,a_2,l2);
*(s+l1+l2) = 0;
::free(a_1);
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_cat : dec\n");
#endif
mem::decrement(s_cstr().c_str());
#endif
a_1 = s;
return true;
}
inline void str_rev(char* a_s) {
size_t l = ::strlen(a_s);
size_t hl = l/2;
char* beg = a_s;
char* end = a_s+l-1;
for(size_t i=0;i<hl;i++) {
char c = *end;
*end = *beg;
*beg = c;
beg++;end--;
}
}
inline char* str_sub(const char* a_s,
unsigned int a_pos,
unsigned int a_sz = 0) { //0 = take up end.
size_t l = ::strlen(a_s);
if(a_pos>=l) return 0; //throw std::out_of_range
size_t ls;
if(a_sz) {
ls = (a_sz<(l-a_pos)?a_sz:(l-a_pos)); //min(a_sz,l-a_pos)
} else {
ls = l-a_pos;
}
char* s = (char*)::malloc(ls+1);
if(!s) return 0;
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_sub \"%s\"\n",a_s);
#endif
mem::increment(s_cstr().c_str());
#endif
//abcdefgh l=8
//0123456789
::memcpy(s,a_s+a_pos,ls);
*(s+ls) = 0;
return s;
}
inline char* str_rep(const char* a_s,unsigned int a_pos,unsigned int a_sz,const char* a_new) {
//not tested yet.
size_t las = ::strlen(a_s);
if(a_pos>=las) return 0; //throw std::out_of_range
if(a_pos+a_sz>las) return 0;
size_t lan = ::strlen(a_new);
unsigned int num = a_sz<lan?a_sz:(unsigned int)lan;
//abcdefghij : l = 10
//0123456789
// p
size_t le = las-(a_pos+a_sz);
size_t ls = a_pos+num+le;
char* s = (char*)::malloc(ls+1);
if(!s) return 0;
#ifdef TOOLS_MEM
#ifdef TOOLS_CSTR_DEBUG_MEM
::printf("debug : str_rep \"%s\"\n",a_s);
#endif
mem::increment(s_cstr().c_str());
#endif
::memcpy(s,a_s,a_pos);
::memcpy(s+a_pos,a_new,num);
if(le) ::memcpy(s+a_pos+num,a_s+a_pos+a_sz,le);
*(s+ls) = 0;
return s;
}
inline void str_skip(char*& a_cstr,char a_c) {
while(true) {
if(*a_cstr!=a_c) break;
a_cstr++;
}
}
}
#include <clocale>
namespace tools {
inline char* beg_LC_NUMERIC() {
char* _sl = ::setlocale(LC_NUMERIC,0);
char* old = _sl?str_dup(_sl):0;
::setlocale(LC_NUMERIC,"C");
return old;
}
inline void end_LC_NUMERIC(char*& a_s) {
if(a_s) {
::setlocale(LC_NUMERIC,a_s);
str_del(a_s);
}
}
inline bool str_2d(const char* a_s,double& a_v) {
char* olcn = beg_LC_NUMERIC();
char* end;
a_v = ::strtod(a_s,&end);
if(end==a_s) {
a_v = 0;
end_LC_NUMERIC(olcn);
return false;
}
end_LC_NUMERIC(olcn);
return true;
}
/*
inline bool str_2d(const char* a_s,double& a_v) {
char* _sl = ::setlocale(LC_NUMERIC,0);
char* old = _sl?str_dup(_sl):0;
::setlocale(LC_NUMERIC,"C");
char* end;
a_v = ::strtod(a_s,&end);
bool status = true;
if(end==a_s) {
status = false;
a_v = 0;
}
if(old) {
::setlocale(LC_NUMERIC,old);
str_del(old);
}
return status;
}
*/
inline size_t str_lcpy(char *dst, const char *src, size_t siz) {
// Copy src to string dst of size siz. At most siz-1 characters
// will be copied. Always NUL terminates (unless siz == 0).
// Returns strlen(src); if retval >= siz, truncation occurred.
// code taken from CERN-ROOT/core/clib to compile exlib/tests/h2root.cpp.
// strlcpy, strlcat are in string.h on BSD based systems.
// Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>.
/*register*/ char* d = dst;
/*register*/ const char* s = src;
/*register*/ size_t n = siz;
// Copy as many bytes as will fit :
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0) break;
} while (--n != 0);
}
// Not enough room in dst, add NUL and traverse rest of src :
if (n == 0) {
if (siz != 0) *d = '\0'; // NUL-terminate dst.
while (*s++);
}
return(s - src - 1); // count does not include NUL.
}
inline size_t str_lcat(char *dst, const char *src, size_t siz) {
// Appends src to string dst of size siz (unlike strncat, siz is the
// full size of dst, not space left). At most siz-1 characters
// will be copied. Always NUL terminates (unless siz <= strlen(dst)).
// Returns strlen(src) + MIN(siz, strlen(initial dst)).
// If retval >= siz, truncation occurred.
// code taken from CERN-ROOT/core/clib to compile exlib/tests/h2root.cpp.
// strlcpy, strlcat are in string.h on BSD based systems.
// Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>.
/*register*/ char* d = dst;
/*register*/ const char* s = src;
/*register*/ size_t n = siz;
size_t dlen;
// Find the end of dst and adjust bytes left but don't go past end :
while (n-- != 0 && *d != '\0') d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0) return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); // count does not include NUL.
}
template <class VECTOR>
inline bool str_2ds(char* a_s,const char* a_sep,VECTOR& a_v) {
a_v.clear();
const char* tok;
double d;
for (tok = ::strtok(a_s,a_sep);tok && *tok;tok = ::strtok(NULL,a_sep)) {
if(!str_2d(tok,d)) {a_v.clear();return false;}
a_v.push_back(d);
}
return true;
}
}
#endif
+63
View File
@@ -0,0 +1,63 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_curve
#define tools_curve
#include "scast"
#include "S_STRING"
#ifdef TOOLS_MEM
#include "mem"
#endif
#include "lina/vec3f"
#include "lina/mat4f"
namespace tools {
class curve {
public:
TOOLS_SCLASS(tools::curve)
virtual void* cast(const std::string& a_class) const {
if(void* p = cmp_cast<curve>(this,a_class)) {return p;}
return 0;
}
public:
virtual void copy(curve*&) const = 0;
public:
virtual bool pos_tan_nor(float a_s,
vec3f& a_pos,
vec3f& a_tan,
vec3f& a_nor) const = 0;
public:
curve(){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
m_model.set_identity();
}
virtual ~curve(){
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
curve(const curve& a_from):m_model(a_from.m_model){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
curve& operator=(const curve& a_from){
m_model = a_from.m_model;
return *this;
}
public:
void set_model_matrix(const mat4f& a_m) {m_model = a_m;}
protected:
mat4f m_model;
};
}
#endif
+137
View File
@@ -0,0 +1,137 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_data_axis
#define tools_data_axis
#include "mathf"
namespace tools {
class data_axis {
public:
data_axis():m_min_value(0),m_max_value(0),m_is_log(false){}
virtual ~data_axis(){}
public:
data_axis(const data_axis& a_from)
:m_min_value(a_from.m_min_value)
,m_max_value(a_from.m_max_value)
,m_is_log(a_from.m_is_log)
{}
data_axis& operator=(const data_axis& a_from){
m_min_value = a_from.m_min_value;
m_max_value = a_from.m_max_value;
m_is_log = a_from.m_is_log;
return *this;
}
public:
bool set_is_log(bool a_v) {if(m_is_log==a_v) return false;m_is_log = a_v;return true;}
bool set_min_value(float a_v) {if(m_min_value==a_v) return false;m_min_value = a_v;return true;}
bool set_max_value(float a_v) {if(m_max_value==a_v) return false;m_max_value = a_v;return true;}
#ifdef tools_data_axis //g4tools backcomp :
bool is_log(bool a_v) {if(m_is_log==a_v) return false;m_is_log = a_v;return true;}
bool min_value(float a_v) {if(m_min_value==a_v) return false;m_min_value = a_v;return true;}
bool max_value(float a_v) {if(m_max_value==a_v) return false;m_max_value = a_v;return true;}
#endif
float min_value() const {return m_min_value;}
float max_value() const {return m_max_value;}
bool is_log() const {return m_is_log;}
void adjust() { //from hippodraw.
int _axis = 0;
float step;
float mylow, myhigh;
int N_NICE = 4;
static const float nice[/*N_NICE*/4] = { 1.0,2.0,2.5,5.0 };
if (m_min_value > m_max_value) {
float low = m_min_value;
m_min_value = m_max_value;
m_max_value = low;
} else if (m_min_value == m_max_value) {
float value = m_min_value;
m_min_value = value - 1;
m_max_value = value + 1;
return;
}
//if (m_steps <= 0) { //if letting the if and m_steps as a field, twice this function do not give the same result.
_axis = 1;
unsigned int m_steps = 10;
//}
// Round the "bin width" to a nice number.
// If this is being done for an axis (ie m_steps was 0 , then
// we don't have to go > *m_max_value.
//
float w = (m_max_value - m_min_value)/((float)m_steps);
float mag = ffloor(flog10(w));
int i = 0;
do {
step = nice[i] * fpow(10.0,mag);
mylow = ffloor(m_min_value/step) * step;
//myhigh = _axis==1 ? fceil(m_max_value/step) * step : mylow + step * m_steps;
myhigh = fceil(m_max_value/step) * step; //quiet Coverity.
i++;
if (i>=N_NICE) {i = 0;mag++;}
}
while ( ( (_axis==1) && (myhigh < m_max_value)) ||
( (_axis==0) && (myhigh <= m_max_value)) );
float range = myhigh - mylow;
// we now have decided on a range. Try to move
// m_min_value/m_max_value a little
// to end up on a nice number.
//
// first check if either end is near 0.0
if ( !m_is_log && (m_min_value >= 0.0) &&
(( (_axis==1) && (range>=m_max_value) ) ||
( (_axis==0) && (range>m_max_value) )) ) {
m_min_value = 0.0;
m_max_value = range;
return;
}
if ( (( (_axis==1) && (m_max_value<=0.0) ) ||
( (_axis==0) && (m_max_value<0.0) ))
&& (-range<=m_min_value)) {
m_max_value = 0.0;
m_min_value = -range;
return;
}
// try to round *m_min_value.
// correction
if( m_is_log && (m_min_value<=0.0)) m_min_value = 1.0;
i = N_NICE-1;
mag = myhigh != 0.0 ? fceil(flog10(ffabs(myhigh))) : fceil(flog10(ffabs(mylow)));
do {
step = nice[i] * fpow(10.0,mag);
mylow = ffloor(m_min_value/step) * step;
myhigh = mylow + range;
i--;
if (i<0) {
i = N_NICE-1;
mag--;
}
}
while (( m_is_log && (mylow <= 0.0) ) ||
( (_axis==1) && (myhigh < m_max_value) ) ||
( (_axis==0) && (myhigh <= m_max_value) ) );
m_min_value = mylow;
m_max_value = myhigh;
}
protected:
float m_min_value;
float m_max_value;
//int m_steps;
bool m_is_log;
};
}
#endif
+97
View File
@@ -0,0 +1,97 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_eqT
#define tools_eqT
namespace tools {
template <class NUMBER,class PREC>
inline bool numbers_are_equal(const NUMBER& a_left,const NUMBER& a_right,const PREC& a_prec,PREC(*a_fabs)(const NUMBER&)) {
NUMBER diff = a_left - a_right;
if(a_fabs(diff)>=a_prec) return false;
return true;
}
template <class NUMBER,class PREC>
inline bool is_zero(const NUMBER& a_left,const PREC& a_prec,PREC(*a_fabs)(const NUMBER&)) {
if(a_fabs(a_left)>=a_prec) return false;
return true;
}
template <class VEC,class PREC>
inline bool vectors_are_equal(const VEC& a_1,const VEC& a_2,const PREC& a_prec,PREC(*a_fabs)(const PREC&)) {
if(a_1.size()!=a_2.size()) return false;
typedef typename VEC::size_type sz_t;
sz_t sz = a_1.size();
//bool status = true;
for(sz_t index=0;index<sz;index++) {
if(!numbers_are_equal(a_1[index],a_2[index],a_prec,a_fabs))
//{ ::printf("debug : vectors_are_equals : %lu : %g %g\n",index,a_1[index],a_2[index]);
return false;
//status = false;
//}
}
return true;
//return status;
}
template <class VECVEC,class PREC>
inline bool vecvecs_are_equal(const VECVEC& a_1,const VECVEC& a_2,const PREC& a_prec,PREC(*a_fabs)(const PREC&)) {
if(a_1.size()!=a_2.size()) return false;
typedef typename VECVEC::size_type sz_t;
sz_t sz = a_1.size();
for(sz_t index=0;index<sz;index++) {
if(!vectors_are_equal(a_1[index],a_2[index],a_prec,a_fabs)) return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// PREC(*a_fabs)(PREC) : /////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// for histo equals functions.
template <class NUMBER,class PREC>
inline bool numbers_are_equal(const NUMBER& a_left,const NUMBER& a_right,const PREC& a_prec,PREC(*a_fabs)(NUMBER)) {
NUMBER diff = a_left - a_right;
if(a_fabs(diff)>=a_prec) return false;
return true;
}
template <class VEC,class PREC>
inline bool vectors_are_equal(const VEC& a_1,const VEC& a_2,const PREC& a_prec,PREC(*a_fabs)(PREC)) {
if(a_1.size()!=a_2.size()) return false;
typedef typename VEC::size_type sz_t;
sz_t sz = a_1.size();
//bool status = true;
for(sz_t index=0;index<sz;index++) {
if(!numbers_are_equal(a_1[index],a_2[index],a_prec,a_fabs))
//{ ::printf("debug : vectors_are_equals : %lu : %g %g\n",index,a_1[index],a_2[index]);
return false;
//status = false;
//}
}
return true;
//return status;
}
template <class VECVEC,class PREC>
inline bool vecvecs_are_equal(const VECVEC& a_1,const VECVEC& a_2,const PREC& a_prec,PREC(*a_fabs)(PREC)) {
if(a_1.size()!=a_2.size()) return false;
typedef typename VECVEC::size_type sz_t;
sz_t sz = a_1.size();
for(sz_t index=0;index<sz;index++) {
if(!vectors_are_equal(a_1[index],a_2[index],a_prec,a_fabs)) return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif
+640
View File
@@ -0,0 +1,640 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_file
#define tools_file
#include "gzip"
#include "forit"
#include "words" //is_hippo
#include "path" //suffix
#include "S_STRING"
#include <cstdlib>
#include <cstring>
#ifdef TOOLS_MEM
#include "mem"
#endif
namespace tools {
namespace file {
inline bool exists(const std::string& a_string) {
FILE* file = ::fopen(a_string.c_str(),"rb");
if(!file) return false;
::fclose(file);
return true;
}
inline bool write(const std::string& a_file,const std::string& a_string) {
// a_string could contain \n separated lines.
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) return false;
if(::fprintf(file,"%s",a_string.c_str())<0) {
::fclose(file);
return false;
}
::fclose(file);
return true;
}
inline bool write(const std::string& a_file,const std::vector<std::string>& a_text){
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) return false;
tools_vforcit(std::string,a_text,it) {
if(::fprintf(file,"%s\n",(*it).c_str())<0) {
::fclose(file);
return false;
}
}
::fclose(file);
return true;
}
inline bool make_empty(const std::string& a_file) {
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) return false;
::fclose(file);
return true;
}
inline bool read_buff(FILE* a_file,char* a_buff,unsigned int a_lbuf,size_t& a_length) {
a_length = ::fread(a_buff,1,a_lbuf,a_file);
return true;
}
inline bool read_cstring(FILE* a_file,char* a_buff,unsigned int a_lbuf,size_t& a_length) {
if(::fgets(a_buff,a_lbuf,a_file)==NULL) {
a_length = 0;
return false; //EOF
}
size_t l = ::strlen(a_buff);
// On Windows, editors when saving binary files,
// put \r\n at place of \n ; we then look for \r\n.
if( (l>=2) && (a_buff[l-2]=='\r') && (a_buff[l-1]=='\n') ) {
a_buff[l-2] = '\0';
l -= 2;
} else if( (l>=1) && (a_buff[l-1]=='\n') ) {
a_buff[l-1] = '\0';
l -= 1;
}
a_length = l;
return true;
}
inline bool read(FILE* a_FILE,std::vector<std::string>& a_text){
a_text.clear();
unsigned int BUFSIZE = 65536;
char* buffer = new char[BUFSIZE+1];
if(!buffer) return false;
while(true) {
size_t l;
if(!read_cstring(a_FILE,buffer,BUFSIZE,l)) break; // EOF.
a_text.push_back(buffer);
}
delete [] buffer;
return true;
}
inline bool read(const std::string& a_file,std::vector<std::string>& a_text){
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) {a_text.clear();return false;}
bool status = read(file,a_text);
::fclose(file);
return status;
}
inline bool read_num(const std::string& a_file,std::vector<std::string>::size_type a_num,std::vector<std::string>& a_text,const std::string& a_cmt = ""){
a_text.clear();
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) return false;
unsigned int BUFSIZE = 65536;
char* buffer = new char[BUFSIZE+1];
if(!buffer) {::fclose(file);return false;}
while(true) {
size_t l;
if(!read_cstring(file,buffer,BUFSIZE,l)) break; // EOF.
if(a_cmt.size()&&(!strncmp(a_cmt.c_str(),buffer,a_cmt.size()))) continue;
if(a_text.size()<a_num) {
a_text.push_back(buffer);
} else {
break;
}
}
delete [] buffer;
::fclose(file);
return true;
}
inline bool read_bytes(const std::string& a_file,char*& a_buffer,long& a_length){
// Returned buffer should be deleted with delete [].
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) {
a_buffer = 0;
a_length = 0L;
return false;
}
// Get file size :
::fseek(file,0L,SEEK_END);
long filesize = ::ftell(file);
if(!filesize) {
::fclose(file);
a_buffer = new char[1];
#ifdef TOOLS_MEM
mem::increment(s_new().c_str());
#endif
a_length = 0L;
return true; //empty file.
}
// Add one byte to be able to add \n if file contain lines.
a_buffer = new char[filesize+1];
if(!a_buffer) {
::fclose(file);
a_buffer = 0;
a_length = 0L;
return false;
}
#ifdef TOOLS_MEM
mem::increment(s_new().c_str());
#endif
::rewind(file);
size_t nitem = ::fread(a_buffer,(size_t)filesize,(size_t)1,file);
if(nitem!=1){
::fclose(file);
delete [] a_buffer;
#ifdef TOOLS_MEM
mem::decrement(s_new().c_str());
#endif
a_buffer = 0;
a_length = 0L;
return false;
}
::fclose(file);
a_buffer[filesize] = 0;
a_length = filesize;
return true;
}
inline bool write_bytes(const std::string& a_file,const char* a_buffer,size_t a_length){
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) return false;
if(!a_length) {
::fclose(file);
return true;
}
size_t nitem = ::fwrite((char*)a_buffer,a_length,(size_t)1,file);
::fclose(file);
return (nitem!=1?false:true);
}
inline bool num_csv_doubles(const std::string& a_string,char& a_sep,unsigned int& a_number){
if(a_string.empty()) {a_sep=0;a_number=0;return true;} //it is ok.
//guess sep :
char sep = 0;
{const char* buffer = a_string.c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
const char* mx = buffer+a_string.size();
char* end;
{double d = ::strtod(pos,&end);(void)d;}
//::printf("debug : d first %g\n",d);
if(end==pos) {a_sep=0;a_number=0;return false;} //not starting with a number.
if(end==mx) {a_sep=0;a_number=1;return true;} //is ok, one number only.
sep = *end;}
//::printf("debug : %d\n",sep);
unsigned int number = 0;
const char* buffer = a_string.c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
const char* mx = buffer+a_string.size();
while(true) {
char* end;
{double d = ::strtod(pos,&end);(void)d;}
if(end==pos) {
if(end>=mx) break;
a_sep = sep;
a_number = number;
return false; //since a number expected.
}
//::printf("debug : d %g\n",d);
number++;
if(*end!=sep) {
if(end>=mx) break;
a_sep = sep;
a_number = number;
return false; //since a sep is expected.
}
pos = end+1;
if(pos>mx) break;
}
a_sep = sep;
a_number = number;
return true;
}
// NOTE : take care of the open in exlib/app/tntnet/main_cpp which can't work by using suffix.
inline bool is_hippo(const std::string& a_file,bool& a_is){
//if((suffix(a_file)=="hiptxt")||(suffix(a_file)=="tnt")) {
// a_is = true;
// return true;
//}
// An hippo file as :
// one line for title.
// one line with n labels separated by \t
// data lines with n numbers separated by a char sep (not necessary \t) (at least one data line expected).
std::vector<std::string> txt;
if(!file::read_num(a_file,3,txt)) {a_is=false;return false;}
if(txt.size()<3) {a_is=false;return true;}
char csep;
unsigned int number;
if(!num_csv_doubles(txt[2],csep,number)) {a_is=false;return true;}
std::vector<std::string> ws;
words(txt[1],"\t",false,ws);
if(ws.size()!=number) {a_is=false;return true;}
bool all_doubles = true;
tools_vforcit(std::string,ws,it) {
const char* pos = (*it).c_str();
char* end;
double d = ::strtod(pos,&end);(void)d;
if(end==pos) {all_doubles=false;break;}
}
a_is = all_doubles?false:true; //all_double=false then we assume the second line is labels of columns.
return true;
}
// NOTE : the below is_csv() does not take into account a column with strings.
inline bool is_csv(const std::vector<std::string>& a_txt,bool& a_is){
//a_sep = 0;
a_is = false;
if(a_txt.empty()) return true;
//guess sep from first data line :
char sep = 0;
{const char* buffer = a_txt[0].c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
char* end;
{double d = ::strtod(pos,&end);(void)d;}
//::printf("debug : d first %g\n",d);
if(end==pos) return true; //not starting with a number.
//end==mx is ok, one column only.
sep = *end;}
//::printf("debug : %d\n",sep);
unsigned int first_coln = 0;
tools_vforcit(std::string,a_txt,it) {
const char* buffer = (*it).c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
const char* mx = buffer+(*it).size();
unsigned int coln = 0;
while(true) {
char* end;
{double d = ::strtod(pos,&end);(void)d;}
if(end==pos) break;
//::printf("debug : d %g\n",d);
if(*end!=sep) return true;
coln++;
pos = end+1;
if(pos>mx) break;
}
//::printf("debug : coln %d\n",coln);
if(it==a_txt.begin()) {
first_coln = coln;
} else {
if(coln!=first_coln) return true;
}
}
//a_sep = sep;
a_is = true;
return true;
}
inline bool is_csv(const std::string& a_file,bool& a_is){
// look at suffix. Some file can't be guessed.
if(suffix(a_file)=="csv") {a_is = true;return true;}
//try to guess :
std::vector<std::string> txt;
if(!file::read_num(a_file,3,txt,"#")) {a_is=false;return false;}
return is_csv(txt,a_is);
}
inline bool is_lua(const std::string& a_file,bool& a_is){
// look at suffix. Some file can't be guessed.
if(suffix(a_file)=="lua") {a_is = true;return true;}
//try to guess ?
a_is = false;
return true;
}
inline bool is_py(const std::string& a_file,bool& a_is){
// look at suffix. Some file can't be guessed.
if(suffix(a_file)=="py") {a_is = true;return true;}
//try to guess ?
a_is = false;
return true;
}
inline bool is_kumac(const std::string& a_file,bool& a_is){
// look at suffix. Some file can't be guessed.
if(suffix(a_file)=="kumac") {a_is = true;return true;}
//try to guess ?
a_is = false;
return true;
}
inline bool is_insh(const std::string& a_file,bool& a_is){
if(suffix(a_file)=="insh") {a_is = true;return true;}
unsigned char head[6];
{unsigned int num = 6;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=6) {a_is = false;return true;}}
if(head[0]!='#') {a_is = false;return true;}
if(head[1]!='!') {a_is = false;return true;}
if(head[2]!='i') {a_is = false;return true;}
if(head[3]!='n') {a_is = false;return true;}
if(head[4]!='s') {a_is = false;return true;}
if(head[5]!='h') {a_is = false;return true;}
a_is = true;
return true;
}
}}
#include "fileis"
namespace tools {
namespace file {
inline bool mime_type(const std::string& a_file,std::string& a_mime){
////////////////
// binaries :
////////////////
{bool is;
if(is_jpeg(a_file,is)&&is) {
a_mime = "image/jpeg";
return true;
}}
{bool is;
if(is_png(a_file,is)&&is) {
a_mime = "image/png";
return true;
}}
{bool is;
if(is_ico(a_file,is)&&is) {
a_mime = "image/vnd.microsoft.icon";
return true;
}}
{bool is;
if(is_fits(a_file,is)&&is) {
a_mime = "image/fits";
return true;
}}
{bool is;
if(is_gzip(a_file,is)&&is) {
a_mime = "application/gzip";
return true;
}}
{bool is;
if(is_zip(a_file,is)&&is) {
a_mime = "application/zip";
return true;
}}
{bool is;
if(is_root(a_file,is)&&is) {
a_mime = "application/octet-stream";
return true;
}}
////////////////
// text :
////////////////
{bool is;
if(is_aida(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_exsg(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_scenarios(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_slides(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_gdml(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_ps(a_file,is)&&is) {
a_mime = "application/postscript";
return true;
}}
{bool is;
if(is_fog(a_file,is)&&is) {
a_mime = "text/plain";
return true;
}}
{bool is;
if(is_csv(a_file,is)&&is) {
a_mime = "text/csv";
return true;
}}
{bool is;
if(is_hippo(a_file,is)&&is) {
a_mime = "text/plain";
return true;
}}
{bool is;
if(is_dot(a_file,is)&&is) {
a_mime = "text/plain";
return true;
}}
{bool is;
if(is_iv(a_file,is)&&is) {
a_mime = "application/octet-stream";
return true;
}}
a_mime = "application/octet-stream";
return false;
}
/*
inline bool copy(const std::string& a_from,const std::string& a_to){
if(a_to==a_from) return true; //done
std::vector<std::string> text;
if(!file::read(a_from,text)) return false;
return file::write(a_to,text);
}
*/
inline bool found(const std::string& a_file,const std::string& a_what,std::vector<std::string>& a_found){
a_found.clear();
std::vector<std::string> text;
if(!file::read(a_file,text)) return false;
tools_vforcit(std::string,text,it) {
if((*it).find(a_what)!=std::string::npos) {
a_found.push_back(*it);
}
}
return true;
}
inline bool std_remove(const std::string& a_file) {
if(a_file.empty()) return true;
return (::remove(a_file.c_str()) ==0 ? true : false);
}
inline bool std_remove(std::vector<std::string>& a_files) {
bool status = true;
tools_vforit(std::string,a_files,it) {
if(!std_remove(*it)) status = false;
}
a_files.clear();
return status;
}
inline bool std_rename(const std::string& a_from,const std::string& a_to) {
//NOTE : a_from must not be a path !
// Darwin is ok with a path but not Linux !
// For example :
// ::rename("/tmp/tmp01","x");
// return -1 on Linux.
// To do the upper then someone must use move.
// But there is no move in the standard lib C !
return (::rename(a_from.c_str(),a_to.c_str()) == 0 ? true : false);
}
inline bool copy_bytes(const std::string& a_from,const std::string& a_to) {
if(a_to==a_from) return true;
char* buffer;
long length;
if(!read_bytes(a_from,buffer,length)) return false;
bool status = write_bytes(a_to,buffer,(size_t)length);
delete [] buffer;
#ifdef TOOLS_MEM
mem::decrement(s_new().c_str());
#endif
return status;
}
/*
class holder {
public:
TOOLS_SCLASS(tools::file::holder)
public:
holder(const std::string& a_path):m_path(a_path){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
virtual ~holder() {
std_remove(m_path);
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
holder(const holder& a_from):m_path(a_from.m_path){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
holder& operator=(const holder& a_from){
m_path = a_from.m_path;
return *this;
}
protected:
std::string m_path;
};
*/
}}
#include "file_reader"
namespace tools {
class FILE_reader : public virtual file::reader {
public: //file_reader
virtual bool open(const std::string& a_file) {
if(m_FILE) return false;
m_FILE = ::fopen(a_file.c_str(),"rb");
if(!m_FILE) return false;
return true;
}
virtual void close() {
if(!m_FILE) return;
::fclose(m_FILE);
m_FILE = 0;
}
virtual bool is_open() const {return m_FILE?true:false;}
virtual bool read(char* a_buff,unsigned int a_lbuf,size_t& a_length) {
a_length = ::fread(a_buff,1,a_lbuf,m_FILE);
return true;
}
virtual bool get_line(char* a_buff,unsigned int a_lbuf) {
return ::fgets(a_buff,a_lbuf,m_FILE)==NULL?false:true;
}
virtual bool eof() const {
#if defined(_MSC_VER) && _MSC_VER <= 1400
return feof(m_FILE)?true:false;
#else
return ::feof(m_FILE)?true:false;
#endif
}
public:
FILE_reader():m_FILE(0){}
virtual ~FILE_reader() {if(m_FILE) ::fclose(m_FILE);}
protected:
FILE_reader(const FILE_reader& a_from)
:file::reader(a_from)
,m_FILE(0)
{}
FILE_reader& operator=(const FILE_reader&){return *this;}
protected:
FILE* m_FILE;
};
}
#include "file_format" //backcomp
#include "fsize" //backcomp
#endif
+239
View File
@@ -0,0 +1,239 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_file_format
#define tools_file_format
#include "S_STRING"
#include <string>
#include <vector>
namespace tools {
namespace file {
TOOLS_GLOBAL_STRING(format_guessed)
TOOLS_GLOBAL_STRING(format_hdf5)
TOOLS_GLOBAL_STRING(format_fits)
TOOLS_GLOBAL_STRING(format_fog)
TOOLS_GLOBAL_STRING(format_dot)
TOOLS_GLOBAL_STRING(format_dcm)
TOOLS_GLOBAL_STRING(format_iv)
TOOLS_GLOBAL_STRING(format_wrl)
TOOLS_GLOBAL_STRING(format_jpeg)
TOOLS_GLOBAL_STRING(format_png)
TOOLS_GLOBAL_STRING(format_root)
TOOLS_GLOBAL_STRING(format_dst) //pmx,agora.
TOOLS_GLOBAL_STRING(format_csv)
TOOLS_GLOBAL_STRING(format_hippo)
TOOLS_GLOBAL_STRING(format_scenarios)
TOOLS_GLOBAL_STRING(format_slides)
TOOLS_GLOBAL_STRING(format_zvid)
TOOLS_GLOBAL_STRING(format_exsg)
TOOLS_GLOBAL_STRING(format_gdml)
TOOLS_GLOBAL_STRING(format_mac)
TOOLS_GLOBAL_STRING(format_cmnd)
TOOLS_GLOBAL_STRING(format_aida)
TOOLS_GLOBAL_STRING(format_bsg)
TOOLS_GLOBAL_STRING(format_jive)
TOOLS_GLOBAL_STRING(format_heprep)
TOOLS_GLOBAL_STRING(format_zheprep)
TOOLS_GLOBAL_STRING(format_lua)
TOOLS_GLOBAL_STRING(format_py)
TOOLS_GLOBAL_STRING(format_kumac)
TOOLS_GLOBAL_STRING(format_insh)
TOOLS_GLOBAL_STRING(format_shp)
TOOLS_GLOBAL_STRING(format_simbad)
#define TOOLS_GLOBAL_EXT(a_name)\
inline const std::string& s_ext_##a_name() {\
static const std::string s_v("."+std::string(#a_name));\
return s_v;\
}
TOOLS_GLOBAL_EXT(hdf5)
TOOLS_GLOBAL_EXT(fits)
TOOLS_GLOBAL_EXT(fog)
TOOLS_GLOBAL_EXT(dot)
TOOLS_GLOBAL_EXT(dcm)
TOOLS_GLOBAL_EXT(iv)
TOOLS_GLOBAL_EXT(hiv)
TOOLS_GLOBAL_EXT(wrl)
TOOLS_GLOBAL_EXT(jpeg)
TOOLS_GLOBAL_EXT(jpg)
TOOLS_GLOBAL_EXT(png)
TOOLS_GLOBAL_EXT(root)
TOOLS_GLOBAL_EXT(dst)
TOOLS_GLOBAL_EXT(csv)
TOOLS_GLOBAL_EXT(hiptxt)
TOOLS_GLOBAL_EXT(tnt)
TOOLS_GLOBAL_EXT(scenarios)
TOOLS_GLOBAL_EXT(slides)
TOOLS_GLOBAL_EXT(zvid)
TOOLS_GLOBAL_EXT(exsg)
TOOLS_GLOBAL_EXT(gdml)
TOOLS_GLOBAL_EXT(mac)
TOOLS_GLOBAL_EXT(cmnd)
TOOLS_GLOBAL_EXT(aida)
TOOLS_GLOBAL_EXT(bsg)
TOOLS_GLOBAL_EXT(jive)
TOOLS_GLOBAL_EXT(heprep)
TOOLS_GLOBAL_EXT(zheprep)
TOOLS_GLOBAL_EXT(lua)
TOOLS_GLOBAL_EXT(py)
TOOLS_GLOBAL_EXT(kumac)
TOOLS_GLOBAL_EXT(insh)
TOOLS_GLOBAL_EXT(shp)
TOOLS_GLOBAL_EXT(simbad)
#undef TOOLS_GLOBAL_EXT
inline void formats(std::vector<std::string>& a_v) {
a_v.clear();
a_v.push_back(s_format_guessed());
a_v.push_back(s_format_hdf5());
a_v.push_back(s_format_fits());
a_v.push_back(s_format_fog());
a_v.push_back(s_format_dot());
a_v.push_back(s_format_dcm());
a_v.push_back(s_format_iv());
a_v.push_back(s_format_wrl());
a_v.push_back(s_format_jpeg());
a_v.push_back(s_format_png());
a_v.push_back(s_format_root());
a_v.push_back(s_format_dst());
a_v.push_back(s_format_csv());
a_v.push_back(s_format_hippo());
a_v.push_back(s_format_scenarios());
a_v.push_back(s_format_slides());
a_v.push_back(s_format_zvid());
a_v.push_back(s_format_exsg());
a_v.push_back(s_format_bsg());
a_v.push_back(s_format_gdml());
a_v.push_back(s_format_mac());
a_v.push_back(s_format_cmnd());
a_v.push_back(s_format_aida());
a_v.push_back(s_format_jive());
a_v.push_back(s_format_heprep());
a_v.push_back(s_format_zheprep());
a_v.push_back(s_format_lua());
a_v.push_back(s_format_py());
a_v.push_back(s_format_kumac());
a_v.push_back(s_format_insh());
a_v.push_back(s_format_shp());
a_v.push_back(s_format_simbad());
}
inline std::string ext_fmt(const std::string& a_ext) {
if(a_ext==s_ext_fits()) return s_format_fits();
if(a_ext==s_ext_aida()) return s_format_aida();
if(a_ext==s_ext_root()) return s_format_root();
if(a_ext==s_ext_dst()) return s_format_dst();
if(a_ext==s_ext_csv()) return s_format_csv();
if(a_ext==s_ext_tnt()) return s_format_hippo();
if(a_ext==s_ext_hiptxt()) return s_format_hippo();
if(a_ext==s_ext_hdf5()) return s_format_hdf5();
if(a_ext==s_ext_jpeg()) return s_format_jpeg();
if(a_ext==s_ext_jpg()) return s_format_jpeg();
if(a_ext==s_ext_png()) return s_format_png();
if(a_ext==s_ext_fog()) return s_format_fog();
if(a_ext==s_ext_dot()) return s_format_dot();
if(a_ext==s_ext_dcm()) return s_format_dcm();
if(a_ext==s_ext_iv()) return s_format_iv();
if(a_ext==s_ext_hiv()) return s_format_iv();
if(a_ext==s_ext_wrl()) return s_format_wrl();
if(a_ext==s_ext_exsg()) return s_format_exsg();
if(a_ext==s_ext_bsg()) return s_format_bsg();
if(a_ext==s_ext_scenarios()) return s_format_scenarios();
if(a_ext==s_ext_slides()) return s_format_slides();
if(a_ext==s_ext_zvid()) return s_format_zvid();
if(a_ext==s_ext_gdml()) return s_format_gdml();
if(a_ext==s_ext_mac()) return s_format_mac();
if(a_ext==s_ext_cmnd()) return s_format_cmnd();
if(a_ext==s_ext_jive()) return s_format_jive();
if(a_ext==s_ext_heprep()) return s_format_heprep();
if(a_ext==s_ext_zheprep()) return s_format_zheprep();
if(a_ext==s_ext_lua()) return s_format_lua();
if(a_ext==s_ext_py()) return s_format_py();
if(a_ext==s_ext_kumac()) return s_format_kumac();
if(a_ext==s_ext_insh()) return s_format_insh();
if(a_ext==s_ext_shp()) return s_format_shp();
if(a_ext==s_ext_simbad()) return s_format_simbad();
return s_format_guessed();
}
inline bool need_placement(const std::string& a_format) {
if(a_format==s_format_guessed()) return true;
//if(a_format==s_format_hdf5()) return true;
//if(a_format==s_format_fits()) return true;
//if(a_format==s_format_fog()) return true; //load in static_sg.
//if(a_format==s_format_dot()) return true;
//if(a_format==s_format_dcm()) return true;
//if(a_format==s_format_iv()) return true; //load in static_sg.
//if(a_format==s_format_wrl()) return true; //load in static_sg.
//if(a_format==s_format_jpeg()) return true;
//if(a_format==s_format_png()) return true;
//if(a_format==s_format_root()) return true;
//if(a_format==s_format_dst()) return true;
//if(a_format==s_format_csv()) return true;
//if(a_format==s_format_hippo()) return true;
//if(a_format==s_format_scenarios()) return true;
//if(a_format==s_format_slides()) return true;
//if(a_format==s_format_zvid()) return true;
if(a_format==s_format_exsg()) return true;
//if(a_format==s_format_gdml()) return true; //load in static_sg.
//if(a_format==s_format_mac()) return true;
//if(a_format==s_format_cmnd()) return true;
//if(a_format==s_format_aida()) return true;
if(a_format==s_format_bsg()) return true;
//if(a_format==s_format_jive()) return true; //load in dynamic_sg.
//if(a_format==s_format_heprep()) return true; //load in static_sg.
//if(a_format==s_format_zheprep()) return true; //load in static_sg.
//if(a_format==s_format_lua()) return true;
//if(a_format==s_format_py()) return true;
//if(a_format==s_format_kumac()) return true;
//if(a_format==s_format_insh()) return true;
//if(a_format==s_format_shp()) return true; //load in static_sg.
//if(a_format==s_format_simbad()) return true; //load in arg sep.
return false;
}
// related files : sg/write_paper, paper_format.
inline bool is_paper_format(const std::string& a_format) {
if(a_format=="gl2ps_eps") return true;
if(a_format=="gl2ps_ps") return true;
if(a_format=="gl2ps_pdf") return true;
if(a_format=="gl2ps_svg") return true;
if(a_format=="gl2ps_tex") return true;
if(a_format=="gl2ps_pgf") return true;
if(a_format=="inzb_ps") return true;
if(a_format=="inzb_jpeg") return true;
if(a_format=="inzb_png") return true;
return false;
}
inline bool is_inzb_format(const std::string& a_format) {
if(a_format=="inzb_ps") return true;
if(a_format=="inzb_jpeg") return true;
if(a_format=="inzb_png") return true;
return false;
}
inline bool paper_format_extension(const std::string& a_format,std::string& a_ext) {
if(a_format=="gl2ps_eps") {a_ext = "eps";return true;}
if(a_format=="gl2ps_ps") {a_ext = "ps";return true;}
if(a_format=="gl2ps_pdf") {a_ext = "pdf";return true;}
if(a_format=="gl2ps_svg") {a_ext = "svg";return true;}
if(a_format=="gl2ps_tex") {a_ext = "tex";return true;}
if(a_format=="gl2ps_pgf") {a_ext = "pgf";return true;}
if(a_format=="inzb_ps") {a_ext = "ps";return true;}
if(a_format=="inzb_jpeg") {a_ext = "jpeg";return true;}
if(a_format=="inzb_png") {a_ext = "png";return true;}
a_ext.clear();
return false;
}
}}
#endif
+74
View File
@@ -0,0 +1,74 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_file_name
#define tools_file_name
#include "srep"
#include <cstdlib>
namespace tools {
// OpenPAW, Panoramix :
inline bool rep_env(std::string& a_string) {
char spec_char = '\n';
std::string::size_type dollar;
while((dollar=a_string.find('$'))!=std::string::npos){
std::string::size_type slash = a_string.find('/',dollar+1);
std::string::size_type back_slash = a_string.find('\\',dollar+1);
std::string::size_type pos = std::string::npos;
if(slash!=std::string::npos) {
if(back_slash!=std::string::npos) {
pos = slash<back_slash?slash:back_slash;
} else {
pos = slash;
}
} else {
if(back_slash!=std::string::npos) {
pos = back_slash;
} else {
pos = std::string::npos;
}
}
std::string env;
if(pos==std::string::npos) {
env = a_string.substr(dollar+1,a_string.length()-(dollar+1));
} else {
// abc$xxx/ef
// 0 3 7 9
env = a_string.substr(dollar+1,pos-(dollar+1));
}
char* val = ::getenv(env.c_str());
if(!val) {
// We may have $ in a_string not attached to an env variable.
// For example at LAL, some Windows account name have a leading $
// that is found back in the home directory path. To bypass this
// problem we change temporarily the $ by spec_char and continue
// the loop. We change back all the spec_chars to $ at end.
a_string[dollar] = spec_char;
} else {
std::string value = a_string.substr(0,dollar);
value += val;
if(pos!=std::string::npos) value += a_string.substr(pos,a_string.length()-pos);
a_string = value;
}
}
replace(a_string,spec_char,'$');
return true;
}
inline bool file_name(const std::string& a_path,std::string& a_name) {
//used in osc packages and a tools::xml::parser::load_file() compatible for OnX.
a_name = a_path;
if(!rep_env(a_name)) {a_name.clear();return false;}
#ifdef _WIN32
replace(a_name,"/","\\");
replace(a_name,"\"","");
#endif
return true;
}
}
#endif
+27
View File
@@ -0,0 +1,27 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_file_reader
#define tools_file_reader
#include <string>
#include <cstdio>
namespace tools {
namespace file {
class reader {
public:
virtual ~reader() {}
public:
virtual bool open(const std::string&) = 0;
virtual void close() = 0;
virtual bool is_open() const = 0;
virtual bool read(char*,unsigned int,size_t&) = 0;
virtual bool get_line(char*,unsigned int) = 0;
virtual bool eof() const = 0;
};
}}
#endif
+363
View File
@@ -0,0 +1,363 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_fileis
#define tools_fileis
#include "signature"
#include <cstring>
namespace tools {
namespace file {
inline bool is_zip(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!='P') {a_is = false;return true;}
if(head[1]!='K') {a_is = false;return true;}
if(head[2]!=3) {a_is = false;return true;}
if(head[3]!=4) {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_jpeg(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!=255) {a_is = false;return true;}
if(head[1]!=216) {a_is = false;return true;}
if(head[2]!=255) {a_is = false;return true;}
//if(head[3]!=224) {a_is = false;return true;} //LRI.jpg is 225 !
a_is = true;
return true;
}
inline bool is_ico(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!=0) {a_is = false;return true;}
if(head[1]!=0) {a_is = false;return true;}
if(head[2]!=1) {a_is = false;return true;}
if(head[3]!=0) {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_png(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!=137) {a_is = false;return true;}
if(head[1]!='P') {a_is = false;return true;}
if(head[2]!='N') {a_is = false;return true;}
if(head[3]!='G') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_root(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!='r') {a_is = false;return true;}
if(head[1]!='o') {a_is = false;return true;}
if(head[2]!='o') {a_is = false;return true;}
if(head[3]!='t') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_iv(const std::string& a_file,bool& a_is){
unsigned char head[9];
{unsigned int num = 9;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=9) {a_is = false;return true;}}
if(head[0]!='#') {a_is = false;return true;}
if(head[1]!='I') {a_is = false;return true;}
if(head[2]!='n') {a_is = false;return true;}
if(head[3]!='v') {a_is = false;return true;}
if(head[4]!='e') {a_is = false;return true;}
if(head[5]!='n') {a_is = false;return true;}
if(head[6]!='t') {a_is = false;return true;}
if(head[7]!='o') {a_is = false;return true;}
if(head[8]!='r') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_wrl(const std::string& a_file,bool& a_is){
unsigned char head[5];
{unsigned int num = 5;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=5) {a_is = false;return true;}}
if(head[0]!='#') {a_is = false;return true;}
if(head[1]!='V') {a_is = false;return true;}
if(head[2]!='R') {a_is = false;return true;}
if(head[3]!='M') {a_is = false;return true;}
if(head[4]!='L') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_fog(const std::string& a_file,bool& a_is){
unsigned char head[256];
{unsigned int num = 256;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=256) {a_is = false;return true;}}
head[255] = 0; //to have a C string.
a_is = ::strstr((const char*)head,"#nb super-volumes")?true:false;
return true;
}
inline bool is_dot(const std::string& a_file,bool& a_is){
unsigned char head[8];
{unsigned int num = 7;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=7) {a_is = false;return true;}}
head[7] = 0; //to have a C string.
a_is = ::strcmp((const char*)head,"digraph")?false:true;
return true;
}
inline bool is_dcm(const std::string& a_file,bool& a_is){
unsigned char head[132];
{unsigned int num = 132;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=132) {a_is = false;return true;}}
if(head[128]!='D') {a_is = false;return true;}
if(head[129]!='I') {a_is = false;return true;}
if(head[130]!='C') {a_is = false;return true;}
if(head[131]!='M') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_gdml(const std::string& a_file,bool& a_is){
//NOTE : it assumes that the file is not compressed.
unsigned char head[1024];
{unsigned int num = 1024;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=1024) {a_is = false;return true;}}
head[1023] = 0; //to have a C string.
a_is = ::strstr((const char*)head,"<gdml")?true:false;
return true;
}
inline bool is_exsg(unsigned int a_sz,const char* a_buffer){
if(a_sz<5) return false;
if(a_buffer[0]!='<') return false;
if(a_buffer[1]!='e') return false;
if(a_buffer[2]!='x') return false;
if(a_buffer[3]!='s') return false;
if(a_buffer[4]!='g') return false;
return true;
}
inline bool is_exsg(const std::string& a_file,bool& a_is){
unsigned char head[5];
{unsigned int num = 5;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=5) {a_is = false;return true;}}
a_is = is_exsg(5,(const char*)head);
return true;
}
inline bool is_bsg(unsigned int a_sz,const char* a_buffer){
if(a_sz<7) return false;
if(a_buffer[0]!='i') return false;
if(a_buffer[1]!='n') return false;
if(a_buffer[2]!='e') return false;
if(a_buffer[3]!='x') return false;
if(a_buffer[4]!='b') return false;
if(a_buffer[5]!='s') return false;
if(a_buffer[6]!='g') return false;
return true;
}
inline bool is_bsg(const std::string& a_file,bool& a_is){
unsigned char head[7];
{unsigned int num = 7;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=7) {a_is = false;return true;}}
a_is = is_bsg(7,(const char*)head);
return true;
}
inline bool is_scenarios(const std::string& a_file,bool& a_is){
unsigned char head[10];
{unsigned int num = 10;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=10) {a_is = false;return true;}}
if(head[0]!='<') {a_is = false;return true;}
if(head[1]!='s') {a_is = false;return true;}
if(head[2]!='c') {a_is = false;return true;}
if(head[3]!='e') {a_is = false;return true;}
if(head[4]!='n') {a_is = false;return true;}
if(head[5]!='a') {a_is = false;return true;}
if(head[6]!='r') {a_is = false;return true;}
if(head[7]!='i') {a_is = false;return true;}
if(head[8]!='o') {a_is = false;return true;}
if(head[9]!='s') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_slides(const std::string& a_file,bool& a_is){
unsigned char head[7];
{unsigned int num = 7;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=7) {a_is = false;return true;}}
if(head[0]!='<') {a_is = false;return true;}
if(head[1]!='s') {a_is = false;return true;}
if(head[2]!='l') {a_is = false;return true;}
if(head[3]!='i') {a_is = false;return true;}
if(head[4]!='d') {a_is = false;return true;}
if(head[5]!='e') {a_is = false;return true;}
if(head[6]!='s') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_fits(const std::string& a_file,bool& a_is){
unsigned char head[6];
{unsigned int num = 6;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=6) {a_is = false;return true;}}
if(head[0]!='S') {a_is = false;return true;}
if(head[1]!='I') {a_is = false;return true;}
if(head[2]!='M') {a_is = false;return true;}
if(head[3]!='P') {a_is = false;return true;}
if(head[4]!='L') {a_is = false;return true;}
if(head[5]!='E') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_hdf(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!=137) {a_is = false;return true;}
if(head[1]!='H') {a_is = false;return true;}
if(head[2]!='D') {a_is = false;return true;}
if(head[3]!='F') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_ps(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!='%') {a_is = false;return true;}
if(head[1]!='!') {a_is = false;return true;}
if(head[2]!='P') {a_is = false;return true;}
if(head[3]!='S') {a_is = false;return true;}
a_is = true;
return true;
}
inline bool is_simbad(const std::string& a_file,bool& a_is){
unsigned char head[10];
{unsigned int num = 10;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=10) {a_is = false;return true;}}
if(head[0]!=':') {a_is = false;return true;}
if(head[1]!=':') {a_is = false;return true;}
if(head[2]!='s') {a_is = false;return true;}
if(head[3]!='c') {a_is = false;return true;}
if(head[4]!='r') {a_is = false;return true;}
if(head[5]!='i') {a_is = false;return true;}
if(head[6]!='p') {a_is = false;return true;}
if(head[7]!='t') {a_is = false;return true;}
if(head[8]!=':') {a_is = false;return true;}
if(head[9]!=':') {a_is = false;return true;}
a_is = true;
return true;
}
}}
#include "fsize"
namespace tools {
namespace file {
inline bool is_aida(const std::string& a_file,bool& a_is){
long sz;
if(!size(a_file,sz)) {a_is = false;return false;}
//NOTE : it assumes that the file is not compressed.
unsigned char head[1024];
{unsigned int num = 1024;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=1024) {a_is = false;return true;}}
head[1023] = 0; //to have a C string.
a_is = ::strstr((const char*)head,"<aida")?true:false;
return true;
}
inline bool is_jive(const std::string& a_file,bool& a_is){
long sz;
if(!size(a_file,sz)) {a_is = false;return false;}
//NOTE : it assumes that the file is not compressed.
unsigned char head[1024];
{unsigned int num = 1024;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=1024) {a_is = false;return true;}}
head[1023] = 0; //to have a C string.
if(::strstr((const char*)head,"<?ATLAS")) {a_is = true;return true;}
a_is = ::strstr((const char*)head,"<!DOCTYPE Event")?true:false;
return true;
}
inline bool is_heprep(const std::string& a_file,bool& a_is){
long sz;
if(!size(a_file,sz)) {a_is = false;return false;}
//NOTE : it assumes that the file is not compressed.
unsigned char head[1024];
{unsigned int num = 1024;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=1024) {a_is = false;return true;}}
head[1023] = 0; //to have a C string.
a_is = ::strstr((const char*)head,"<heprep")?true:false;
return true;
}
}}
#include <climits>
namespace tools {
namespace file {
inline bool is_shp(const std::string& a_file,bool& a_is){
long sz;
if(!size(a_file,sz)) {a_is = false;return false;}
// below logic from shapelib-1.5.0/shpopen.c.
unsigned char head[100];
{unsigned int num = 100;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=100) {a_is = false;return true;}}
unsigned int _sz = (static_cast<unsigned int>(head[24])<<24)|(head[25]<<16)|(head[26]<<8)|head[27];
if(_sz<(UINT_MAX/2)) _sz *= 2;
else _sz = (UINT_MAX/2)*2;
a_is = sz==long(_sz)?true:false;
return true;
}
}}
#endif
+95
View File
@@ -0,0 +1,95 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_fmanip
#define tools_fmanip
#include "file"
#include "sep"
#include "sout"
#include <ostream>
namespace tools {
inline bool find_with_dirs(std::ostream& a_out,
const std::vector<std::string>& a_dirs,
const std::string& a_file,
std::string& a_path,
bool a_verbose = false ) {
std::vector<std::string>::const_iterator it;
for(it=a_dirs.begin();it!=a_dirs.end();++it) {
if((*it).empty()) {
// with a "" in dirs, this case could solve :
// - a_file in the current directory.
// - a_file with an absolute path name.
a_path = a_file; //may be an absolute file name.
} else {
a_path = *it;
a_path += sep();
a_path += a_file;
}
if(a_verbose) {
a_out << "find_with_dirs :"
<< " look for " << sout(a_path) << " ..."
<< std::endl;
}
if(file::exists(a_path)) {
if(a_verbose) {
a_out << "find_with_dirs :"
<< " found " << sout(a_path) << "."
<< std::endl;
}
return true;
}
}
a_path.clear();
if(a_verbose) {
a_out << "find_with_dirs :"
<< " " << sout(a_file) << " not found."
<< std::endl;
}
return false;
}
}
#include "get_env"
namespace tools {
inline bool find_with_env(std::ostream& a_out,
const std::string& a_env,
const std::string& a_file,
std::string& a_path,
bool a_verbose = false ) {
std::string PATH;
if(!get_env(a_env,PATH)) {
//look for a a_file in current directory.
if(file::exists(a_file)) {
//a_out << "tools::find_with_env :"
// << " env variable " << sout(a_env) << " not defined, but file " << sout(a_file) << " exists."
// << std::endl;
a_path = a_file;
return true;
}
a_out << "tools::find_with_env : env variable " << sout(a_env) << " not defined." << std::endl;
a_path.clear();
return false;
}
if(a_verbose) {
a_out << "find_with_env : env " << sout(a_env) << " is " << sout(PATH) << std::endl;
}
std::vector<std::string> dirs;
words(PATH,psep(),false,dirs); //or true ?
return find_with_dirs(a_out,dirs,a_file,a_path,a_verbose);
}
}
#endif
+62
View File
@@ -0,0 +1,62 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_forit
#define tools_forit
#define tools_vforcit(a__T,a__v,a__it) \
for(std::vector< a__T >::const_iterator a__it = (a__v).begin();(a__it)!=(a__v).end();++(a__it))
#define tools_vforcit_beg(a__T,a__v,a__beg,a__it) \
for(std::vector< a__T >::const_iterator a__it = a__beg;(a__it)!=(a__v).end();++(a__it))
#define tools_vforit(a__T,a__v,a__it) \
for(std::vector< a__T >::iterator a__it = (a__v).begin();(a__it)!=(a__v).end();++(a__it))
#define tools_vforcrit(a__T,a__v,a__it) \
for(std::vector< a__T >::const_reverse_iterator a__it = (a__v).rbegin();(a__it)!=(a__v).rend();++(a__it))
#define tools_vforrit(a__T,a__v,a__it) \
for(std::vector< a__T >::reverse_iterator a__it = (a__v).rbegin();(a__it)!=(a__v).rend();++(a__it))
#define tools_vforcit_npp(a__T,a__v,a__it) \
for(std::vector< a__T >::const_iterator a__it = (a__v).begin();(a__it)!=(a__v).end();)
#define tools_vforit_npp(a__T,a__v,a__it) \
for(std::vector< a__T >::iterator a__it = (a__v).begin();(a__it)!=(a__v).end();)
#define tools_typename_vforcit(a__T,a__v,a__it) \
for(typename std::vector< a__T >::const_iterator a__it = (a__v).begin();(a__it)!=(a__v).end();++(a__it))
#define tools_typename_vforit(a__T,a__v,a__it) \
for(typename std::vector< a__T >::iterator a__it = (a__v).begin();(a__it)!=(a__v).end();++(a__it))
#define tools_sforcit(a__s,a__it) \
for(std::string::const_iterator a__it = (a__s).begin();(a__it)!=(a__s).end();++(a__it))
#define tools_sforit(a__s,a__it) \
for(std::string::iterator a__it = (a__s).begin();(a__it)!=(a__s).end();++(a__it))
#define tools_lforcit(a__T,a__l,a__it) \
for(std::list< a__T >::const_iterator a__it = (a__l).begin();(a__it)!=(a__l).end();++(a__it))
#define tools_lforit(a__T,a__l,a__it) \
for(std::list< a__T >::iterator a__it = (a__l).begin();(a__it)!=(a__l).end();++(a__it))
#define tools_lforit_npp(a__T,a__v,a__it) \
for(std::list< a__T >::iterator a__it = (a__v).begin();(a__it)!=(a__v).end();)
#define tools_mforcit(a__K,a__V,a__m,a__it) \
for(std::map< a__K , a__V >::const_iterator a__it = (a__m).begin();(a__it)!=(a__m).end();++(a__it))
#define tools_mforit(a__K,a__V,a__m,a__it) \
for(std::map< a__K , a__V >::iterator a__it = (a__m).begin();(a__it)!=(a__m).end();++(a__it))
#define tools_typename_mforcit(a__K,a__V,a__m,a__it) \
for(typename std::map< a__K, a__V >::const_iterator a__it = (a__m).begin();(a__it)!=(a__m).end();++(a__it))
#define tools_typename_mforit(a__K,a__V,a__m,a__it) \
for(typename std::map< a__K, a__V >::iterator a__it = (a__m).begin();(a__it)!=(a__m).end();++(a__it))
#endif
+34
View File
@@ -0,0 +1,34 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_fsize
#define tools_fsize
#include <string>
#include <cstdio>
namespace tools {
namespace file {
inline bool size(const std::string& a_file,long& a_size){
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) {
a_size = 0L;
return false;
}
//::rewind(file);
::fseek(file,0L,SEEK_END);
a_size = ::ftell(file);
::fclose(file);
return true;
}
inline bool is_empty(const std::string& a_file){
long sz;
if(!size(a_file,sz)) return true; //if not existing, consider it empty.
return (sz==0L)?true:false;
}
}}
#endif
+44
View File
@@ -0,0 +1,44 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_get_env
#define tools_get_env
#include <cstdlib>
#include "sto"
namespace tools {
inline bool is_env(const std::string& a_string){
const char* env = ::getenv(a_string.c_str());
return (env?true:false);
}
inline bool get_env(const std::string& a_string,std::string& a_value){
const char* env = ::getenv(a_string.c_str());
if(env) {
a_value = std::string(env?env:"");
return true;
} else {
a_value.clear();
return false;
}
}
template <class T>
inline bool get_env(const std::string& a_string,T& a_v,const T& a_def = T()){
std::string s;
if(!get_env(a_string,s)) {a_v = a_def;return false;}
return to<T>(s,a_v,a_def);
}
inline bool get_env_bool(const std::string& a_string,bool& a_v){
std::string s;
if(!get_env(a_string,s)) return false;
return to(s,a_v);
}
}
#endif
+46
View File
@@ -0,0 +1,46 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_get_lines
#define tools_get_lines
#include "cstr"
#include <string>
#include <vector>
namespace tools {
inline void get_lines(const std::string& a_string,std::vector<std::string>& a_lines){
// a_string is a list separated by "\n" or "\\n".
// For "xxx\n\nxxx", {"xxx","","xxx"} will be created.
// WARNING : if a_string is a Windows file name, it may
// contains a \n which is not a delimiter ; like ..\data\ntuples.hbook.
a_lines.clear();
size_t length = a_string.length();
if(!length) return;
char* cstring = str_dup(a_string.c_str());
if(!cstring) return;
size_t pos = 0;
length++;
for(size_t count=0;count<length;count++) {
if( (cstring[count]=='\n') ||
(cstring[count]=='\0') ||
( (cstring[count]=='\\') && (cstring[count+1]=='n') ) ) {
char shift_one = (cstring[count]=='\n' ? 1 : 0);
cstring[count] = '\0';
a_lines.push_back(cstring+pos);
if(shift_one==1) {
pos = count+1;
} else {
pos = count+2;
count++;
}
}
}
str_del(cstring);
}
}
#endif
File diff suppressed because it is too large Load Diff
+78
View File
@@ -0,0 +1,78 @@
#include "gl2ps_def.h"
/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
inline tools_GLboolean tools_dummy_glIsEnabled (tools_GLenum) {return TOOLS_GL_FALSE;}
inline void tools_dummy_glBegin (tools_GLenum) {}
inline void tools_dummy_glEnd () {}
inline void tools_dummy_glGetFloatv (tools_GLenum,tools_GLfloat*) {}
inline void tools_dummy_glVertex3f (tools_GLfloat,tools_GLfloat,tools_GLfloat) {}
inline void tools_dummy_glGetBooleanv (tools_GLenum,tools_GLboolean*) {}
inline void tools_dummy_glGetIntegerv (tools_GLenum,tools_GLint*) {}
inline tools_GLint tools_dummy_glRenderMode (tools_GLenum) {return 0;}
inline void tools_dummy_glFeedbackBuffer (tools_GLsizei,tools_GLenum,tools_GLfloat*) {}
inline void tools_dummy_glPassThrough (tools_GLfloat ) {}
inline tools_gl2ps_gl_funcs_t& tools_gl2ps_get_s_funcs() {
static tools_gl2ps_gl_funcs_t s_gl_funcs = {
tools_dummy_glIsEnabled,
tools_dummy_glBegin,
tools_dummy_glEnd,
tools_dummy_glGetFloatv,
tools_dummy_glVertex3f,
tools_dummy_glGetBooleanv,
tools_dummy_glGetIntegerv,
tools_dummy_glRenderMode,
tools_dummy_glFeedbackBuffer,
tools_dummy_glPassThrough
};
return s_gl_funcs;
}
TOOLS_GL2PSDLL_API void tools_gl2ps_set_gl_funcs(tools_gl2ps_gl_funcs_t* a_funcs) {
tools_gl2ps_gl_funcs_t& s_gl_funcs = tools_gl2ps_get_s_funcs();
s_gl_funcs.m_glIsEnabled = a_funcs->m_glIsEnabled;
s_gl_funcs.m_glBegin = a_funcs->m_glBegin;
s_gl_funcs.m_glEnd = a_funcs->m_glEnd;
s_gl_funcs.m_glGetFloatv = a_funcs->m_glGetFloatv;
s_gl_funcs.m_glVertex3f = a_funcs->m_glVertex3f;
s_gl_funcs.m_glGetBooleanv = a_funcs->m_glGetBooleanv;
s_gl_funcs.m_glGetIntegerv = a_funcs->m_glGetIntegerv;
s_gl_funcs.m_glRenderMode = a_funcs->m_glRenderMode;
s_gl_funcs.m_glFeedbackBuffer = a_funcs->m_glFeedbackBuffer;
s_gl_funcs.m_glPassThrough = a_funcs->m_glPassThrough;
}
TOOLS_GL2PSDLL_API void tools_gl2ps_reset_gl_funcs() {
tools_gl2ps_gl_funcs_t& s_gl_funcs = tools_gl2ps_get_s_funcs();
s_gl_funcs.m_glIsEnabled = tools_dummy_glIsEnabled;
s_gl_funcs.m_glBegin = tools_dummy_glBegin;
s_gl_funcs.m_glEnd = tools_dummy_glEnd;
s_gl_funcs.m_glGetFloatv = tools_dummy_glGetFloatv;
s_gl_funcs.m_glVertex3f = tools_dummy_glVertex3f;
s_gl_funcs.m_glGetBooleanv = tools_dummy_glGetBooleanv;
s_gl_funcs.m_glGetIntegerv = tools_dummy_glGetIntegerv;
s_gl_funcs.m_glRenderMode = tools_dummy_glRenderMode;
s_gl_funcs.m_glFeedbackBuffer = tools_dummy_glFeedbackBuffer;
s_gl_funcs.m_glPassThrough = tools_dummy_glPassThrough;
}
#define tools_glIsEnabled (*(tools_gl2ps_get_s_funcs().m_glIsEnabled))
#define tools_glBegin (*(tools_gl2ps_get_s_funcs().m_glBegin))
#define tools_glEnd (*(tools_gl2ps_get_s_funcs().m_glEnd))
#define tools_glGetFloatv (*(tools_gl2ps_get_s_funcs().m_glGetFloatv))
#define tools_glVertex3f (*(tools_gl2ps_get_s_funcs().m_glVertex3f))
#define tools_glGetBooleanv (*(tools_gl2ps_get_s_funcs().m_glGetBooleanv))
#define tools_glGetIntegerv (*(tools_gl2ps_get_s_funcs().m_glGetIntegerv))
#define tools_glRenderMode (*(tools_gl2ps_get_s_funcs().m_glRenderMode))
#define tools_glFeedbackBuffer (*(tools_gl2ps_get_s_funcs().m_glFeedbackBuffer))
#define tools_glPassThrough (*(tools_gl2ps_get_s_funcs().m_glPassThrough))
/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
+197
View File
@@ -0,0 +1,197 @@
/* Copyright (C) 2010, Guy Barrand. All rights reserved. */
/* See the file tools.license for terms. */
#ifndef tools_gl2ps_def_h
#define tools_gl2ps_def_h
typedef int tools_GLint;
typedef unsigned int tools_GLuint;
typedef float tools_GLfloat;
typedef unsigned int tools_GLenum;
typedef short tools_GLshort;
typedef unsigned short tools_GLushort;
typedef int tools_GLsizei;
typedef unsigned char tools_GLboolean;
/*----------------------------------------------------------*/
/*--- from gl2ps.h : --------------------------------------*/
/*----------------------------------------------------------*/
#define TOOLS_GL2PSDLL_API inline
#define TOOLS_GL2PS_MAJOR_VERSION 1
#define TOOLS_GL2PS_MINOR_VERSION 4
#define TOOLS_GL2PS_PATCH_VERSION 0
#define TOOLS_GL2PS_EXTRA_VERSION ""
#define TOOLS_GL2PS_VERSION (TOOLS_GL2PS_MAJOR_VERSION + \
0.01 * TOOLS_GL2PS_MINOR_VERSION + \
0.0001 * TOOLS_GL2PS_PATCH_VERSION)
#define TOOLS_GL2PS_COPYRIGHT "(C) 1999-2017 C. Geuzaine"
/* Output file formats (the values and the ordering are important!) */
#define TOOLS_GL2PS_PS 0
#define TOOLS_GL2PS_EPS 1
#define TOOLS_GL2PS_TEX 2
#define TOOLS_GL2PS_PDF 3
#define TOOLS_GL2PS_SVG 4
#define TOOLS_GL2PS_PGF 5
/* Sorting algorithms */
#define TOOLS_GL2PS_NO_SORT 1
#define TOOLS_GL2PS_SIMPLE_SORT 2
#define TOOLS_GL2PS_BSP_SORT 3
/* Message levels and error codes */
#define TOOLS_GL2PS_SUCCESS 0
#define TOOLS_GL2PS_INFO 1
#define TOOLS_GL2PS_WARNING 2
#define TOOLS_GL2PS_ERROR 3
#define TOOLS_GL2PS_NO_FEEDBACK 4
#define TOOLS_GL2PS_OVERFLOW 5
#define TOOLS_GL2PS_UNINITIALIZED 6
/* Options for tools_gl2psBeginPage */
#define TOOLS_GL2PS_NONE 0
#define TOOLS_GL2PS_DRAW_BACKGROUND (1<<0)
#define TOOLS_GL2PS_SIMPLE_LINE_OFFSET (1<<1)
#define TOOLS_GL2PS_SILENT (1<<2)
#define TOOLS_GL2PS_BEST_ROOT (1<<3)
#define TOOLS_GL2PS_OCCLUSION_CULL (1<<4)
#define TOOLS_GL2PS_NO_TEXT (1<<5)
#define TOOLS_GL2PS_LANDSCAPE (1<<6)
#define TOOLS_GL2PS_NO_PS3_SHADING (1<<7)
#define TOOLS_GL2PS_NO_PIXMAP (1<<8)
#define TOOLS_GL2PS_USE_CURRENT_VIEWPORT (1<<9)
#define TOOLS_GL2PS_COMPRESS (1<<10)
#define TOOLS_GL2PS_NO_BLENDING (1<<11)
#define TOOLS_GL2PS_TIGHT_BOUNDING_BOX (1<<12)
#define TOOLS_GL2PS_NO_OPENGL_CONTEXT (1<<13)
/* Arguments for tools_gl2psEnable/tools_gl2psDisable */
#define TOOLS_GL2PS_POLYGON_OFFSET_FILL 1
#define TOOLS_GL2PS_POLYGON_BOUNDARY 2
#define TOOLS_GL2PS_LINE_STIPPLE 3
#define TOOLS_GL2PS_BLEND 4
/* Arguments for tools_gl2psLineCap/Join */
#define TOOLS_GL2PS_LINE_CAP_BUTT 0
#define TOOLS_GL2PS_LINE_CAP_ROUND 1
#define TOOLS_GL2PS_LINE_CAP_SQUARE 2
#define TOOLS_GL2PS_LINE_JOIN_MITER 0
#define TOOLS_GL2PS_LINE_JOIN_ROUND 1
#define TOOLS_GL2PS_LINE_JOIN_BEVEL 2
/* Text alignment (o=raster position; default mode is BL):
+---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o
| o | o | | o | | | | | | | | | | | |
+---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+
C CL CR B BL BR T TL TR */
#define TOOLS_GL2PS_TEXT_C 1
#define TOOLS_GL2PS_TEXT_CL 2
#define TOOLS_GL2PS_TEXT_CR 3
#define TOOLS_GL2PS_TEXT_B 4
#define TOOLS_GL2PS_TEXT_BL 5
#define TOOLS_GL2PS_TEXT_BR 6
#define TOOLS_GL2PS_TEXT_T 7
#define TOOLS_GL2PS_TEXT_TL 8
#define TOOLS_GL2PS_TEXT_TR 9
typedef tools_GLfloat tools_GL2PSrgba[4];
typedef tools_GLfloat tools_GL2PSxyz[3];
typedef struct {
tools_GL2PSxyz xyz;
tools_GL2PSrgba rgba;
} tools_GL2PSvertex;
/* Primitive types */
#define TOOLS_GL2PS_NO_TYPE -1
#define TOOLS_GL2PS_TEXT 1
#define TOOLS_GL2PS_POINT 2
#define TOOLS_GL2PS_LINE 3
#define TOOLS_GL2PS_QUADRANGLE 4
#define TOOLS_GL2PS_TRIANGLE 5
#define TOOLS_GL2PS_PIXMAP 6
#define TOOLS_GL2PS_IMAGEMAP 7
#define TOOLS_GL2PS_IMAGEMAP_WRITTEN 8
#define TOOLS_GL2PS_IMAGEMAP_VISIBLE 9
#define TOOLS_GL2PS_SPECIAL 10
/*----------------------------------------------------------*/
/*--- from OpenGL : ----------------------------------------*/
/*----------------------------------------------------------*/
#define TOOLS_GL_TRUE 1
#define TOOLS_GL_FALSE 0
#define TOOLS_GL_FLOAT 0x1406
#define TOOLS_GL_BLEND 0x0BE2
#define TOOLS_GL_SRC_ALPHA 0x0302
#define TOOLS_GL_ONE_MINUS_SRC_ALPHA 0x0303
#define TOOLS_GL_RGB 0x1907
#define TOOLS_GL_RGBA 0x1908
#define TOOLS_GL_POINTS 0x0000
#define TOOLS_GL_CURRENT_RASTER_POSITION_VALID 0x0B08
#define TOOLS_GL_CURRENT_RASTER_POSITION 0x0B07
#define TOOLS_GL_CURRENT_RASTER_COLOR 0x0B04
#define TOOLS_GL_ZERO 0
#define TOOLS_GL_ONE 1
#define TOOLS_GL_COLOR_INDEX 0x1900
#define TOOLS_GL_POINT_TOKEN 0x0701
#define TOOLS_GL_LINE_TOKEN 0x0702
#define TOOLS_GL_LINE_RESET_TOKEN 0x0707
#define TOOLS_GL_POLYGON_TOKEN 0x0703
#define TOOLS_GL_BITMAP_TOKEN 0x0704
#define TOOLS_GL_DRAW_PIXEL_TOKEN 0x0705
#define TOOLS_GL_COPY_PIXEL_TOKEN 0x0706
#define TOOLS_GL_PASS_THROUGH_TOKEN 0x0700
#define TOOLS_GL_FEEDBACK 0x1C01
#define TOOLS_GL_COLOR_CLEAR_VALUE 0x0C22
#define TOOLS_GL_INDEX_CLEAR_VALUE 0x0C20
#define TOOLS_GL_RENDER 0x1C00
#define TOOLS_GL_VIEWPORT 0x0BA2
#define TOOLS_GL_BLEND_SRC 0x0BE1
#define TOOLS_GL_BLEND_DST 0x0BE0
#define TOOLS_GL_3D_COLOR 0x0602
#define TOOLS_GL_POLYGON_OFFSET_FACTOR 0x8038
#define TOOLS_GL_POLYGON_OFFSET_UNITS 0x2A00
#define TOOLS_GL_LINE_STIPPLE_PATTERN 0x0B25
#define TOOLS_GL_LINE_STIPPLE_REPEAT 0x0B26
#define TOOLS_GL_ZOOM_X 0x0D16
#define TOOLS_GL_ZOOM_Y 0x0D17
/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
typedef struct {
tools_GLboolean (*m_glIsEnabled) (tools_GLenum);
void (*m_glBegin) (tools_GLenum);
void (*m_glEnd) ();
void (*m_glGetFloatv) (tools_GLenum,tools_GLfloat*);
void (*m_glVertex3f) (tools_GLfloat,tools_GLfloat,tools_GLfloat);
void (*m_glGetBooleanv) (tools_GLenum,tools_GLboolean*);
void (*m_glGetIntegerv) (tools_GLenum,tools_GLint*);
tools_GLint (*m_glRenderMode) (tools_GLenum);
void (*m_glFeedbackBuffer) (tools_GLsizei,tools_GLenum,tools_GLfloat*);
void (*m_glPassThrough) (tools_GLfloat);
} tools_gl2ps_gl_funcs_t;
#endif
+42
View File
@@ -0,0 +1,42 @@
TOOLS_GL2PSDLL_API tools_GLint tools_gl2psSetBackgroundColor(float a_r,float a_g,float a_b)
{
if(!tools_gl2ps_context) return TOOLS_GL2PS_UNINITIALIZED;
tools_gl2ps_context->bgcolor[0] = a_r;
tools_gl2ps_context->bgcolor[1] = a_g;
tools_gl2ps_context->bgcolor[2] = a_b;
tools_gl2ps_context->bgcolor[3] = 1.0F;
return TOOLS_GL2PS_SUCCESS;
}
#undef TOOLS_GL2PS_EPSILON
#undef TOOLS_GL2PS_ZSCALE
#undef TOOLS_GL2PS_ZOFFSET
#undef TOOLS_GL2PS_ZOFFSET_LARGE
#undef TOOLS_GL2PS_ZERO
#undef TOOLS_GL2PS_COINCIDENT
#undef TOOLS_GL2PS_IN_FRONT_OF
#undef TOOLS_GL2PS_IN_BACK_OF
#undef TOOLS_GL2PS_SPANNING
#undef TOOLS_GL2PS_POINT_COINCIDENT
#undef TOOLS_GL2PS_POINT_INFRONT
#undef TOOLS_GL2PS_POINT_BACK
#undef TOOLS_GL2PS_BEGIN_OFFSET_TOKEN
#undef TOOLS_GL2PS_END_OFFSET_TOKEN
#undef TOOLS_GL2PS_BEGIN_BOUNDARY_TOKEN
#undef TOOLS_GL2PS_END_BOUNDARY_TOKEN
#undef TOOLS_GL2PS_BEGIN_STIPPLE_TOKEN
#undef TOOLS_GL2PS_END_STIPPLE_TOKEN
#undef TOOLS_GL2PS_POINT_SIZE_TOKEN
#undef TOOLS_GL2PS_LINE_CAP_TOKEN
#undef TOOLS_GL2PS_LINE_JOIN_TOKEN
#undef TOOLS_GL2PS_LINE_WIDTH_TOKEN
#undef TOOLS_GL2PS_BEGIN_BLEND_TOKEN
#undef TOOLS_GL2PS_END_BLEND_TOKEN
#undef TOOLS_GL2PS_SRC_BLEND_TOKEN
#undef TOOLS_GL2PS_DST_BLEND_TOKEN
#undef TOOLS_GL2PS_IMAGEMAP_TOKEN
#undef TOOLS_GL2PS_DRAW_PIXELS_TOKEN
#undef TOOLS_GL2PS_TEXT_TOKEN
+34
View File
@@ -0,0 +1,34 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_glbuf
#define tools_glbuf
//define of TOOLS_HAS_GL_VBO decided in the build systems.
// To have prototypes of glGenBuffers,etc...
#ifdef TOOLS_HAS_GL_VBO
#ifdef TOOLS_TOOLS_GL
#else
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if TARGET_OS_IPHONE
#elif defined(ANDROID)
#elif _WIN32
#include <GL/glext.h>
#elif __APPLE__
#include <OpenGL/glext.h> //Cocoa
#else
#include <GL/glext.h>
#endif
#endif //TOOLS_TOOLS_GL
#endif //TOOLS_HAS_GL_VBO
#endif
+622
View File
@@ -0,0 +1,622 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_glprims
#define tools_glprims
//same as OpenGL GL_[POINTS,etc...], but for the case we don't have OpenGL.
#include <cstddef> //size_t
namespace tools {
namespace gl {
typedef unsigned char mode_t;
inline mode_t points() {return 0x0000;}
inline mode_t lines() {return 0x0001;} //segments
inline mode_t line_loop() {return 0x0002;}
inline mode_t line_strip() {return 0x0003;} //polyline
inline mode_t triangles() {return 0x0004;}
inline mode_t triangle_strip() {return 0x0005;}
inline mode_t triangle_fan() {return 0x0006;}
//inline mode_t quads() {return 0x0007;}
//inline mode_t quad_strip() {return 0x0008;}
//inline mode_t polygon() {return 0x0009;}
inline bool is_mode(mode_t a_mode) {
return a_mode<=0x006?true:false;
}
inline bool is_line(mode_t a_mode) {
if(a_mode==points()) return true; //0 sz line !
if(a_mode==lines()) return true;
if(a_mode==line_loop()) return true;
if(a_mode==line_strip()) return true;
return false;
}
inline void cvt_2to3(size_t a_npt,const float* a_xys,float*& a_xyzs) {
const float* vpos = a_xys;
float x,y;
for(size_t i=0;i<a_npt;i++) {
x = *vpos;vpos++;
y = *vpos;vpos++;
*a_xyzs = x;a_xyzs++;
*a_xyzs = y;a_xyzs++;
*a_xyzs = 0;a_xyzs++;
}
}
inline void triangle_fan_to_triangles(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
// a_pxyzs = (a_npt-2)*3*3
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float z2 = *vpos;vpos++;
float x3,y3,z3;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
z3 = *vpos;vpos++;
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = z3;a_pxyzs++;
x2 = x3;
y2 = y3;
z2 = z3;
}
}
inline void triangle_fan_to_triangles_texture(size_t a_npt,const float* a_xyzs,const float* a_tcs,float*& a_pxyzs,float*& a_ptcs) {
// a_pxyzs = (a_npt-2)*3*3
// a_ptcs = (a_npt-2)*3*2
const float* vpos = a_xyzs;
const float* tpos = a_tcs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
float tx1 = *tpos;tpos++;
float ty1 = *tpos;tpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float z2 = *vpos;vpos++;
float tx2 = *tpos;tpos++;
float ty2 = *tpos;tpos++;
float x3,y3,z3,tx3,ty3;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
z3 = *vpos;vpos++;
tx3 = *tpos;tpos++;
ty3 = *tpos;tpos++;
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_ptcs = tx1;a_ptcs++;
*a_ptcs = ty1;a_ptcs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
*a_ptcs = tx2;a_ptcs++;
*a_ptcs = ty2;a_ptcs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = z3;a_pxyzs++;
*a_ptcs = tx3;a_ptcs++;
*a_ptcs = ty3;a_ptcs++;
x2 = x3;
y2 = y3;
z2 = z3;
tx2 = tx3;
ty2 = ty3;
}
}
inline void triangle_strip_to_triangles(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
// a_pxyzs = (a_npt-2)*3*3
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float z2 = *vpos;vpos++;
float x3,y3,z3;
bool flip = false;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
z3 = *vpos;vpos++;
if(flip) {
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = z3;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
} else {
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = z3;a_pxyzs++;
}
x1 = x2;
y1 = y2;
z1 = z2;
x2 = x3;
y2 = y3;
z2 = z3;
flip = flip?false:true;
}
}
inline void triangle_strip_to_triangles_texture(size_t a_npt,const float* a_xyzs,const float* a_tcs,float*& a_pxyzs,float*& a_ptcs) {
// a_pxyzs = (a_npt-2)*3*3
// a_ptcs = (a_npt-2)*3*2
const float* vpos = a_xyzs;
const float* tpos = a_tcs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
float tx1 = *tpos;tpos++;
float ty1 = *tpos;tpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float z2 = *vpos;vpos++;
float tx2 = *tpos;tpos++;
float ty2 = *tpos;tpos++;
float x3,y3,z3,tx3,ty3;
bool flip = false;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
z3 = *vpos;vpos++;
tx3 = *tpos;tpos++;
ty3 = *tpos;tpos++;
if(flip) {
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_ptcs = tx1;a_ptcs++;
*a_ptcs = ty1;a_ptcs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = z3;a_pxyzs++;
*a_ptcs = tx3;a_ptcs++;
*a_ptcs = ty3;a_ptcs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
*a_ptcs = tx2;a_ptcs++;
*a_ptcs = ty2;a_ptcs++;
} else {
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_ptcs = tx1;a_ptcs++;
*a_ptcs = ty1;a_ptcs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
*a_ptcs = tx2;a_ptcs++;
*a_ptcs = ty2;a_ptcs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = z3;a_pxyzs++;
*a_ptcs = tx3;a_ptcs++;
*a_ptcs = ty3;a_ptcs++;
}
x1 = x2;
y1 = y2;
z1 = z2;
tx1 = tx2;
ty1 = ty2;
x2 = x3;
y2 = y3;
z2 = z3;
tx2 = tx3;
ty2 = ty3;
flip = flip?false:true;
}
}
inline void triangle_fan_to_triangles_nms(size_t a_npt,const float* a_xyzs,const float* a_nms,float*& a_pxyzs,float*& a_pnms) {
triangle_fan_to_triangles(a_npt,a_xyzs,a_pxyzs);
triangle_fan_to_triangles(a_npt,a_nms,a_pnms);
}
inline void triangle_strip_to_triangles_nms(size_t a_npt,const float* a_xyzs,const float* a_nms,float*& a_pxyzs,float*& a_pnms) {
// a_pxyzs, a_pnms = (a_npt-2)*3*3
triangle_strip_to_triangles(a_npt,a_xyzs,a_pxyzs);
triangle_strip_to_triangles(a_npt,a_nms,a_pnms);
}
inline void triangle_fan_to_triangles_2to3(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float x3,y3;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
x2 = x3;
y2 = y3;
}
}
inline void triangle_strip_to_triangles_2to3(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float x3,y3;
bool flip = false;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
if(flip) {
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
} else {
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
*a_pxyzs = x3;a_pxyzs++;
*a_pxyzs = y3;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
}
x1 = x2;
y1 = y2;
x2 = x3;
y2 = y3;
flip = flip?false:true;
}
}
inline void line_strip_to_lines_2to3(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float x2,y2;
for(size_t i=1;i<a_npt;i++) {
x2 = *vpos;vpos++;
y2 = *vpos;vpos++;
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = 0;a_pxyzs++;
x1 = x2;
y1 = y2;
}
}
inline void line_strip_to_lines(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
// a_pxyzs = (a_npt-1)*2*3
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
float x2,y2,z2;
for(size_t i=1;i<a_npt;i++) {
x2 = *vpos;vpos++;
y2 = *vpos;vpos++;
z2 = *vpos;vpos++;
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
x1 = x2;
y1 = y2;
z1 = z2;
}
}
inline void line_loop_to_lines(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
// a_pxyzs = a_npt*2*3
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
float x0 = x1;
float y0 = y1;
float z0 = z1;
float x2,y2,z2;
for(size_t i=1;i<a_npt;i++) {
x2 = *vpos;vpos++;
y2 = *vpos;vpos++;
z2 = *vpos;vpos++;
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_pxyzs = x2;a_pxyzs++;
*a_pxyzs = y2;a_pxyzs++;
*a_pxyzs = z2;a_pxyzs++;
x1 = x2;
y1 = y2;
z1 = z2;
}
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
*a_pxyzs = x0;a_pxyzs++;
*a_pxyzs = y0;a_pxyzs++;
*a_pxyzs = z0;a_pxyzs++;
}
inline void line_loop_to_line_strip(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
// a_pxyzs = (a_npt+1)*3
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
for(size_t i=0;i<a_npt;i++) {
*a_pxyzs = *vpos;vpos++;a_pxyzs++;
*a_pxyzs = *vpos;vpos++;a_pxyzs++;
*a_pxyzs = *vpos;vpos++;a_pxyzs++;
}
*a_pxyzs = x1;a_pxyzs++;
*a_pxyzs = y1;a_pxyzs++;
*a_pxyzs = z1;a_pxyzs++;
}
/// for DirectX_action :
inline void triangle_fan_to_triangles_2to3(size_t a_npt,const float* a_xyzs,
float a_r,float a_g,float a_b,float a_a,
float*& a_pxyz_rgbas) {
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float x3,y3;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
*a_pxyz_rgbas = x1;a_pxyz_rgbas++;
*a_pxyz_rgbas = y1;a_pxyz_rgbas++;
*a_pxyz_rgbas = 0;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_a;a_pxyz_rgbas++;
*a_pxyz_rgbas = x2;a_pxyz_rgbas++;
*a_pxyz_rgbas = y2;a_pxyz_rgbas++;
*a_pxyz_rgbas = 0;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_a;a_pxyz_rgbas++;
*a_pxyz_rgbas = x3;a_pxyz_rgbas++;
*a_pxyz_rgbas = y3;a_pxyz_rgbas++;
*a_pxyz_rgbas = 0;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_a;a_pxyz_rgbas++;
x2 = x3;
y2 = y3;
}
}
inline void triangle_fan_to_triangles(size_t a_npt,const float* a_xyzs,
float a_r,float a_g,float a_b,float a_a,
float*& a_pxyz_rgbas) {
const float* vpos = a_xyzs;
float x1 = *vpos;vpos++;
float y1 = *vpos;vpos++;
float z1 = *vpos;vpos++;
float x2 = *vpos;vpos++;
float y2 = *vpos;vpos++;
float z2 = *vpos;vpos++;
float x3,y3,z3;
for(size_t i=2;i<a_npt;i++) {
x3 = *vpos;vpos++;
y3 = *vpos;vpos++;
z3 = *vpos;vpos++;
*a_pxyz_rgbas = x1;a_pxyz_rgbas++;
*a_pxyz_rgbas = y1;a_pxyz_rgbas++;
*a_pxyz_rgbas = z1;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_a;a_pxyz_rgbas++;
*a_pxyz_rgbas = x2;a_pxyz_rgbas++;
*a_pxyz_rgbas = y2;a_pxyz_rgbas++;
*a_pxyz_rgbas = z2;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_a;a_pxyz_rgbas++;
*a_pxyz_rgbas = x3;a_pxyz_rgbas++;
*a_pxyz_rgbas = y3;a_pxyz_rgbas++;
*a_pxyz_rgbas = z3;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
*a_pxyz_rgbas = a_a;a_pxyz_rgbas++;
x2 = x3;
y2 = y3;
z2 = z3;
}
}
}}
#endif
+140
View File
@@ -0,0 +1,140 @@
/*
G.Barrand : glu.h of Mesa-7.8.1 but containing only tess related material.
We bring also the needed material from gl.h.
*/
#ifndef tools_glutess__glu
#define tools_glutess__glu
#include "rename"
/* //////////////////////////////////////////////////////////////// */
/* //////////////////////////////////////////////////////////////// */
typedef unsigned int GLUenum;
typedef void GLUvoid;
typedef double GLUdouble;
typedef unsigned char GLUboolean;
typedef float GLUfloat; /* single precision float */
typedef double GLUclampd; /* double precision float in [0,1] */
/* //////////////////////////////////////////////////////////////// */
/* //////////////////////////////////////////////////////////////// */
/* //////////////////////////////////////////////////////////////// */
/* TessCallback */
#define GLU_TESS_BEGIN_DATA 100106
#define GLU_TESS_VERTEX_DATA 100107
#define GLU_TESS_END_DATA 100108
#define GLU_TESS_ERROR_DATA 100109
#define GLU_TESS_COMBINE_DATA 100111
/* TessProperty */
#define GLU_TESS_WINDING_RULE 100140
//#define GLU_TESS_TOLERANCE 100142
/* TessWinding */
#define GLU_TESS_WINDING_ODD 100130
#define GLU_TESS_WINDING_POSITIVE 100132
#define GLU_TESS_WINDING_NEGATIVE 100133
/*************************************************************/
// mesa glu has the below for Windows.
//#define GLUAPIENTRY __stdcall
//typedef void (__stdcall* _GLUfuncptr)();
#define GLUAPIENTRY
typedef void (* _GLUfuncptr)();
#define GLUAPI
typedef struct GLUtesselator GLUtesselator;
typedef GLUtesselator GLUtesselatorObj;
typedef GLUtesselator GLUtriangulatorObj;
/*
GLUAPI GLUtesselator* GLUAPIENTRY gluNewTess (void);
GLUAPI void GLUAPIENTRY gluDeleteTess (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessBeginContour (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLUvoid* data);
GLUAPI void GLUAPIENTRY gluTessCallback (GLUtesselator* tess, GLUenum which, _GLUfuncptr CallBackFunc);
GLUAPI void GLUAPIENTRY gluTessEndContour (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessNormal (GLUtesselator* tess, GLUdouble valueX, GLUdouble valueY, GLUdouble valueZ);
GLUAPI void GLUAPIENTRY gluTessProperty (GLUtesselator* tess, GLUenum which, GLUdouble data);
GLUAPI void GLUAPIENTRY gluTessVertex (GLUtesselator* tess, GLUdouble *location, GLUvoid* data);
*/
#define GLU_MIN(x,y) ((x) <= (y) ? (x) : (y))
#define GLU_MAX(x,y) ((x) >= (y) ? (x) : (y))
#define GLU_ABS(x) ((x) < 0 ? -(x) : (x))
/* //////////////////////////////////////////////////////////////// */
/* //////////////////////////////////////////////////////////////// */
/* //////////////////////////////////////////////////////////////// */
/* Boolean values */
#define TOOLS_GLU_FALSE 0x0
#define TOOLS_GLU_TRUE 0x1
/* Primitives */
#define GLU_LINE_LOOP 0x0002
#define GLU_TRIANGLES 0x0004
#define GLU_TRIANGLE_STRIP 0x0005
#define GLU_TRIANGLE_FAN 0x0006
#define GLU_TESS_MAX_COORD 1.0e150
/* ErrorCode */
#define GLU_INVALID_ENUM 100900
#define GLU_INVALID_VALUE 100901
#define GLU_OUT_OF_MEMORY 100902
#define GLU_INCOMPATIBLE_GL_VERSION 100903
#define GLU_INVALID_OPERATION 100904
/* TessCallback */
#define GLU_TESS_BEGIN 100100
#define GLU_TESS_VERTEX 100101
#define GLU_TESS_END 100102
#define GLU_TESS_ERROR 100103
#define GLU_TESS_EDGE_FLAG 100104
#define GLU_EDGE_FLAG 100104
#define GLU_TESS_COMBINE 100105
#define GLU_TESS_EDGE_FLAG_DATA 100110
/* TessContour */
#define GLU_CW 100120
#define GLU_CCW 100121
#define GLU_INTERIOR 100122
#define GLU_EXTERIOR 100123
#define GLU_UNKNOWN 100124
/* TessProperty */
#define GLU_TESS_BOUNDARY_ONLY 100141
#define GLU_TESS_TOLERANCE 100142
/* TessError */
#define GLU_TESS_ERROR1 100151
#define GLU_TESS_ERROR2 100152
#define GLU_TESS_ERROR3 100153
#define GLU_TESS_ERROR4 100154
#define GLU_TESS_ERROR5 100155
#define GLU_TESS_ERROR6 100156
#define GLU_TESS_ERROR7 100157
#define GLU_TESS_ERROR8 100158
#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
#define GLU_TESS_MISSING_END_POLYGON 100153
#define GLU_TESS_MISSING_END_CONTOUR 100154
#define GLU_TESS_COORD_TOO_LARGE 100155
#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
/* TessWinding */
#define GLU_TESS_WINDING_NONZERO 100131
#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
#endif /* __glu_h__ */
+133
View File
@@ -0,0 +1,133 @@
// see license file for original license.
#ifndef tools_glutess__tess
#define tools_glutess__tess
#include "mesh"
#include "dict"
#include "priorityq"
#include <csetjmp>
/* The begin/end calls must be properly nested. We keep track of
* the current state to enforce the ordering.
*/
enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
/* We cache vertex data for single-contour polygons so that we can
* try a quick-and-dirty decomposition first.
*/
#define GLU_TESS_MAX_CACHE 100
typedef struct CachedVertex {
GLUdouble coords[3];
void *data;
} CachedVertex;
struct GLUtesselator {
/*** state needed for collecting the input data ***/
enum TessState state; /* what begin/end calls have we seen? */
GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
GLUmesh *mesh; /* stores the input contours, and eventually
the tessellation itself */
void (GLUAPIENTRY *callError)( GLUenum errnum );
/*** state needed for projecting onto the sweep plane ***/
GLUdouble normal[3]; /* user-specified normal (if provided) */
GLUdouble sUnit[3]; /* unit vector in s-direction (debugging) */
GLUdouble tUnit[3]; /* unit vector in t-direction (debugging) */
/*** state needed for the line sweep ***/
GLUdouble relTolerance; /* tolerance for merging features */
GLUenum windingRule; /* rule for determining polygon interior */
GLUboolean fatalError; /* fatal error: needed combine callback */
Dict *dict; /* edge dictionary for sweep line */
PriorityQ *pq; /* priority queue of vertex events */
GLUvertex *event; /* current sweep event being processed */
void (GLUAPIENTRY *callCombine)( GLUdouble coords[3], void *data[4],
GLUfloat weight[4], void **outData );
/*** state needed for rendering callbacks (see render.c) ***/
GLUboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
GLUboolean boundaryOnly; /* Extract contours, not triangles */
GLUface *lonelyTriList;
/* list of triangles which could not be rendered as strips or fans */
void (GLUAPIENTRY *callBegin)( GLUenum type );
void (GLUAPIENTRY *callEdgeFlag)( GLUboolean boundaryEdge );
void (GLUAPIENTRY *callVertex)( void *data );
void (GLUAPIENTRY *callEnd)( void );
void (GLUAPIENTRY *callMesh)( GLUmesh *mesh );
/*** state needed to cache single-contour polygons for renderCache() */
GLUboolean emptyCache; /* empty cache on next vertex() call */
int cacheCount; /* number of cached vertices */
CachedVertex cache[GLU_TESS_MAX_CACHE]; /* the vertex data */
/*** rendering callbacks that also pass polygon data ***/
void (GLUAPIENTRY *callBeginData)( GLUenum type, void *polygonData );
void (GLUAPIENTRY *callEdgeFlagData)( GLUboolean boundaryEdge,
void *polygonData );
void (GLUAPIENTRY *callVertexData)( void *data, void *polygonData );
void (GLUAPIENTRY *callEndData)( void *polygonData );
void (GLUAPIENTRY *callErrorData)( GLUenum errnum, void *polygonData );
void (GLUAPIENTRY *callCombineData)( GLUdouble coords[3], void *data[4],
GLUfloat weight[4], void **outData,
void *polygonData );
jmp_buf env; /* place to jump to when memAllocs fail */
void *polygonData; /* client data for current polygon */
};
void GLUAPIENTRY __gl_noBeginData( GLUenum type, void *polygonData );
void GLUAPIENTRY __gl_noEdgeFlagData( GLUboolean boundaryEdge, void *polygonData );
void GLUAPIENTRY __gl_noVertexData( void *data, void *polygonData );
void GLUAPIENTRY __gl_noEndData( void *polygonData );
void GLUAPIENTRY __gl_noErrorData( GLUenum errnum, void *polygonData );
void GLUAPIENTRY __gl_noCombineData( GLUdouble coords[3], void *data[4],
GLUfloat weight[4], void **outData,
void *polygonData );
#define CALL_BEGIN_OR_BEGIN_DATA(a) \
if (tess->callBeginData != &__gl_noBeginData) \
(*tess->callBeginData)((a),tess->polygonData); \
else (*tess->callBegin)((a));
#define CALL_VERTEX_OR_VERTEX_DATA(a) \
if (tess->callVertexData != &__gl_noVertexData) \
(*tess->callVertexData)((a),tess->polygonData); \
else (*tess->callVertex)((a));
#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
(*tess->callEdgeFlagData)((a),tess->polygonData); \
else (*tess->callEdgeFlag)((a));
#define CALL_END_OR_END_DATA() \
if (tess->callEndData != &__gl_noEndData) \
(*tess->callEndData)(tess->polygonData); \
else (*tess->callEnd)();
#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
if (tess->callCombineData != &__gl_noCombineData) \
(*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
else (*tess->callCombine)((a),(b),(c),(d));
#define CALL_ERROR_OR_ERROR_DATA(a) \
if (tess->callErrorData != &__gl_noErrorData) \
(*tess->callErrorData)((a),tess->polygonData); \
else (*tess->callError)((a));
#endif
+127
View File
@@ -0,0 +1,127 @@
// see license file for original license.
#ifndef tools_glutess_dict_list
#define tools_glutess_dict_list
/* Use #define's so that another heap implementation can use this one */
#define DictKey DictListKey
#define Dict DictList
#define DictNode DictListNode
#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
#define dictKey(n) __gl_dictListKey(n)
#define dictSucc(n) __gl_dictListSucc(n)
#define dictPred(n) __gl_dictListPred(n)
#define dictMin(d) __gl_dictListMin(d)
#define dictMax(d) __gl_dictListMax(d)
typedef void *DictKey;
typedef struct Dict Dict;
typedef struct DictNode DictNode;
#define __gl_dictListKey(n) ((n)->key)
#define __gl_dictListSucc(n) ((n)->next)
#define __gl_dictListPred(n) ((n)->prev)
#define __gl_dictListMin(d) ((d)->head.next)
#define __gl_dictListMax(d) ((d)->head.prev)
#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
/*** Private data structures ***/
struct DictNode {
DictKey key;
DictNode *next;
DictNode *prev;
};
struct Dict {
DictNode head;
void *frame;
int (*leq)(void *frame, DictKey key1, DictKey key2);
};
////////////////////////////////////////////////////////
/// inlined C code : ///////////////////////////////////
////////////////////////////////////////////////////////
#include <cstddef>
#include "memalloc"
inline Dict *dictNewDict( void *frame,int (*leq)(void *frame, DictKey key1, DictKey key2) ) {
Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
DictNode *head;
if (dict == NULL) return NULL;
head = &dict->head;
head->key = NULL;
head->next = head;
head->prev = head;
dict->frame = frame;
dict->leq = leq;
return dict;
}
inline void dictDeleteDict( Dict *dict ) {
DictNode *node, *next;
for( node = dict->head.next; node != &dict->head; node = next ) {
next = node->next;
memFree( node );
}
memFree( dict );
}
/* Search returns the node with the smallest key greater than or equal
* to the given key. If there is no such key, returns a node whose
* key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
*/
inline DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) {
DictNode *newNode;
do {
node = node->prev;
} while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
newNode = (DictNode *) memAlloc( sizeof( DictNode ));
if (newNode == NULL) return NULL;
newNode->key = key;
newNode->next = node->next;
node->next->prev = newNode;
newNode->prev = node;
node->next = newNode;
return newNode;
}
inline void dictDelete( Dict * /*dict*/, DictNode *node ) /*ARGSUSED*/
{
node->next->prev = node->prev;
node->prev->next = node->next;
memFree( node );
}
inline DictNode *dictSearch( Dict *dict, DictKey key )
{
DictNode *node = &dict->head;
do {
node = node->next;
} while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
return node;
}
#endif
+241
View File
@@ -0,0 +1,241 @@
// see license file for original license.
#ifndef tools_glutess_geom
#define tools_glutess_geom
#include "mesh"
#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t)
#define VertLeq(u,v) (((u)->s < (v)->s) || ((u)->s == (v)->s && (u)->t <= (v)->t))
#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
#define TransLeq(u,v) (((u)->t < (v)->t) || \
((u)->t == (v)->t && (u)->s <= (v)->s))
#define TransEval(u,v,w) __gl_transEval(u,v,w)
#define TransSign(u,v,w) __gl_transSign(u,v,w)
#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org )
#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst )
#define VertL1dist(u,v) (GLU_ABS(u->s - v->s) + GLU_ABS(u->t - v->t))
#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
////////////////////////////////////////////////////////
/// inlined C code : ///////////////////////////////////
////////////////////////////////////////////////////////
inline int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
{
/* Returns TOOLS_GLU_TRUE if u is lexicographically <= v. */
return VertLeq( u, v );
}
inline GLUdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
* Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
* If uw is vertical (and thus passes thru v), the result is zero.
*
* The calculation is extremely accurate and stable, even when v
* is very close to u or w. In particular if we set v->t = 0 and
* let r be the negated result (this evaluates (uw)(v->s)), then
* r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
*/
GLUdouble gapL, gapR;
assert( VertLeq( u, v ) && VertLeq( v, w ));
gapL = v->s - u->s;
gapR = w->s - v->s;
if( gapL + gapR > 0 ) {
if( gapL < gapR ) {
return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
} else {
return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
inline GLUdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Returns a number whose sign matches EdgeEval(u,v,w) but which
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
* as v is above, on, or below the edge uw.
*/
GLUdouble gapL, gapR;
/*
#define VertLeq(u,v) (((u)->s < (v)->s) || \
((u)->s == (v)->s && (u)->t <= (v)->t))
*/
assert( VertLeq( u, v ) && VertLeq( v, w ));
gapL = v->s - u->s;
gapR = w->s - v->s;
if( gapL + gapR > 0 ) {
return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
}
/* vertical line */
return 0;
}
/***********************************************************************
* Define versions of EdgeSign, EdgeEval with s and t transposed.
*/
inline GLUdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
* Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
* If uw is vertical (and thus passes thru v), the result is zero.
*
* The calculation is extremely accurate and stable, even when v
* is very close to u or w. In particular if we set v->s = 0 and
* let r be the negated result (this evaluates (uw)(v->t)), then
* r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
*/
GLUdouble gapL, gapR;
assert( TransLeq( u, v ) && TransLeq( v, w ));
gapL = v->t - u->t;
gapR = w->t - v->t;
if( gapL + gapR > 0 ) {
if( gapL < gapR ) {
return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
} else {
return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
inline GLUdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* Returns a number whose sign matches TransEval(u,v,w) but which
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
* as v is above, on, or below the edge uw.
*/
GLUdouble gapL, gapR;
assert( TransLeq( u, v ) && TransLeq( v, w ));
gapL = v->t - u->t;
gapR = w->t - v->t;
if( gapL + gapR > 0 ) {
return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
}
/* vertical line */
return 0;
}
inline int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
{
/* For almost-degenerate situations, the results are not reliable.
* Unless the floating-point arithmetic can be performed without
* rounding errors, *any* implementation will give incorrect results
* on some degenerate inputs, so the client must have some way to
* handle this situation.
*/
return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
}
/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
* or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
* this in the rare case that one argument is slightly negative.
* The implementation is extremely stable numerically.
* In particular it guarantees that the result r satisfies
* MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
* even when a and b differ greatly in magnitude.
*/
#define Interpolate(a,x,b,y) \
(a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
((a <= b) ? ((b == 0) ? ((x+y) / 2) \
: (x + (y-x) * (a/(a+b)))) \
: (y + (x-y) * (b/(a+b)))))
//#define Swap(a,b) if (1) { GLUvertex *t = a; a = b; b = t; } else
#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while(false)
inline void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
GLUvertex *o2, GLUvertex *d2,
GLUvertex *v )
/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
* The computed point is guaranteed to lie in the intersection of the
* bounding rectangles defined by each edge.
*/
{
GLUdouble z1, z2;
/* This is certainly not the most efficient way to find the intersection
* of two line segments, but it is very numerically stable.
*
* Strategy: find the two middle vertices in the VertLeq ordering,
* and interpolate the intersection s-value from these. Then repeat
* using the TransLeq ordering to find the intersection t-value.
*/
if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
if( ! VertLeq( o2, d1 )) {
/* Technically, no intersection -- do our best */
v->s = (o2->s + d1->s) / 2;
} else if( VertLeq( d1, d2 )) {
/* Interpolate between o2 and d1 */
z1 = EdgeEval( o1, o2, d1 );
z2 = EdgeEval( o2, d1, d2 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->s = Interpolate( z1, o2->s, z2, d1->s );
} else {
/* Interpolate between o2 and d2 */
z1 = EdgeSign( o1, o2, d1 );
z2 = -EdgeSign( o1, d2, d1 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->s = Interpolate( z1, o2->s, z2, d2->s );
}
/* Now repeat the process for t */
if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
if( ! TransLeq( o2, d1 )) {
/* Technically, no intersection -- do our best */
v->t = (o2->t + d1->t) / 2;
} else if( TransLeq( d1, d2 )) {
/* Interpolate between o2 and d1 */
z1 = TransEval( o1, o2, d1 );
z2 = TransEval( o2, d1, d2 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->t = Interpolate( z1, o2->t, z2, d1->t );
} else {
/* Interpolate between o2 and d2 */
z1 = TransSign( o1, o2, d1 );
z2 = -TransSign( o1, d2, d1 );
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
v->t = Interpolate( z1, o2->t, z2, d2->t );
}
}
#endif
+619
View File
@@ -0,0 +1,619 @@
// see license file for original license.
#ifndef tools_glutess_glutess
#define tools_glutess_glutess
#include "_tess"
GLUAPI GLUtesselator* GLUAPIENTRY gluNewTess (void);
GLUAPI void GLUAPIENTRY gluDeleteTess (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessBeginContour (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLUvoid* data);
GLUAPI void GLUAPIENTRY gluTessCallback (GLUtesselator* tess, GLUenum which, _GLUfuncptr CallBackFunc);
GLUAPI void GLUAPIENTRY gluTessEndContour (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
GLUAPI void GLUAPIENTRY gluTessNormal (GLUtesselator* tess, GLUdouble valueX, GLUdouble valueY, GLUdouble valueZ);
GLUAPI void GLUAPIENTRY gluTessProperty (GLUtesselator* tess, GLUenum which, GLUdouble data);
GLUAPI void GLUAPIENTRY gluTessVertex (GLUtesselator* tess, GLUdouble *location, GLUvoid* data);
#include "mesh"
#include "normal"
#include "sweep"
#include "tessmono"
#include "render"
#define GLU_TESS_DEFAULT_TOLERANCE 0.0
#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
/*ARGSUSED*/ inline/*static*/ void GLUAPIENTRY static_noBegin( GLUenum /*type*/ ) {}
/*ARGSUSED*/ inline/*static*/ void GLUAPIENTRY static_noEdgeFlag( GLUboolean /*boundaryEdge*/ ) {}
/*ARGSUSED*/ inline/*static*/ void GLUAPIENTRY static_noVertex( void * /*data*/ ) {}
/*ARGSUSED*/ inline/*static*/ void GLUAPIENTRY static_noEnd( void ) {}
/*ARGSUSED*/ inline/*static*/ void GLUAPIENTRY static_noError( GLUenum /*errnum*/ ) {}
/*ARGSUSED*/ inline/*static*/ void GLUAPIENTRY static_noCombine( GLUdouble /*coords*/[3], void* /*data*/[4],
GLUfloat /*weight*/[4], void** /*dataOut*/ ) {}
/*ARGSUSED*/ inline/*static*/ void GLUAPIENTRY static_noMesh( GLUmesh* /*mesh*/ ) {}
inline /*ARGSUSED*/ void GLUAPIENTRY __gl_noBeginData( GLUenum /*type*/, void* /*polygonData*/ ) {}
inline /*ARGSUSED*/ void GLUAPIENTRY __gl_noEdgeFlagData( GLUboolean /*boundaryEdge*/, void* /*polygonData*/ ) {}
inline /*ARGSUSED*/ void GLUAPIENTRY __gl_noVertexData( void* /*data*/, void* /*polygonData*/ ) {}
inline /*ARGSUSED*/ void GLUAPIENTRY __gl_noEndData( void* /*polygonData*/ ) {}
inline /*ARGSUSED*/ void GLUAPIENTRY __gl_noErrorData( GLUenum /*errnum*/, void* /*polygonData*/ ) {}
inline /*ARGSUSED*/ void GLUAPIENTRY __gl_noCombineData( GLUdouble /*coords*/[3],
void* /*data*/[4],
GLUfloat /*weight*/[4],
void** /*outData*/,
void* /*polygonData*/ ) {}
/* Half-edges are allocated in pairs (see mesh.c) */
//typedef struct { GLUhalfEdge e, eSym; } EdgePair;
inline size_t MAX_FAST_ALLOC() {
static const size_t s_value = (GLU_MAX(sizeof(EdgePair),GLU_MAX(sizeof(GLUvertex),sizeof(GLUface))));
return s_value;
}
inline GLUtesselator * GLUAPIENTRY
gluNewTess( void )
{
GLUtesselator *tess;
/* Only initialize fields which can be changed by the api. Other fields
* are initialized where they are used.
*/
if (memInit( MAX_FAST_ALLOC() ) == 0) {
return 0; /* out of memory */
}
tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
if (tess == NULL) {
return 0; /* out of memory */
}
tess->state = T_DORMANT;
tess->normal[0] = 0;
tess->normal[1] = 0;
tess->normal[2] = 0;
tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
tess->windingRule = GLU_TESS_WINDING_ODD;
tess->flagBoundary = TOOLS_GLU_FALSE;
tess->boundaryOnly = TOOLS_GLU_FALSE;
tess->callBegin = &static_noBegin;
tess->callEdgeFlag = &static_noEdgeFlag;
tess->callVertex = &static_noVertex;
tess->callEnd = &static_noEnd;
tess->callError = &static_noError;
tess->callCombine = &static_noCombine;
tess->callMesh = &static_noMesh;
tess->callBeginData= &__gl_noBeginData;
tess->callEdgeFlagData= &__gl_noEdgeFlagData;
tess->callVertexData= &__gl_noVertexData;
tess->callEndData= &__gl_noEndData;
tess->callErrorData= &__gl_noErrorData;
tess->callCombineData= &__gl_noCombineData;
tess->polygonData= NULL;
return tess;
}
inline/*static*/ void static_MakeDormant( GLUtesselator *tess )
{
/* Return the tessellator to its original dormant state. */
if( tess->mesh != NULL ) {
__gl_meshDeleteMesh( tess->mesh );
}
tess->state = T_DORMANT;
tess->lastEdge = NULL;
tess->mesh = NULL;
}
#define RequireState( tess, s ) if( tess->state != s ) static_GotoState(tess,s)
inline/*static*/ void static_GotoState( GLUtesselator *tess, enum TessState newState )
{
while( tess->state != newState ) {
/* We change the current state one level at a time, to get to
* the desired state.
*/
if( tess->state < newState ) {
switch( tess->state ) {
case T_DORMANT:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
gluTessBeginPolygon( tess, NULL );
break;
case T_IN_POLYGON:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
gluTessBeginContour( tess );
break;
default:
;
}
} else {
switch( tess->state ) {
case T_IN_CONTOUR:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
gluTessEndContour( tess );
break;
case T_IN_POLYGON:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
/* gluTessEndPolygon( tess ) is too much work! */
static_MakeDormant( tess );
break;
default:
;
}
}
}
}
inline void GLUAPIENTRY
gluDeleteTess( GLUtesselator *tess )
{
RequireState( tess, T_DORMANT );
memFree( tess );
}
inline void GLUAPIENTRY
gluTessProperty( GLUtesselator *tess, GLUenum which, GLUdouble value )
{
GLUenum windingRule;
switch( which ) {
case GLU_TESS_TOLERANCE:
if( value < 0.0 || value > 1.0 ) break;
tess->relTolerance = value;
return;
case GLU_TESS_WINDING_RULE:
windingRule = (GLUenum) value;
if( windingRule != value ) break; /* not an integer */
switch( windingRule ) {
case GLU_TESS_WINDING_ODD:
case GLU_TESS_WINDING_NONZERO:
case GLU_TESS_WINDING_POSITIVE:
case GLU_TESS_WINDING_NEGATIVE:
case GLU_TESS_WINDING_ABS_GEQ_TWO:
tess->windingRule = windingRule;
return;
default:
break;
}
return; //G.Barrand : add : seen with g++-8.1.0.
case GLU_TESS_BOUNDARY_ONLY:
tess->boundaryOnly = (value != 0);
return;
default:
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
return;
}
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
}
/* Returns tessellator property */
inline void GLUAPIENTRY
gluGetTessProperty( GLUtesselator *tess, GLUenum which, GLUdouble *value )
{
switch (which) {
case GLU_TESS_TOLERANCE:
/* tolerance should be in range [0..1] */
assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
*value= tess->relTolerance;
break;
case GLU_TESS_WINDING_RULE:
assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
tess->windingRule == GLU_TESS_WINDING_NONZERO ||
tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
*value= tess->windingRule;
break;
case GLU_TESS_BOUNDARY_ONLY:
assert(tess->boundaryOnly == TOOLS_GLU_TRUE || tess->boundaryOnly == TOOLS_GLU_FALSE);
*value= tess->boundaryOnly;
break;
default:
*value= 0.0;
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
break;
}
} /* gluGetTessProperty() */
inline void GLUAPIENTRY
gluTessNormal( GLUtesselator *tess, GLUdouble x, GLUdouble y, GLUdouble z )
{
tess->normal[0] = x;
tess->normal[1] = y;
tess->normal[2] = z;
}
// G.Barrand : begin : g++-8.1.0 : the five below functions introduced to avoid warnings :
// warning :cast between incompatible function types
inline void GLUAPIENTRY
gluTessCallback_GLU_TESS_VERTEX_DATA(GLUtesselator *tess,void (GLUAPIENTRY* a_fn)(void *, void *)) {
tess->callVertexData = (a_fn == NULL) ? &__gl_noVertexData : a_fn;
}
inline void GLUAPIENTRY
gluTessCallback_GLU_TESS_BEGIN_DATA(GLUtesselator *tess,void (GLUAPIENTRY* a_fn)(GLUenum, void *)) {
tess->callBeginData = (a_fn == NULL) ? &__gl_noBeginData : a_fn;
}
inline void GLUAPIENTRY
gluTessCallback_GLU_TESS_END_DATA(GLUtesselator *tess,void (GLUAPIENTRY* a_fn)(void *)) {
tess->callEndData = (a_fn == NULL) ? &__gl_noEndData : a_fn;
}
inline void GLUAPIENTRY
gluTessCallback_GLU_TESS_ERROR_DATA(GLUtesselator *tess,void (GLUAPIENTRY* a_fn)(GLUenum, void *)) {
tess->callErrorData = (a_fn == NULL) ? &__gl_noErrorData : a_fn;
}
inline void GLUAPIENTRY
gluTessCallback_GLU_TESS_COMBINE_DATA(GLUtesselator *tess,
void (GLUAPIENTRY* a_fn)(GLUdouble [3],void *[4],GLUfloat [4],void **,void *)) {
tess->callCombineData = (a_fn == NULL) ? &__gl_noCombineData : a_fn;
}
// G.Barrand : end : g++-8.1.0.
inline void GLUAPIENTRY
gluTessCallback( GLUtesselator *tess, GLUenum which, _GLUfuncptr fn)
{
switch( which ) {
case GLU_TESS_BEGIN:
tess->callBegin = (fn == NULL) ? &static_noBegin : (void (GLUAPIENTRY *)(GLUenum)) fn;
return;
case GLU_TESS_BEGIN_DATA:
tess->callBeginData = (fn == NULL) ?
&__gl_noBeginData : (void (GLUAPIENTRY *)(GLUenum, void *)) fn;
return;
case GLU_TESS_EDGE_FLAG:
tess->callEdgeFlag = (fn == NULL) ? &static_noEdgeFlag :
(void (GLUAPIENTRY *)(GLUboolean)) fn;
/* If the client wants boundary edges to be flagged,
* we render everything as separate triangles (no strips or fans).
*/
tess->flagBoundary = (fn != NULL);
return;
case GLU_TESS_EDGE_FLAG_DATA:
tess->callEdgeFlagData= (fn == NULL) ?
&__gl_noEdgeFlagData : (void (GLUAPIENTRY *)(GLUboolean, void *)) fn;
/* If the client wants boundary edges to be flagged,
* we render everything as separate triangles (no strips or fans).
*/
tess->flagBoundary = (fn != NULL);
return;
case GLU_TESS_VERTEX:
tess->callVertex = (fn == NULL) ? &static_noVertex :
(void (GLUAPIENTRY *)(void *)) fn;
return;
case GLU_TESS_VERTEX_DATA:
tess->callVertexData = (fn == NULL) ?
&__gl_noVertexData : (void (GLUAPIENTRY *)(void *, void *)) fn;
return;
case GLU_TESS_END:
tess->callEnd = (fn == NULL) ? &static_noEnd : (void (GLUAPIENTRY *)(void)) fn;
return;
case GLU_TESS_END_DATA:
tess->callEndData = (fn == NULL) ? &__gl_noEndData :
(void (GLUAPIENTRY *)(void *)) fn;
return;
case GLU_TESS_ERROR:
tess->callError = (fn == NULL) ? &static_noError : (void (GLUAPIENTRY *)(GLUenum)) fn;
return;
case GLU_TESS_ERROR_DATA:
tess->callErrorData = (fn == NULL) ?
&__gl_noErrorData : (void (GLUAPIENTRY *)(GLUenum, void *)) fn;
return;
case GLU_TESS_COMBINE:
tess->callCombine = (fn == NULL) ? &static_noCombine :
(void (GLUAPIENTRY *)(GLUdouble [3],void *[4], GLUfloat [4], void ** )) fn;
return;
case GLU_TESS_COMBINE_DATA:
tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
(void (GLUAPIENTRY *)(GLUdouble [3],
void *[4],
GLUfloat [4],
void **,
void *)) fn;
return;
case GLU_TESS_MESH:
tess->callMesh = (fn == NULL) ? &static_noMesh : (void (GLUAPIENTRY *)(GLUmesh *)) fn;
return;
default:
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
return;
}
}
inline/*static*/ int static_AddVertex( GLUtesselator *tess, GLUdouble coords[3], void *data )
{
GLUhalfEdge *e;
e = tess->lastEdge;
if( e == NULL ) {
/* Make a self-loop (one vertex, one edge). */
e = __gl_meshMakeEdge( tess->mesh );
if (e == NULL) return 0;
if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
} else {
/* Create a new vertex and edge which immediately follow e
* in the ordering around the left face.
*/
if (__gl_meshSplitEdge( e ) == NULL) return 0;
e = e->Lnext;
}
/* The new vertex is now e->Org. */
e->Org->data = data;
e->Org->coords[0] = coords[0];
e->Org->coords[1] = coords[1];
e->Org->coords[2] = coords[2];
/* The winding of an edge says how the winding number changes as we
* cross from the edge''s right face to its left face. We add the
* vertices in such an order that a CCW contour will add +1 to
* the winding number of the region inside the contour.
*/
e->winding = 1;
e->Sym->winding = -1;
tess->lastEdge = e;
return 1;
}
inline/*static*/ void static_CacheVertex( GLUtesselator *tess, GLUdouble coords[3], void *data )
{
CachedVertex *v = &tess->cache[tess->cacheCount];
v->data = data;
v->coords[0] = coords[0];
v->coords[1] = coords[1];
v->coords[2] = coords[2];
++tess->cacheCount;
}
inline/*static*/ int static_EmptyCache( GLUtesselator *tess )
{
CachedVertex *v = tess->cache;
CachedVertex *vLast;
tess->mesh = __gl_meshNewMesh();
if (tess->mesh == NULL) return 0;
for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
if ( !static_AddVertex( tess, v->coords, v->data ) ) return 0;
}
tess->cacheCount = 0;
tess->emptyCache = TOOLS_GLU_FALSE;
return 1;
}
inline void GLUAPIENTRY
gluTessVertex( GLUtesselator *tess, GLUdouble coords[3], void *data )
{
int i, tooLarge = TOOLS_GLU_FALSE;
GLUdouble x, clamped[3];
RequireState( tess, T_IN_CONTOUR );
if( tess->emptyCache ) {
if ( !static_EmptyCache( tess ) ) {
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
return;
}
tess->lastEdge = NULL;
}
for( i = 0; i < 3; ++i ) {
x = coords[i];
if( x < - GLU_TESS_MAX_COORD ) {
x = - GLU_TESS_MAX_COORD;
tooLarge = TOOLS_GLU_TRUE;
}
if( x > GLU_TESS_MAX_COORD ) {
x = GLU_TESS_MAX_COORD;
tooLarge = TOOLS_GLU_TRUE;
}
clamped[i] = x;
}
if( tooLarge ) {
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
}
if( tess->mesh == NULL ) {
if( tess->cacheCount < GLU_TESS_MAX_CACHE ) {
static_CacheVertex( tess, clamped, data );
return;
}
if ( !static_EmptyCache( tess ) ) {
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
return;
}
}
if ( !static_AddVertex( tess, clamped, data ) ) {
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
}
}
inline void GLUAPIENTRY
gluTessBeginPolygon( GLUtesselator *tess, void *data )
{
RequireState( tess, T_DORMANT );
tess->state = T_IN_POLYGON;
tess->cacheCount = 0;
tess->emptyCache = TOOLS_GLU_FALSE;
tess->mesh = NULL;
tess->polygonData= data;
}
inline void GLUAPIENTRY
gluTessBeginContour( GLUtesselator *tess )
{
RequireState( tess, T_IN_POLYGON );
tess->state = T_IN_CONTOUR;
tess->lastEdge = NULL;
if( tess->cacheCount > 0 ) {
/* Just set a flag so we don't get confused by empty contours
* -- these can be generated accidentally with the obsolete
* NextContour() interface.
*/
tess->emptyCache = TOOLS_GLU_TRUE;
}
}
inline void GLUAPIENTRY
gluTessEndContour( GLUtesselator *tess )
{
RequireState( tess, T_IN_CONTOUR );
tess->state = T_IN_POLYGON;
}
inline void GLUAPIENTRY
gluTessEndPolygon( GLUtesselator *tess )
{
GLUmesh *mesh;
if (setjmp(tess->env) != 0) {
/* come back here if out of memory */
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
return;
}
RequireState( tess, T_IN_POLYGON );
tess->state = T_DORMANT;
if( tess->mesh == NULL ) {
if( ! tess->flagBoundary && tess->callMesh == &static_noMesh ) {
/* Try some special code to make the easy cases go quickly
* (eg. convex polygons). This code does NOT handle multiple contours,
* intersections, edge flags, and of course it does not generate
* an explicit mesh either.
*/
if( __gl_renderCache( tess )) {
tess->polygonData= NULL;
return;
}
}
if ( !static_EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
}
/* Determine the polygon normal and project vertices onto the plane
* of the polygon.
*/
__gl_projectPolygon( tess );
/* __gl_computeInterior( tess ) computes the planar arrangement specified
* by the given contours, and further subdivides this arrangement
* into regions. Each region is marked "inside" if it belongs
* to the polygon, according to the rule given by tess->windingRule.
* Each interior region is guaranteed be monotone.
*/
if ( !__gl_computeInterior( tess ) ) {
longjmp(tess->env,1); /* could've used a label */
}
mesh = tess->mesh;
if( ! tess->fatalError ) {
int rc = 1;
/* If the user wants only the boundary contours, we throw away all edges
* except those which separate the interior from the exterior.
* Otherwise we tessellate all the regions marked "inside".
*/
if( tess->boundaryOnly ) {
rc = __gl_meshSetWindingNumber( mesh, 1, TOOLS_GLU_TRUE );
} else {
rc = __gl_meshTessellateInterior( mesh );
}
if (rc == 0) longjmp(tess->env,1); /* could've used a label */
__gl_meshCheckMesh( mesh );
if( tess->callBegin != &static_noBegin || tess->callEnd != &static_noEnd
|| tess->callVertex != &static_noVertex || tess->callEdgeFlag != &static_noEdgeFlag
|| tess->callBeginData != &__gl_noBeginData
|| tess->callEndData != &__gl_noEndData
|| tess->callVertexData != &__gl_noVertexData
|| tess->callEdgeFlagData != &__gl_noEdgeFlagData )
{
if( tess->boundaryOnly ) {
__gl_renderBoundary( tess, mesh ); /* output boundary contours */
} else {
__gl_renderMesh( tess, mesh ); /* output strips and fans */
}
}
if( tess->callMesh != &static_noMesh ) {
/* Throw away the exterior faces, so that all faces are interior.
* This way the user doesn't have to check the "inside" flag,
* and we don't need to even reveal its existence. It also leaves
* the freedom for an implementation to not generate the exterior
* faces in the first place.
*/
__gl_meshDiscardExterior( mesh );
(*tess->callMesh)( mesh ); /* user wants the mesh itself */
tess->mesh = NULL;
tess->polygonData= NULL;
return;
}
}
__gl_meshDeleteMesh( mesh );
tess->polygonData= NULL;
tess->mesh = NULL;
}
/*******************************************************/
/* Obsolete calls -- for backward compatibility */
/*
inline void GLUAPIENTRY
gluBeginPolygon( GLUtesselator *tess )
{
gluTessBeginPolygon( tess, NULL );
gluTessBeginContour( tess );
}
inline void GLUAPIENTRY
gluNextContour( GLUtesselator *tess, GLUenum type )
{
gluTessEndContour( tess );
gluTessBeginContour( tess );
}
inline void GLUAPIENTRY
gluEndPolygon( GLUtesselator *tess )
{
gluTessEndContour( tess );
gluTessEndPolygon( tess );
}
*/
#include "undef"
#endif
+33
View File
@@ -0,0 +1,33 @@
/*
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
*
* 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 including the dates of first publication and
* either this permission notice or a reference to
* http://oss.sgi.com/projects/FreeB/
* 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
* SILICON GRAPHICS, INC. 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.
*
* Except as contained in this notice, the name of Silicon Graphics, Inc.
* shall not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization from
* Silicon Graphics, Inc.
*/
/*
** Author: Eric Veach, July 1994.
**
*/
+45
View File
@@ -0,0 +1,45 @@
// see license file for original license.
#ifndef tools_glutess_memalloc
#define tools_glutess_memalloc
////////////////////////////////////////////////////////
/// inlined C code : ///////////////////////////////////
////////////////////////////////////////////////////////
#ifdef TOOLS_MEM
#include "../mem"
#include <cstdlib>
namespace tools {
inline void* mem_alloc(size_t a_size){
mem::increment(tools::s_malloc().c_str());
return ::malloc(a_size);
}
inline void* mem_realloc(void* a_ptr,size_t a_size){
if(a_ptr==NULL) mem::increment(tools::s_malloc().c_str());
return ::realloc(a_ptr,a_size);
}
inline void mem_free(void* a_ptr){
if(a_ptr!=NULL) mem::decrement(tools::s_malloc().c_str());
::free(a_ptr);
}
inline int mem_init( size_t /*maxFast*/) {return 1;}
}
#else
#include <cstdlib>
#include <cstring>
namespace tools {
inline void* mem_alloc(size_t a_size) {return ::memset( ::malloc( a_size ), 0xa5, a_size);}
inline void* mem_realloc(void* a_ptr,size_t a_size){return ::realloc(a_ptr,a_size);}
inline void mem_free(void* a_ptr){::free(a_ptr);}
inline int mem_init( size_t /*maxFast*/) {return 1;}
}
#endif
#define memAlloc tools::mem_alloc
#define memRealloc tools::mem_realloc
#define memFree tools::mem_free
#define memInit tools::mem_init
#endif
+973
View File
@@ -0,0 +1,973 @@
// see license file for original license.
#ifndef tools_glutess_mesh
#define tools_glutess_mesh
#include "_glu"
typedef struct GLUmesh GLUmesh;
typedef struct GLUvertex GLUvertex;
typedef struct GLUface GLUface;
typedef struct GLUhalfEdge GLUhalfEdge;
typedef struct ActiveRegion ActiveRegion; /* Internal data */
/* The mesh structure is similar in spirit, notation, and operations
* to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
* for the manipulation of general subdivisions and the computation of
* Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
* For a simplified description, see the course notes for CS348a,
* "Mathematical Foundations of Computer Graphics", available at the
* Stanford bookstore (and taught during the fall quarter).
* The implementation also borrows a tiny subset of the graph-based approach
* use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
* to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
*
* The fundamental data structure is the "half-edge". Two half-edges
* go together to make an edge, but they point in opposite directions.
* Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
* its origin vertex (Org), the face on its left side (Lface), and the
* adjacent half-edges in the CCW direction around the origin vertex
* (Onext) and around the left face (Lnext). There is also a "next"
* pointer for the global edge list (see below).
*
* The notation used for mesh navigation:
* Sym = the mate of a half-edge (same edge, but opposite direction)
* Onext = edge CCW around origin vertex (keep same origin)
* Dnext = edge CCW around destination vertex (keep same dest)
* Lnext = edge CCW around left face (dest becomes new origin)
* Rnext = edge CCW around right face (origin becomes new dest)
*
* "prev" means to substitute CW for CCW in the definitions above.
*
* The mesh keeps global lists of all vertices, faces, and edges,
* stored as doubly-linked circular lists with a dummy header node.
* The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
*
* The circular edge list is special; since half-edges always occur
* in pairs (e and e->Sym), each half-edge stores a pointer in only
* one direction. Starting at eHead and following the e->next pointers
* will visit each *edge* once (ie. e or e->Sym, but not both).
* e->Sym stores a pointer in the opposite direction, thus it is
* always true that e->Sym->next->Sym->next == e.
*
* Each vertex has a pointer to next and previous vertices in the
* circular list, and a pointer to a half-edge with this vertex as
* the origin (NULL if this is the dummy header). There is also a
* field "data" for client data.
*
* Each face has a pointer to the next and previous faces in the
* circular list, and a pointer to a half-edge with this face as
* the left face (NULL if this is the dummy header). There is also
* a field "data" for client data.
*
* Note that what we call a "face" is really a loop; faces may consist
* of more than one loop (ie. not simply connected), but there is no
* record of this in the data structure. The mesh may consist of
* several disconnected regions, so it may not be possible to visit
* the entire mesh by starting at a half-edge and traversing the edge
* structure.
*
* The mesh does NOT support isolated vertices; a vertex is deleted along
* with its last edge. Similarly when two faces are merged, one of the
* faces is deleted (see __gl_meshDelete below). For mesh operations,
* all face (loop) and vertex pointers must not be NULL. However, once
* mesh manipulation is finished, __gl_MeshZapFace can be used to delete
* faces of the mesh, one at a time. All external faces can be "zapped"
* before the mesh is returned to the client; then a NULL face indicates
* a region which is not part of the output polygon.
*/
struct GLUvertex {
GLUvertex *next; /* next vertex (never NULL) */
GLUvertex *prev; /* previous vertex (never NULL) */
GLUhalfEdge *anEdge; /* a half-edge with this origin */
void *data; /* client's data */
/* Internal data (keep hidden) */
GLUdouble coords[3]; /* vertex location in 3D */
GLUdouble s, t; /* projection onto the sweep plane */
long pqHandle; /* to allow deletion from priority queue */
};
struct GLUface {
GLUface *next; /* next face (never NULL) */
GLUface *prev; /* previous face (never NULL) */
GLUhalfEdge *anEdge; /* a half edge with this left face */
void *data; /* room for client's data */
/* Internal data (keep hidden) */
GLUface *trail; /* "stack" for conversion to strips */
GLUboolean marked; /* flag for conversion to strips */
GLUboolean inside; /* this face is in the polygon interior */
};
struct GLUhalfEdge {
GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
GLUhalfEdge *Sym; /* same edge, opposite direction */
GLUhalfEdge *Onext; /* next edge CCW around origin */
GLUhalfEdge *Lnext; /* next edge CCW around left face */
GLUvertex *Org; /* origin vertex (Overtex too long) */
GLUface *Lface; /* left face */
/* Internal data (keep hidden) */
ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
int winding; /* change in winding number when crossing
from the right face to the left face */
};
#define Rface Sym->Lface
#define Dst Sym->Org
#define Oprev Sym->Lnext
#define Lprev Onext->Sym
#define Dprev Lnext->Sym
#define Rprev Sym->Onext
#define Dnext Rprev->Sym /* 3 pointers */
#define Rnext Oprev->Sym /* 3 pointers */
struct GLUmesh {
GLUvertex vHead; /* dummy header for vertex list */
GLUface fHead; /* dummy header for face list */
GLUhalfEdge eHead; /* dummy header for edge list */
GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
};
/* The mesh operations below have three motivations: completeness,
* convenience, and efficiency. The basic mesh operations are MakeEdge,
* Splice, and Delete. All the other edge operations can be implemented
* in terms of these. The other operations are provided for convenience
* and/or efficiency.
*
* When a face is split or a vertex is added, they are inserted into the
* global list *before* the existing vertex or face (ie. e->Org or e->Lface).
* This makes it easier to process all vertices or faces in the global lists
* without worrying about processing the same data twice. As a convenience,
* when a face is split, the "inside" flag is copied from the old face.
* Other internal data (v->data, v->activeRegion, f->data, f->marked,
* f->trail, e->winding) is set to zero.
*
* ********************** Basic Edge Operations **************************
*
* __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
* The loop (face) consists of the two new half-edges.
*
* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
* mesh connectivity and topology. It changes the mesh so that
* eOrg->Onext <- OLD( eDst->Onext )
* eDst->Onext <- OLD( eOrg->Onext )
* where OLD(...) means the value before the meshSplice operation.
*
* This can have two effects on the vertex structure:
* - if eOrg->Org != eDst->Org, the two vertices are merged together
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
*
* Similarly (and independently) for the face structure,
* - if eOrg->Lface == eDst->Lface, one loop is split into two
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
*
* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
* the newly created loop will contain eDel->Dst. If the deletion of eDel
* would create isolated vertices, those are deleted as well.
*
* ********************** Other Edge Operations **************************
*
* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
* eOrg and eNew will have the same left face.
*
* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
* eOrg and eNew will have the same left face.
*
* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
* to eDst->Org, and returns the corresponding half-edge eNew.
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
* loops are merged into one, and the loop eDst->Lface is destroyed.
*
* ************************ Other Operations *****************************
*
* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
* and no loops (what we usually call a "face").
*
* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
* both meshes, and returns the new mesh (the old meshes are destroyed).
*
* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
*
* __gl_meshZapFace( fZap ) destroys a face and removes it from the
* global face list. All edges of fZap will have a NULL pointer as their
* left face. Any edges which also have a NULL pointer as their right face
* are deleted entirely (along with any isolated vertices this produces).
* An entire mesh can be deleted by zapping its faces, one at a time,
* in any order. Zapped faces cannot be used in further mesh operations!
*
* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
*/
////////////////////////////////////////////////////////
/// inlined C code : ///////////////////////////////////
////////////////////////////////////////////////////////
//#include "gluos"
#include <cstddef>
#include <cassert>
#include "memalloc"
inline/*static*/ GLUvertex *static_allocVertex()
{
return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
}
inline/*static*/ GLUface *static_allocFace()
{
return (GLUface *)memAlloc( sizeof( GLUface ));
}
/************************ Utility Routines ************************/
/* Allocate and free half-edges in pairs for efficiency.
* The *only* place that should use this fact is allocation/free.
*/
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
/* MakeEdge creates a new pair of half-edges which form their own loop.
* No vertex or face structures are allocated, but these must be assigned
* before the current edge operation is completed.
*/
inline/*static*/ GLUhalfEdge *static_MakeEdge( GLUhalfEdge *eNext )
{
GLUhalfEdge *e;
GLUhalfEdge *eSym;
GLUhalfEdge *ePrev;
EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
if (pair == NULL) return NULL;
e = &pair->e;
eSym = &pair->eSym;
/* Make sure eNext points to the first edge of the edge pair */
if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
/* Insert in circular doubly-linked list before eNext.
* Note that the prev pointer is stored in Sym->next.
*/
ePrev = eNext->Sym->next;
eSym->next = ePrev;
ePrev->Sym->next = e;
e->next = eNext;
eNext->Sym->next = eSym;
e->Sym = eSym;
e->Onext = e;
e->Lnext = eSym;
e->Org = NULL;
e->Lface = NULL;
e->winding = 0;
e->activeRegion = NULL;
eSym->Sym = e;
eSym->Onext = eSym;
eSym->Lnext = e;
eSym->Org = NULL;
eSym->Lface = NULL;
eSym->winding = 0;
eSym->activeRegion = NULL;
return e;
}
/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
* CS348a notes (see mesh.h). Basically it modifies the mesh so that
* a->Onext and b->Onext are exchanged. This can have various effects
* depending on whether a and b belong to different face or vertex rings.
* For more explanation see __gl_meshSplice() below.
*/
inline/*static*/ void static_Splice( GLUhalfEdge *a, GLUhalfEdge *b )
{
GLUhalfEdge *aOnext = a->Onext;
GLUhalfEdge *bOnext = b->Onext;
aOnext->Sym->Lnext = b;
bOnext->Sym->Lnext = a;
a->Onext = bOnext;
b->Onext = aOnext;
}
/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
* origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
* a place to insert the new vertex in the global vertex list. We insert
* the new vertex *before* vNext so that algorithms which walk the vertex
* list will not see the newly created vertices.
*/
inline/*static*/ void static_MakeVertex( GLUvertex *newVertex,
GLUhalfEdge *eOrig, GLUvertex *vNext )
{
GLUhalfEdge *e;
GLUvertex *vPrev;
GLUvertex *vNew = newVertex;
assert(vNew != NULL);
/* insert in circular doubly-linked list before vNext */
vPrev = vNext->prev;
vNew->prev = vPrev;
vPrev->next = vNew;
vNew->next = vNext;
vNext->prev = vNew;
vNew->anEdge = eOrig;
vNew->data = NULL;
/* leave coords, s, t undefined */
/* fix other edges on this vertex loop */
e = eOrig;
do {
e->Org = vNew;
e = e->Onext;
} while( e != eOrig );
}
/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
* face of all edges in the face loop to which eOrig belongs. "fNext" gives
* a place to insert the new face in the global face list. We insert
* the new face *before* fNext so that algorithms which walk the face
* list will not see the newly created faces.
*/
inline/*static*/ void static_MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
{
GLUhalfEdge *e;
GLUface *fPrev;
GLUface *fNew = newFace;
assert(fNew != NULL);
/* insert in circular doubly-linked list before fNext */
fPrev = fNext->prev;
fNew->prev = fPrev;
fPrev->next = fNew;
fNew->next = fNext;
fNext->prev = fNew;
fNew->anEdge = eOrig;
fNew->data = NULL;
fNew->trail = NULL;
fNew->marked = TOOLS_GLU_FALSE;
/* The new face is marked "inside" if the old one was. This is a
* convenience for the common case where a face has been split in two.
*/
fNew->inside = fNext->inside;
/* fix other edges on this face loop */
e = eOrig;
do {
e->Lface = fNew;
e = e->Lnext;
} while( e != eOrig );
}
/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
* and removes from the global edge list.
*/
inline/*static*/ void static_KillEdge( GLUhalfEdge *eDel )
{
GLUhalfEdge *ePrev, *eNext;
/* Half-edges are allocated in pairs, see EdgePair above */
if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
/* delete from circular doubly-linked list */
eNext = eDel->next;
ePrev = eDel->Sym->next;
eNext->Sym->next = ePrev;
ePrev->Sym->next = eNext;
memFree( eDel );
}
/* KillVertex( vDel ) destroys a vertex and removes it from the global
* vertex list. It updates the vertex loop to point to a given new vertex.
*/
inline/*static*/ void static_KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
{
GLUhalfEdge *e, *eStart = vDel->anEdge;
GLUvertex *vPrev, *vNext;
/* change the origin of all affected edges */
e = eStart;
do {
e->Org = newOrg;
e = e->Onext;
} while( e != eStart );
/* delete from circular doubly-linked list */
vPrev = vDel->prev;
vNext = vDel->next;
vNext->prev = vPrev;
vPrev->next = vNext;
memFree( vDel );
}
/* KillFace( fDel ) destroys a face and removes it from the global face
* list. It updates the face loop to point to a given new face.
*/
inline/*static*/ void static_KillFace( GLUface *fDel, GLUface *newLface )
{
GLUhalfEdge *e, *eStart = fDel->anEdge;
GLUface *fPrev, *fNext;
/* change the left face of all affected edges */
e = eStart;
do {
e->Lface = newLface;
e = e->Lnext;
} while( e != eStart );
/* delete from circular doubly-linked list */
fPrev = fDel->prev;
fNext = fDel->next;
fNext->prev = fPrev;
fPrev->next = fNext;
memFree( fDel );
}
/****************** Basic Edge Operations **********************/
/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
* The loop consists of the two new half-edges.
*/
inline GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
{
GLUvertex *newVertex1= static_allocVertex();
GLUvertex *newVertex2= static_allocVertex();
GLUface *newFace= static_allocFace();
GLUhalfEdge *e;
/* if any one is null then all get freed */
if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
if (newVertex1 != NULL) memFree(newVertex1);
if (newVertex2 != NULL) memFree(newVertex2);
if (newFace != NULL) memFree(newFace);
return NULL;
}
e = static_MakeEdge( &mesh->eHead );
if (e == NULL) {
memFree(newVertex1);
memFree(newVertex2);
memFree(newFace);
return NULL;
}
static_MakeVertex( newVertex1, e, &mesh->vHead );
static_MakeVertex( newVertex2, e->Sym, &mesh->vHead );
static_MakeFace( newFace, e, &mesh->fHead );
return e;
}
/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
* mesh connectivity and topology. It changes the mesh so that
* eOrg->Onext <- OLD( eDst->Onext )
* eDst->Onext <- OLD( eOrg->Onext )
* where OLD(...) means the value before the meshSplice operation.
*
* This can have two effects on the vertex structure:
* - if eOrg->Org != eDst->Org, the two vertices are merged together
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
*
* Similarly (and independently) for the face structure,
* - if eOrg->Lface == eDst->Lface, one loop is split into two
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
*
* Some special cases:
* If eDst == eOrg, the operation has no effect.
* If eDst == eOrg->Lnext, the new face will have a single edge.
* If eDst == eOrg->Lprev, the old face will have a single edge.
* If eDst == eOrg->Onext, the new vertex will have a single edge.
* If eDst == eOrg->Oprev, the old vertex will have a single edge.
*/
inline int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
{
int joiningLoops = TOOLS_GLU_FALSE;
int joiningVertices = TOOLS_GLU_FALSE;
if( eOrg == eDst ) return 1;
if( eDst->Org != eOrg->Org ) {
/* We are merging two disjoint vertices -- destroy eDst->Org */
joiningVertices = TOOLS_GLU_TRUE;
static_KillVertex( eDst->Org, eOrg->Org );
}
if( eDst->Lface != eOrg->Lface ) {
/* We are connecting two disjoint loops -- destroy eDst->Lface */
joiningLoops = TOOLS_GLU_TRUE;
static_KillFace( eDst->Lface, eOrg->Lface );
}
/* Change the edge structure */
static_Splice( eDst, eOrg );
if( ! joiningVertices ) {
GLUvertex *newVertex= static_allocVertex();
if (newVertex == NULL) return 0;
/* We split one vertex into two -- the new vertex is eDst->Org.
* Make sure the old vertex points to a valid half-edge.
*/
static_MakeVertex( newVertex, eDst, eOrg->Org );
eOrg->Org->anEdge = eOrg;
}
if( ! joiningLoops ) {
GLUface *newFace= static_allocFace();
if (newFace == NULL) return 0;
/* We split one loop into two -- the new loop is eDst->Lface.
* Make sure the old face points to a valid half-edge.
*/
static_MakeFace( newFace, eDst, eOrg->Lface );
eOrg->Lface->anEdge = eOrg;
}
return 1;
}
/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
* the newly created loop will contain eDel->Dst. If the deletion of eDel
* would create isolated vertices, those are deleted as well.
*
* This function could be implemented as two calls to __gl_meshSplice
* plus a few calls to memFree, but this would allocate and delete
* unnecessary vertices and faces.
*/
inline int __gl_meshDelete( GLUhalfEdge *eDel )
{
GLUhalfEdge *eDelSym = eDel->Sym;
int joiningLoops = TOOLS_GLU_FALSE;
/* First step: disconnect the origin vertex eDel->Org. We make all
* changes to get a consistent mesh in this "intermediate" state.
*/
if( eDel->Lface != eDel->Rface ) {
/* We are joining two loops into one -- remove the left face */
joiningLoops = TOOLS_GLU_TRUE;
static_KillFace( eDel->Lface, eDel->Rface );
/* G.Barrand : note : Coverity says that there is a problem using eDel->Lface->anEdge in the below,
but it appears that at the out of the upper static_KillFace() call (then here), eDel->Lface before
(the pointer freeed) is not the same than after (then here). */
}
if( eDel->Onext == eDel ) {
static_KillVertex( eDel->Org, NULL );
} else {
/* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
eDel->Rface->anEdge = eDel->Oprev;
eDel->Org->anEdge = eDel->Onext;
static_Splice( eDel, eDel->Oprev );
if( ! joiningLoops ) {
GLUface *newFace= static_allocFace();
if (newFace == NULL) return 0;
/* We are splitting one loop into two -- create a new loop for eDel. */
static_MakeFace( newFace, eDel, eDel->Lface );
}
}
/* Claim: the mesh is now in a consistent state, except that eDel->Org
* may have been deleted. Now we disconnect eDel->Dst.
*/
if( eDelSym->Onext == eDelSym ) {
static_KillVertex( eDelSym->Org, NULL );
static_KillFace( eDelSym->Lface, NULL );
} else {
/* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
eDel->Lface->anEdge = eDelSym->Oprev;
eDelSym->Org->anEdge = eDelSym->Onext;
static_Splice( eDelSym, eDelSym->Oprev );
}
/* Any isolated vertices or faces have already been freed. */
static_KillEdge( eDel );
return 1;
}
/******************** Other Edge Operations **********************/
/* All these routines can be implemented with the basic edge
* operations above. They are provided for convenience and efficiency.
*/
/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
* eOrg and eNew will have the same left face.
*/
inline GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
{
GLUhalfEdge *eNewSym;
GLUhalfEdge *eNew = static_MakeEdge( eOrg );
if (eNew == NULL) return NULL;
eNewSym = eNew->Sym;
/* Connect the new edge appropriately */
static_Splice( eNew, eOrg->Lnext );
/* Set the vertex and face information */
eNew->Org = eOrg->Dst;
{
GLUvertex *newVertex= static_allocVertex();
if (newVertex == NULL) return NULL;
static_MakeVertex( newVertex, eNewSym, eNew->Org );
}
eNew->Lface = eNewSym->Lface = eOrg->Lface;
return eNew;
}
/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
* eOrg and eNew will have the same left face.
*/
inline GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
{
GLUhalfEdge *eNew;
GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
if (tempHalfEdge == NULL) return NULL;
eNew = tempHalfEdge->Sym;
/* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
static_Splice( eOrg->Sym, eOrg->Sym->Oprev );
static_Splice( eOrg->Sym, eNew );
/* Set the vertex and face information */
eOrg->Dst = eNew->Org;
eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
eNew->Rface = eOrg->Rface;
eNew->winding = eOrg->winding; /* copy old winding information */
eNew->Sym->winding = eOrg->Sym->winding;
return eNew;
}
/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
* to eDst->Org, and returns the corresponding half-edge eNew.
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
* loops are merged into one, and the loop eDst->Lface is destroyed.
*
* If (eOrg == eDst), the new face will have only two edges.
* If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
* If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
*/
inline GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
{
GLUhalfEdge *eNewSym;
int joiningLoops = TOOLS_GLU_FALSE;
GLUhalfEdge *eNew = static_MakeEdge( eOrg );
if (eNew == NULL) return NULL;
eNewSym = eNew->Sym;
if( eDst->Lface != eOrg->Lface ) {
/* We are connecting two disjoint loops -- destroy eDst->Lface */
joiningLoops = TOOLS_GLU_TRUE;
static_KillFace( eDst->Lface, eOrg->Lface );
}
/* Connect the new edge appropriately */
static_Splice( eNew, eOrg->Lnext );
static_Splice( eNewSym, eDst );
/* Set the vertex and face information */
eNew->Org = eOrg->Dst;
eNewSym->Org = eDst->Org;
eNew->Lface = eNewSym->Lface = eOrg->Lface;
/* Make sure the old face points to a valid half-edge */
eOrg->Lface->anEdge = eNewSym;
if( ! joiningLoops ) {
GLUface *newFace= static_allocFace();
if (newFace == NULL) return NULL;
/* We split one loop into two -- the new loop is eNew->Lface */
static_MakeFace( newFace, eNew, eOrg->Lface );
}
return eNew;
}
/******************** Other Operations **********************/
/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
* global face list. All edges of fZap will have a NULL pointer as their
* left face. Any edges which also have a NULL pointer as their right face
* are deleted entirely (along with any isolated vertices this produces).
* An entire mesh can be deleted by zapping its faces, one at a time,
* in any order. Zapped faces cannot be used in further mesh operations!
*/
inline void __gl_meshZapFace( GLUface *fZap )
{
GLUhalfEdge *eStart = fZap->anEdge;
GLUhalfEdge *e, *eNext, *eSym;
GLUface *fPrev, *fNext;
/* walk around face, deleting edges whose right face is also NULL */
eNext = eStart->Lnext;
do {
e = eNext;
eNext = e->Lnext;
e->Lface = NULL;
if( e->Rface == NULL ) {
/* delete the edge -- see __gl_MeshDelete above */
if( e->Onext == e ) {
static_KillVertex( e->Org, NULL );
} else {
/* Make sure that e->Org points to a valid half-edge */
e->Org->anEdge = e->Onext;
static_Splice( e, e->Oprev );
}
eSym = e->Sym;
if( eSym->Onext == eSym ) {
static_KillVertex( eSym->Org, NULL );
} else {
/* Make sure that eSym->Org points to a valid half-edge */
eSym->Org->anEdge = eSym->Onext;
static_Splice( eSym, eSym->Oprev );
}
static_KillEdge( e );
}
} while( e != eStart );
/* delete from circular doubly-linked list */
fPrev = fZap->prev;
fNext = fZap->next;
fNext->prev = fPrev;
fPrev->next = fNext;
memFree( fZap );
}
/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
* and no loops (what we usually call a "face").
*/
inline GLUmesh *__gl_meshNewMesh( void )
{
GLUvertex *v;
GLUface *f;
GLUhalfEdge *e;
GLUhalfEdge *eSym;
GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
if (mesh == NULL) {
return NULL;
}
v = &mesh->vHead;
f = &mesh->fHead;
e = &mesh->eHead;
eSym = &mesh->eHeadSym;
v->next = v->prev = v;
v->anEdge = NULL;
v->data = NULL;
f->next = f->prev = f;
f->anEdge = NULL;
f->data = NULL;
f->trail = NULL;
f->marked = TOOLS_GLU_FALSE;
f->inside = TOOLS_GLU_FALSE;
e->next = e;
e->Sym = eSym;
e->Onext = NULL;
e->Lnext = NULL;
e->Org = NULL;
e->Lface = NULL;
e->winding = 0;
e->activeRegion = NULL;
eSym->next = eSym;
eSym->Sym = e;
eSym->Onext = NULL;
eSym->Lnext = NULL;
eSym->Org = NULL;
eSym->Lface = NULL;
eSym->winding = 0;
eSym->activeRegion = NULL;
return mesh;
}
/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
* both meshes, and returns the new mesh (the old meshes are destroyed).
*/
inline GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
{
GLUface *f1 = &mesh1->fHead;
GLUvertex *v1 = &mesh1->vHead;
GLUhalfEdge *e1 = &mesh1->eHead;
GLUface *f2 = &mesh2->fHead;
GLUvertex *v2 = &mesh2->vHead;
GLUhalfEdge *e2 = &mesh2->eHead;
/* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
if( f2->next != f2 ) {
f1->prev->next = f2->next;
f2->next->prev = f1->prev;
f2->prev->next = f1;
f1->prev = f2->prev;
}
if( v2->next != v2 ) {
v1->prev->next = v2->next;
v2->next->prev = v1->prev;
v2->prev->next = v1;
v1->prev = v2->prev;
}
if( e2->next != e2 ) {
e1->Sym->next->Sym->next = e2->next;
e2->next->Sym->next = e1->Sym->next;
e2->Sym->next->Sym->next = e1;
e1->Sym->next = e2->Sym->next;
}
memFree( mesh2 );
return mesh1;
}
#ifdef DELETE_BY_ZAPPING
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
*/
inline void __gl_meshDeleteMesh( GLUmesh *mesh )
{
GLUface *fHead = &mesh->fHead;
while( fHead->next != fHead ) {
__gl_meshZapFace( fHead->next );
}
assert( mesh->vHead.next == &mesh->vHead );
memFree( mesh );
}
#else
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
*/
inline void __gl_meshDeleteMesh( GLUmesh *mesh )
{
GLUface *f, *fNext;
GLUvertex *v, *vNext;
GLUhalfEdge *e, *eNext;
for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
fNext = f->next;
memFree( f );
}
for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
vNext = v->next;
memFree( v );
}
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
/* One call frees both e and e->Sym (see EdgePair above) */
eNext = e->next;
memFree( e );
}
memFree( mesh );
}
#endif
inline void __gl_meshCheckMesh( GLUmesh *mesh )
{
GLUface *fHead = &mesh->fHead;
GLUvertex *vHead = &mesh->vHead;
GLUhalfEdge *eHead = &mesh->eHead;
GLUface *f, *fPrev;
GLUvertex *v, *vPrev;
GLUhalfEdge *e, *ePrev;
fPrev = fHead;
for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
assert( f->prev == fPrev );
e = f->anEdge;
do {
assert( e->Sym != e );
assert( e->Sym->Sym == e );
assert( e->Lnext->Onext->Sym == e );
assert( e->Onext->Sym->Lnext == e );
assert( e->Lface == f );
e = e->Lnext;
} while( e != f->anEdge );
}
assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
vPrev = vHead;
for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
assert( v->prev == vPrev );
e = v->anEdge;
do {
assert( e->Sym != e );
assert( e->Sym->Sym == e );
assert( e->Lnext->Onext->Sym == e );
assert( e->Onext->Sym->Lnext == e );
assert( e->Org == v );
e = e->Onext;
} while( e != v->anEdge );
}
assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
ePrev = eHead;
for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
assert( e->Sym->next == ePrev->Sym );
assert( e->Sym != e );
assert( e->Sym->Sym == e );
assert( e->Org != NULL );
assert( e->Dst != NULL );
assert( e->Lnext->Onext->Sym == e );
assert( e->Onext->Sym->Lnext == e );
}
assert( e->Sym->next == ePrev->Sym
&& e->Sym == &mesh->eHeadSym
&& e->Sym->Sym == e
&& e->Org == NULL && e->Dst == NULL
&& e->Lface == NULL && e->Rface == NULL );
}
#endif
+209
View File
@@ -0,0 +1,209 @@
// see license file for original license.
#ifndef tools_glutess_normal
#define tools_glutess_normal
#include "_tess"
/* __gl_projectPolygon( tess ) determines the polygon normal
* and project vertices onto the plane of the polygon.
*/
//void __gl_projectPolygon( GLUtesselator *tess );
////////////////////////////////////////////////////////
/// inlined C code : ///////////////////////////////////
////////////////////////////////////////////////////////
#include <cmath>
#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
inline/*static*/ int static_LongAxis( GLUdouble v[3] )
{
int i = 0;
if( GLU_ABS(v[1]) > GLU_ABS(v[0]) ) { i = 1; }
if( GLU_ABS(v[2]) > GLU_ABS(v[i]) ) { i = 2; }
return i;
}
inline/*static*/ void static_ComputeNormal( GLUtesselator *tess, GLUdouble norm[3] )
{
GLUvertex *v, *v1, *v2;
GLUdouble c, tLen2, maxLen2;
GLUdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
GLUvertex *maxVert[3], *minVert[3];
GLUvertex *vHead = &tess->mesh->vHead;
int i;
maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
minVert[0] = 0;minVert[1] = 0;minVert[2] = 0; //G.Barrand : to quiet Coverity.
maxVert[0] = 0;maxVert[1] = 0;maxVert[2] = 0; //G.Barrand : to quiet Coverity.
for( v = vHead->next; v != vHead; v = v->next ) {
for( i = 0; i < 3; ++i ) {
c = v->coords[i];
if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
}
}
/* Find two vertices separated by at least 1/sqrt(3) of the maximum
* distance between any two vertices
*/
i = 0;
if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
if( minVal[i] >= maxVal[i] ) {
/* All vertices are the same -- normal doesn't matter */
norm[0] = 0; norm[1] = 0; norm[2] = 1;
return;
}
/* Look for a third vertex which forms the triangle with maximum area
* (Length of normal == twice the triangle area)
*/
maxLen2 = 0;
v1 = minVert[i];
v2 = maxVert[i];
if( !v1 || !v2 ) {norm[0] = 0; norm[1] = 0; norm[2] = 1;return;} //G.Barrand.
d1[0] = v1->coords[0] - v2->coords[0];
d1[1] = v1->coords[1] - v2->coords[1];
d1[2] = v1->coords[2] - v2->coords[2];
for( v = vHead->next; v != vHead; v = v->next ) {
d2[0] = v->coords[0] - v2->coords[0];
d2[1] = v->coords[1] - v2->coords[1];
d2[2] = v->coords[2] - v2->coords[2];
tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
if( tLen2 > maxLen2 ) {
maxLen2 = tLen2;
norm[0] = tNorm[0];
norm[1] = tNorm[1];
norm[2] = tNorm[2];
}
}
if( maxLen2 <= 0 ) {
/* All points lie on a single line -- any decent normal will do */
norm[0] = norm[1] = norm[2] = 0;
norm[static_LongAxis(d1)] = 1;
}
}
inline/*static*/ void static_CheckOrientation( GLUtesselator *tess )
{
GLUdouble area;
GLUface *f, *fHead = &tess->mesh->fHead;
GLUvertex *v, *vHead = &tess->mesh->vHead;
GLUhalfEdge *e;
/* When we compute the normal automatically, we choose the orientation
* so that the sum of the signed areas of all contours is non-negative.
*/
area = 0;
for( f = fHead->next; f != fHead; f = f->next ) {
e = f->anEdge;
if( e->winding <= 0 ) continue;
do {
area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
e = e->Lnext;
} while( e != f->anEdge );
}
if( area < 0 ) {
/* Reverse the orientation by flipping all the t-coordinates */
for( v = vHead->next; v != vHead; v = v->next ) {
v->t = - v->t;
}
tess->tUnit[0] = - tess->tUnit[0];
tess->tUnit[1] = - tess->tUnit[1];
tess->tUnit[2] = - tess->tUnit[2];
}
}
#if defined(SLANTED_SWEEP)
/* The "feature merging" is not intended to be complete. There are
* special cases where edges are nearly parallel to the sweep line
* which are not implemented. The algorithm should still behave
* robustly (ie. produce a reasonable tesselation) in the presence
* of such edges, however it may miss features which could have been
* merged. We could minimize this effect by choosing the sweep line
* direction to be something unusual (ie. not parallel to one of the
* coordinate axes).
*/
#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
#define S_UNIT_Y 0.86052074622010633
#else
#define S_UNIT_X 1.0
#define S_UNIT_Y 0.0
#endif
/* Determine the polygon normal and project vertices onto the plane
* of the polygon.
*/
inline void __gl_projectPolygon( GLUtesselator *tess )
{
GLUvertex *v, *vHead = &tess->mesh->vHead;
GLUdouble norm[3];
GLUdouble *sUnit, *tUnit;
int i, computedNormal = TOOLS_GLU_FALSE;
norm[0] = tess->normal[0];
norm[1] = tess->normal[1];
norm[2] = tess->normal[2];
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
static_ComputeNormal( tess, norm );
computedNormal = TOOLS_GLU_TRUE;
}
sUnit = tess->sUnit;
tUnit = tess->tUnit;
i = static_LongAxis( norm );
#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
/* Choose the initial sUnit vector to be approximately perpendicular
* to the normal.
*/
Normalize( norm );
sUnit[i] = 0;
sUnit[(i+1)%3] = S_UNIT_X;
sUnit[(i+2)%3] = S_UNIT_Y;
/* Now make it exactly perpendicular */
w = Dot( sUnit, norm );
sUnit[0] -= w * norm[0];
sUnit[1] -= w * norm[1];
sUnit[2] -= w * norm[2];
Normalize( sUnit );
/* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
Normalize( tUnit );
#else
/* Project perpendicular to a coordinate axis -- better numerically */
sUnit[i] = 0;
sUnit[(i+1)%3] = S_UNIT_X;
sUnit[(i+2)%3] = S_UNIT_Y;
tUnit[i] = 0;
tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
#endif
/* Project the vertices onto the sweep plane */
for( v = vHead->next; v != vHead; v = v->next ) {
v->s = Dot( v->coords, sUnit );
v->t = Dot( v->coords, tUnit );
}
if( computedNormal ) {
static_CheckOrientation( tess );
}
}
#endif
+572
View File
@@ -0,0 +1,572 @@
// see license file for original license.
#ifndef tools_glutess_priorityq
#define tools_glutess_priorityq
#include <climits> /* LONG_MAX */
#include "memalloc"
/* Include all the code for the regular heap-based queue here. */
/////////////////////////////////////////////////////////////////
//#include "priorityq-heap.ic"
//#include "priorityq-heap"
/* Use #define's so that another heap implementation can use this one */
#define PQkey PQHeapKey
#define PQhandle PQHeapHandle
#define PriorityQ PriorityQHeap
#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq)
#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq)
/* The basic operations are insertion of a new key (pqInsert),
* and examination/extraction of a key whose value is minimum
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
* for this purpose pqInsert returns a "handle" which is supplied
* as the argument.
*
* An initial heap may be created efficiently by calling pqInsert
* repeatedly, then calling pqInit. In any case pqInit must be called
* before any operations other than pqInsert are used.
*
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
* This may also be tested with pqIsEmpty.
*/
#define pqInit(pq) __gl_pqHeapInit(pq)
#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key)
#define pqMinimum(pq) __gl_pqHeapMinimum(pq)
#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq)
#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle)
#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq)
/* Since we support deletion the data structure is a little more
* complicated than an ordinary heap. "nodes" is the heap itself;
* active nodes are stored in the range 1..pq->size. When the
* heap exceeds its allocated size (pq->max), its size doubles.
* The children of node i are nodes 2i and 2i+1.
*
* Each node stores an index into an array "handles". Each handle
* stores a key, plus a pointer back to the node which currently
* represents that key (ie. nodes[handles[i].node].handle == i).
*/
typedef void *PQkey;
typedef long PQhandle;
typedef struct PriorityQ PriorityQ;
typedef struct { PQhandle handle; } PQnode;
typedef struct { PQkey key; PQhandle node; } PQhandleElem;
struct PriorityQ {
PQnode *nodes;
PQhandleElem *handles;
long size, max;
PQhandle freeList;
int initialized;
int (*leq)(PQkey key1, PQkey key2);
};
#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
//#define INIT_SIZE 32
inline long INIT_SIZE() {
static const long s_value = 32;
return s_value;
}
/* Violates modularity, but a little faster */
#include "geom"
#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
/* really __gl_pqHeapNewPriorityQ */
inline PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
{
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
if (pq == NULL) return NULL;
pq->size = 0;
pq->max = INIT_SIZE();
pq->nodes = (PQnode *)memAlloc( (INIT_SIZE() + 1) * sizeof(pq->nodes[0]) );
if (pq->nodes == NULL) {
memFree(pq);
return NULL;
}
pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE() + 1) * sizeof(pq->handles[0]) );
if (pq->handles == NULL) {
memFree(pq->nodes);
memFree(pq);
return NULL;
}
pq->initialized = TOOLS_GLU_FALSE;
pq->freeList = 0;
pq->leq = leq;
pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
pq->handles[1].key = NULL;
return pq;
}
/* really __gl_pqHeapDeletePriorityQ */
inline void pqDeletePriorityQ( PriorityQ *pq )
{
memFree( pq->handles );
memFree( pq->nodes );
memFree( pq );
}
inline/*static*/ void static_FloatDown( PriorityQ *pq, long curr )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
PQhandle hCurr, hChild;
long child;
hCurr = n[curr].handle;
for( ;; ) {
child = curr << 1;
if( child < pq->size && LEQ( h[n[child+1].handle].key,
h[n[child].handle].key )) {
++child;
}
assert(child <= pq->max);
hChild = n[child].handle;
if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
n[curr].handle = hCurr;
h[hCurr].node = curr;
break;
}
n[curr].handle = hChild;
h[hChild].node = curr;
curr = child;
}
}
inline/*static*/ void static_FloatUp( PriorityQ *pq, long curr )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
PQhandle hCurr, hParent;
long parent;
hCurr = n[curr].handle;
for( ;; ) {
parent = curr >> 1;
hParent = n[parent].handle;
if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
n[curr].handle = hCurr;
h[hCurr].node = curr;
break;
}
n[curr].handle = hParent;
h[hParent].node = curr;
curr = parent;
}
}
/* really __gl_pqHeapInit */
inline void pqInit( PriorityQ *pq )
{
long i;
/* This method of building a heap is O(n), rather than O(n lg n). */
for( i = pq->size; i >= 1; --i ) {
static_FloatDown( pq, i );
}
pq->initialized = TOOLS_GLU_TRUE;
}
/* really __gl_pqHeapInsert */
/* returns LONG_MAX iff out of memory */
inline PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
{
long curr;
PQhandle free;
curr = ++ pq->size;
if( (curr*2) > pq->max ) {
PQnode *saveNodes= pq->nodes;
PQhandleElem *saveHandles= pq->handles;
/* If the heap overflows, double its size. */
pq->max <<= 1;
pq->nodes = (PQnode *)memRealloc( pq->nodes,
(size_t)
((pq->max + 1) * sizeof( pq->nodes[0] )));
if (pq->nodes == NULL) {
pq->nodes = saveNodes; /* restore ptr to free upon return */
return LONG_MAX;
}
pq->handles = (PQhandleElem *)memRealloc( pq->handles,
(size_t)
((pq->max + 1) *
sizeof( pq->handles[0] )));
if (pq->handles == NULL) {
pq->handles = saveHandles; /* restore ptr to free upon return */
return LONG_MAX;
}
}
if( pq->freeList == 0 ) {
free = curr;
} else {
free = pq->freeList;
pq->freeList = pq->handles[free].node;
}
pq->nodes[curr].handle = free;
pq->handles[free].node = curr;
pq->handles[free].key = keyNew;
if( pq->initialized ) {
static_FloatUp( pq, curr );
}
assert(free != LONG_MAX);
return free;
}
/* really __gl_pqHeapExtractMin */
inline PQkey pqExtractMin( PriorityQ *pq )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
PQhandle hMin = n[1].handle;
PQkey min = h[hMin].key;
if( pq->size > 0 ) {
n[1].handle = n[pq->size].handle;
h[n[1].handle].node = 1;
h[hMin].key = NULL;
h[hMin].node = pq->freeList;
pq->freeList = hMin;
if( -- pq->size > 0 ) {
static_FloatDown( pq, 1 );
}
}
return min;
}
/* really __gl_pqHeapDelete */
inline void pqDelete( PriorityQ *pq, PQhandle hCurr )
{
PQnode *n = pq->nodes;
PQhandleElem *h = pq->handles;
long curr;
assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
curr = h[hCurr].node;
n[curr].handle = n[pq->size].handle;
h[n[curr].handle].node = curr;
if( curr <= -- pq->size ) {
if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
static_FloatDown( pq, curr );
} else {
static_FloatUp( pq, curr );
}
}
h[hCurr].key = NULL;
h[hCurr].node = pq->freeList;
pq->freeList = hCurr;
}
/* Now redefine all the function names to map to their "Sort" versions. */
/////////////////////////////////////////////////////////////////
//#include "priorityq-sort"
#undef PQkey
#undef PQhandle
#undef PriorityQ
#undef pqNewPriorityQ
#undef pqDeletePriorityQ
#undef pqInit
#undef pqInsert
#undef pqMinimum
#undef pqExtractMin
#undef pqDelete
#undef pqIsEmpty
/* Use #define's so that another heap implementation can use this one */
#define PQkey PQSortKey
#define PQhandle PQSortHandle
#define PriorityQ PriorityQSort
#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
/* The basic operations are insertion of a new key (pqInsert),
* and examination/extraction of a key whose value is minimum
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
* for this purpose pqInsert returns a "handle" which is supplied
* as the argument.
*
* An initial heap may be created efficiently by calling pqInsert
* repeatedly, then calling pqInit. In any case pqInit must be called
* before any operations other than pqInsert are used.
*
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
* This may also be tested with pqIsEmpty.
*/
#define pqInit(pq) __gl_pqSortInit(pq)
#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
#define pqMinimum(pq) __gl_pqSortMinimum(pq)
#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
/* Since we support deletion the data structure is a little more
* complicated than an ordinary heap. "nodes" is the heap itself;
* active nodes are stored in the range 1..pq->size. When the
* heap exceeds its allocated size (pq->max), its size doubles.
* The children of node i are nodes 2i and 2i+1.
*
* Each node stores an index into an array "handles". Each handle
* stores a key, plus a pointer back to the node which currently
* represents that key (ie. nodes[handles[i].node].handle == i).
*/
typedef PQHeapKey PQkey;
typedef PQHeapHandle PQhandle;
typedef struct PriorityQ PriorityQ;
struct PriorityQ {
PriorityQHeap *heap;
PQkey *keys;
PQkey **order;
PQhandle size, max;
int initialized;
int (*leq)(PQkey key1, PQkey key2);
};
/* really __gl_pqSortNewPriorityQ */
inline PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
{
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
if (pq == NULL) return NULL;
pq->heap = __gl_pqHeapNewPriorityQ( leq );
if (pq->heap == NULL) {
memFree(pq);
return NULL;
}
pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE() * sizeof(pq->keys[0]) );
if (pq->keys == NULL) {
__gl_pqHeapDeletePriorityQ(pq->heap);
memFree(pq);
return NULL;
}
pq->size = 0;
pq->max = INIT_SIZE();
pq->initialized = TOOLS_GLU_FALSE;
pq->leq = leq;
return pq;
}
/* really __gl_pqSortDeletePriorityQ */
inline void pqDeletePriorityQ( PriorityQ *pq )
{
assert(pq != NULL);
if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
if (pq->order != NULL) memFree( pq->order );
if (pq->keys != NULL) memFree( pq->keys );
memFree( pq );
}
#define LT(x,y) (! LEQ(y,x))
#define GT(x,y) (! LEQ(x,y))
//#define pq_Swap(a,b) if(1){PQkey *tmp = *a; *a = *b; *b = tmp;}else
#define pq_Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;} while(false)
/* really __gl_pqSortInit */
inline int pqInit( PriorityQ *pq )
{
PQkey **p, **r, **i, **j, *piv;
struct { PQkey **p, **r; } Stack[50], *top = Stack;
unsigned long seed = 2016473283;
/* Create an array of indirect pointers to the keys, so that we
* the handles we have returned are still valid.
*/
/*
pq->order = (PQHeapKey **)memAlloc( (size_t)
(pq->size * sizeof(pq->order[0])) );
*/
pq->order = (PQHeapKey **)memAlloc( (size_t)
((pq->size+1) * sizeof(pq->order[0])) );
/* the previous line is a patch to compensate for the fact that IBM */
/* machines return a null on a malloc of zero bytes (unlike SGI), */
/* so we have to put in this defense to guard against a memory */
/* fault four lines down. from fossum@austin.ibm.com. */
if (pq->order == NULL) return 0;
p = pq->order;
r = p + pq->size - 1;
for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
*i = piv;
}
/* Sort the indirect pointers in descending order,
* using randomized Quicksort
*/
top->p = p; top->r = r; ++top;
while( --top >= Stack ) {
p = top->p;
r = top->r;
while( r > p + 10 ) {
seed = seed * 1539415821 + 1;
i = p + seed % (r - p + 1);
piv = *i;
*i = *p;
*p = piv;
i = p - 1;
j = r + 1;
do {
do { ++i; } while( GT( **i, *piv ));
do { --j; } while( LT( **j, *piv ));
pq_Swap( i, j );
} while( i < j );
pq_Swap( i, j ); /* Undo last swap */
if( i - p < r - j ) {
top->p = j+1; top->r = r; ++top;
r = i-1;
} else {
top->p = p; top->r = i-1; ++top;
p = j+1;
}
}
/* Insertion sort small lists */
for( i = p+1; i <= r; ++i ) {
piv = *i;
for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
*j = *(j-1);
}
*j = piv;
}
}
pq->max = pq->size;
pq->initialized = TOOLS_GLU_TRUE;
__gl_pqHeapInit( pq->heap ); /* always succeeds */
#ifndef NDEBUG
p = pq->order;
r = p + pq->size - 1;
for( i = p; i < r; ++i ) {
assert( LEQ( **(i+1), **i ));
}
#endif
return 1;
}
/* really __gl_pqSortInsert */
/* returns LONG_MAX iff out of memory */
inline PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
{
long curr;
if( pq->initialized ) {
return __gl_pqHeapInsert( pq->heap, keyNew );
}
curr = pq->size;
if( ++ pq->size >= pq->max ) {
PQkey *saveKey= pq->keys;
/* If the heap overflows, double its size. */
pq->max <<= 1;
pq->keys = (PQHeapKey *)memRealloc( pq->keys,
(size_t)
(pq->max * sizeof( pq->keys[0] )));
if (pq->keys == NULL) {
pq->keys = saveKey; /* restore ptr to free upon return */
return LONG_MAX;
}
}
assert(curr != LONG_MAX);
pq->keys[curr] = keyNew;
/* Negative handles index the sorted array. */
return -(curr+1);
}
/* really __gl_pqSortExtractMin */
inline PQkey pqExtractMin( PriorityQ *pq )
{
PQkey sortMin, heapMin;
if( pq->size == 0 ) {
return __gl_pqHeapExtractMin( pq->heap );
}
sortMin = *(pq->order[pq->size-1]);
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
heapMin = __gl_pqHeapMinimum( pq->heap );
if( LEQ( heapMin, sortMin )) {
return __gl_pqHeapExtractMin( pq->heap );
}
}
do {
-- pq->size;
} while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
return sortMin;
}
/* really __gl_pqSortMinimum */
inline PQkey pqMinimum( PriorityQ *pq )
{
PQkey sortMin, heapMin;
if( pq->size == 0 ) {
return __gl_pqHeapMinimum( pq->heap );
}
sortMin = *(pq->order[pq->size-1]);
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
heapMin = __gl_pqHeapMinimum( pq->heap );
if( LEQ( heapMin, sortMin )) {
return heapMin;
}
}
return sortMin;
}
/* really __gl_pqSortIsEmpty */
inline int pqIsEmpty( PriorityQ *pq )
{
return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
}
/* really __gl_pqSortDelete */
inline void pqDelete( PriorityQ *pq, PQhandle curr )
{
if( curr >= 0 ) {
__gl_pqHeapDelete( pq->heap, curr );
return;
}
curr = -(curr+1);
assert( curr < pq->max && pq->keys[curr] != NULL );
pq->keys[curr] = NULL;
while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
-- pq->size;
}
}
#endif
+80
View File
@@ -0,0 +1,80 @@
#ifndef tools_glutess_rename
#define tools_glutess_rename
/* G.Barrand : name space protection : */
#define gluTessBeginContour tools_gluTessBeginContour
#define gluTessBeginPolygon tools_gluTessBeginPolygon
#define gluTessCallback tools_gluTessCallback
#define gluTessEndContour tools_gluTessEndContour
#define gluTessEndPolygon tools_gluTessEndPolygon
#define gluTessNormal tools_gluTessNormal
#define gluTessProperty tools_gluTessProperty
#define gluTessVertex tools_gluTessVertex
/* internal */
#define gluBeginPolygon tools_gluBeginPolygon
#define gluDeleteTess tools_gluDeleteTess
#define gluEndPolygon tools_gluEndPolygon
#define gluGetTessProperty tools_gluGetTessProperty
#define gluNewTess tools_gluNewTess
#define gluNextContour tools_gluNextContour
#define __gl_computeInterior tools__gl_computeInterior
#define __gl_dictListDelete tools__gl_dictListDelete
#define __gl_dictListDeleteDict tools__gl_dictListDeleteDict
#define __gl_dictListInsertBefore tools__gl_dictListInsertBefore
#define __gl_dictListNewDict tools__gl_dictListNewDict
#define __gl_dictListSearch tools__gl_dictListSearch
#define __gl_edgeEval tools__gl_edgeEval
#define __gl_edgeIntersect tools__gl_edgeIntersect
#define __gl_edgeSign tools__gl_edgeSign
/* done in memalloc.h :
#define __gl_memInit tools__gl_memInit
*/
#define __gl_meshAddEdgeVertex tools__gl_meshAddEdgeVertex
#define __gl_meshCheckMesh tools__gl_meshCheckMesh
#define __gl_meshConnect tools__gl_meshConnect
#define __gl_meshDelete tools__gl_meshDelete
#define __gl_meshDeleteMesh tools__gl_meshDeleteMesh
#define __gl_meshDiscardExterior tools__gl_meshDiscardExterior
#define __gl_meshMakeEdge tools__gl_meshMakeEdge
#define __gl_meshNewMesh tools__gl_meshNewMesh
#define __gl_meshSetWindingNumber tools__gl_meshSetWindingNumber
#define __gl_meshSplice tools__gl_meshSplice
#define __gl_meshSplitEdge tools__gl_meshSplitEdge
#define __gl_meshTessellateInterior tools__gl_meshTessellateInterior
#define __gl_meshTessellateMonoRegion tools__gl_meshTessellateMonoRegion
#define __gl_meshUnion tools__gl_meshUnion
#define __gl_meshZapFace tools__gl_meshZapFace
#define __gl_noBeginData tools__gl_noBeginData
#define __gl_noCombineData tools__gl_noCombineData
#define __gl_noEdgeFlagData tools__gl_noEdgeFlagData
#define __gl_noEndData tools__gl_noEndData
#define __gl_noErrorData tools__gl_noErrorData
#define __gl_noVertexData tools__gl_noVertexData
#define __gl_pqHeapDelete tools__gl_pqHeapDelete
#define __gl_pqHeapDeletePriorityQ tools__gl_pqHeapDeletePriorityQ
#define __gl_pqHeapExtractMin tools__gl_pqHeapExtractMin
#define __gl_pqHeapInit tools__gl_pqHeapInit
#define __gl_pqHeapInsert tools__gl_pqHeapInsert
#define __gl_pqHeapNewPriorityQ tools__gl_pqHeapNewPriorityQ
#define __gl_pqSortDelete tools__gl_pqSortDelete
#define __gl_pqSortDeletePriorityQ tools__gl_pqSortDeletePriorityQ
#define __gl_pqSortExtractMin tools__gl_pqSortExtractMin
#define __gl_pqSortInit tools__gl_pqSortInit
#define __gl_pqSortInsert tools__gl_pqSortInsert
#define __gl_pqSortIsEmpty tools__gl_pqSortIsEmpty
#define __gl_pqSortMinimum tools__gl_pqSortMinimum
#define __gl_pqSortNewPriorityQ tools__gl_pqSortNewPriorityQ
#define __gl_projectPolygon tools__gl_projectPolygon
#define __gl_renderBoundary tools__gl_renderBoundary
#define __gl_renderCache tools__gl_renderCache
#define __gl_renderMesh tools__gl_renderMesh
#define __gl_transEval tools__gl_transEval
#define __gl_transSign tools__gl_transSign
#define __gl_vertCCW tools__gl_vertCCW
#define __gl_vertLeq tools__gl_vertLeq
#endif
+481
View File
@@ -0,0 +1,481 @@
// see license file for original license.
#ifndef tools_glutess_render
#define tools_glutess_render
#include "mesh"
/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
* fans, strips, and separate triangles. A substantial effort is made
* to use as few rendering primitives as possible (ie. to make the fans
* and strips as large as possible).
*
* The rendering output is provided as callbacks (see the api).
*/
//void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
//void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
//GLUboolean __gl_renderCache( GLUtesselator *tess );
////////////////////////////////////////////////////////
/// inlined C code : ///////////////////////////////////
////////////////////////////////////////////////////////
#include "_tess"
/* This structure remembers the information we need about a primitive
* to be able to render it later, once we have determined which
* primitive is able to use the most triangles.
*/
struct FaceCount {
long size; /* number of triangles used */
GLUhalfEdge *eStart; /* edge where this primitive starts */
void (*render)(GLUtesselator *, GLUhalfEdge *, long);
/* routine to render this primitive */
};
inline/*static*/ struct FaceCount static_MaximumFan( GLUhalfEdge *eOrig );
inline/*static*/ struct FaceCount static_MaximumStrip( GLUhalfEdge *eOrig );
inline/*static*/ void static_RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
inline/*static*/ void static_RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
inline/*static*/ void static_RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
long size );
inline/*static*/ void static_RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
inline/*static*/ void static_RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
/************************ Strips and Fans decomposition ******************/
/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
* fans, strips, and separate triangles. A substantial effort is made
* to use as few rendering primitives as possible (ie. to make the fans
* and strips as large as possible).
*
* The rendering output is provided as callbacks (see the api).
*/
inline void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
{
GLUface *f;
/* Make a list of separate triangles so we can render them all at once */
tess->lonelyTriList = NULL;
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
f->marked = TOOLS_GLU_FALSE;
}
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
/* We examine all faces in an arbitrary order. Whenever we find
* an unprocessed face F, we output a group of faces including F
* whose size is maximum.
*/
if( f->inside && ! f->marked ) {
static_RenderMaximumFaceGroup( tess, f );
assert( f->marked );
}
}
if( tess->lonelyTriList != NULL ) {
static_RenderLonelyTriangles( tess, tess->lonelyTriList );
tess->lonelyTriList = NULL;
}
}
inline/*static*/ void static_RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
{
/* We want to find the largest triangle fan or strip of unmarked faces
* which includes the given face fOrig. There are 3 possible fans
* passing through fOrig (one centered at each vertex), and 3 possible
* strips (one for each CCW permutation of the vertices). Our strategy
* is to try all of these, and take the primitive which uses the most
* triangles (a greedy approach).
*/
GLUhalfEdge *e = fOrig->anEdge;
struct FaceCount max, newFace;
max.size = 1;
max.eStart = e;
max.render = &static_RenderTriangle;
if( ! tess->flagBoundary ) {
newFace = static_MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
newFace = static_MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
newFace = static_MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
newFace = static_MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
newFace = static_MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
newFace = static_MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
}
(*(max.render))( tess, max.eStart, max.size );
}
/* Macros which keep track of faces we have marked temporarily, and allow
* us to backtrack when necessary. With triangle fans, this is not
* really necessary, since the only awkward case is a loop of triangles
* around a single origin vertex. However with strips the situation is
* more complicated, and we need a general tracking method like the
* one here.
*/
#define Marked(f) (! (f)->inside || (f)->marked)
#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TOOLS_GLU_TRUE)
//#define FreeTrail(t) if( 1 ) { while( (t) != NULL ) { (t)->marked = TOOLS_GLU_FALSE; t = (t)->trail; } } else
#define FreeTrail(t) do { while( (t) != NULL ) { (t)->marked = TOOLS_GLU_FALSE; t = (t)->trail; } } while(false)
inline/*static*/ struct FaceCount static_MaximumFan( GLUhalfEdge *eOrig )
{
/* eOrig->Lface is the face we want to render. We want to find the size
* of a maximal fan around eOrig->Org. To do this we just walk around
* the origin vertex as far as possible in both directions.
*/
struct FaceCount newFace = { 0, NULL, &static_RenderFan };
GLUface *trail = NULL;
GLUhalfEdge *e;
for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
AddToTrail( e->Lface, trail );
++newFace.size;
}
for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
AddToTrail( e->Rface, trail );
++newFace.size;
}
newFace.eStart = e;
/*LINTED*/
FreeTrail( trail );
return newFace;
}
#define IsEven(n) (((n) & 1) == 0)
inline/*static*/ struct FaceCount static_MaximumStrip( GLUhalfEdge *eOrig )
{
/* Here we are looking for a maximal strip that contains the vertices
* eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
* reverse, such that all triangles are oriented CCW).
*
* Again we walk forward and backward as far as possible. However for
* strips there is a twist: to get CCW orientations, there must be
* an *even* number of triangles in the strip on one side of eOrig.
* We walk the strip starting on a side with an even number of triangles;
* if both side have an odd number, we are forced to shorten one side.
*/
struct FaceCount newFace = { 0, NULL, &static_RenderStrip };
long headSize = 0, tailSize = 0;
GLUface *trail = NULL;
GLUhalfEdge *e, *eTail, *eHead;
for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
AddToTrail( e->Lface, trail );
++tailSize;
e = e->Dprev;
if( Marked( e->Lface )) break;
AddToTrail( e->Lface, trail );
}
eTail = e;
for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
AddToTrail( e->Rface, trail );
++headSize;
e = e->Oprev;
if( Marked( e->Rface )) break;
AddToTrail( e->Rface, trail );
}
eHead = e;
newFace.size = tailSize + headSize;
if( IsEven( tailSize )) {
newFace.eStart = eTail->Sym;
} else if( IsEven( headSize )) {
newFace.eStart = eHead;
} else {
/* Both sides have odd length, we must shorten one of them. In fact,
* we must start from eHead to guarantee inclusion of eOrig->Lface.
*/
--newFace.size;
newFace.eStart = eHead->Onext;
}
/*LINTED*/
FreeTrail( trail );
return newFace;
}
inline/*static*/ void static_RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
{
/* Just add the triangle to a triangle list, so we can render all
* the separate triangles at once.
*/
assert( size == 1 );
AddToTrail( e->Lface, tess->lonelyTriList );
(void)size;
}
inline/*static*/ void static_RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
{
/* Now we render all the separate triangles which could not be
* grouped into a triangle fan or strip.
*/
GLUhalfEdge *e;
int newState;
int edgeState = -1; /* force edge state output for first vertex */
CALL_BEGIN_OR_BEGIN_DATA( GLU_TRIANGLES );
for( ; f != NULL; f = f->trail ) {
/* Loop once for each edge (there will always be 3 edges) */
e = f->anEdge;
do {
if( tess->flagBoundary ) {
/* Set the "edge state" to TOOLS_GLU_TRUE just before we output the
* first vertex of each edge on the polygon boundary.
*/
newState = ! e->Rface->inside;
if( edgeState != newState ) {
edgeState = newState;
CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
}
}
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
e = e->Lnext;
} while( e != f->anEdge );
}
CALL_END_OR_END_DATA();
}
inline/*static*/ void static_RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
{
/* Render as many CCW triangles as possible in a fan starting from
* edge "e". The fan *should* contain exactly "size" triangles
* (otherwise we've goofed up somewhere).
*/
CALL_BEGIN_OR_BEGIN_DATA( GLU_TRIANGLE_FAN );
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
while( ! Marked( e->Lface )) {
e->Lface->marked = TOOLS_GLU_TRUE;
--size;
e = e->Onext;
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
}
assert( size == 0 );
CALL_END_OR_END_DATA();
}
inline/*static*/ void static_RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
{
/* Render as many CCW triangles as possible in a strip starting from
* edge "e". The strip *should* contain exactly "size" triangles
* (otherwise we've goofed up somewhere).
*/
CALL_BEGIN_OR_BEGIN_DATA( GLU_TRIANGLE_STRIP );
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
while( ! Marked( e->Lface )) {
e->Lface->marked = TOOLS_GLU_TRUE;
--size;
e = e->Dprev;
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
if( Marked( e->Lface )) break;
e->Lface->marked = TOOLS_GLU_TRUE;
--size;
e = e->Onext;
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
}
assert( size == 0 );
CALL_END_OR_END_DATA();
}
/************************ Boundary contour decomposition ******************/
/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
* contour for each face marked "inside". The rendering output is
* provided as callbacks (see the api).
*/
inline void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
{
GLUface *f;
GLUhalfEdge *e;
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
if( f->inside ) {
CALL_BEGIN_OR_BEGIN_DATA( GLU_LINE_LOOP );
e = f->anEdge;
do {
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
e = e->Lnext;
} while( e != f->anEdge );
CALL_END_OR_END_DATA();
}
}
}
/************************ Quick-and-dirty decomposition ******************/
//#define SIGN_INCONSISTENT 2
inline int SIGN_INCONSISTENT() {
static const int s_value = 2;
return s_value;
}
inline/*static*/ int static_ComputeNormal( GLUtesselator *tess, GLUdouble norm[3], int check )
/*
* If check==TOOLS_GLU_FALSE, we compute the polygon normal and place it in norm[].
* If check==TOOLS_GLU_TRUE, we check that each triangle in the fan from v0 has a
* consistent orientation with respect to norm[]. If triangles are
* consistently oriented CCW, return 1; if CW, return -1; if all triangles
* are degenerate return 0; otherwise (no consistent orientation) return
* SIGN_INCONSISTENT.
*/
{
CachedVertex *v0 = tess->cache;
CachedVertex *vn = v0 + tess->cacheCount;
CachedVertex *vc;
GLUdouble dot, xc, yc, zc, xp, yp, zp, n[3];
int sign = 0;
/* Find the polygon normal. It is important to get a reasonable
* normal even when the polygon is self-intersecting (eg. a bowtie).
* Otherwise, the computed normal could be very tiny, but perpendicular
* to the true plane of the polygon due to numerical noise. Then all
* the triangles would appear to be degenerate and we would incorrectly
* decompose the polygon as a fan (or simply not render it at all).
*
* We use a sum-of-triangles normal algorithm rather than the more
* efficient sum-of-trapezoids method (used in CheckOrientation()
* in normal.c). This lets us explicitly reverse the signed area
* of some triangles to get a reasonable normal in the self-intersecting
* case.
*/
if( ! check ) {
norm[0] = norm[1] = norm[2] = 0.0;
}
vc = v0 + 1;
xc = vc->coords[0] - v0->coords[0];
yc = vc->coords[1] - v0->coords[1];
zc = vc->coords[2] - v0->coords[2];
while( ++vc < vn ) {
xp = xc; yp = yc; zp = zc;
xc = vc->coords[0] - v0->coords[0];
yc = vc->coords[1] - v0->coords[1];
zc = vc->coords[2] - v0->coords[2];
/* Compute (vp - v0) cross (vc - v0) */
n[0] = yp*zc - zp*yc;
n[1] = zp*xc - xp*zc;
n[2] = xp*yc - yp*xc;
dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
if( ! check ) {
/* Reverse the contribution of back-facing triangles to get
* a reasonable normal for self-intersecting polygons (see above)
*/
if( dot >= 0 ) {
norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
} else {
norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
}
} else if( dot != 0 ) {
/* Check the new orientation for consistency with previous triangles */
if( dot > 0 ) {
if( sign < 0 ) return SIGN_INCONSISTENT();
sign = 1;
} else {
if( sign > 0 ) return SIGN_INCONSISTENT();
sign = -1;
}
}
}
return sign;
}
/* __gl_renderCache( tess ) takes a single contour and tries to render it
* as a triangle fan. This handles convex polygons, as well as some
* non-convex polygons if we get lucky.
*
* Returns TOOLS_GLU_TRUE if the polygon was successfully rendered. The rendering
* output is provided as callbacks (see the api).
*/
inline GLUboolean __gl_renderCache( GLUtesselator *tess )
{
CachedVertex *v0 = tess->cache;
CachedVertex *vn = v0 + tess->cacheCount;
CachedVertex *vc;
GLUdouble norm[3];
int sign;
if( tess->cacheCount < 3 ) {
/* Degenerate contour -- no output */
return TOOLS_GLU_TRUE;
}
norm[0] = tess->normal[0];
norm[1] = tess->normal[1];
norm[2] = tess->normal[2];
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
static_ComputeNormal( tess, norm, TOOLS_GLU_FALSE );
}
sign = static_ComputeNormal( tess, norm, TOOLS_GLU_TRUE );
if( sign == SIGN_INCONSISTENT() ) {
/* Fan triangles did not have a consistent orientation */
return TOOLS_GLU_FALSE;
}
if( sign == 0 ) {
/* All triangles were degenerate */
return TOOLS_GLU_TRUE;
}
/* Make sure we do the right thing for each winding rule */
switch( tess->windingRule ) {
case GLU_TESS_WINDING_ODD:
case GLU_TESS_WINDING_NONZERO:
break;
case GLU_TESS_WINDING_POSITIVE:
if( sign < 0 ) return TOOLS_GLU_TRUE;
break;
case GLU_TESS_WINDING_NEGATIVE:
if( sign > 0 ) return TOOLS_GLU_TRUE;
break;
case GLU_TESS_WINDING_ABS_GEQ_TWO:
return TOOLS_GLU_TRUE;
}
CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GLU_LINE_LOOP
: (tess->cacheCount > 3) ? GLU_TRIANGLE_FAN
: GLU_TRIANGLES );
CALL_VERTEX_OR_VERTEX_DATA( v0->data );
if( sign > 0 ) {
for( vc = v0+1; vc < vn; ++vc ) {
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
}
} else {
for( vc = vn-1; vc > v0; --vc ) {
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
}
}
CALL_END_OR_END_DATA();
return TOOLS_GLU_TRUE;
}
#endif
File diff suppressed because it is too large Load Diff
+203
View File
@@ -0,0 +1,203 @@
// see license file for original license.
#ifndef tools_glutess_tessmono
#define tools_glutess_tessmono
/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
* (what else would it do??) The region must consist of a single
* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
* case means that any vertical line intersects the interior of the
* region in a single interval.
*
* Tessellation consists of adding interior edges (actually pairs of
* half-edges), to split the region into non-overlapping triangles.
*
* __gl_meshTessellateInterior( mesh ) tessellates each region of
* the mesh which is marked "inside" the polygon. Each such region
* must be monotone.
*
* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
* which are not marked "inside" the polygon. Since further mesh operations
* on NULL faces are not allowed, the main purpose is to clean up the
* mesh so that exterior loops are not represented in the data structure.
*
* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
* winding numbers on all edges so that regions marked "inside" the
* polygon have a winding number of "value", and regions outside
* have a winding number of 0.
*
* If keepOnlyBoundary is TOOLS_GLU_TRUE, it also deletes all edges which do not
* separate an interior region from an exterior one.
*/
//int __gl_meshTessellateMonoRegion( GLUface *face );
//int __gl_meshTessellateInterior( GLUmesh *mesh );
//void __gl_meshDiscardExterior( GLUmesh *mesh );
//int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
// GLUboolean keepOnlyBoundary );
////////////////////////////////////////////////////////
/// inlined C code : ///////////////////////////////////
////////////////////////////////////////////////////////
#include "geom"
#include "mesh"
/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
* (what else would it do??) The region must consist of a single
* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
* case means that any vertical line intersects the interior of the
* region in a single interval.
*
* Tessellation consists of adding interior edges (actually pairs of
* half-edges), to split the region into non-overlapping triangles.
*
* The basic idea is explained in Preparata and Shamos (which I don''t
* have handy right now), although their implementation is more
* complicated than this one. The are two edge chains, an upper chain
* and a lower chain. We process all vertices from both chains in order,
* from right to left.
*
* The algorithm ensures that the following invariant holds after each
* vertex is processed: the untessellated region consists of two
* chains, where one chain (say the upper) is a single edge, and
* the other chain is concave. The left vertex of the single edge
* is always to the left of all vertices in the concave chain.
*
* Each step consists of adding the rightmost unprocessed vertex to one
* of the two chains, and forming a fan of triangles from the rightmost
* of two chain endpoints. Determining whether we can add each triangle
* to the fan is a simple orientation test. By making the fan as large
* as possible, we restore the invariant (check it yourself).
*/
inline int __gl_meshTessellateMonoRegion( GLUface *face )
{
GLUhalfEdge *up, *lo;
/* All edges are oriented CCW around the boundary of the region.
* First, find the half-edge whose origin vertex is rightmost.
* Since the sweep goes from left to right, face->anEdge should
* be close to the edge we want.
*/
up = face->anEdge;
assert( up->Lnext != up && up->Lnext->Lnext != up );
for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
;
for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
;
lo = up->Lprev;
while( up->Lnext != lo ) {
if( VertLeq( up->Dst, lo->Org )) {
/* up->Dst is on the left. It is safe to form triangles from lo->Org.
* The EdgeGoesLeft test guarantees progress even when some triangles
* are CW, given that the upper and lower chains are truly monotone.
*/
while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
|| EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
if (tempHalfEdge == NULL) return 0;
lo = tempHalfEdge->Sym;
}
lo = lo->Lprev;
} else {
/* lo->Org is on the left. We can make CCW triangles from up->Dst. */
while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
|| EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
if (tempHalfEdge == NULL) return 0;
up = tempHalfEdge->Sym;
}
up = up->Lnext;
}
}
/* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
* can be tessellated in a fan from this leftmost vertex.
*/
assert( lo->Lnext != up );
while( lo->Lnext->Lnext != up ) {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
if (tempHalfEdge == NULL) return 0;
lo = tempHalfEdge->Sym;
}
return 1;
}
/* __gl_meshTessellateInterior( mesh ) tessellates each region of
* the mesh which is marked "inside" the polygon. Each such region
* must be monotone.
*/
inline int __gl_meshTessellateInterior( GLUmesh *mesh )
{
GLUface *f, *next;
/*LINTED*/
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
/* Make sure we don''t try to tessellate the new triangles. */
next = f->next;
if( f->inside ) {
if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
}
}
return 1;
}
/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
* which are not marked "inside" the polygon. Since further mesh operations
* on NULL faces are not allowed, the main purpose is to clean up the
* mesh so that exterior loops are not represented in the data structure.
*/
inline void __gl_meshDiscardExterior( GLUmesh *mesh )
{
GLUface *f, *next;
/*LINTED*/
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
/* Since f will be destroyed, save its next pointer. */
next = f->next;
if( ! f->inside ) {
__gl_meshZapFace( f );
}
}
}
//#define MARKED_FOR_DELETION 0x7fffffff
/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
* winding numbers on all edges so that regions marked "inside" the
* polygon have a winding number of "value", and regions outside
* have a winding number of 0.
*
* If keepOnlyBoundary is TOOLS_GLU_TRUE, it also deletes all edges which do not
* separate an interior region from an exterior one.
*/
inline int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
GLUboolean keepOnlyBoundary )
{
GLUhalfEdge *e, *eNext;
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
eNext = e->next;
if( e->Rface->inside != e->Lface->inside ) {
/* This is a boundary edge (one side is interior, one is exterior). */
e->winding = (e->Lface->inside) ? value : -value;
} else {
/* Both regions are interior, or both are exterior. */
if( ! keepOnlyBoundary ) {
e->winding = 0;
} else {
if ( !__gl_meshDelete( e ) ) return 0;
}
}
}
return 1;
}
#endif
+231
View File
@@ -0,0 +1,231 @@
#ifndef tools_glutess_undef
#define tools_glutess_undef
#undef GLU_TESS_MAX_CACHE
#undef CALL_BEGIN_OR_BEGIN_DATA
#undef CALL_VERTEX_OR_VERTEX_DATA
#undef CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA
#undef CALL_END_OR_END_DATA
#undef CALL_COMBINE_OR_COMBINE_DATA
#undef CALL_ERROR_OR_ERROR_DATA
#undef __gl_dictListDelete
#undef __gl_dictListDeleteDict
#undef __gl_dictListInsertBefore
#undef __gl_dictListNewDict
#undef __gl_dictListSearch
#undef DictKey
#undef Dict
#undef DictNode
#undef dictNewDict
#undef dictDeleteDict
#undef dictSearch
#undef dictInsert
#undef dictInsertBefore
#undef dictDelete
#undef dictKey
#undef dictSucc
#undef dictPred
#undef dictMin
#undef dictMax
#undef __gl_dictListKey
#undef __gl_dictListSucc
#undef __gl_dictListPred
#undef __gl_dictListMin
#undef __gl_dictListMax
#undef __gl_dictListInsert
#undef VertEq
#undef VertLeq
#undef EdgeEval
#undef EdgeSign
#undef TransLeq
#undef TransEval
#undef TransSign
#undef EdgeGoesLeft
#undef EdgeGoesRight
#undef VertL1dist
#undef VertCCW
#undef VertLeq
#undef Interpolate
#undef Swap
#undef GLUAPI
/*
#undef GLUAPIENTRY
#undef GLU_TESS_BEGIN_DATA
#undef GLU_TESS_VERTEX_DATA
#undef GLU_TESS_END_DATA
#undef GLU_TESS_ERROR_DATA
#undef GLU_TESS_COMBINE_DATA
#undef GLU_TESS_WINDING_RULE
#undef GLU_TESS_WINDING_ODD
#undef GLU_TESS_WINDING_POSITIVE
#undef GLU_TESS_WINDING_NEGATIVE
*/
#undef GLU_MIN
#undef GLU_MAX
#undef GLU_ABS
#undef TOOLS_GLU_FALSE
#undef TOOLS_GLU_TRUE
#undef GLU_LINE_LOOP
#undef GLU_TRIANGLES
#undef GLU_TRIANGLE_STRIP
#undef GLU_TRIANGLE_FAN
#undef GLU_TESS_MAX_COORD
#undef GLU_INVALID_ENUM
#undef GLU_INVALID_VALUE
#undef GLU_OUT_OF_MEMORY
#undef GLU_INCOMPATIBLE_GL_VERSION
#undef GLU_INVALID_OPERATION
#undef GLU_TESS_BEGIN
#undef GLU_TESS_VERTEX
#undef GLU_TESS_END
#undef GLU_TESS_ERROR
#undef GLU_TESS_EDGE_FLAG
#undef GLU_EDGE_FLAG
#undef GLU_TESS_COMBINE
#undef GLU_TESS_EDGE_FLAG_DATA
#undef GLU_CW
#undef GLU_CCW
#undef GLU_INTERIOR
#undef GLU_EXTERIOR
#undef GLU_UNKNOWN
#undef GLU_TESS_BOUNDARY_ONLY
#undef GLU_TESS_TOLERANCE
#undef GLU_TESS_ERROR1
#undef GLU_TESS_ERROR2
#undef GLU_TESS_ERROR3
#undef GLU_TESS_ERROR4
#undef GLU_TESS_ERROR5
#undef GLU_TESS_ERROR6
#undef GLU_TESS_ERROR7
#undef GLU_TESS_ERROR8
#undef GLU_TESS_MISSING_BEGIN_POLYGON
#undef GLU_TESS_MISSING_BEGIN_CONTOUR
#undef GLU_TESS_MISSING_END_POLYGON
#undef GLU_TESS_MISSING_END_CONTOUR
#undef GLU_TESS_COORD_TOO_LARGE
#undef GLU_TESS_NEED_COMBINE_CALLBACK
#undef GLU_TESS_WINDING_NONZERO
#undef GLU_TESS_WINDING_ABS_GEQ_TWO
#undef memAlloc
#undef memRealloc
#undef memFree
#undef memInit
#undef Rface
#undef Dst
#undef Oprev
#undef Lprev
#undef Dprev
#undef Rprev
#undef Dnext
#undef Rnext
#undef Dot
#undef S_UNIT_X
#undef S_UNIT_Y
#undef PQkey
#undef PQhandle
#undef PriorityQ
#undef pqNewPriorityQ
#undef pqDeletePriorityQ
#undef pqInit
#undef pqInsert
#undef pqMinimum
#undef pqExtractMin
#undef pqDelete
#undef pqIsEmpty
#undef __gl_pqHeapMinimum
#undef __gl_pqHeapIsEmpty
#undef LEQ
#undef PQkey
#undef PQhandle
#undef PriorityQ
#undef pqNewPriorityQ
#undef pqDeletePriorityQ
#undef pqInit
#undef pqInsert
#undef pqMinimum
#undef pqExtractMin
#undef pqDelete
#undef pqIsEmpty
#undef LT
#undef GT
#undef pq_Swap
//#undef gluTessBeginContour
//#undef gluTessBeginPolygon
//#undef gluTessCallback
//#undef gluTessEndContour
//#undef gluTessEndPolygon
//#undef gluTessNormal
//#undef gluTessProperty
//#undef gluTessVertex
//#undef gluBeginPolygon
//#undef gluDeleteTess
//#undef gluEndPolygon
//#undef gluGetTessProperty
//#undef gluNewTess
//#undef gluNextContour
#undef __gl_computeInterior
#undef __gl_dictListDelete
#undef __gl_dictListDeleteDict
#undef __gl_dictListInsertBefore
#undef __gl_dictListNewDict
#undef __gl_dictListSearch
#undef __gl_edgeEval
#undef __gl_edgeIntersect
#undef __gl_edgeSign
#undef __gl_memInit
#undef __gl_meshAddEdgeVertex
#undef __gl_meshCheckMesh
#undef __gl_meshConnect
#undef __gl_meshDelete
#undef __gl_meshDeleteMesh
#undef __gl_meshDiscardExterior
#undef __gl_meshMakeEdge
#undef __gl_meshNewMesh
#undef __gl_meshSetWindingNumber
#undef __gl_meshSplice
#undef __gl_meshSplitEdge
#undef __gl_meshTessellateInterior
#undef __gl_meshTessellateMonoRegion
#undef __gl_meshUnion
#undef __gl_meshZapFace
#undef __gl_noBeginData
#undef __gl_noCombineData
#undef __gl_noEdgeFlagData
#undef __gl_noEndData
#undef __gl_noErrorData
#undef __gl_noVertexData
#undef __gl_pqHeapDelete
#undef __gl_pqHeapDeletePriorityQ
#undef __gl_pqHeapExtractMin
#undef __gl_pqHeapInit
#undef __gl_pqHeapInsert
#undef __gl_pqHeapNewPriorityQ
#undef __gl_pqSortDelete
#undef __gl_pqSortDeletePriorityQ
#undef __gl_pqSortExtractMin
#undef __gl_pqSortInit
#undef __gl_pqSortInsert
#undef __gl_pqSortIsEmpty
#undef __gl_pqSortMinimum
#undef __gl_pqSortNewPriorityQ
#undef __gl_projectPolygon
#undef __gl_renderBoundary
#undef __gl_renderCache
#undef __gl_renderMesh
#undef __gl_transEval
#undef __gl_transSign
#undef __gl_vertCCW
#undef __gl_vertLeq
#undef Marked
#undef AddToTrail
#undef FreeTrail
#undef IsEven
#undef RegionBelow
#undef RegionAbove
#undef DebugEvent
#undef AddWinding
#undef GLU_TESS_DEFAULT_TOLERANCE
#undef GLU_TESS_MESH
#undef RequireState
#endif
+46
View File
@@ -0,0 +1,46 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_gzip
#define tools_gzip
#include "signature"
namespace tools {
namespace file {
inline bool is_gzip(const std::string& a_file,bool& a_is){
unsigned char head[4];
{unsigned int num = 4;
if(!signature(a_file,head,num)) {a_is = false;return false;}
if(num!=4) {a_is = false;return true;}}
if(head[0]!=31) {a_is = false;return true;}
if(head[1]!=139) {a_is = false;return true;}
//if(head[2]!=8) {a_is = false;return true;}
//if(head[3]!=8) {a_is = false;return true;}
a_is = true;
return true;
}
inline bool gzip_usize(const std::string& a_file,unsigned int& a_usz){
bool is;
if(!is_gzip(a_file,is)) {a_usz=0;return false;}
if(!is) {a_usz=0;return false;}
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) {a_usz=0;return false;}
::fseek(file,-4,SEEK_END);
unsigned char buf[4];
size_t n = ::fread(buf,1,4,file);
::fclose(file);
if(n!=4) {a_usz=0;return false;}
unsigned int b4 = buf[0];
unsigned int b3 = buf[1];
unsigned int b2 = buf[2];
unsigned int b1 = buf[3];
a_usz = (b1 << 24) | ((b2 << 16) + (b3 << 8) + b4);
return true;
}
}}
#endif
+92
View File
@@ -0,0 +1,92 @@
// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_handle
#define tools_handle
#ifdef TOOLS_MEM
#include "mem"
#endif
#include <string>
namespace tools {
class base_handle {
static const std::string& s_class() {
static const std::string s_v("tools::handle");
return s_v;
}
public:
virtual void* object() const = 0;
virtual base_handle* copy() = 0; //can't be const.
virtual void disown() = 0;
public:
base_handle(){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
base_handle(const std::string& a_class):m_class(a_class){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
virtual ~base_handle(){
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
protected:
base_handle(base_handle& a_from):m_class(a_from.m_class){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
private:
base_handle& operator=(base_handle& a_from){
m_class = a_from.m_class;
return *this;
}
public:
const std::string& object_class() const {return m_class;}
private:
std::string m_class;
};
template <class T>
class handle : public base_handle {
typedef base_handle parent;
public:
virtual void* object() const {return m_obj;}
virtual base_handle* copy() {return new handle<T>(*this);}
virtual void disown() {m_owner = false;}
public:
handle(T* a_obj,bool a_owner = true):parent(),m_obj(a_obj),m_owner(a_owner){}
handle(const std::string& a_class,T* a_obj,bool a_owner = true):parent(a_class),m_obj(a_obj),m_owner(a_owner){}
virtual ~handle(){if(m_owner) delete m_obj;}
private:
handle(handle& a_from):parent(a_from){
m_obj = a_from.m_obj;
if(a_from.m_owner) {
// this take ownership.
m_owner = true;
a_from.m_owner = false;
} else {
m_owner = false;
}
//a_from.m_obj = 0; //we do not remove the obj ref in a_from.
}
private:
// in principle the below are not used.
//handle(const handle& a_from){}
//handle& operator=(const handle&){return *this;}
handle& operator=(handle&){return *this;}
protected:
T* m_obj;
bool m_owner;
};
}
#endif

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