-------------------------------------------
 Csurf -- cortical surface program manager
-------------------------------------------
#############
tardate=251126
#############

Overview

The csurf program generates and records command
lines to run freesurfer cortical surface analysis
and display programs (e.g., tkmedit, fourier,
paint, tksurfer, mri_surf2surf).  It serves the
function of an analysis and display shell script,
but with more convenient interactivity.

Csurf saves analysis and rendering parameters for
each scandir in a session to make it easy to
redo, adjust, re-display, or re-batch-run
analyses (see SessionTools -> Run Batch Process).
The next time the session is opened, the saved
display parameters will be used.

Any sequence of user interface actions in
tksurfer and tkmedit can be automated using a tcl
script.  See R-click help on the "tcl:" label in
tksurfer and tkmedit to find out how to record
the tcl commands executed by interface actions.
A tcl script can be run interactively from
tksurfer and tkmedit, but can also be run
completely non-interactively from the command
line:

  tksurfer marty rh inflated -tcl myscript.tcl ...
  tkmedit marty orig.mgz -tcl myscript.tcl ...

Typical Use

First reconstruct a single subject's surface
(MGHTools or manual SubjectsTools).

Then, one or more functional sessions can be
associated with each subject and analyzed
(SessionTools).  Single subject activations can
then be viewed on the surface or as 2D slice
overlays with SessionTools -> View Functional
Data.

See Help -> Retinotopy HOWTO for step-by-step
instructions.

Cross-subject complex-valued surface averages can
be computed in a spherically morphed common
surface coordinate system analagous to 3D
Talairach coordinates (CrossSessTools).  There is
some support for 3-D cross subject complex-valued
average (manual registration).

Help/Instructions

Help files are available for each analysis step
in the csurf Help menu, arranged in typical order
of use.

The small "h" buttons at one corner of csurf,
tksurfer, tkmedit, and tkregister bring up
general help for that application).

In addition, every button, checkbox, and text
entry in csurf, tksurfer, tkmedit, and tkregister
has a context-sensitive R-click popup help panel.
Each help panel can be searched for keywords
using Cmd-f (linux: Alt-f) in the help panel (use
<Return> or Cmd/Alt-g for 'find next').

The csurf menu item:

  Help -> All Help Contents (clickable)

makes a clickable table of contents of all csurf,
tksurfer, tkmedit, and tkregister help panels.

Finally, all help panels are gathered into a
single file (35K lines) here:

  $CSURF_DIR/lib/help/CSURF_HELP.txt

To get that entire file (35K lines) into one,
searchable help window, middle-click the lower
right "h" button on csurf.

Image Outputs

By default, rendered images are saved as 3 byte
per pixel tiffs by tksurfer and tkmedit.  To
restore the old behavior of saving images as SGI
rgb files, unclick:

  Preferences -> Save .tiff (else SGI rgb)

For surface views, to obtain a 4 byte per pixel
tiff with pure black background areas changed to
transparent, use:

  Preferences -> Black to Transparent

Since some programs may not be able to display or
use 4 byte per pixel tiffs, this option is off by
default (no effect on SGI rgb output).

Directory Structure

The data base consists of two main directories:

(1) subjects tree (e.g., /usr1/subjects)

  Permanent home of structural MRI data, filtered
  MRI data, and folded, unfolded, and flattened
  surfaces for subjects.  The startup value of
  this must be set with:

    setenv SUBJECTS_DIR <whatever>  # csh/tcsh
    export SUBJECTS_DIR=<whatever>  # sh/bash

  The directory (database) name for each subject
  is typically a first name plus last initial
  (e.g., martys).  This root of the subjects tree
  can be interactively changed with csurf.

  For ease of navigation, any string typed into
  the "subject:" entry that doesn't exactly match
  a subject brings up a panel of partial matches.

  Here is a shortcut to start csurf for a
  particular subject:

    csurf <subject>

(2) functional sessions tree (e.g., /usr1/sessions)

  Directory containing individual functional
  sessions.  The startup value of this must be
  set with:

    setenv FUNCTIONALS_DIR <whatever>  # csh/tcsh
    export FUNCTIONALS_DIR=<whatever>  # sh/bash

  A session is defined as a set of scans taken
  with one subject, in one position, in one RF
  coil.  Individual sessions can be saved
  anywhere.  A convenient style for a session
  name is a 6 numeral date, then initials.  Use a
  date in year/month/day order (YYMMDD) so 'ls'
  or file browsers sort them chronologically
  (e.g., 190928MS).  This root of the sessions
  tree can be interactively changed with csurf.

  As with the subjects dropdown, any string typed
  into the "session:" entry that doesn't exactly
  match a session brings up a panel of partial
  matches (e.g., with default sesson names, MS
  matches all scans on subject MS, while 1906*MS
  matches June 2019 scans on subject MS).

  Here is a shortcut to start csurf for a
  particular session:

    csurf <session>

A new subject directory is initially created with
either:

  File -> New Subject
  MGHTools -> Run recon-all

A new empty sessions or cross-subject spherical
average session directory is initially created
with:

  File -> New Functional
  File -> New Spherical Avg

Avoid spaces within paths and names

Csurf programs can now correctly deal with
pathnames (e.g., CSURF_DIR, SUBJECTS_DIR,
FUNCTIONALS_DIR) that have spaces in them (e.g.,
the impractical default brand names given to some
removeable disks).  However, spaces in paths will
break many MGH freesurfer 5.3 scripts and
programs (e.g., recon-all, mris_pmake [for
geodesics]).  If at all possible, just remove
spaces from paths.

Subject/Session Association

Each functional session directory (e.g.,
120928MS) is associated with a particular subject
directory (e.g., marser) chosen when the session
is created.  Several different functional
sessions may point to the same subject.

The association between a functional session and
a particular subject is completely determined by
the (relative) subject directory name stored in
an ASCII file, "name".  For example:

  $FUNCTIONALS_DIR/120928MS/image/name

To change this (e.g., if a new surface is created
for a subject), edit the name file or use:

  Preferences -> Change Subject for Curr Session

Note that if you do this, all scandirs in this
session have to be re-registered to the T1 data
used to make the new surface, and stats have to
to be re-PAINT'ed onto the new surface.  If you
want to save the original analysis, first make a
copy of it (File -> Copy Functional), before you
update the name file.

If the contents of the subjects or sesssions
directories are updated outside of csurf, use
File -> Update Subjects & Functionals to refresh
the dropdowns.

Scripts Directory

The csurf interface generally runs programs from
the "scripts" subdirectory inside the currently
selected session or subject.  The current working
directory is shown in the csurf window title bar.
A flat ASCII file of current configs -- csurf.dat
-- is stored in the scripts dir.  It is read by
csurf upon selecting that session or subject, and
written when you press SAVE or SAVE/CLOSE on one
of the csurf configuration panels, or when you
actually perform an action.  If you remove or
move aside the csurf.dat file, the current
configuration of a session or subject directory
will be forgotten, but no data files will be
affected.

The scripts directory is also the directory in
which ASCII notes are conventially made:

  File -> Open Subject NOTES
  File -> Open Functional NOTES

automatically open (or create) the current
subject or session's scripts dir NOTES file in a
text editor to encourage this practice.

MGHTools and SubjectsTools

UCSD/UCL csurf has two different processing
streams for making surfaces.

The MGHTools menu provides an easy way to run a
separately-installed MGH freesurfer distribution
to make, flatten, and register (spherically
morph) surfaces in the csurf-maintained
SUBJECTS_DIR.  This is the default processing
stream for making surfaces for csurf.  To run MGH
freesurfer from csurf, set the environment
variable, FSURF_DIR, to the location of the MGH
install directory before starting csurf.  Subject
directories created elsewhere by MGH freesurfer
are also csurf-useable without change.

Second, the SubjectTools menu contains a set of
items ending in "... (hi-res)" for making high
resolution surfaces from 512^3/0.5mm^3 data.
(N.B.: the "hi-res" tools also work with
256^3/1.0mm^3 data sets, where the flexible
initialization can be useful for non-standard
brains). This processing stream currently
requires manual intervention (in Expert
Preferences panels) to set thresholds, cutting
planes, and fill seeds.

SessionTools and CrossSessTools

There are two menu items for operating on
functional session directories.

The SessionTools menu contains items arranged in
the order in which they are typically used for
single subject (first level) analysis.  Cross
session but within-subject averages can also be
made using SessionTools -> Combine Surface Stats.

The CrossSessTools menu manipulates spherically
morphed cross subject (second level) average
directories, which are stored in FUNCTIONALS_DIR
alongside the single subject sessions.  Cross
session dirs are similar to functional sessions
but can only contain one scandir.

Double-clicking the "subject:", "surface:",
"session:" or "scandir:" labels on the main csurf
panel will bring any currently open panel back to
the front.

Log View

As csurf runs command-line programs in the
background, it pipes the command lines as well as
the resulting outputs into a log.  These log
outputs can be viewed at any time with
Preferences -> View Logs (Linux: Alt-l, Mac:
Cmd-l).  There are three parts of the log -- one
for tkmedit, one for tksurfer, and one for all
other command line programs.  When you quit
csurf, the entire contents of the log is saved
into a file in the current scriptsdir, csurf.log
(full path echoed to stdout on quit).

To save *just* the commands executed by csurf to
a separate file (e.g., as the basis for your own
shell script), use:

  Preferences -> Open csurf cmds-only file
  Preferences -> Close csurf cmds-only file

See also tksurfer.log and tkmedit.log which save
tcl commands below.

User Setup

The csurf program tree can be installed anywhere.
There is a patch setup command that needs to be
sourced (different versions for csh/tsh and
sh/bash).

The least invasive way to setup your environment
variables is via an alias in your .cshrc or
.tcshrc file (so each new window won't
automatically have its path and environment
reset).  Then, in a new window, to start up, you
would type:

  fs         -> setup csurf/FreeSurfer0.8 paths
  csurf      -> start csurf interface (or: csurf &)

Here is an example of an alias, 'fs', that could
be added to your Linux .cshrc (or .tcshrc) file
that assumes you installed MGH freesurfer in the
standard place, csurf in your home directory, and
that you have subjects and sessions directories
in your home directory:

alias fs \
   "setenv FSURF_DIR /usr/local/freesurfer; \
    setenv SUBJECTS_DIR ~/subjects; \
    setenv FUNCTIONALS_DIR ~/sessions; \
    pushd ~/csurf; \
    source FreeSurferEnv.csh; \
    popd"

Here is how to add a .bashrc function to achieve
the same effect (or use a sh/bash alias):

fs() {
  export FSURF_DIR=/usr/local/freesurfer
  export SUBJECTS_DIR=~/subjects
  export FUNCTIONALS_DIR=~/sessions
  pushd ~/csurf
  source FreeSurferEnv.sh
  popd
}

On Mac, the FSURF_DIR path line for tcsh and
bash would typically instead be:

  setenv FSURF_DIR /Applications/freesurfer   # tcsh
  export FSURF_DIR=/Applications/freesurfer   # bash

If you want the csurf text editor to be vi in a
gterm or xterm (instead of a default graphical
editor like gedit), you can also add one of these
to your .cshrc:

  setenv CSURFEDITORVIGTERM   # or bash: export ...
  setenv CSURFEDITORVIXTERM   # or bash: export ...

Other useful aliases

  ## cd to subj/sess scriptsdir with just name
  alias cds  'cd $SUBJECTS_DIR/\!*/scripts'
  alias cdf  'cd $FUNCTIONALS_DIR/\!*/*/scripts'

Keyboard shortcuts

There are a few csurf keyboard shortcuts for the
most commonly used menu items (N.B.: on Linux,
the shortcut command key is "Alt" while on Mac,
the shortcut command key is "command", both usu.
immediately left of the space bar).

 Alt/Cmd-u   File -> Update Sessions/Subjects
 Alt/Cmd-f    SessionTools -> View Functional Data
 Alt/Cmd-b   SessionTools -> View Saved Bitmaps
 Alt/Cmd-l    Preferences -> View/Hide Logs
 Alt/Cmd-o   Preferences -> Don't Ask to Overwrite

The panels presenting lists of saved bitmaps to
view (e.g., from Alt/Cmd-b) have another
shortcut (documented on the panels):

 Alt/Cmd-e   select all (every)

Binary File Byte Order

All FreeSurfer generated data files are stored in
most-significant byte first (MSB first) order.
This is (was!) the native byte order on
SGI/Sun/PowerPC.  On Linux and Intel Mac, the
byte order is swapped on file read and write.

Surface Format Read

  native freesurfer tri or quad (binary)
  native freesurfer tri or quad (ASCII)
  ICO tri (ASCII)
  VTK tri (ASCII)
  OFF tri (ASCII)
  GIFTI tri (base64 ASCII)
  OBJ tri (ASCII)
  SRF tri (binary)

Surface Format Write

  native freesurfer format (binary)
  freesurfer format (ASCII)
  vtk 3.0 format (ASCII)
  object file format: OFF,COFF (ASCII)
  stereolithography format: 3D printer (ASCII)
  glTF 2.0: GL transmission format (binary)


##############################
Volume Binary File Formats
##############################

 COR directory:
    ------- COR-.info header file -----------
    imnr0 1	# zmin
    imnr1 256	# zmax
    ptype 2	# planetype (0=hor,1=sag,2=cor/def)
    x 256	# zsize
    y 256	# ysize
    fov 0.256000	# FOV (meters)
    thick 0.001000	# slice thick (meters)
    psiz 0.001000	# pix size (meters)
    locatn 0.000000	# def=0
    strtx -0.128000
    endx 0.128000
    strty -0.128000
    endy 0.128000
    strtz -0.128000
    endz 0.128000
    tr 0.000000
    te 0.000000
    ti 0.000000
    xform talairach.xfm
    ------- COR-??? byte images -------------
    COR-001
    ...
    COR-256 (256x256)
	*or*
    COR-512 (512x512)
    -----------------------------------------

 AFNI BRIK (see AFNI docs for full spec):
    ------------ header file ----------------
    header: <stem>+orig.HEAD (ASCII)
        ...
        type = string-attribute
        name = TYPESTRING
        count = 15
        '3DIM_HEAD_ANAT~

        type = integer-attribute
        name = SCENE_DATA
        count = 8
         0 2 0 -999 -999
         -999 -999 -99

        type = integer-attribute
        name = ORIENT_SPECIFIC
        count = 3
         0 3 4

        type  = float-attribute
        name  = ORIGIN
        count = 3
         -81.500008 -15.857000 77.750862

        type  = float-attribute
        name  = DELTA
        count = 3
         1.697917 1.697917 1.697917

        type = integer-attribute
        name = DATASET_RANK
        count = 8
         3 1 0 0 0
         0 0 0

        type = integer-attribute
        name = DATASET_DIMENSIONS
        count = 5
         96 96 30 0 0

        type = integer-attribute
        name = BRICK_TYPES
        count = 1
         3     => 0=byte,1=short,3=float

        type = float-attribute
        name = BRICK_FLOAT_FACS
        count = 1
         0

        type = string-attribute
        name = BYTEORDER_STRING
        count = 10
        'MSB_FIRST~
        ...
    ------------- volume file -----------------
    data:  <stem>+orig.BRIK (binary, any byteorder)
    -------------------------------------------

 MGH .mgh/.mgz file (.mgz is gzipped .mgh):
    --- header (284 bytes) -------------------
    (int) 1		# version
    (int) 256		# width
    (int) 256		# height 
    (int) 256		# depth
    (int) 1		# nframes
    (int) type		# 0=uchar,1=int,3=float,4=short
    (int) dof		# degress of freedom
    (float) spacingX		# pix dim (usu. 0.0!)
    (float) spacingY		# pix dim (usu. 0.0!)
    (float) spacingZ		# pix dim (usu. 0.0!)
    (short) goodRASFlag	# 0/1
    (float) -1.0		# x_r (def)
    (float) 0.0		# x_a
    (float) 0.0		# x_s
    (float) 0.0		# y_r
    (float) 0.0		# y_a
    (float) -1.0		# y_s
    (float) 0.0		# z_r
    (float) 1.0		# z_a
    (float) 0.0		# z_s
    [...zero pad to byte 283 (0-based)]
    --- image data begins -------------------
    ...
    --- optional footer ---------------------
    (float) 0.0		# TR
    (float) 0.0		# flip
    (float) 0.0		# TE
    (float) 0.0		# TI
    (float) 256.0		# FoV
    --- optional tags -----------------------
    (int) 31		# tagID example
    (int) 74		# length example
    (variable)		# tag content
    ... [additional tags]
    -----------------------------------------

##############################
Surface Geometry Binary File Formats
##############################

All of the following formats are auto-detected by
the tcl/C function:

  read_binary_surface

There are two main types of surface formats for
individual brains in FreeSurfer.  The first
format contains quadrangles, which come from the
faces of the voxels categorized as white matter
touching not-white-matter.

  Quad Surface File Format (short vtx coords):
    -------------- header ---------------------
      3-byte magic number (16777215)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      2-byte int vertex x-position (mm x 100)
      2-byte int vertex y-position (mm x 100)
      2-byte int vertex z-position (mm x 100)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here implicit from above, 0-based]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

  New Quad Surface File Format (float vtx coord):
    -------------- header ---------------------
      3-byte magic number (16777213)
      3-byte int vertex count (~150,000)
      3-byte int face count (~150,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      4-byte float vertex x-position (mm)
      4-byte float vertex y-position (mm)
      4-byte float vertex z-position (mm)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here implicit from above, 0-based]
      [num each face ordered CCW from outside]
      corner1 corner2 corner3 corner4
      ... [quadruples up to face count]
    -------------------------------------------

  ASCII Quadrangle Surface File Format (ASCII):
    -------------- header ---------------------
      #!ascii ... quadrangles  ... (magic=2302305)
      vertexcount facecount
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      corner1  corner2  corner3  corner4
      corner1  corner2  corner3  corner4
      ... [quadruples up to face count]
    -------------------------------------------

The second surface file format contains triangles.
These are initially made by subdividing each
voxel-face quadrangle into two triangles.

  Triangle Surface File Format:
    -------------- header ---------------------
      3-byte magic number (16777214)
      less-than-200-char '\n'-terminated string
      [e.g., "created by %s=user on %s=time\n"] 
      4-byte int vertex count (~150,000)
      4-byte int face count (~300,000)
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      4-byte float vertex x-position (mm)
      4-byte float vertex y-position (mm)
      4-byte float vertex z-position (mm)
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      [vtx nums here are implicit ones above]
      [vtx nums here implicit from above, 0-based]
      corner1 corner2 corner3
      ... [triples up to face count]
    -------------------------------------------

  ICO Triangle Surface File Format (ASCII):
    ---------- vertex positions ---------------
      163842  (e.g., ico7  ASCII vertex count)
      1   x1   y1   z1      (ic7.tri: radius=1)
      2   x1   y1   z2
      ... [numbered x,y,z triples to vtx count]
    ---- vertex numbers around each face ------
      327680   (e.g., ico7 ASCII face count)
      1   corner1  corner2  corner3
      2   corner1  corner2  corner3
      [vtx nums here are explicit nums above]
      [num each face ordered CCW from outside]
      ... [numbered triples to face count]
    -------------------------------------------

  ASCII Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      #!ascii ... [triangles] ... (magic=2302305)
      vertexcount facecount
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      corner1  corner2  corner3
      corner1  corner2  corner3
      ... [triples up to face count]
    -------------------------------------------

  VTK Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      # vtk DataFile Version 3.0
      <filename or other single-line info>
      ASCII
      DATASET POLYDATA
      POINTS <vertexcount> float
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      POLYGONS <facecount> <totaltokens>
      [faces are implicitly numbered]
      3  corner1  corner2  corner3
      3  corner1  corner2  corner3
      ... [4-tuples up to face count]
    -------------------------------------------
      [optional columns of vertex overlay data]
      [ignored if file read as surface]
      POINT_DATA <vertexcount>
      SCALARS EmbedVertex float <columncount>
      LOOKUP_TABLE default
      column1value column2value ... [columncount entries]
      column1value column2value ... [columncount entries]
      ... [implicitly num'd tuples to vertexcount]
    -------------------------------------------

  OFF Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      OFF (or COFF)
      # comment line ...
      <vertex-count> <face-count> <edge-count>
    ---------- vertex positions ---------------
      [vertex triples are implicitly numbered]
      x y z
      x y z
      ... [x,y,z triples up to vertex count]
    ---- vertex numbers around each face ------
      [faces are implicitly numbered]
      3  corner1  corner2  corner3
      3  corner1  corner2  corner3
      ... [4-tuples up to face count]
    -------------------------------------------

  GIFTI Triangle Surface File Format (ASCII)
    -------------- header ---------------------
      <?xml version="1.0" encoding="UTF-8"?>
      <GIFTI xmlns:xsi="http://www.w3.org/...
         ...
         Version="1"
         NumberOfDataArrays="2">
        ...
        <DataArray Intent="NIFTI_INTENT_POINTSET"
                   DataType="NIFTI_TYPE_FLOAT32"
                   ArrayIndexingOrder="RowMajorOrder"
                   Dimensionality="2"
                   Dim0="32492"
                   Dim1="3"
                   Encoding="GZipBase64Binary"
                   Endian="LittleEndian"
                   ExternalFileName=""
                   ExternalFileOffset="0">
              ...
          <Data>
            [usu: base64 encoded gzipped binary floats]
          </Data>
        </DataArray>
        <DataArray Intent="NIFTI_INTENT_TRIANGLE"
                   DataType="NIFTI_TYPE_INT32"
                   ArrayIndexingOrder="RowMajorOrder"
                   Dimensionality="2"
                   Dim0="64980"
                   Dim1="3"
                   Encoding="GZipBase64Binary"
                   Endian="LittleEndian"
                   ExternalFileName=""
                   ExternalFileOffset="0">
          ...
          <Data>
            [usu: base64 encoded gzipped binary ints]
          </Data>
        </DataArray>
      </GIFTI>
    -------------------------------------------

  OBJ (Wavefront) Triangle Surface File Format (ASCII):
    -------------- header ---------------------
      # comment line (no req'd header)
      [vertex triples implicitly numbered]
      "v"  x  y  z  [r  g  b]
      "v"  x  y  z  [r  g  b]
      ... [x,y,z triples or sextuples up to vertex count]

      [normal triples implicitly num'd, norm maybe!=1]
      [N.B.: currently ignored here and recalc'd as usual]
      "vn"  x  y  z
      "vn"  x  y  z
      ... [x,y,z triples up to vertex count]

      [face triples implicitly num'd]
      [entries: vtx, vtx/tex, vtx//norm, vtx/tex/norm]
      [N.B.: vtx/tex/norm nums are 1-based!]
      [N.B.: ignores tex/norm nums]
      "f" vtx1 vtx2 vtx3
               *or*
      "f" vtx1/tex1 vtx2/tex2 vtx3/tex3
               *or*
      "f" vtx1//norm1 vtx2//norm2 vtx3//norm3
               *or*
      "f" vtx1/tex1/norm1 vtx2/tex2/norm2 vtx3/tex3/norm3
      ... [triples up to face count]
    -------------------------------------------

  SRF (BrainVoyager) Triangle Surface File Format (binary):
    -------------- header ---------------------
     4-byte float version (4)
     4-byte int reserved (must be 0)
     4-byte int vertexcnt
     4-byte int facecnt
     4-byte float centx
     4-byte float centy
     4-byte float centz
     vertexcnt*4-byte floats x (N.B.: left-handed coords!)
     vertexcnt*4-byte floats y
     vertexcnt*4-byte floats z
     vertexcnt*4-byte floats normal x (inward pointing!)
     vertexcnt*4-byte floats normal y
     vertexcnt*4-byte floats normal z
     4*4-byte float convex curv color r,g,b,a
     4*4-byte float concave curv color r,g,b,a
     vertexcnt*4-byte int vertex colors
     foreach vertex
       4-byte int neighbor count [N.B.: varies]
       count*4-byte int neighbors
     facecnt*3*4-byte int face corner vtx numbers
     [optional triangle strips] 
    -------------------------------------------


Notes

For GIFTI surface, csurf/tksurfer currently reads
encodings:

  Base64Binary
  GZipBase64Binary

but not:

  ASCII
  ExternalFileBinary

For details of the GIFTI format, see:
https://www.nitrc.org/projects/gifti/

GIFTI surfaces will appear in the "surface:"
dropdown if they are in the "surf" subdir of an
otherwise empty new subject made by:

  File -> New Subject (Manual Recon)

and if they match the following pattern:

  *.{L,R}.*.surf.gii

OBJ (Wavefront) surfaces will appear if they
match the following pattern:

  *.obj

To make a *.vtk (or other .obj) surface appear in
the "surface:" dropdown, add a hemisphere and
freesurfer surface-type prefix, for example,
rename

  <some_arbitrary_long_filename>.vtk

to

  rh.orig.<some_arbitrary_long_filename>.vtk


##############################
Per-Surface-Vertex Binary/ASCII File Formats
##############################

  The format of some of the per-vertex files was
  updated from the original FreeSurfer.  The
  curvature file (*.curv, *.sulc) format was
  updated from short*100 to float.  The old area
  file format (*.area) was discontinued (new area
  and thickness files are same format as new
  curvature).  The patch file format
  ($hemi.$name.patch.flat/3d), which contains
  patch vertex x,y,z positions for a subset of
  vertices in a full/parent surface, was updated
  from short*100 to float.  The value file format
  (e.g., paint output files, *.w) is unchanged,
  although curv format files or 1-D .mgh formats
  are often used for value files.  The fieldsign
  and fieldsign mask files are unchanged.

  The curvature and area files list data for
  every vertex and contain no vertex numbers.
  The patch file contains a subset of one-based
  surface vertices with the sign used as a flag
  for boundary vertices.  The value files
  (wfiles) contain a list of vertex/value pairs
  so a subset of vertices may be specified.  The
  wfile vertex numbers are zero-based.  The
  fieldsign and fieldsign mask files require all
  vertices and have a single float datum per
  vertex.  The byte sizes for the different file
  types are:

  file type                old         new
  --------------------------------------------
  curv (*.curv,*.sulc)    33{2},..    344{4},..
  patch (*.*.patch.*)     4{4222},..  44(4444),..
  area (*.area)           33{4},..    344{4},..
  val (*.w)               23{34},..   23{34},.. 
  fieldsign (*.fs,*.fm)   4{4},...    4{4},...
  --------------------------------------------

Details of binary file formats are as follows
(byte sizes in brackets, repeating group
indicated by "...", byteorder MSB):

  --------------------------------------------
  oldcurv  [no magic]
    header:  vertexcnt[3],facecnt[3]
    data:    floatcurv*100[2], ...
  --------------------------------------------
  newcurv  [magic: -1 => 16777215 read in 3bytes]
    header:  -1[3],vcnt[4],fcnt[4],valspervtx[4]
    data:    floatcurv[4], ...
  --------------------------------------------
  oldarea  [no magic]
    header:  vertexcnt[3],facecnt[3]
    data:    floatarea[4], ...
  --------------------------------------------
  newarea, thickness
    [same as newcurv]
  --------------------------------------------
  oldpatch  [no magic]
    header:  vcnt[4]
    data:    vtx[4], floatx*100[2], y, z, ...
               [vtx=[+,-]1-based: neg->border]
  --------------------------------------------
  newpatch  [magic: -1 read as 4byte int]
    header:  -1[4],vcnt[4]
    data:    vtx[4], floatx[4], y, z, ...
               [vtx=[+,-]1-based: neg->border]
  --------------------------------------------
  valfile  [no magic]
    header:  latency[2],vertexcnt[3]
    data:    {vtxnum[3],floatval[4]}, ...
  --------------------------------------------
  fieldsign files  [no magic]
    header:  vcnt[4]  (must be full)
    data:    floatval[4], ...
  --------------------------------------------
  .mgh file [no magic]
    format: 1frame, nx1x1 .mgh file -- see above
  --------------------------------------------
  _000.bfloat file [no magic]
    header:  matching 1-line ASCII *.hdr file: 1 <vtxcnt> 1 0
    data:    floatval[4], ...
  --------------------------------------------

Details of ASCII vertexwise file formats:

  --------------------------------------------
  .vtk files [magic: 2302070 (read "# vtk" as 3byte int)]
    format: optionalsurf + overlaydata -- see above
  --------------------------------------------
  .gii files [magic: 3948408 (read "<?xml" as 3byte int)]
             [format: single frame vertex list]
    <?xml version="1.0" encoding="UTF-8"?>
    <GIFTI ...
           NumberOfDataArrays="1">
    ...
      <DataArray Intent="NIFTI_INTENT_NORMAL"
                 DataType="NIFTI_TYPE_FLOAT32"
                 ArrayIndexingOrder="RowMajorOrder"
                 Dimensionality="1"
                 Dim0="32492"
                 Encoding="GZipBase64Binary"
                 Endian="LittleEndian"
                 ExternalFileName=""
                 ExternalFileOffset="0">
        ...
        <Data>
          [usu: base64 encoded gzipped binary data]
        </Data>
      </DataArray>
    </GIFTI>
  --------------------------------------------

N.B.: see the R-click help for the entry on the
"label:" line for the format of MGH annotation
files (*.annot), BV patches-of-interest (*.poi)
files, and GIFTI annotation files (*.gii).

##############################
"Template" Binary File Format
##############################

The morph target "template" files are multi-frame
uncompressed 256x512 pixel TIFF files, with 32
bits per pixel, one sample per pixel.  The
standard morph target files:

  rh.average.curvature.filled.buckner40.tif
  lh.average.curvature.filled.buckner40.tif

are stored in $FSURF_DIR/average (subdir in MGH
freesurfer distribution), and contain 3 kinds of
data, with 3 frames for each kind, for a total of
9 (zero-based) frames:

  0: average inflated.H -- mean curvature = (kmin+kmax)/2
  1: variance of inflated.H
  2: degrees of freedom (dof=39 means 40 subjects)
  3: average sulc
  4: variance of sulc
  5: degrees of freedom
  6: average curv
  7: variance of curv
  8: degrees of freedom

The file represents a Mercator projection (yup)
of the curvature values for the registered
sphere.  The degrees of freedom (number of
subjects minus 1) is stored as a floating point
value in the single bottom-left pixel in an
otherwise black third image.

If FSURF_DIR is defined, these frames can be
viewed on sphere.reg surface by loading them from
tksurfer as a "curv:" file (at bottom of list).

##############################
[end file format specifications]
##############################


Default variable values and overrides

The various csurf panels save the state of many
different variables passed to FreeSurfer command
line programs.  For example, the SessionTools ->
View Functional Data panel saves the state of
many (but not all) tksurfer rendering variables.

These values can be overridden in a large number
of ways.  Here are the gory details of what
happens when a functional scan is rendered with
the SURFACE-STATS button.

All of the possible places places where default
values of variables can be overriden are
identified (like this: **2**, **3**, ...)

csurf (on open View Functional Data panel):

  1) csurf reads parm vals from csurf.dat in
       the scripts dir, defaulting most if
       missing

tksurfer (on click SURFACE-STATS button):

  2) tksurfer.c: starts up with default value C
       global variables (before read cmdline opts)

  3) tksurfer.c: reads any known-by-tksurfer vars
       from environment, may reset C vars: **2**

       (N.B.: since MacOSX 10.11+ breaks
       /usr/bin/env by making it not pass
       PATH/DYLD vars, csurf now writes env vars
       to tmpfile, /tmp/TmpEnvCsurf.$pid, and
       tksurfer reads them from there with
       readenv.tcl, which still reads env vars)

  4) tksurfer.c: reads its command line options,
       may reset C vars: **3** (this is how csurf
       passes most variable values from csurf.dat
       to tksurfer)

  5) tksurfer.c: starts tcl interpreter which
       imports curr values of many C global
       variables into tcl interpreter and sets
       up two-way mirroring of tcl<=>C vars

  6) tksurfer.c: runs tksurfer.tcl to make
       interface, can reset some now-joined
       tcl<=>C vars from tcl script **4**

  7) clicks/typing on surfer tools interface
       window may reset joined tcl<=>C vars 
       from tcl **5**

  8) rendering script (e.g., polar-views.tcl)
       may reset tcl<=>C vars from tcl **6**

  9) rendering script calls readenv.tcl to
       (re)-read current state of environment
       **7** (this is the original mechanism of
       controlling render variables from cmdline
       shell scripts in a terminal window, now
       rare)

 10a) if var nosave set (="test" clicked),
        render script calls saveviews.tcl
        to just redraw surface, which may
        reset vars **8**

             *or*
              
 10b) if var nosave *not* set ("save" clicked
        or batch run), render script calls
        saveviews.tcl to redraw *and* save
        bitmap, which may reset vars **8**

             *or*

 10c) manually click WRITE rgb button which
        saves current window after popping it
        and redrawing (to make sure on top)

Explicitly setting a variable in saveviews.tcl,
the last step in this chain (or saveflat.tcl), is
thus the surest way to set the values of a
tcl<=>C variable.  However, this is particularly
inflexible because it will affect all subsequent
renders.

Custom Tcl Scripts

To get complex control of all variables you can
write a custom render script (use polar-views.tcl
and saveviews.tcl as a model), and put it in the
current scripts dir.  Any scriptsdir file ending
in *.tcl will appear at the top of the list in
the "3D" or "Flat" dropdown scripts fields at the
bottom of View Functional Data panel (in addition
to the default scripts in $CSURF/lib/tcl).

If the script is general enough, it can be put
into $CSURF/lib/tcl and added to the list of
scripts in $defscriptlist in tksurfer.tcl that
always appear in the tksurfer tools tcl script
dropdown.

Such a script can be run by specifying it as
a command line option to tksurfer:

  tksurfer marty rh smoothwm -tcl zz.tcl

or it can be sourced from the tcl prompt
after starting tksurfer in a terminal:

  tksurfer marty rh smoothwm
  % source zz.tcl

or it can be sourced from the tksurfer.tcl
interface.  First enter the path to the script in
the "tcl:" entry with the following conventions:

  zz.tcl => look in curr session "scripts" dir
  #/zz.tcl => look in $CSURF_DIR/lib/scripts
  /full/patch/zz.tcl => anywhere

then click:

  EDIT => if you want to view/edit script
  GO => to run script

Here is a simple tcl script example that opens a
window, displays the curvature on the currently
selected surface, slightly zooms in, and then
saves a bitmap of it:

  set overlayflag 0
  read_binary_curv
  open_window
  make_lateral_view
  scale_brain 1.3
  redraw
  set rgb /tmp/zz.tiff
  save_rgb

Here is how to start with the rendered results of
one of standard scripts, and then modify it with
additional tcl commands:

  setfile script #/eccen-views.tcl
  source $script
  ... [your additional tcl code here]
  ... [your additional tcl code here]
  redraw
  set rgb /tmp/zz.tiff
  save_rgb

To find the names of all tcl variables and procs'
understood by the tksurfer tcl interpreter, type
"tksurfer -help".

See tksurfer R-click popup for "tcl:" entry for
more help and more examples.

HOWTO render very high resolution images

To render and save an image with a higher pixel
resolution than the screen, open an offscreen
window using a tcl script.  Here is a bare-bones
script to do this:

  set renderoffscreen 1
  resize_window 3500  ;# pixels
  open_window
  make_lateral_view
  ## cmds here to read data, adj pose
  redraw
  set rgb /tmp/zz.tiff
  save_rgb 

To run this script, save the script above into a
file and run:

  tksurfer <subj> <hemi> <surf> -tcl <scriptname>

For a more detaled example with overlay data, see
the right-click help for the "rgb:" entry.

Record Tcl Commands for Interface Actions

To get a file containing all the tcl commands
that have been executed as tksurfer or tkmedit
interface buttons and entries were interactively
manipulated, use:

  Preferences -> Log tksurfer actions as tcl cmds
  Preferences -> Log tkmedit actions as tcl cmds

This will dump all the tcl commands into:

  $FUNCTIONALS_DIR/$session/image/scripts/tksurfer.log
  $FUNCTIONALS_DIR/$session/image/scripts/tkmedit.log

N.B.: if these menu items are enabled, every time
tksurfer or tkmedit is restarted from csurf, the
previous tksurfer.log or tkmedit.log in the
scripts dir in this session is erased and a new
clean one is begun.

To see the tcl commands as they are deposited to
one of these logs after each click, use 'tail -f'
(i.e., watch end of file for additions):

  cd $FUNCTIONALS_DIR/$session/image/scripts
  tail -f tksurfer.log
    *or*
  tail -f tkmedit.log

Csurf Hacking

The csurf tcl/tk/tix program is a single 24K-line
ASCII file that can be viewed and modified in a
text editor.  Its only dependency is a small
utility script, wrappers.tcl, that is sourced at
startup ($CSURF_DIR/lib/tcl/wrappers.tcl, also
sourced by tksurfer, tkmedit, tkregister).

Csurf saves scandir-specific parameters for a given
session in:

  $CSURF_DIR/$session/image/scripts/csurf.dat

which contains ASCII dumps of configuration
parameters.  These are in the form of a parameter
arrayname on one line (e.g., functscanlists)
followed by a list of name-value pairs on the
next (long) line, where the format of name is:

  <iscandir>,<parmeter-name>

and the format of value is text or a number.  For
example:

  % cat csurf.dat
  ...
  csurf arrayname: functscanlists
  image/1-pol1,regdat register.dat image/1-pol1,fmid 2.2 ...
  ...

To get terminal window access to the csurf tcl
interpreter for debugging, inspection, or
hacking, do:

  cd $CSURF_DIR
  source FreeSurfer.{c}sh
  wish8.5
  % source $env(CSURF_DIR)/bin/noarch/csurf

You will now be able to see and modify/run all
csurf tcl vars and procs/commands.  For example:

  % info vars [patt]			=> list all vars [or subset]
  % info commands [patt]			=> list all cmds [or subset]
  % set <var>			=> see curr value
  % set <var> <value>			=> set new value
  % <command> <args ...>			=> run command
  % info commands .*			=> list interface win parts
  % .main.right.label config			=> see state this widget
  % .main.right.label config -text FunctionalBLAH	=> mod

--------------
References
--------------

Sereno, M.I., A.M. Dale, J.B. Reppas, K.K. Kwong,
  J.W. Belliveau, T.J. Brady, B.R. Rosen, and
  R.B.H. Tootell (1995) Borders of multiple
  visual areas in human revealed by functional
  magnetic resonance imaging. Science
  268:889-893.

Dale, A.M., B. Fischl, and M.I. Sereno (1999)
  Cortical surface-based analysis I: Segmentation
  and surface reconstruction. NeuroImage
  9:179-194.

Fischl, B., M.I. Sereno and A.M. Dale (1999)
  Cortical surface-based analysis II: Inflation,
  flattening, and a surface-based coordinate
  system. NeuroImage 9:195-207.

Fischl B., M.I. Sereno, R.B.H. Tootell and A.M.
  Dale (1999) High-resolution inter-subject
  averaging and a surface-based coordinate
  system.  Human Brain Mapping 8:272-284.

Hagler, D.J. Jr., A.P. Saygin, and M.I. Sereno
  (2006) Smoothing and cluster thresholding for
  cortical surface-based group analysis of fMRI
  data. Neuroimage 33:1093-1103.

Hagler, D.J. Jr., L. Riecke, and M.I. Sereno
  (2007) Pointing and saccades rely on common
  parietal and superior frontal visuospatial
  maps.  Neuroimage 35:1562-1577.

Sereno, M.I., A. Lutti, N. Weiskopf, and F. Dick
  (2012) Mapping the human cortical surface by
  combining quantitative T1 with retinotopy.
  Cerebral Cortex 23:2261-2268.

Huang, R.-S. and M.I. Sereno (2013) Bottom-up
  retinotopic organization supports top-down
  mental imagery.  The Open Neuroimaging Journal
  7:58-67.

Sood, M. and M.I. Sereno (2016) Areas activated
  during naturalistic reading comprehension
  overlap topological visual, auditory, and
  somatotomotor maps. Human Brain Mapping
  37:2784-2810.

Sereno, M.I., J. Diedrichsen, M. Tachrount, G.
  Testa-Silva, H. d'Arceuil, and C. De Zeeuw
  (2020) The human cerebellum has almost 80% of
  the surface area of the neocortex.  Proceedings
  of the National Academy of Sciences USA
  117:19538-19543.

