Update of /cvsroot/pure-data/externals/pdp/scaf/rules
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/scaf/rules
Added Files:
Makefile carules.scaf
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: carules.scaf ---
( Pure Data Packet - ca rules library. )
( Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org> )
( )
( This program is free software; you can redistribute it and/or modify )
( it under the terms of the GNU General Public License as published by )
( the Free Software Foundation; either version 2 of the License, or )
( [at your option] any later version. )
( )
( This program is distributed in the hope that it will be useful, )
( but WITHOUT ANY WARRANTY; without even the implied warranty of )
( MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the )
( GNU General Public License for more details. )
( )
( You should have received a copy of the GNU General Public License )
( along with this program; if not, write to the Free Software )
( Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. )
( this is the standard ca rules library )
( a rule that is accessible from the ouside should start with "rule_" )
( and has to return exactly one item on the stack (this is checked in pdp_ca) )
( a word is a sequence of non whitespace characters (\S+) )
( words are separated by whitespace (\s+) )
( so "word ;" is not the same as "word;" )
( all words between the "(" word and the ")" word are ignored )
( ":" starts a definition, the next word is the name of the new word )
( newline ends a definition )
( no more than one definition per line )
( no more than one line per definition )
( ";" returns to calling word )
( if no ";" is encountered the next defined word is executed )
( this is to have multiple entry points )
( multiple exit points don't make sense since there are no conditional words )
: +(4) ++++ ; ( 4 bit add TOS - carry on TOS )
: +(3) +++ ; ( 3 bit add TOS - carry on TOS )
: +(2) ++ ; ( 2 bit add TOS - carry on TOS )
: +top @-+ +(4) drop @0+ +(4) drop @++ +(4) ; ( add top row to reg - carry on TOS )
: +mid @-0 +(4) drop @00 +(4) drop @+0 +(4) ; ( add mid row to reg - carry on TOS )
: +bot @-- +(4) drop @0- +(4) drop @+- +(4) ; ( add bot row to reg - carry on TOS )
: +all +top drop +mid drop +bot ; ( add all cells to reg - carry on TOS )
: +mid-1 @-0 +(4) drop @+0 +(4) ; ( add mid row except center element to reg - carry on TOS )
: +all-1 +top drop +mid-1 drop +bot ; ( add all cells expet middle one to reg - carry on TOS )
: countall a-0 +all drop ; ( count all cells - no stack effect )
: countall-1 a-0 +all-1 drop ; ( count all cells except middle one - no stack effect )
: +topbot @0+ +(3) drop @0- +(3) ;
: +leftright @+0 +(3) drop @-0 +(3) ;
: +star +topbot drop +leftright ;
: countstar a-0 +star drop ;
: =2or3? @a2 not @a1 and ; ( sum equal to 2 or 3? only checks 3 bits )
: =3? =2or3? @a0 and ; ( sum equal to 3 ? )
: =2? =2or3? @a0 not and ; ( sum equal to 2 ? )
: =4? @a2 @a1 not and @a0 not and ; ( sum equal to 4 ? )
( some test rules )
( : rule_one 1 ; )
( : rule_zero 0 ; )
( : rule_id @00 ; )
: rule_shiftleft @+0 ;
: rule_shifttop @0- ;
: rule_shiftbot @0+ ;
: rule_shifttopright @-- ;
: rule_strobe @00 not ;
( game of life )
: rule_gameoflife countall-1 =2? @00 and =3? or ;
( wolfram's rule 110)
: rule_w110 @00 @+0 and not @-0 @00 @+0 or or and ;
( some other rules )
: rule_w110mod @0+ @+0 and not @-+ @0+ @++ or or and ;
: rule_w110mod2 @0+ @+0 and not @-+ @0+ @+0 or or and ;
: rule_w110mod3 @0+ @++ and not @-+ @0+ @++ or or and @-0 @00 @+0 or or and ;
: rule_golmod countall-1 =3? @00 and =2? or ;
: rule_golmod2 countall-1 =2? @0+ and =3? or ;
: rule_golmod3 countall-1 =2? @++ and =3? or ;
: rule_golmod4 countall-1 =2? @++ @-- or and =3? or ;
: rule_golmod5 countall-1 =2? @++ @-- or and =3? @+- and or ;
: rule_golmod6 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or ;
: rule_golmod7 countall-1 =2? @++ @-- or and =3? @+- and or @0+ or @00 and ;
( ca's with a short settling time )
: rule_block countstar =4? not =2? and @00 or ;
: rule_noiseedges countstar =4? =3? or not =2? and @00 or @++ xor ;
: rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ;
( : rule_noiseplanes countstar =4? =3? or not =2? and @00 or @++ xor @-- xor ; )
: rule_fire countall-1 =2? @0+ and =3? or ;
--- NEW FILE: Makefile ---
OBJ = carules.scafo
.SUFFIXES: .scaf
.SUFFIXES: .scafo
.scaf.scafo:
../compiler/scafc $*.scaf
all: $(OBJ)
clean:
rm -f *.scafo
rm -f *.s
rm -f *~
Update of /cvsroot/pure-data/externals/pdp/system
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/system
Added Files:
CONTENTS Makefile pdp.c
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp.c ---
/*
* Pure Data Packet system implementation: setup code
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdio.h>
#include "pdp_config.h"
#include "pdp_post.h"
/* all symbols are C style */
#ifdef __cplusplus
extern "C"
{
#endif
/* module setup declarations (all C-style) */
/* pdp system / internal stuff */
void pdp_debug_setup(void);
void pdp_list_setup(void);
void pdp_pdsym_setup(void);
void pdp_forth_setup(void);
void pdp_forth_def_setup(void);
void pdp_symbol_setup(void);
void pdp_type_setup(void);
void pdp_packet_setup(void);
void pdp_ut_setup(void);
void pdp_queue_setup(void);
void pdp_control_setup(void);
void pdp_image_setup(void);
void pdp_bitmap_setup(void);
void pdp_matrix_setup(void);
/* pdp modules */
void pdp_xv_setup(void);
void pdp_add_setup(void);
void pdp_mul_setup(void);
void pdp_mix_setup(void);
void pdp_randmix_setup(void);
void pdp_qt_setup(void);
void pdp_v4l_setup(void);
void pdp_reg_setup(void);
void pdp_conv_setup(void);
void pdp_bq_setup(void);
void pdp_del_setup(void);
void pdp_snap_setup(void);
void pdp_trigger_setup(void);
void pdp_route_setup(void);
void pdp_noise_setup(void);
void pdp_gain_setup(void);
void pdp_chrot_setup(void);
void pdp_scope_setup(void);
void pdp_scale_setup(void);
void pdp_zoom_setup(void);
void pdp_scan_setup(void);
void pdp_scanxy_setup(void);
void pdp_sdl_setup(void);
void pdp_cheby_setup(void);
void pdp_grey2mask_setup(void);
void pdp_constant_setup(void);
void pdp_logic_setup(void);
void pdp_glx_setup(void);
void pdp_loop_setup(void);
void pdp_description_setup(void);
void pdp_convert_setup(void);
void pdp_stateless_setup(void);
void pdp_mat_mul_setup(void);
void pdp_mat_lu_setup(void);
void pdp_mat_vec_setup(void);
void pdp_plasma_setup(void);
void pdp_cog_setup(void);
void pdp_histo_setup(void);
void pdp_array_setup(void);
void pdp_udp_send_setup(void);
void pdp_udp_receive_setup(void);
void pdp_rawin_setup(void);
void pdp_rawout_setup(void);
/* hacks */
void pdp_inspect_setup(void);
/* testing */
void pdp_dpd_test_setup(void);
/* library setup routine */
void pdp_setup(void){
/* babble */
pdp_post ("PDP: pure data packet");
#ifdef PDP_VERSION
pdp_post("PDP: version " PDP_VERSION );
#endif
/* setup pdp system */
/* kernel */
pdp_pdsym_setup();
pdp_debug_setup();
pdp_symbol_setup();
pdp_list_setup();
pdp_type_setup();
pdp_packet_setup();
pdp_control_setup();
/* types */
pdp_image_setup();
pdp_bitmap_setup();
#ifdef HAVE_PDP_GSL
pdp_matrix_setup();
#endif
pdp_queue_setup();
/* setup utility toolkit */
pdp_ut_setup();
/* setup pdp pd modules*/
pdp_add_setup();
pdp_mul_setup();
pdp_mix_setup();
pdp_randmix_setup();
pdp_reg_setup();
pdp_conv_setup();
pdp_bq_setup();
pdp_del_setup();
pdp_snap_setup();
pdp_trigger_setup();
pdp_route_setup();
pdp_noise_setup();
pdp_plasma_setup();
pdp_gain_setup();
pdp_chrot_setup();
pdp_scope_setup();
pdp_scale_setup();
pdp_zoom_setup();
pdp_scan_setup();
pdp_scanxy_setup();
pdp_grey2mask_setup();
pdp_constant_setup();
pdp_logic_setup();
pdp_loop_setup();
pdp_description_setup();
pdp_convert_setup();
pdp_stateless_setup();
pdp_cog_setup();
pdp_array_setup();
pdp_rawin_setup();
pdp_rawout_setup();
/* experimental stuff */
pdp_inspect_setup();
pdp_udp_send_setup();
pdp_udp_receive_setup();
/* testing */
//pdp_dpd_test_setup();
/* optional stuff */
#ifdef HAVE_PDP_READLINE
pdp_forthconsole_setup();
#endif
#ifdef HAVE_PDP_GSL
pdp_histo_setup();
pdp_cheby_setup();
pdp_mat_mul_setup();
pdp_mat_lu_setup();
pdp_mat_vec_setup();
#endif
#ifdef HAVE_PDP_QT
pdp_qt_setup();
#endif
#ifdef HAVE_PDP_XV
pdp_xv_setup();
#endif
#ifdef HAVE_PDP_SDL
pdp_sdl_setup();
#endif
#ifdef HAVE_PDP_V4L
pdp_v4l_setup();
#endif
#ifdef HAVE_PDP_GLX
pdp_glx_setup();
#endif
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: Makefile ---
include ../Makefile.config
all: $(PDP_TARGET) pdp.o
common:
make -C net
make -C X11
make -C png
make -C type
make -C kernel
make -C image $(PDP_TARGET)
linux_mmx: common
make -C mmx
linux: common
darwin: common
clean:
rm -f *~
rm -f *.o
make -C mmx clean
make -C net clean
make -C X11 clean
make -C png clean
make -C image clean
make -C type clean
make -C kernel clean
--- NEW FILE: CONTENTS ---
X11 x window specific code
forth packet forth code
image image processing code
kernel the core pdp system
mmx mmx assembly code
net networking support
png png support
type different packet type implementations
Update of /cvsroot/pure-data/externals/pdp/scaf
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/scaf
Added Files:
COPYING Makefile Makefile.config Makefile.config.in README
README.scaf TODO configure configure.ac
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: configure ---
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59.
#
# Copyright (C) 2003 Free Software Foundation, Inc.
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## --------------------- ##
## M4sh Initialization. ##
## --------------------- ##
# Be Bourne compatible
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
# Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
[...4085 lines suppressed...]
# config.status does its own redirection, appending to config.log.
# Unfortunately, on DOS this fails, as config.log is still kept open
# by configure, so config.status won't be able to write to it; its
# output is simply discarded. So we exec the FD to /dev/null,
# effectively closing config.log, so it can be properly (re)opened and
# appended to by config.status. When coming back to configure, we
# need to make the FD available again.
if test "$no_create" != yes; then
ac_cs_success=:
ac_config_status_args=
test "$silent" = yes &&
ac_config_status_args="$ac_config_status_args --quiet"
exec 5>/dev/null
$SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
exec 5>>config.log
# Use ||, not &&, to avoid exiting from the if with $? = 1, which
# would make configure fail if this is the last instruction.
$ac_cs_success || { (exit 1); exit 1; }
fi
--- NEW FILE: Makefile ---
include Makefile.config
all: pdp_scaf.pd_linux
pdp_scaf_all:
make -C include
make -C compiler
make -C rules
make -C pdp
clean:
rm -f *~
rm -f pdp_scaf.pd_linux
make -C include clean
make -C compiler clean
make -C rules clean
make -C pdp clean
mrproper: clean
rm -rf configure
rm -rf config.status
rm -rf config.log
rm -rf autom4te.cache
#this needs to stay in
#rm -rf Makefile.config
pdp_scaf.pd_linux: pdp_scaf_all
rm -f pdp_scaf.pd_linux
gcc -export_dynamic -shared -o pdp_scaf.pd_linux pdp/*.o $(PDP_CA_LIBS)
install: all
install -d $(prefix)/lib/scaf
install -m 755 compiler/scafc $(prefix)/bin || echo failed
install -m 755 compiler/scafc.pl $(prefix)/lib/scaf || echo failed
install -m 644 compiler/kernel.scaf $(prefix)/lib/scaf || echo failed
install -m 644 compiler/scafmacro.s $(prefix)/lib/scaf || echo failed
install -m 644 compiler/optim.rules $(prefix)/lib/scaf || echo failed
install -m 755 rules/carules.scafo $(prefix)/lib/scaf/default.scafo || echo failed
#Check if pd is installed in $(prefix)/lib/pd.
#If this fails the pdp_scaf lib and the docs won't be installed.
test -d $(prefix)/lib/pd
install -m 755 pdp_scaf.pd_linux $(prefix)/lib/pd/externs
install -m 644 doc/*.pd $(prefix)/lib/pd/doc/5.reference
--- NEW FILE: README.scaf ---
SCAF - simple cellular automaton forth
scaf is a virtual machine / forth environment for binary arithmic
tailored to 2D 1 cell neighbourhood cellular automata.
scaf is a compiled language. programs run inside a "feeder"
(sort of operating system if you want)
the feeder is responsable for loading/storing CA cells
from/to memory. data in memory is organized as a scanline
encoded toroidial bitplane (lsb = left). to simplify the feeder
and the stack machine, the top left corner of the rectangular grid
of pixels will shift down every processing step. this enables
to keep a cell neighbourhood in a couple of registers.
the stack machine has the following architecture:
CA stack: (%esi), TOS: %mm0 (32x2 cells. lsb = top left)
CA horizon: (%edi) (64x4 cells. (%edi) = top row. lsb = left)
scratch register: %mm1, %mm2
bitmask register: %mm3 = 0xffffffffffffffff
4 bit counter: %mm4-%mm7
the stack size / organization is not known to the stack machine.
it can be thought of as operating on a 3x3 cell neightbourhood.
the only purpose of the forth program is to determine the CA local update rule.
the machine is supposed to be very minimal. no looping control.
no adressing modes. no conditional code. so recursion is not allowed
(no way to stop it) there are 9 words to load the cell neigbourhood
on the stack. the rest is just logic and stack manips.
the counter can be used for counting neighbourhood cells, like in the
game of life. the zero test and sign bit can be used for comparisons.
there are kernel words for loading constants into the counter register,
and for communication between stack and register.
the horizon is limited to 3x3, however it can be easily extended to
32x3. extending it further than that would require a redesign of the
forth + feeder.
HOW TO CREATE NEW CA RULES
edit scaf/modules/carules.scaf or create your own source lib and add
the name to the scaf/modules/Makefile. type make in scaf/modules
to compile. if you get error messages from the assembler saying things
like
Error: no such instruction: `xxx'
or
Error: invalid character '_' in mnemonic
this means there are undefined words in your source file. since not
all characters are allowed in an asm file, the offending characters are
converted to _SOMETHINGELSE_
if you are stuck somewhere, just look at the output of scaf.pl on
your .scaf file to determine where the problem is.
words that can be accessed from inside pdp_ca have to start with the
prefix rule_ and have to leave a single item on the data stack (the return
value) other rules can have all the stack effect you want, but for safety
reasons they can't be accessed from within pdp_ca.
FORTH SYSTEM CODE
the forth system is made up of the following files:
kernel.scaf: a collection of forth kernel words
scafmacro.s: a set of asm macro definitions used in kernel.scaf
optim.rules: some substitution rules to eliminate redundant
stack manipulations
scaf.pl: the compiler
scaf.pl is run like this:
scaf.pl -Isystemdir source.scaf
if the -I switch is left out, the current directory is searched
for the system files. the compiler produces an assembler source
that includes scafmacro.s on standard output.
the code it produces is relatively fast. it only uses and/or/xor
and shift mmx instructions. it's not optimal use of silicon but
it's pretty fast given what's possible. the feeder routine could
be improved though.
porting to another platform would require a rewrite of scafmacro.s
the rest can be reused. if the target machine has 64 bit registers
(or if you can emulate this one using more registers) porting is
relatively easy. for larger registers a small change needs to
be made to the feeder routine in pdp_ca.c
--- NEW FILE: Makefile.config ---
# build flags
# define the include paths here if configure can't find them
# PDP_CFLAGS=-I/somehere/pdp/include
# PD_CFLAGS=-I/somewhere/pd/src
prefix=/usr/local
PDP_CA_INCLUDE = -I/home/tom/pd/packet/include -I/home/tom/pd/packet/scaf/include
PDP_CA_LIBS = -ldl -lm
DEFAULT_RULES_LIB = /usr/local/lib/scaf/default.scafo
PDP_CA_AFLAGS =
#--gstabs
PDP_CA_CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \
-Wall -W -Wstrict-prototypes -Werror \
-Wno-unused -Wno-parentheses -Wno-switch -g $(PDP_CFLAGS) $(PD_CFLAGS) \
-DPDP_CA_RULES_LIB=\"$(DEFAULT_RULES_LIB)\"
# -Wshadow
# compiler and assembler
#CC = gcc-3.2
#CC = gcc
#AS = as
# build rules
.c.o:
$(CC) $(PDP_CA_CFLAGS) $(PDP_CA_INCLUDE) $(PDP_CA_DEFS) -o $*.o -c $*.c
.s.o:
$(AS) -o $*.o $*.s $(PDP_CA_AFLAGS)
--- NEW FILE: configure.ac ---
AC_INIT(pdp/pdp_ca_system.c)
AC_PROG_CC
AC_HEADER_STDC
dnl default install prefix is /usr/local
if test $prefix == "NONE";
then
prefix=/usr/local
fi
AC_PATH_PROG(PDP_CONFIG,pdp-config,"no", $PATH)
AC_CHECK_LIB(m,sin)
AC_CHECK_LIB(dl,dlopen,, echo libdl not found. sorry... || exit 1)
TOPSRC=`pwd`
PARENT=`dirname $TOPSRC`
dnl if pdp-config is found use it to get the cflags
if ! test $PDP_CONFIG == "no"
then
PDP_CPPFLAGS=`$PDP_CONFIG --cflags`
dnl if not, check in the parent dir (in case we are distributed with the pdp package)
elif test -f $PARENT/include/pdp.h
then
PDP_CPPFLAGS="-I$PARENT/include"
fi
CPPFLAGS="$CPPFLAGS $PDP_CPPFLAGS"
AC_CHECK_HEADER(m_pd.h,,PD_OK=no)
AC_CHECK_HEADER(pdp.h,,PDP_OK=no)
if test PD_OK == "no";
then
echo "WARNING: m_pd.h not found. Is PD installed?
echo "WARNING: You can ignore this warning if you have set the PD_CFLAGS manually in Makefile.config.in
fi
if test PDP_OK == "no";
then
echo "WARNING: pdp.h not found. Is PDP installed?
echo "WARNING: You can ignore this warning if you have set the PDP_CFLAGS manually in Makefile.config.in
fi
CPPFLAGS="$CPPFLAGS $PDFLAGS $PDPFLAGS -I$TOPSRC/include"
DEFAULT_RULES_LIB=$prefix/lib/scaf/default.scafo;
AC_SUBST(DEFAULT_RULES_LIB)
AC_CONFIG_FILES(Makefile.config)
AC_OUTPUT
--- NEW FILE: Makefile.config.in ---
# build flags
# define the include paths here if configure can't find them
# PDP_CFLAGS=-I/somehere/pdp/include
# PD_CFLAGS=-I/somewhere/pd/src
prefix=@prefix@
PDP_CA_INCLUDE = @CPPFLAGS@
PDP_CA_LIBS = @LIBS@
DEFAULT_RULES_LIB = @DEFAULT_RULES_LIB@
PDP_CA_AFLAGS =
#--gstabs
PDP_CA_CFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -ffast-math \
-Wall -W -Wstrict-prototypes -Werror \
-Wno-unused -Wno-parentheses -Wno-switch -g $(PDP_CFLAGS) $(PD_CFLAGS) \
-DPDP_CA_RULES_LIB=\"$(DEFAULT_RULES_LIB)\"
# -Wshadow
# compiler and assembler
#CC = gcc-3.2
#CC = gcc
#AS = as
# build rules
.c.o:
$(CC) $(PDP_CA_CFLAGS) $(PDP_CA_INCLUDE) $(PDP_CA_DEFS) -o $*.o -c $*.c
.s.o:
$(AS) -o $*.o $*.s $(PDP_CA_AFLAGS)
--- NEW FILE: COPYING ---
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR PDP.LICENSE, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
--- NEW FILE: README ---
PDP_SCAF for pdp v0.7
Cellular Automata modules for PDP
Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The GNU Public Licence can be found in the file COPYING
------------------------------------------------------------------
This is a pdp extension lib that contains modules for cellular
automata built on a (very) minimal forth-like virtual system
(scaf - simple cellular automaton forth) to define update rules. a
compiler is included to produce scafo object code that can be
dynamically loaded into the pdp_ca module. so it is possible to
add/change rules without restarting pd (note however you need to close
all lib files before the dynamic loader reloads the lib). see
scaf/README for details.
pdp_ca2image and pdp_image2ca are included for conversion between
CA packets and image packets. (pdp_ca2image produces greyscale
images)
Have a look at the patches in test/ for some crude docs. The file
README.scaf contains some more info on the internals.
Requirements:
* pd
* pdp
* linux
* perl for the forth compiler
* an intel/amd processor that supports MMX
Building:
./configure
make
make install
If you don't have both libraries in the same dir and want to keep
it that way, hardcode the paths in Makefile.config.in and run
configure. You need to do "make install" to install the scaf compiler
"scafc" and the default ruleset. This is to be able to load plain
(text) rule files and have the default rules loaded when you create
a pdp_ca object.
Using:
add "-lib <SCAF_DIR>/pdp_scaf" to the pd command line after the
"-lib <PDP_DIR>/pdp" part.
launch pd with the options -lib $PDP_DIR/pdp -path $PDP_DIR/abstractions
Directory structure:
include/ header files
pdp/ pdp external code
compiler/ forth system code
test/ some test patches (cryptic doc)
rules/ ca rule libraries
Please let me know if you discover a bug or think something doesn't work
right. Code, documentation or example patches are more than welcome of
course.
Have Fun,
Tom
last modified: 2003/01/12
--- NEW FILE: TODO ---
* add decimating to pdp_ca2image
* clean up library
* add translation option to pdp_ca (modify so horizontal shifts by 1 are possible)
Update of /cvsroot/pure-data/externals/pdp/scaf/pdp
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/scaf/pdp
Added Files:
Makefile pdp_ca.c pdp_ca_system.c scaf_feeder.s
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_ca.c ---
/*
* Pure Data Packet module for cellular automata
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "pdp_ca.h"
#include "pdp_internals.h"
#include <dlfcn.h>
#include <stdio.h>
t_class *pdp_ca_class; // a cellular automaton processor: single input - single output
//t_class *pdp_ca2_class; // double input - single output
t_class *pdp_ca2image_class; // converter from ca -> grey/yv12
t_class *pdp_image2ca_class; // converter from grey/yv12 -> ca
// *********************** CA CLASS STUFF *********************
// this is defined in the makefile
// #define PDP_CA_RULES_LIB "/path/default.scafo"
#define PDP_CA_STACKSIZE 256
#define PDP_CA_MODE_1D 1
#define PDP_CA_MODE_2D 2
typedef struct pdp_ca_data_struct
{
unsigned int env[2*4];
unsigned int reg[2*4];
unsigned int stack[2*PDP_CA_STACKSIZE];
short int random_seed[4];
} t_pdp_ca_data;
typedef struct pdp_ca_struct
{
t_object x_obj;
t_float x_f;
t_outlet *x_outlet0;
int x_queue_id;
/* double buffering data packets */
int x_packet0;
int x_packet1;
/* some data on the ca_routine */
void (*x_ca_routine)(void);
void *x_ca_libhandle;
char *x_ca_rulenames;
int x_ca_nbrules;
char ** x_ca_rulename;
t_symbol *x_lastrule;
/* nb of iterations */
int x_iterations;
/* shift ca on output */
int x_horshift;
int x_vershift;
/* operation mode */
int x_mode;
int x_fullscreen1d;
/* aligned vector data */
t_pdp_ca_data *x_data;
/* output packet type */
t_symbol *x_packet_type;
} t_pdp_ca;
/* 1D: process from packet0 -> packet0 */
static void pdp_ca_process_ca_1D(t_pdp_ca *x)
{
t_pdp *header = pdp_packet_header(x->x_packet0);
unsigned int *data = (unsigned int *)pdp_packet_data (x->x_packet0);
int width = pdp_type_ca_info(header)->width;
int height = pdp_type_ca_info(header)->height;
int i;
unsigned int saved;
/* load TOS in middle of buffer to limit the effect of stack errors */
unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)];
unsigned int *env = &x->x_data->env[0];
unsigned int *reg = &x->x_data->reg[0];
void *ca_routine = x->x_ca_routine;
unsigned int rtos;
/* double word width: number of unsigned ints per row */
int dwwidth = width >> 5;
int currow = pdp_type_ca_info(header)->currow;
unsigned long long result = 0;
unsigned short temp;
unsigned short *usdata;
/* set destination row to 4th row from top (ca time horizon is 3 deep) */
int dwrow0 = (((currow + height - 3) % height) * width) >> 5;
int dwrow1 = (((currow + height - 2) % height) * width) >> 5;
int dwrow2 = (((currow + height - 1) % height) * width) >> 5;
int dwrow3 = (currow * width) >> 5;
/* exit if there isn't a valid routine */
if(!ca_routine) return;
/* compute new row */
for(i=0; i < (dwwidth-1) ; i+=1){
env[0] = data[dwrow0 + i];
env[1] = data[dwrow0 + i + 1];
env[2] = data[dwrow1 + i];
env[3] = data[dwrow1 + i + 1];
env[4] = data[dwrow2 + i];
env[5] = data[dwrow2 + i + 1];
result = scaf_feeder(tos, reg, ca_routine, env);
data[dwrow3 + i] = result & 0xffffffff;
}
// i == dwwidth-1
/* compute last column in row */
env[0] = data[dwrow0 + i];
env[1] = data[dwrow0];
env[2] = data[dwrow1 + i];
env[3] = data[dwrow1];
env[4] = data[dwrow2 + i];
env[5] = data[dwrow2];
result = scaf_feeder(tos, reg, ca_routine, env);
data[dwrow3 + i] = result & 0xffffffff;
/* undo the shift */
usdata = (unsigned short *)(&data[dwrow3]);
temp = usdata[(dwwidth*2)-1];
for (i = (dwwidth*2 - 1); i > 0; i--){
usdata[i] = usdata[i-1];
}
usdata[0] = temp;
/* check data stack pointer */
rtos = (unsigned int)tos;
if (env[0] != rtos){
if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine");
if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item");
x->x_ca_routine = 0;
post("pdp_ca: rule disabled");
}
/* save current row */
pdp_type_ca_info(header)->currow = (currow + 1) % height;
}
/* 2D: process from packet0 -> packet1 */
static void pdp_ca_process_ca_2D(t_pdp_ca *x)
{
t_pdp *header0 = pdp_packet_header(x->x_packet0);
t_pdp *header1 = pdp_packet_header(x->x_packet1);
unsigned int *data0 = (unsigned int *)pdp_packet_data (x->x_packet0);
unsigned int *data1 = (unsigned int *)pdp_packet_data (x->x_packet1);
int width = pdp_type_ca_info(header0)->width;
int height = pdp_type_ca_info(header0)->height;
int i,j;
/* load TOS in middle of buffer to limit the effect of stack errors */
unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)];
unsigned int *env = &x->x_data->env[0];
unsigned int *reg = &x->x_data->reg[0];
void *ca_routine = x->x_ca_routine;
unsigned int rtos;
int offset = pdp_type_ca_info(header0)->offset;
int xoffset = offset % width;
int yoffset = offset / width;
/* double word width: number of unsigned ints per row */
int dwwidth = width >> 5;
unsigned long long result = 0;
/* exit if there isn't a valid routine */
if(!ca_routine) return;
if(!header0) return;
if(!header1) return;
//post("pdp_ca: PRE offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
/* calculate new offset: lines shift up, rows shift left by 16 cells */
xoffset = (xoffset + width - 16) % width;
yoffset = (yoffset + height - 1) % height;
offset = yoffset * width + xoffset;
//post("pdp_ca: PST offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
pdp_type_ca_info(header1)->offset = offset;
for(j=0; j<dwwidth*(height - 2); j+=(dwwidth<<1)){
for(i=0; i < (dwwidth-1) ; i+=1){
env[0] = data0[i + j];
env[1] = data0[i + j + 1];
env[2] = data0[i + j + dwwidth];
env[3] = data0[i + j + dwwidth + 1];
env[4] = data0[i + j + (dwwidth<<1)];
env[5] = data0[i + j + (dwwidth<<1) + 1];
env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
env[7] = data0[i + j + (dwwidth<<1) + dwwidth + 1];
result = scaf_feeder(tos, reg, ca_routine, env);
data1[i + j] = result & 0xffffffff;
data1[i + j + dwwidth] = result >> 32;
}
// i == dwwidth-1
env[0] = data0[i + j];
env[1] = data0[j];
env[2] = data0[i + j + dwwidth];
env[3] = data0[j + dwwidth];
env[4] = data0[i + j + (dwwidth<<1)];
env[5] = data0[j + (dwwidth<<1)];
env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
env[7] = data0[j + (dwwidth<<1) + dwwidth];
result = scaf_feeder(tos, reg, ca_routine, env);
data1[i + j] = result & 0xffffffff;
data1[i + j + dwwidth] = result >> 32;
}
// j == dwwidth*(height - 2)
for(i=0; i < (dwwidth-1) ; i+=1){
env[0] = data0[i + j];
env[1] = data0[i + j + 1];
env[2] = data0[i + j + dwwidth];
env[3] = data0[i + j + dwwidth + 1];
env[4] = data0[i];
env[5] = data0[i + 1];
env[6] = data0[i + dwwidth];
env[7] = data0[i + dwwidth + 1];
result = scaf_feeder(tos, reg, ca_routine, env);
data1[i + j] = result & 0xffffffff;
data1[i + j + dwwidth] = result >> 32;
}
// j == dwwidth*(height - 2)
// i == dwwidth-1
env[0] = data0[i + j];
env[1] = data0[j];
env[2] = data0[i + j + dwwidth];
env[3] = data0[j + dwwidth];
env[4] = data0[i];
env[5] = data0[0];
env[6] = data0[i + dwwidth];
env[7] = data0[dwwidth];
result = scaf_feeder(tos, reg, ca_routine, env);
data1[i + j] = result & 0xffffffff;
data1[i + j + dwwidth] = result >> 32;
/* check data stack pointer */
rtos = (unsigned int)tos;
if (env[0] != rtos){
if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine");
if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item");
x->x_ca_routine = 0;
post("pdp_ca: rule disabled");
}
return;
}
static void pdp_ca_swappackets(t_pdp_ca *x)
{
/* swap packets */
int packet = x->x_packet1;
x->x_packet1 = x->x_packet0;
x->x_packet0 = packet;
}
/* tick advance CA one timestep */
static void pdp_ca_bang_thread(t_pdp_ca *x)
{
int encoding;
int packet;
int i;
int iterations = x->x_iterations;
/* invariant: the two packets are allways valid and compatible
so a bang is allways possible. this means that in the pdp an
invalid packet needs to be converted to a valid one */
if (-1 == x->x_packet0) pdp_post("warning: packet 0 invalid");
if (-1 == x->x_packet1) pdp_post("warning: packet 1 invalid");
if (PDP_CA_MODE_2D == x->x_mode){
for(i=0; i < iterations; i++){
/* process form packet0 -> packet1 */
pdp_ca_process_ca_2D(x);
/* swap */
pdp_ca_swappackets(x);
}
}
else if (PDP_CA_MODE_1D == x->x_mode){
if (x->x_fullscreen1d){
t_pdp *header0 = pdp_packet_header(x->x_packet0);
pdp_type_ca_info(header0)->currow = 0;
pdp_type_ca_info(header0)->offset = 0;
iterations = pdp_type_ca_info(header0)->height;
}
for(i=0; i < iterations; i++){
pdp_ca_process_ca_1D(x);
}
}
}
static void pdp_ca_sendpacket(t_pdp_ca *x)
{
/* adjust offset before sending */
t_pdp *header0 = pdp_packet_header(x->x_packet0);
int offset, width, height, xoffset, yoffset, horshift, vershift;
if (!header0) return;
offset = pdp_type_ca_info(header0)->offset;
width = pdp_type_ca_info(header0)->width;
height = pdp_type_ca_info(header0)->height;
xoffset = offset % width;
yoffset = offset / width;
horshift = x->x_horshift;
vershift = x->x_vershift;
horshift %= width;
if (horshift < 0) horshift += width;
vershift %= height;
if (vershift < 0) vershift += height;
xoffset = (xoffset + horshift) % width;
yoffset = (yoffset + vershift) % height;
offset = yoffset * width + xoffset;
pdp_type_ca_info(header0)->offset = offset;
/* output the packet */
outlet_pdp(x->x_outlet0, x->x_packet0);
}
static void pdp_ca_bang(t_pdp_ca *x)
{
/* we don't use input packets for testing dropping here
but check the queue_id to see if processing is
still going on */
if (-1 == x->x_queue_id){
pdp_queue_add(x, pdp_ca_bang_thread, pdp_ca_sendpacket, &x->x_queue_id);
}
else{
pdp_control_notify_drop(-1);
}
}
/* this method stores the packet into x->x_packet0 (the packet
to be processed) if it is valid. x->x_packet1 is not compatible
it is regenerated so that it is
in short, when this routine returns both packets are valid
and compatible.
*/
static void pdp_ca_copy_rw_if_valid(t_pdp_ca *x, int packet)
{
t_pdp *header = pdp_packet_header(packet);
t_pdp *header1 = pdp_packet_header(x->x_packet1);
int grabpacket;
int convertedpacket;
/* check if header is valid */
if (!header) return;
if (PDP_CA != header->type) return;
if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return;
/* packet is a ca, register it */
pdp_packet_mark_unused(x->x_packet0);
x->x_packet0 = pdp_packet_copy_rw(packet);
/* make sure we have the right header */
header = pdp_packet_header(x->x_packet0);
/* make sure that the other packet is compatible */
if ((pdp_type_ca_info(header1)->width != pdp_type_ca_info(header)->width) ||
(pdp_type_ca_info(header1)->height != pdp_type_ca_info(header)->height)) {
/* if not, throw away and clone the new one */
pdp_packet_mark_unused(x->x_packet1);
x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
}
if (-1 == x->x_packet0) pdp_post("warning: packet 0 invalid");
if (-1 == x->x_packet1) pdp_post("warning: packet 1 invalid");
};
/* hot packet inlet */
static void pdp_ca_input_0(t_pdp_ca *x, t_symbol *s, t_floatarg f)
{
if (s == gensym("register_rw")){
pdp_ca_copy_rw_if_valid(x, (int)f);
}
else if (s == gensym("process")){
pdp_ca_bang(x);
}
}
/* cold packet inlet */
static void pdp_ca_input_1(t_pdp_ca *x, t_symbol *s, t_floatarg f)
{
if (s == gensym("register_rw"))
{
pdp_ca_copy_rw_if_valid(x, (int)f);
}
}
static void pdp_ca_rule_string(t_pdp_ca *x, char *c)
{
char tmp[256];
void (*ca_routine)(void);
/* check if we can find string */
sprintf(tmp, "rule_%s", c);
if (!(ca_routine = dlsym(x->x_ca_libhandle, tmp))){
post("pdp_ca: can't fine ca rule %s (symbol: %s)", c, tmp);
return;
}
/* ok, so store routine address */
else{
x->x_ca_routine = ca_routine;
x->x_lastrule = gensym(c);
}
}
static void pdp_ca_rule(t_pdp_ca *x, t_symbol *s)
{
/* make sure lib is loaded */
if (!x->x_ca_libhandle) return;
/* set rule by name */
pdp_ca_rule_string(x, s->s_name);
}
static void pdp_ca_rule_index(t_pdp_ca *x, t_float f)
{
int i = (int)f;
/* make sure lib is loaded */
if (!x->x_ca_libhandle) return;
/* check index */
if (i<0) return;
if (i>=x->x_ca_nbrules) return;
/* set rule by index */
pdp_ca_rule_string(x, x->x_ca_rulename[i]);
}
static void pdp_ca_close(t_pdp_ca *x)
{
if (x->x_ca_libhandle){
dlclose(x->x_ca_libhandle);
x->x_ca_libhandle = 0;
x->x_ca_routine = 0;
if (x->x_ca_rulename){
free (x->x_ca_rulename);
x->x_ca_rulename = 0;
}
}
}
static void pdp_ca_printrules(t_pdp_ca *x)
{
int i;
if (!(x->x_ca_libhandle)) return;
post("pdp_ca: found %d rules: ", x->x_ca_nbrules);
for(i=0;i<x->x_ca_nbrules; i++) post("%3d: %s ", i, x->x_ca_rulename[i]);
}
/* open code library */
static void pdp_ca_openlib(t_pdp_ca *x, t_symbol *s)
{
char *c;
int words;
/* close current lib, if one */
pdp_ca_close(x);
/* try to open new lib */
if (!(x->x_ca_libhandle = dlopen(s->s_name, RTLD_NOW))){
post("pdp_ca: can't open ca library %s\n%s", s->s_name, dlerror());
x->x_ca_libhandle = 0;
return;
}
/* scan for valid rules */
if (!(x->x_ca_rulenames = (char *)dlsym(x->x_ca_libhandle, "rulenames"))){
post("pdp_ca: ERROR: %s does not contain a name table. closing.", s->s_name);
pdp_ca_close(x);
return;
}
/* count rules */
words = 0;
for(c = (char *)x->x_ca_rulenames; *c;){
words++;
while(*c++);
}
x->x_ca_nbrules = words;
x->x_ca_rulename = (char **)malloc(sizeof(char *) * words);
/* build name array */
words = 0;
for(c = (char *)x->x_ca_rulenames; *c;){
x->x_ca_rulename[words] = c;
words++;
while(*c++);
}
/* ok, we're done */
post("pdp_ca: opened rule library %s", s->s_name ,x->x_ca_nbrules);
/* print rule names */
//pdp_ca_printrules(x);
/* set last selected rule */
pdp_ca_rule(x, x->x_lastrule);
}
/* compile source file and open resulting code library */
static void pdp_ca_opensrc(t_pdp_ca *x, t_symbol *s)
{
#define TMPSIZE 1024
char commandline[TMPSIZE];
char library[TMPSIZE];
int status;
/* setup compiler args */
snprintf(library, TMPSIZE, "%so", s->s_name);
snprintf(commandline, TMPSIZE, "scafc %s %s", s->s_name, library);
/* call compiler */
if (system(commandline))
{
post ("pdp_ca: error compiling %s", s->s_name);
}
else
{
post("pdp_ca: compiled %s", s->s_name);
pdp_ca_openlib(x, gensym(library));
}
}
/* open a source file or a library, depending on extension */
static void pdp_ca_open(t_pdp_ca *x, t_symbol *s)
{
char *name = s->s_name;
char *end = name;
while(*end) end++;
if (end == name){
post("pdp_ca: invalid file name");
return;
}
/* if the name ends with 'o' assume it is a library */
if (end[-1] == 'o'){
pdp_ca_openlib(x, s);
}
/* otherwize, assume it is a source file */
else{
pdp_ca_opensrc(x, s);
}
}
/* init the current packet with random noise */
static void pdp_ca_rand(t_pdp_ca *x){
t_pdp *header = pdp_packet_header(x->x_packet0);
short int *data = (short int *) pdp_packet_data(x->x_packet0);
int i;
int nbshortints = (pdp_type_ca_info(header)->width >> 4) * pdp_type_ca_info(header)->height;
for(i=0; i<nbshortints; i++)
data[i] = random();
}
static void pdp_ca_newca(t_pdp_ca *x, t_float width, t_float height)
{
/* delete old packets */
pdp_packet_mark_unused(x->x_packet0);
pdp_packet_mark_unused(x->x_packet1);
/* create new packets */
x->x_packet0 = pdp_packet_new_ca(PDP_CA, width, height);
x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
}
static void pdp_ca_iterations(t_pdp_ca *x, t_float f)
{
int i = (int)f;
if (i < 0) i = 0;
x->x_iterations = i;
}
static void pdp_ca_horshift16(t_pdp_ca *x, t_float f)
{
x->x_horshift = 16 * (int)f;
}
static void pdp_ca_vershift(t_pdp_ca *x, t_float f)
{
x->x_vershift = (int)f;
}
static void pdp_ca_set1d(t_pdp_ca *x)
{
x->x_mode = PDP_CA_MODE_1D;
}
static void pdp_ca_set2d(t_pdp_ca *x)
{
x->x_mode = PDP_CA_MODE_2D;
}
static void pdp_ca_fullscreen1d(t_pdp_ca *x, t_floatarg f)
{
if (f == 0.0f) x->x_fullscreen1d = 0;
if (f == 1.0f) x->x_fullscreen1d = 1;
}
static void pdp_ca_free(t_pdp_ca *x)
{
pdp_packet_mark_unused(x->x_packet0);
pdp_packet_mark_unused(x->x_packet1);
pdp_ca_close(x);
free(x->x_data);
}
void *pdp_ca_new(void)
{
t_pdp_ca *x = (t_pdp_ca *)pd_new(pdp_ca_class);
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("iterations"));
x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
x->x_packet0 = -1;
x->x_packet1 = -1;
x->x_queue_id = -1;
x->x_data = (t_pdp_ca_data *)malloc(sizeof(t_pdp_ca_data));
x->x_ca_routine = 0;
x->x_ca_libhandle = 0;
x->x_ca_rulename = 0;
x->x_horshift = 0;
x->x_vershift = 0;
pdp_ca_newca(x, 64, 64);
pdp_ca_iterations(x, 1);
pdp_ca_set2d(x);
pdp_ca_fullscreen1d(x, 0);
x->x_packet_type = gensym("grey");
x->x_lastrule = gensym("gameoflife");
pdp_ca_openlib(x, gensym(PDP_CA_RULES_LIB));
return (void *)x;
}
// *********************** CA CONVERTER CLASSES STUFF *********************
// TODO: move this to a separate file later together with other converters (part of system?)
#define PDP_CA2IMAGE 1
#define PDP_IMAGE2CA 2
typedef struct pdp_ca_conv_struct
{
t_object x_obj;
t_float x_f;
int x_threshold;
int x_packet;
t_outlet *x_outlet0;
/* solve identity crisis */
int x_whoami;
/* output packet type */
/* only greyscale for now */
t_symbol *x_packet_type;
} t_pdp_ca_conv;
/* hot packet inlet */
static void pdp_ca_conv_input_0(t_pdp_ca_conv *x, t_symbol *s, t_floatarg f)
{
int packet = -1;
if (s == gensym("register_ro")){
pdp_packet_mark_unused(x->x_packet);
x->x_packet = pdp_packet_copy_ro((int)f);
return;
}
else if (s == gensym("process")){
switch(x->x_whoami){
case PDP_CA2IMAGE:
packet = pdp_type_ca2grey(x->x_packet);
break;
case PDP_IMAGE2CA:
packet = pdp_type_grey2ca(x->x_packet, x->x_threshold);
break;
}
/* throw away the original packet */
pdp_packet_mark_unused(x->x_packet);
x->x_packet = -1;
/* pass the fresh packet */
pdp_packet_pass_if_valid(x->x_outlet0, &packet);
/* unregister the freshly created packet */
//pdp_packet_mark_unused(packet);
/* output if valid */
//if (-1 != packet) outlet_pdp(x->x_outlet0, packet);
}
}
void pdp_ca_conv_free(t_pdp_ca_conv *x)
{
pdp_packet_mark_unused(x->x_packet);
}
void pdp_image2ca_threshold(t_pdp_ca_conv *x, t_float f)
{
f *= 0x8000;
if (f < -0x7fff) f = -0x7fff;
if (f > 0x7fff) f = 0x7fff;
x->x_threshold = (short int)f;
}
void *pdp_ca2image_new(void)
{
t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_ca2image_class);
x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
x->x_packet_type = gensym("grey");
x->x_packet = -1;
x->x_whoami = PDP_CA2IMAGE;
return (void *)x;
}
void *pdp_image2ca_new(void)
{
t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_image2ca_class);
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("threshold"));
x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
x->x_packet_type = gensym("grey");
x->x_packet = -1;
x->x_whoami = PDP_IMAGE2CA;
x->x_threshold = 0x4000;
return (void *)x;
}
// *********************** CLASS SETUP FUNCTIONS *********************
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_ca2image_setup(void)
{
pdp_ca2image_class = class_new(gensym("pdp_ca2image"), (t_newmethod)pdp_ca2image_new,
(t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
class_addmethod(pdp_ca2image_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
}
void pdp_image2ca_setup(void)
{
pdp_image2ca_class = class_new(gensym("pdp_image2ca"), (t_newmethod)pdp_image2ca_new,
(t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
class_addmethod(pdp_image2ca_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
class_addmethod(pdp_image2ca_class, (t_method)pdp_image2ca_threshold, gensym("threshold"), A_FLOAT, A_NULL);
}
void pdp_ca_setup(void)
{
pdp_ca_class = class_new(gensym("pdp_ca"), (t_newmethod)pdp_ca_new,
(t_method)pdp_ca_free, sizeof(t_pdp_ca), 0, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_iterations, gensym("iterations"), A_FLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_bang, gensym("bang"), A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_printrules, gensym("rules"), A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_rand, gensym("random"), A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("ca"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_horshift16, gensym("hshift16"), A_FLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_vershift, gensym("vshift"), A_FLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_close, gensym("close"), A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_openlib, gensym("openlib"), A_SYMBOL, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_opensrc, gensym("opensrc"), A_SYMBOL, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_open, gensym("open"), A_SYMBOL, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule, gensym("rule"), A_SYMBOL, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule_index, gensym("ruleindex"), A_FLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_set1d, gensym("1D"), A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_set2d, gensym("2D"), A_NULL);
class_addmethod(pdp_ca_class, (t_method)pdp_ca_fullscreen1d, gensym("fullscreen1D"), A_FLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_ca_system.c ---
/*
* Cellular Automata Extension Module for pdp - Main system code
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "pdp_ca.h"
#include "pdp_internals.h"
/* all symbols are C-style */
#ifdef __cplusplus
extern "C"
{
#endif
/* check if packet is a valid ca packet */
int pdp_packet_ca_isvalid(int packet)
{
t_pdp *header = pdp_packet_header(packet);
if (!header) return 0;
if (PDP_CA != header->type) return 0;
if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return 0;
return 1;
}
static t_pdp_symbol *pdp_packet_ca_get_description(int packet)
{
t_pdp *header = pdp_packet_header(packet);
char description[1024];
char *c = description;
int encoding;
if (!header) return pdp_gensym("invalid");
if (header->type == PDP_CA){
c += sprintf(c, "ca");
switch(pdp_type_ca_info(header)->encoding){
case PDP_CA_STANDARD: c += sprintf(c, "/1bit2D"); break;
default:
c += sprintf(c, "/unknown"); goto exit;
}
c += sprintf(c, "/%dx%d",
pdp_type_ca_info(header)->width,
pdp_type_ca_info(header)->height);
exit:
return pdp_gensym(description);
}
else return pdp_gensym("unknown");
}
/* create a new ca packet */
int pdp_packet_new_ca(int encoding, int width, int height)
{
int p;
int w = (int)width;
int h = (int)height;
int bytesize;
t_pdp *header;
/* ensure with = multiple of 64 */
w &= 0xffffffc0;
/* ensure height = multiple of 4 */
w &= 0xfffffffc;
w = (w<64) ? 64 : w;
h = (h<4) ? 4 : h;
bytesize = (w>>3) * h;
/* create new packets */
p = pdp_packet_new(PDP_CA, bytesize);
header = pdp_packet_header(p);
if (!header) {
pdp_post("error: can't create CA packet");
return -1;
}
pdp_type_ca_info(header)->encoding = PDP_CA_STANDARD;
pdp_type_ca_info(header)->width = w;
pdp_type_ca_info(header)->height = h;
pdp_type_ca_info(header)->offset = 0;
pdp_type_ca_info(header)->currow = 0; /* only used for 1D ca */
pdp_type_ca_info(header)->currow = 0;
header->desc = 0;
header->desc = pdp_packet_ca_get_description(p);
//post("creating %s", header->desc->s_name);
return p;
}
/* convert a CA packet to greyscale */
inline void _pdp_type_ca2grey_convert_word(unsigned short int source, short int *dest)
{
int i;
for (i = 15; i>=0; i--){
dest[i] = ((unsigned short)(((short int)(source & 0x8000)) >> 14)) >> 1;
source <<= 1;
}
}
int pdp_type_ca2grey(int packet)
{
int w, h, s, x, y, srcindex;
long long offset, xoffset, yoffset;
short int *dest;
unsigned short int *source;
t_pdp *header;
t_pdp *newheader;
int newpacket;
if (!(pdp_packet_ca_isvalid(packet))) return -1;
header = pdp_packet_header(packet);
w = pdp_type_ca_info(header)->width;
h = pdp_type_ca_info(header)->height;
s = w*h;
source = (unsigned short int *)pdp_packet_data(packet);
offset = pdp_type_ca_info(header)->offset;
yoffset = (offset / w) * w;
xoffset = offset % w;
//post("pdp_type_ca2grey: offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);
newpacket = pdp_packet_new_image_grey(w, h);
newheader = pdp_packet_header(newpacket);
if (!newheader) return -1;
//newheader->info.image.width = w;
//newheader->info.image.height = h;
//newheader->info.image.encoding = PDP_IMAGE_GREY;
dest = (short int *)pdp_packet_data(newpacket);
#define check_srcindex \
if (srcindex >= (s >> 4)) post ("pdp_type_ca2grey: srcindex out of bound");
#define check_dstindex \
if ((x+y) >= s) post ("pdp_type_ca2grey: dstindex out of bound");
/* debug : dont' shift offset
if (0){
for(y=0; y< (h*w); y+=w){
for(x=0; x<w; x+=16){
_pdp_type_ca2grey_convert_word (source[(x+y)>>4], &dest[x+y]);
}
}
return newpacket;
}
*/
/* create top left */
for (y=0; y < (h*w) - yoffset; y+=w) {
for (x=0; x< (w - xoffset); x+=16) {
srcindex = (x+xoffset + y+yoffset) >> 4;
//check_srcindex;
//check_dstindex;
_pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
}
}
/* create top right */
for (y=0; y < (h*w) - yoffset; y+=w) {
for (x = (w - xoffset); x < w; x+=16) {
srcindex = (x+xoffset-w + y+yoffset) >> 4;
//check_srcindex;
//check_dstindex;
_pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
}
}
/* create bottom left */
for (y=(h*w) - yoffset; y < h*w; y+=w) {
for (x=0; x< (w - xoffset); x+=16) {
srcindex = (x+xoffset + y+yoffset-(w*h)) >> 4;
//check_srcindex;
//check_dstindex;
_pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
}
}
/* create bottom right */
for (y=(h*w) - yoffset; y < h*w; y+=w) {
for (x = (w - xoffset); x < w; x+=16) {
srcindex = (x+xoffset-w + y+yoffset-(w*h)) >> 4;
//check_srcindex;
//check_dstindex;
_pdp_type_ca2grey_convert_word (source[srcindex], &dest[x+y]);
}
}
return newpacket;
}
inline unsigned short int _pdp_type_grey2ca_convert_word(short int *src, short int threshold)
{
short int tmp;
short int dest = 0;
int i;
for (i = 15; i >= 0; i--){
dest <<= 1;
dest |= (src[i] > threshold);
}
return dest;
}
int pdp_type_grey2ca(int packet, short int threshold)
{
int w, h, s, x, y, srcindex;
long long offset, xoffset, yoffset;
short int *dest;
short int *source;
t_pdp *header;
t_pdp *newheader;
int newpacket;
if (!(pdp_packet_image_isvalid(packet))) return -1;
header = pdp_packet_header(packet);
w = header->info.image.width;
h = header->info.image.height;
s = w*h;
source = (unsigned short int *)pdp_packet_data(packet);
if ( (PDP_IMAGE_GREY != header->info.image.encoding)
&& (PDP_IMAGE_YV12 != header->info.image.encoding)) return -1;
newpacket = pdp_packet_new_ca(PDP_CA_STANDARD, w, h);
newheader = pdp_packet_header(newpacket);
if (!newheader) return -1;
dest = (short int *)pdp_packet_data(newpacket);
for(y=0; y< (h*w); y+=w){
for(x=0; x<w; x+=16){
dest[(x+y)>>4] = _pdp_type_grey2ca_convert_word (&source[x+y], threshold);
}
}
return newpacket;
}
/* returns a pointer to the ca subheader given the pdp header */
t_ca *pdp_type_ca_info(t_pdp *x){return (t_ca *)(&x->info.raw);}
void pdp_ca_setup(void);
void pdp_ca2image_setup(void);
void pdp_image2ca_setup(void);
static int _ca_to_image(int packet, t_pdp_symbol *template)
{
return pdp_type_ca2grey(packet);
}
static int _image_to_ca(int packet, t_pdp_symbol *template)
{
// convert with default threshold == 0.5
return pdp_type_grey2ca(packet, 0.5f);
}
void pdp_scaf_setup(void)
{
t_pdp_conversion_program *program;
/* babble */
post ("PDP: pdp_scaf extension library");
/* setup modules */
pdp_ca_setup();
pdp_ca2image_setup();
pdp_image2ca_setup();
/* setup type conversion */
program = pdp_conversion_program_new(_ca_to_image, 0);
pdp_type_register_conversion(pdp_gensym("ca/*/*"), pdp_gensym("image/*/*"), program);
pdp_type_register_conversion(pdp_gensym("ca/*/*"), pdp_gensym("image/grey/*"), program);
program = pdp_conversion_program_new(_image_to_ca, 0);
pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("ca/*/*"), program);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: Makefile ---
current: all_modules
include ../Makefile.config
OBJECTS = pdp_ca.o pdp_ca_system.o scaf_feeder.o
all_modules: $(OBJECTS)
clean:
rm -f *~
rm -f *.o
--- NEW FILE: scaf_feeder.s ---
# Pure Data Packet - scaf feeder routine.
# Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# for dup
.include "../compiler/scafmacro.s"
# *rg is only used for returning the stack pointer
# the 4 bit counter is using registers mm4-mm7 now
# long long scaf_feeder(void *tos, void *rg, *void() ca_rule, void *env)
.globl scaf_feeder
.type scaf_feeder, @function
scaf_feeder:
pushl %ebp
movl %esp, %ebp
push %esi
push %edi
movl 20(%ebp), %edi # load env ptr
movl 8(%ebp), %esi # load TOS2 ptr
movl 16(%ebp), %eax # address of ca routine
pcmpeqw %mm3, %mm3 # load 1 reg
call *%eax # TOS = 32x2 cell result
dup # push %mm0 to memory
movl (%esi), %eax
movl 4(%esi), %edx
lea 16(%esi), %esi # discard stack
movl %esi, (%edi) # store for stack underflow check
emms
pop %edi
pop %esi
leave
ret
Update of /cvsroot/pure-data/externals/pdp/scaf/compiler
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/scaf/compiler
Added Files:
Makefile kernel.scaf optim.rules scafc scafc.pl scafmacro.s
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: scafmacro.s ---
# Pure Data Packet - scaf assembler macros.
# Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# this file contains pure asm macros. it is to be included before assembly
# after scaforth.pl has processed the .scaf file
# *************************** JMP CALL RET **************************************
# j c r
.macro j address
jmp \address
.endm
.macro c address
call \address
.endm
.macro r
ret
.endm
# *************************** CA CELL ACCESS MACROS *****************************
# dropldTL - dropldBR
# shift / load rectangle macros:
# shift rectangle horizontal
# result is in reg1
.macro shift reg1 reg2 count
psllq $(16-\count), \reg1
psrlq $(16+\count), \reg2
psrlq $32, \reg1
psllq $32, \reg2
por \reg2, \reg1
.endm
.macro ldtop reg1 reg2
movq (%edi), \reg1
movq 8(%edi), \reg2
.endm
.macro ldcenter reg1 reg2
movq 8(%edi), \reg1
movq 16(%edi), \reg2
.endm
.macro ldbottom reg1 reg2
movq 16(%edi), \reg1
movq 24(%edi), \reg2
.endm
# dropld from top row
# dropld the top left square
.macro dropldTL
ldtop %mm0, %mm1
shift %mm0, %mm1, -1
.endm
# dropld the top mid square
.macro dropldTM
ldtop %mm0, %mm1
shift %mm0, %mm1, 0
.endm
# dropld the top right square
.macro dropldTR
ldtop %mm0, %mm1
shift %mm0, %mm1, 1
.endm
# dropld from center row
# dropld the mid left square
.macro dropldML
ldcenter %mm0, %mm1
shift %mm0, %mm1, -1
.endm
# dropld the mid mid square
.macro dropldMM
ldcenter %mm0, %mm1
shift %mm0, %mm1, 0
.endm
# dropld the mid right square
.macro dropldMR
ldcenter %mm0, %mm1
shift %mm0, %mm1, 1
.endm
# dropld from bottom row
# dropld the bottom left square
.macro dropldBL
ldbottom %mm0, %mm1
shift %mm0, %mm1, -1
.endm
# dropld the bottom mid square
.macro dropldBM
ldbottom %mm0, %mm1
shift %mm0, %mm1, 0
.endm
# dropld the bottom right square
.macro dropldBR
ldbottom %mm0, %mm1
shift %mm0, %mm1, 1
.endm
# *************************** CA STACK MANIP MACROS *****************************
# these are the only asm macros that have a stack effect other than
# just replacing the TOS
#
# dup drop dropdup swap nip dropover
.macro dup
lea -8(%esi), %esi
movq %mm0, (%esi)
.endm
.macro drop
movq (%esi), %mm0
lea 8(%esi), %esi
.endm
.macro dropdup
movq (%esi), %mm0
.endm
.macro nipdup
movq %mm0, (%esi)
.endm
.macro swap
movq (%esi), %mm1
movq %mm0, (%esi)
movq %mm1, %mm0
.endm
.macro nip
lea 8(%esi), %esi
.endm
.macro dropover
movq 8(%esi), %mm0
.endm
# *************************** CA BOOLEAN LOGIC MACROS *****************************
# overxor overand overor not
.macro overxor
pxor (%esi), %mm0
.endm
.macro overand
pand (%esi), %mm0
.endm
.macro overor
por (%esi), %mm0
.endm
.macro not
pxor %mm3, %mm0
.endm
# *************************** CONSTANTS *****************************
# dropzero dropone
.macro dropzero
pxor %mm0, %mm0
.endm
.macro dropone
pcmpeqw %mm0, %mm0
.endm
# *************************** 4 BIT REG ACCESS ******************************
# dupsta0 - dupsta4 droplda0 - droplda4
# store bit in accumulator
# bit store
.macro dupsta0
movq %mm0, %mm4
.endm
.macro dupsta1
movq %mm0, %mm5
.endm
.macro dupsta2
movq %mm0, %mm6
.endm
.macro dupsta3
movq %mm0, %mm7
.endm
# load bit from accumulator
.macro droplda0
movq %mm4, %mm0
.endm
.macro droplda1
movq %mm5, %mm0
.endm
.macro droplda2
movq %mm6, %mm0
.endm
.macro droplda3
movq %mm7, %mm0
.endm
# *************************** LOAD 4 BIT CONSTANT IN REG ******************************
# a0000 - a1111
.macro ldbit0 value
.ifeq \value
movq %mm1, %mm4
.else
movq %mm3, %mm4
.endif
.endm
.macro ldbit1 value
.ifeq \value
movq %mm1, %mm5
.else
movq %mm3, %mm5
.endif
.endm
.macro ldbit2 value
.ifeq \value
movq %mm1, %mm6
.else
movq %mm3, %mm6
.endif
.endm
.macro ldbit3 value
.ifeq \value
movq %mm1, %mm7
.else
movq %mm3, %mm7
.endif
.endm
.macro ldbin b3 b2 b1 b0
pxor %mm1, %mm1
ldbit0 \b0
ldbit1 \b1
ldbit2 \b2
ldbit3 \b3
.endm
.macro a0000
ldbin 0 0 0 0
.endm
.macro a0001
ldbin 0 0 0 1
.endm
.macro a0010
ldbin 0 0 1 0
.endm
.macro a0011
ldbin 0 0 1 1
.endm
.macro a0100
ldbin 0 1 0 0
.endm
.macro a0101
ldbin 0 1 0 1
.endm
.macro a0110
ldbin 0 1 1 0
.endm
.macro a0111
ldbin 0 1 1 1
.endm
.macro a1000
ldbin 1 0 0 0
.endm
.macro a1001
ldbin 1 0 0 1
.endm
.macro a1010
ldbin 1 0 1 0
.endm
.macro a1011
ldbin 1 0 1 1
.endm
.macro a1100
ldbin 1 1 0 0
.endm
.macro a1101
ldbin 1 1 0 1
.endm
.macro a1110
ldbin 1 1 1 0
.endm
.macro a1111
ldbin 1 1 1 1
.endm
# *************************** 4 BIT COUNTER ******************************
# adds TOS to bit of counter and returns carry in TOS
#
# adb0 - adb3
.macro adb0
movq %mm4, %mm2
pxor %mm0, %mm4
pand %mm2, %mm0
.endm
.macro adb1
movq %mm5, %mm2
pxor %mm0, %mm5
pand %mm2, %mm0
.endm
.macro adb2
movq %mm6, %mm2
pxor %mm0, %mm6
pand %mm2, %mm0
.endm
.macro adb3
movq %mm7, %mm2
pxor %mm0, %mm7
pand %mm2, %mm0
.endm
# *************************** ACCUMULATOR TESTS ***************************
# dropisnonzero4 - dropisnonzero1
.macro dropisnonzero4
movq %mm4, %mm0
por %mm5, %mm0
por %mm6, %mm0
por %mm7, %mm0
.endm
.macro dropisnonzero3
movq %mm4, %mm0
por %mm5, %mm0
por %mm6, %mm0
.endm
.macro dropisnonzero2
movq %mm4, %mm0
por %mm5, %mm0
.endm
.macro dropisnonzero1
movq %mm4, %mm0
.endm
# *************************** REGISTER SHIFT OPERATIONS **********************
# shift and leave shifted out byte on stack
# rotate trough top of stack
.macro dropshiftright
movq %mm4, %mm0
movq %mm5, %mm4
movq %mm6, %mm5
movq %mm7, %mm6
pxor %mm7, %mm7
.endm
.macro dropshiftleft
movq %mm7, %mm0
movq %mm6, %mm7
movq %mm5, %mm6
movq %mm4, %mm5
pxor %mm4, %mm4
.endm
.macro dropshiftrighta
movq %mm4, %mm0
movq %mm5, %mm4
movq %mm6, %mm5
movq %mm7, %mm6
.endm
.macro rotateright
movq %mm4, %mm1
movq %mm5, %mm4
movq %mm6, %mm5
movq %mm7, %mm6
movq %mm1, %mm7
.endm
.macro rotateleft
movq %mm7, %mm1
movq %mm6, %mm7
movq %mm5, %mm6
movq %mm4, %mm5
movq %mm1, %mm4
.endm
.macro rotaterightstack
movq %mm0, %mm1
movq %mm4, %mm0
movq %mm5, %mm4
movq %mm6, %mm5
movq %mm7, %mm6
movq %mm1, %mm7
.endm
.macro rotateleftstack
movq %mm0, %mm1
movq %mm7, %mm0
movq %mm6, %mm7
movq %mm5, %mm6
movq %mm4, %mm5
movq %mm1, %mm4
.endm
# *************************** OTHER REGISTER OPERATIONS **********************
# anot : complement reg (can be used to implement subtraction)
.macro anot
pxor %mm3, %mm4
pxor %mm3, %mm5
pxor %mm3, %mm6
pxor %mm3, %mm7
.endm
--- NEW FILE: kernel.scaf ---
( Pure Data Packet - scaforth kernel. )
( Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org> )
( )
( This program is free software; you can redistribute it and/or modify )
( it under the terms of the GNU General Public License as published by )
( the Free Software Foundation; either version 2 of the License, or )
( [at your option] any later version. )
( )
( This program is distributed in the hope that it will be useful, )
( but WITHOUT ANY WARRANTY; without even the implied warranty of )
( MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the )
( GNU General Public License for more details. )
( )
( You should have received a copy of the GNU General Public License )
( along with this program; if not, write to the Free Software )
( Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. )
( this file contains the inline words in the scaforth kernel. )
( when a file is compiled to asm, it will consist of word )
( definition asm routines, macros and jmp call ret instructions. )
( )
( all words in this file are defined in terms of asm macros )
( defined in scafmacros.s )
( stack manip words )
: over dup dropover ;
( neighbourhood cell fetch words )
: @-+ dup dropldTL ;
: @0+ dup dropldTM ;
: @++ dup dropldTR ;
: @-0 dup dropldML ;
: @00 dup dropldMM ;
: @+0 dup dropldMR ;
: @-- dup dropldBL ;
: @0- dup dropldBM ;
: @+- dup dropldBR ;
( boolean logic )
: or overor nip ;
: xor overxor nip ;
: and overand nip ;
( binary constant loading )
: 1 dup dropone ;
: 0 dup dropzero ;
( 4,3,2,1 bit add stack to register, leave carry on stack )
: ++++ adb0 adb1 adb2 adb3 ;
: +++ adb0 adb1 adb2 ;
: ++ adb0 adb1 ;
: + adb0 ;
( 4,3,2 bit shifted 1 add )
: ++++<<1 adb1 adb2 adb3 ;
: +++<<1 adb1 adb2 ;
: ++<<1 adb1 ;
( 4,3 bit shifted 2 add )
: ++++<<2 adb2 adb3 ;
: +++<<2 adb2 ;
( 4 bit shifted 3 add )
: ++++<<3 adb3 ;
( 4 bit accumulator access )
: !a0 dupsta0 drop ;
: !a1 dupsta1 drop ;
: !a2 dupsta2 drop ;
: !a3 dupsta3 drop ;
: @a0 dup droplda0 ;
: @a1 dup droplda1 ;
: @a2 dup droplda2 ;
: @a3 dup droplda3 ;
( 4,3,2,1 bit accumulator zero tests )
: ?anz dup dropisnonzero4 ;
: ?anz4 dup dropisnonzero4 ;
: ?anz3 dup dropisnonzero3 ;
: ?anz2 dup dropisnonzero2 ;
: ?anz1 dup dropisnonzero1 ;
( load constants into accumulator )
: a0 a0000 ;
: a-0 a0000 ;
: a+0 a0000 ;
: a+1 a0001 ;
: a+2 a0010 ;
: a+3 a0011 ;
: a+4 a0100 ;
: a+5 a0101 ;
: a+6 a0110 ;
: a+7 a0111 ;
: a+8 a1000 ;
: a+9 a1001 ;
: a+10 a1010 ;
: a+11 a1011 ;
: a+12 a1100 ;
: a+13 a1101 ;
: a+14 a1110 ;
: a+15 a1111 ;
: a-8 a1000 ;
: a-7 a1001 ;
: a-6 a1010 ;
: a-5 a1011 ;
: a-4 a1100 ;
: a-3 a1101 ;
: a-2 a1110 ;
: a-1 a1111 ;
--- NEW FILE: scafc ---
#!/bin/sh
#scaf->scafo compiler
if test "xx$1" == "xx"
then
echo
echo "scaf rules compiler"
echo "usage:"
echo " scafc source [dest]"
echo
exit 0
fi
if test "xx$2" == "xx"
then
DEST=$1o
else
DEST=$2
fi
if ! test -f $1
then
echo "source module $1 not found."
exit 1
fi
SCAFDIR=`dirname $0`
if ! test -f $SCAFDIR/scafc.pl;
then
SCAFDIR=`dirname $SCAFDIR`
SCAFDIR="$SCAFDIR/lib/scaf"
if ! test -f $SCAFDIR/scafc.pl
then
echo "scaf library not found in $SCAFDIR"
exit 1
fi
fi
TMP_S=`tempfile -s .s`
$SCAFDIR/scafc.pl -I$SCAFDIR $1 > $TMP_S \
&& gcc -export_dynamic -shared -o $DEST $TMP_S \
&& strip --strip-unneeded $DEST \
&& rm $TMP_S \
|| exit 1
--- NEW FILE: Makefile ---
all:
clean:
rm -f *~
rm -f *.o
--- NEW FILE: scafc.pl ---
#!/usr/bin/perl
# Pure Data Packet - scafc: scaf compiler.
# Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# set this if you want to enable/disable optimizing
$optimize = 1;
# this parses a single scaf line
# it is not very intelligent. only looks for 1 def on a line
# todo: change later so it can read multiple lines
sub remove_illegal_characters {
my $line = shift;
$$line =~ s/\+/_PLUS_/g;
$$line =~ s/-/_MINUS_/g;
$$line =~ s/\@/_AT_/g;
$$line =~ s/:/_COLON_/g;
$$line =~ s/\?/_QMARK_/g;
$$line =~ s/<</_SHIFT_/g;
$$line =~ s/</_ST_/g;
$$line =~ s/>/_GT_/g;
$$line =~ s/=/_EQ_/g;
$$line =~ s/\(/_OPEN_/g;
$$line =~ s/\)/_CLOSE_/g;
}
sub parse_scaf_line {
my $word, $def, $sub;
shift;
# this transforms the source into a parsed assembly like form
# a word label: "<word>:<ret>"
# a word definition line "<tab><word><ret>"
# last def = <ret><ret>
# dont process if line doesn't have a def
# first remove comments
s/\(\s+(\S+\s+)*?\)//g;
if (m/:\s+/){
# separate word and definition
m/:\s+(\S+)\s+(.*)/;
$word = $1;
$def = $2;
# remove illegal characters;
remove_illegal_characters \$word;
remove_illegal_characters \$def;
# format definition in asm style
$def =~ s/(\S+)(\s*)/\t$1\n/g;
# replace ; by r
$def =~ s/\s+;\s*/\n\tr\n/;
# put word: def into one string
$sub = "$word:\n$def\n";
# debug
#$sub =~ s/\t/<tab>/g;
#$sub =~ s/\n/<ret>\n/g;
#print "$sub";
return $sub;
}
};
# load and parse scaf source file
sub load_source {
my $filename = shift;
open(SOURCE, $filename) or die "Can't locate source module $filename\n";
my @parsedsource;
while (<SOURCE>){
my $sub = parse_scaf_line $_;
if ($sub) {
push @parsedsource, ($sub);
}
}
close(SOURCE);
return @parsedsource;
}
# this routine parses the optimization rules
sub load_optim {
my $filename = shift;
open(OPTIM, $filename) or die "Can't locate optimization rule file $filename\n";
my @parsedoptim;
while (<OPTIM>){
unless (m/\A\#/){
if (m/\"\s*(.*?)\s*\".*?\"\s*(.*?)\s*\"/)
{
my $source = $1;
my $dest = $2;
$source =~ s/\s+/\n\t/;
$dest =~ s/\s+/\n\t/;
$source = "\t$source\n";
$dest = "\t$dest\n";
remove_illegal_characters \$source;
remove_illegal_characters \$dest;
push @parsedoptim, ("$source:$dest");
}
}
}
close(OPTIM);
return @parsedoptim;
}
# inline one parsed source's definitions into another parsed source's
sub inline_defs {
my $dest = shift;
my $source = shift;
#print @$dest;
#print @$source;
# loop over file with inline defs
foreach (@$source) {
#print "<SUB>$_</SUB>\n";
m/(\S+):\n(.*)\tr\n/s;
my $def = "\t$1\n";
my $body = $2;
#print "<DEF>$def</DEF>\n";
#print "<BODY>$body</BODY>\n";
foreach (@$dest) {
s/$def/$body/g;
}
}
}
# this changes <WORD> to c <WORD> or j <WORD> all defined words
# the undefined words are supposed to be asm macros
sub call_defs {
my $dest = shift;
foreach (@$dest){
m/(\S+):\n/s;
my $word = $1;
foreach (@$dest){
s/\t$word\n\tr\n/\tj $word\n/sg;
s/\t$word\n/\tc $word\n/sg;
}
}
}
# substitue word sequences in dest using optim table
sub subst_optim {
my $dest = shift;
my $optim = shift;
foreach (@$optim){
m/(.*?):(.*)/s;
my $key = $1;
my $subst = $2;
foreach (@$dest){
s/$key/$subst/sg;
}
}
}
# add directives to produce global symbols
# global symbols need to start with carule_
sub global_syms {
my $source = shift;
foreach (@$source){
s/rule_(\S+):\n/.globl\trule_$1\n.type\trule_$1,\@function\nrule_$1:\n/sg;
}
}
# create an array with names for bookkeeping
sub name_array {
my @namearray;
my $source = shift;
push @namearray, (".globl rulenames\nrulenames:\n");
foreach (@$source){
if (m/rule_(\S+):/s){
push @namearray, (".asciz\t\"$1\"\n");
}
}
push @namearray, (".byte\t0\n");
return @namearray;
}
# main program body
$dir=".";
$source = "-";
# parse command line
foreach (@ARGV){
if (m/-I(.*)/) {
$dir = $1;
}
else {
$source = $_;
}
}
$kernel = "$dir/kernel.scaf";
$macro = "$dir/scafmacro.s";
$rules = "$dir/optim.rules";
# load files
@psource = load_source $source;
@pkernel = load_source $kernel;
@poptim = load_optim $rules;
# substitute kernel defs in source
if ($optimize) {subst_optim \@psource, \@poptim;}
inline_defs \@psource, \@pkernel;
if ($optimize) {subst_optim \@psource, \@poptim;}
call_defs \@psource;
global_syms \@psource;
@pnames = name_array \@psource;
# print out asm file
print ".include \"$macro\"\n\n";
print @psource;
print @pnames;
--- NEW FILE: optim.rules ---
# Pure Data Packet - scaf optimization rules.
# Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# this file contains scaf source optimization rules for scaf compiler
# applied after kernel word inlining and before compilation to asm
# one rule that's not in here, and is the responsability for the
# final compilation step: "word ;" is "jmp word" instead of "call word ret"
# TODO: think about order!
# no discrimination between pre inline and post inline optimization ops yet
# pre inline optimizations
"over xor" -> "overxor"
"over and" -> "overand"
"over or" -> "overor"
"drop 1" -> "dropone"
"drop 0" -> "dropzero"
"over add" -> "overadd"
"over addc" -> "overaddc"
"dup !a0" -> "dupsta0"
"dup !a1" -> "dupsta1"
"dup !a2" -> "dupsta2"
"dup !a3" -> "dupsta3"
"drop @a0" -> "droplda0"
"drop @a1" -> "droplda1"
"drop @a2" -> "droplda2"
"drop @a3" -> "droplda3"
"drop ?anz" -> "dropisnonzero4"
"drop ?anz4" -> "dropisnonzero4"
"drop ?anz3" -> "dropisnonzero3"
"drop ?anz2" -> "dropisnonzero2"
"drop ?anz1" -> "dropisnonzero1"
"drop @-+" -> "dropldTL"
"drop @0+" -> "dropldTM"
"drop @++" -> "dropldTR"
"drop @-0" -> "dropldML"
"drop @00" -> "dropldMM"
"drop @+0" -> "dropldMR"
"drop @--" -> "dropldBL"
"drop @0-" -> "dropldBM"
"drop @+-" -> "dropldBR"
# post inline optimizations
"dup drop" -> ""
"swap drop" -> "nip"
"dup swap" -> "dup"
"drop dup" -> "dropdup"
"drop over" -> "dropover"
"nip dup" -> "nipdup"
Update of /cvsroot/pure-data/externals/pdp/scaf/include
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/scaf/include
Added Files:
Makefile pdp_ca.h
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_ca.h ---
/*
* Cellular Automata Extension Module for pdp - Main header file
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef PDP_CA_H
#define PDP_CA_H
#include "pdp.h"
/* 2D CA DATA PACKET */
typedef struct
{
unsigned int encoding; /* CA data format */
unsigned int width; /* CA width (in 1 bit cells) */
unsigned int height; /* CA height (in 1 bit cells) */
unsigned int offset; /* bit offset of upper left corner */
unsigned int currow; /* current row to compute for 1D CA */
} t_ca;
/* CA encodings */
#define PDP_CA_STANDARD 1 /* rectangular CA */
/* pdp data packet types */
#define PDP_CA 2 /* 1bit toroidial shifted scanline encoded cellular automaton */
/* all symbols are C-style */
#ifdef __cplusplus
extern "C"
{
#endif
/* constructor */
int pdp_packet_new_ca(int encoding, int width, int height);
/* some utility methods for CA */
int pdp_packet_ca_isvalid(int packet);
int pdp_type_ca2grey(int packet);
int pdp_type_grey2ca(int packet, short int threshold);
/* returns a pointer to the ca subheader given the pdp header */
t_ca *pdp_type_ca_info(t_pdp *x);
/* mmx feeder routine */
unsigned long long scaf_feeder(void *tos, void *reg, void (*ca_rule)(void), void *env);
#ifdef __cplusplus
}
#endif
#endif //PDP_CA_H
--- NEW FILE: Makefile ---
current:
clean:
rm -f *~
Update of /cvsroot/pure-data/externals/pdp/opengl/system
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/opengl/system
Added Files:
Makefile pdp_3Dcontext_common.c pdp_3Dcontext_glx.c
pdp_3dp_base.c pdp_mesh.c pdp_opengl.c pdp_texture.c setup.c
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_3Dcontext_common.c ---
/*
* OpenGL Extension Module for pdp - pbuffer packet implementation
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
this code uses glx. i don't know if it is worth to take into
account portabiliy. since it will take a while until pdp runs
on anything else than linux. but in any case, providing a windows/osx
implementation here should not be too difficult..
*/
#include "pdp_3Dcontext.h"
#include <GL/gl.h>
//#include <GL/glx.h>
#include <GL/glu.h>
//#include <GL/glut.h>
#define D if (0)
/* constructor */
/* pbuf operators */
u32 pdp_packet_3Dcontext_width(int packet)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (c) return c->width;
else return 0;
}
u32 pdp_packet_3Dcontext_height(int packet)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (c) return c->height;
else return 0;
}
u32 pdp_packet_3Dcontext_subwidth(int packet)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (c) return c->sub_width;
else return 0;
}
u32 pdp_packet_3Dcontext_subheight(int packet)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (c) return c->sub_height;
else return 0;
}
void pdp_packet_3Dcontext_set_subwidth(int packet, u32 w)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (c) c->sub_width = w;
}
void pdp_packet_3Dcontext_set_subheight(int packet, u32 h)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (c) c->sub_height = h;
}
float pdp_packet_3Dcontext_subaspect(int packet)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (c) return (float)c->sub_width/c->sub_height;
else return 0;
}
int pdp_packet_3Dcontext_isvalid(int packet)
{
t_pdp *header = pdp_packet_header(packet);
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (!header) return 0;
if (!c) return 0;
if (PDP_3DCONTEXT != header->type) return 0;
return 1;
}
t_3Dcontext *pdp_packet_3Dcontext_info(int packet)
{
t_pdp *header = pdp_packet_header(packet);
if (!header) return 0;
if (PDP_3DCONTEXT != header->type) return 0;
return (t_3Dcontext *)&header->info.raw;
}
void pdp_llconv_flip_top_bottom(char *data, int width, int height, int pixelsize);
int pdp_packet_3Dcontext_snap_to_bitmap(int packet, int w, int h)
{
int x, y, new_p, i;
char *data = 0;
// char r;
// int extra = 5;
if (!pdp_packet_3Dcontext_isvalid(packet)) goto error;
x = pdp_packet_3Dcontext_subwidth(packet);
y = pdp_packet_3Dcontext_subheight(packet);
x = (x - w) >> 1;
y = (y - h) >> 1;
x = (x < 0 ) ? 0 : x;
y = (y < 0 ) ? 0 : y;
new_p = pdp_packet_new_bitmap_rgb(w, h);
data = (char *)pdp_packet_data(new_p);
if (-1 == new_p || !data) goto error;
pdp_packet_3Dcontext_set_rendering_context(packet);
// D post("BEGIN READPIXELS %d %d %d %d %x", w, h, x, y, data);
//for (i=0; i<w*h; i++){
// data[3*i] = 255;
// data[3*i+1] = 255;
// data[3*i+2] = 0;
//}
// r = random();
// data[w*h*3] = r;
/* seems nvidia drivers 4191 have a bug
when w % 4 is not zero */
glReadPixels(x,y, w ,h,GL_RGB,GL_UNSIGNED_BYTE, data);
/* inplace swap top to bottom (textures and buffers have
another coordinate system than standard images)
instead of fixing this by using a different texture coordinate
system, a memory swap is performed. this is more expensive
but eliminates hassle when converting between buffers, textures
and bitmaps */
pdp_llconv_flip_top_bottom(data, w, h, 3);
// if (r != data[w*h*3]) post("PANIC");
// post("END READPIXELS %d %d", w, h);
return new_p;
error:
return -1;
}
/* move these to the pdp_3d_context object: they're too specific */
/* setup for 2d operation from pbuf dimensions */
void pdp_packet_3Dcontext_setup_2d_context(int p)
{
u32 w;
u32 h;
float asp;
if (!pdp_packet_3Dcontext_isvalid(p)) return;
w = pdp_packet_3Dcontext_subwidth(p);
h = pdp_packet_3Dcontext_subheight(p);
asp = pdp_packet_3Dcontext_subaspect(p);
/* set the viewport to the size of the sub frame */
glViewport(0, 0, w, h);
/* set orthogonal projection, with a relative frame size of (2asp x 2) */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 2*asp, 0, 2);
/* set the center of view */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(asp, 1, 0);
glScalef(1,-1,1);
}
/* setup for 3d operation from pbuf dimensions */
void pdp_packet_3Dcontext_setup_3d_context(int p)
{
u32 w;
u32 h;
int i;
float asp;
float m_perspect[] = {-1.f, /* left */
1.f, /* right */
-1.f, /* bottom */
1.f, /* top */
1.f, /* front */
20.f};/* back */
if (!pdp_packet_3Dcontext_isvalid(p)) return;
w = pdp_packet_3Dcontext_subwidth(p);
h = pdp_packet_3Dcontext_subheight(p);
asp = pdp_packet_3Dcontext_subaspect(p);
/* set the viewport to the size of the sub frame */
glViewport(0, 0, w, h);
/* set orthogonal projection, with a relative frame size of (2asp x 2) */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(m_perspect[0] * asp, m_perspect[1] * asp, // left, right
m_perspect[2], m_perspect[3], // bottom, top
m_perspect[4], m_perspect[5]); // front, back
/* reset texture matrix */
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
/* set the center of view */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 4, 0, 0, 0, 0, 1, 0);
//glTranslatef(asp, 1, 0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
//glShadeModel(GL_FLAT);
/* disable everything that is enabled in other modules
this resets the ogl state to its initial conditions */
glDisable(GL_LIGHTING);
for (i=0; i<8; i++) glDisable(GL_LIGHT0 + i);
glDisable(GL_COLOR_MATERIAL);
}
void pdp_3Dcontext_common_setup(void)
{
}
--- NEW FILE: pdp_mesh.c ---
/*
* Pure Data Packet module. mesh implementation
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* a very naive approach to triangular meshes */
// $$TODO: some serious memory corruption in this file our the list implementation
#include <math.h>
#include "pdp.h"
#include "pdp_mesh.h"
/* VERTEX methods */
void vertex_add_triangle(t_vertex *v, t_triangle *t)
{
pdp_list_add_pointer(v->trilist, t);
}
void vertex_remove_triangle(t_vertex *v, t_triangle *t)
{
pdp_list_remove_pointer(v->trilist, t);
}
void vertex_add_neighbour(t_vertex *v, t_vertex *neighbour)
{
pdp_list_add_pointer_to_set(v->vertlist, neighbour);
};
/* constructor/destructors are "private"
they may only be called by the mesh object to ensure
the vector list stays sound (i.e. without duplicates) */
void _vertex_free(t_vertex *v)
{
if (!v->trilist) post("WARNING: vertex %x has empty trilist", v);
else{
pdp_list_free(v->trilist);
v->trilist = 0;
}
if (!v->vertlist) post("WARNING: vertex %x has empty vertlist", v);
{
pdp_list_free(v->vertlist);
v->vertlist = 0;
}
pdp_dealloc(v);
}
t_vertex *_vertex_new(float *c, float *n)
{
int k;
t_vertex *v = (t_vertex *) pdp_alloc(sizeof(t_vertex));
I3(k) v->c[k] = c[k];
I3(k) v->n[k] = n[k];
v->trilist = pdp_list_new(0);
v->vertlist = pdp_list_new(0);
return v;
}
void vertex_compute_normal_random(t_vertex *v){int k; I3(k) v->n[k] = _rand();}
void vertex_compute_normal_sphere(t_vertex *v){int k; I3(k) v->n[k] = v->c[k];}
void vertex_compute_normal_prism(t_vertex *v)
{
float scale = 0.0f;
float sum[] = {0.0f, 0.0f, 0.0f};
int k;
t_pdp_atom* i;
t_pdp_list *vl = v->vertlist;
t_vertex *vtx;
PDP_POINTER_IN(vl, i, vtx) {
I3(k) sum[k] += vtx->c[k];
scale = scale + 1.0f;
}
scale = 1.0f / scale;
I3(k) sum[k] *= scale;
I3(k) v->n[k] = v->c[k] - sum[k];
//post("computed normal (%f, %f, %f) of vertex (%f, %f, %f)", v->n[0], v->n[1], v->n[2], v->c[0], v->c[1], v->c[2]);
};
void vertex_compute_normal_average(t_vertex *v)
{
int triangles = pdp_list_size(v->trilist);
float scale = 1.0f / ((float)triangles);
t_pdp_atom* i;
int k;
t_triangle *t;
I3(k) v->n[k] = 0; //reset normal
PDP_POINTER_IN(v->trilist, i, t){
I3(k) v->n[k] += t->n[k];
}
_vector3_scale(v->n, scale);
}
float vertex_normalize(t_vertex *v)
{
return _vector3_normalize(v->c);
}
/* TRIANGLE methods */
/* create triangle (a connection between 3 vertices):
counterclockwize with facing front
this method is "private"
you can only create triangles as part of a mesh */
t_triangle *_triangle_new(t_vertex *v0, t_vertex *v1, t_vertex *v2)
{
int k;
t_triangle *t = (t_triangle *)pdp_alloc(sizeof(t_triangle));
/* store vertex references */
t->v[0] = v0;
t->v[1] = v1;
t->v[2] = v2;
/* reset median vertices */
I3(k) t->m[k] = 0;
/* connect triangle to vertices */
vertex_add_triangle(v0, t);
vertex_add_triangle(v1, t);
vertex_add_triangle(v2, t);
/* connect vertices to vertices */
vertex_add_neighbour(v0, v1);
vertex_add_neighbour(v0, v2);
vertex_add_neighbour(v1, v0);
vertex_add_neighbour(v1, v2);
vertex_add_neighbour(v2, v0);
vertex_add_neighbour(v2, v1);
return t;
}
/* delete a triangle, disconnecting the vertices */
void _triangle_free(t_triangle *t)
{
int k;
/* remove the triangle reference of the vertices */
I3(k) vertex_remove_triangle(t->v[k], t);
/* set references to zero (bug catcher) */
I3(k) t->v[k] = 0;
I3(k) t->m[k] = 0;
/* free struct */
pdp_dealloc(t);
}
/* get triangle that shares the link between v0 and v1 */
t_triangle *triangle_neighbour(t_triangle *t, t_vertex *v0, t_vertex *v1)
{
t_pdp_atom* it;
t_triangle *tri;
PDP_POINTER_IN(v1->trilist, it, tri){
if (tri != t && pdp_list_contains_pointer(v0->trilist, tri)) return tri;
}
return 0;
}
/* add a median vector to a link in a triangle
note: vertices must be in triangle, or behaviour is undefined */
void triangle_add_median(t_triangle *t, t_vertex *v0, t_vertex *v1, t_vertex *median)
{
/* link 0 1 */
if (!((v0 == t->v[2]) || (v1 == t->v[2]))) t->m[0] = median;
/* link 1 2 */
else if (!((v0 == t->v[0]) || (v1 == t->v[0]))) t->m[1] = median;
/* link 2 0 */
else t->m[2] = median;
}
void triangle_compute_normal(t_triangle *t)
{
int k;
float v0[3];
float v1[3];
I3(k) v0[k] = t->v[1]->c[k] - t->v[0]->c[k];
I3(k) v1[k] = t->v[2]->c[k] - t->v[0]->c[k];
_vector3_cross(v0,v1,t->n);
}
void triangle_compute_unit_normal(t_triangle *t)
{
triangle_compute_normal(t);
_vector3_normalize(t->n);
}
/* MESH methods */
/* add and remove methods for vertices and triangles */
t_vertex *mesh_vertex_add(t_mesh *m, float *c, float *n)
{
t_vertex *v = _vertex_new(c, n);
pdp_list_add_pointer(m->vertices, v);
return v;
}
void mesh_vertex_remove(t_mesh *m, t_vertex *v)
{
pdp_list_remove_pointer(m->vertices, v);
_vertex_free(v);
}
t_triangle *mesh_triangle_add(t_mesh *m, t_vertex *v0, t_vertex *v1, t_vertex *v2)
{
t_triangle *t = _triangle_new(v0,v1,v2);
pdp_list_add_pointer(m->triangles, t);
return t;
}
void mesh_triangle_remove(t_mesh *m, t_triangle *t)
{
pdp_list_remove_pointer(m->triangles, t);
_triangle_free(t);
}
/* calculate normals */
void mesh_calculate_normals(t_mesh *m)
{
t_pdp_atom* it;
t_pdp_atom* it_tri;
t_pdp_list *l = m->vertices;
t_pdp_list *l_tri = m->triangles;
t_vertex *v;
t_triangle *t;
//while (v = pdp_list_getnext_pointer(l, &it)) vertex_compute_normal_sphere(v);
switch(m->normal_type){
default:
case MESH_NORMAL_SPHERE: PDP_POINTER_IN(l, it, v) vertex_compute_normal_sphere(v); break;
case MESH_NORMAL_PRISM: PDP_POINTER_IN(l, it, v) vertex_compute_normal_prism(v); break;
case MESH_NORMAL_RANDOM: PDP_POINTER_IN(l, it, v) vertex_compute_normal_random(v); break;
case MESH_NORMAL_AVERAGE:
PDP_POINTER_IN(l_tri, it_tri, t) triangle_compute_unit_normal(t);
PDP_POINTER_IN(l, it, v) vertex_compute_normal_average(v);
break;
}
}
/* split a triangle in 4, using the intermedia median vertex storage */
void mesh_split_four(t_mesh *m, t_triangle *old_t)
{
int k;
t_vertex *v[6];
/* some intermediates */
t_triangle *neighbour;
t_float newv[] = {0,0,0};
t_float nullvect[] = {0,0,0};
/* get main vertices */
I3(k) v[k] = old_t->v[k];
/* get median vertices inserted by neighbouring triangles */
I3(k) v[k+3] = old_t->m[k];
#define GET_MEDIAN(v, v0, v1) \
if (!v){ \
I3(k) newv[k] = 0.5f * (v0->c[k] + v1->c[k]); \
v = mesh_vertex_add(m, newv, nullvect); \
/*vertex_normalize(v);*/ \
if (neighbour = triangle_neighbour(old_t, v0, v1)){ \
triangle_add_median(neighbour, v0, v1, v); \
} \
}
GET_MEDIAN(v[3], v[0], v[1])
GET_MEDIAN(v[4], v[1], v[2])
GET_MEDIAN(v[5], v[2], v[0])
#undef GET_MEDIAN
/* remove the old triangle */
mesh_triangle_remove(m, old_t);
/* create 4 new triangles */
mesh_triangle_add(m, v[0], v[3], v[5]);
mesh_triangle_add(m, v[1], v[4], v[3]);
mesh_triangle_add(m, v[2], v[5], v[4]);
mesh_triangle_add(m, v[3], v[4], v[5]);
}
/* split a triangle in 3 */
void mesh_split_three(t_mesh *m, t_triangle *old_t)
{
int k, l;
t_vertex *v[4];
t_float newv[] = {0,0,0};
t_float nullvect[] = {0,0,0};
/* get vertices */
I3(k) v[k] = old_t->v[k];
/* remove a triangle */
mesh_triangle_remove(m, old_t);
/* compute new vertex coordinates */
I3(k) I3(l) newv[k] += 0.33333f * v[l]->c[k];
/* create new vertex */
v[3] = mesh_vertex_add(m, newv, nullvect);
//vertex_normalize(v[3]);
/* create 3 new triangles */
mesh_triangle_add(m, v[0], v[1], v[3]);
mesh_triangle_add(m, v[1], v[2], v[3]);
mesh_triangle_add(m, v[2], v[0], v[3]);
}
void mesh_split_all_four(t_mesh *m)
{
t_triangle *t;
t_pdp_list *l = pdp_list_copy(m->triangles);
//post("split_all_four: nb triangles %d", pdp_list_size(m->triangles));
while (l->elements){
t = pdp_list_pop(l).w_pointer;
mesh_split_four(m, t);
}
mesh_calculate_normals(m);
pdp_list_free(l);
}
void mesh_split_all_three(t_mesh *m)
{
t_triangle *t;
t_pdp_list *l = pdp_list_copy(m->triangles);
//post("split_all_three: nb triangles %d", pdp_list_size(m->triangles));
while (l->elements){
t = pdp_list_pop(l).w_pointer;
mesh_split_three(m, t);
}
mesh_calculate_normals(m);
pdp_list_free(l);
}
void mesh_split_random_three(t_mesh *m)
{
int size = pdp_list_size(m->triangles);
t_triangle *t = pdp_list_index(m->triangles, (random() % size)).w_pointer;
mesh_split_three(m, t);
mesh_calculate_normals(m);
}
void mesh_free(t_mesh *m)
{
t_pdp_list *l;
t_triangle *t;
t_vertex *v;
/* delete all triangles */
while (m->triangles->elements){
t = pdp_list_pop(m->triangles).w_pointer;
//post("freeing triangle %x", t);
_triangle_free(t);
}
pdp_list_free(m->triangles);
m->triangles = 0;
/* delete all vertices */
while (m->vertices->elements){
v = pdp_list_pop(m->vertices).w_pointer;
//post("freeing vertex %x", v);
_vertex_free(v);
}
pdp_list_free(m->vertices);
m->vertices = 0;
pdp_dealloc(m);
}
t_mesh *_mesh_new(void)
{
t_mesh *m = (t_mesh *)pdp_alloc(sizeof(t_mesh));
/* create main vertex and triangle lists */
m->triangles = pdp_list_new(0);
m->vertices = pdp_list_new(0);
/* set normal type */
m->normal_type = MESH_NORMAL_PRISM;
return m;
}
/* init tetra */
t_mesh *mesh_new_tetra(void)
{
int k;
t_triangle *t[4];
t_vertex *v[4];
t_pdp_atom* it;
t_triangle *tri;
t_mesh *m = _mesh_new();
float n[] = {0,0,0};
float fv[4][3] = {{2,0,0},{0,2,0},{0,0,2}, {-1,-1,-1}};
/* add vertices */
I4(k) v[k] = mesh_vertex_add(m, &fv[k][0], n);
I4(k) vertex_normalize(v[k]);
/* add triangles */
mesh_triangle_add(m, v[0], v[1], v[2]);
mesh_triangle_add(m, v[1], v[0], v[3]);
mesh_triangle_add(m, v[0], v[2], v[3]);
mesh_triangle_add(m, v[1], v[3], v[2]);
/* compute normals */
mesh_calculate_normals(m);
return m;
}
void _mesh_relax_compute_resultant_spring(t_mesh *m, float *center, float d0, float r0)
{
int k;
t_pdp_atom *i, *j;
t_vertex *v, *w;
PDP_POINTER_IN(m->vertices, i, v){
float scale = 0.0f;
float r;
/* compute contribution of origin link */
I3(k) v->n[k] = v->c[k] - center[k];
r = _vector3_normalize(v->n);
I3(k) v->n[k] *= (r0 - r);
PDP_POINTER_IN(v->vertlist, j, w){
int k;
float f[3];
float d, l;
/* compute force contribution of one link (model: spring with rest length == d0) */
I3(k) f[k] = w->c[k] - v->c[k]; // PC: f == distance vector
d = _vector3_normalize(f); // PC: d == distance, vector == unit norm
I3(k) v->n[k] += (d - d0) * f[k]; // PC: n == n_prev + fource resultant
}
}
}
void _mesh_relax_apply_force(t_mesh *m, float k)
{
t_pdp_atom* it;
t_vertex *v;
PDP_POINTER_IN(m->vertices, it, v){
int i;
/* apply fource vector with step */
I3(i) v->c[i] += k * v->n[i];
}
}
void mesh_compute_center(t_mesh *m, float *c)
{
t_pdp_atom*(it);
t_vertex *v;
float scale;
int k;
I3(k) c[k] = 0;
PDP_POINTER_IN(m->vertices, it, v){
I3(k) c[k] += v->c[k];
}
scale = 1.0f / ((float)pdp_list_size(m->vertices));
I3(k) c[k] *= scale;
}
void mesh_translate(t_mesh *m, float *c)
{
t_pdp_atom *it;
t_vertex *v;
int k;
PDP_POINTER_IN(m->vertices, it, v){
I3(k) v->c[k] += c[k];
}
}
/* relax a mesh (move toward equal link length) */
void mesh_relax(t_mesh *m, float step, float d0, float r0)
{
int k;
float c[3];
mesh_compute_center(m, c);
I3(k) c[k] = -c[k];
mesh_translate(m, c);
I3(k) c[k] = 0;
_mesh_relax_compute_resultant_spring(m, c, d0, r0); /* compute force resultant */
_mesh_relax_apply_force(m, step); /* apply "time step towards desired distance" */
mesh_calculate_normals(m); /* restore normals */
}
/* print some debug information */
void mesh_debug(t_mesh *m)
{
int k;
int boundary_edges = 0;
t_pdp_atom* it;
t_triangle *t;
post("mesh info");
post("\tnumber of vertices = %d", pdp_list_size(m->vertices));
post("\tnumber of triangles = %d", pdp_list_size(m->triangles));
PDP_POINTER_IN(m->triangles, it, t){
I3(k) if (!triangle_neighbour(t, t->v[k], t->v[(k+1)%3])) boundary_edges++;
}
post("\tnumber of boundaray edges = %d", boundary_edges);
}
--- NEW FILE: Makefile ---
include ../Makefile.config
all: pdp_texture.o pdp_3Dcontext_glx.o pdp_3Dcontext_common.o \
pdp_opengl.o pdp_3dp_base.o pdp_mesh.o setup.o
clean:
rm -rf *~ *.o
--- NEW FILE: setup.c ---
#include "pdp_opengl.h"
/* 3dp overview:
- texture packets (gl)
- drawable packets (glX windows and pbufs)
the 3dp system connects to a display server and creates a common context
this can be a pbuf context (if supported, glx >= 1.3) or a normal glX context
textures are standard opengl
drawable packets are wrappers around glx drawables (windows or pbufs)
they share the central display connection and rendering context
*/
#ifdef __cplusplus
extern "C"
{
#endif
/* opengl lib kernel setup */
void pdp_opengl_system_setup(void);
/* packet type setup */
void pdp_3Dcontext_glx_setup(void); /* glx specific part of the 3D context packet */
void pdp_3Dcontext_common_setup(void); /* common part of the 3D context packet */
void pdp_texture_setup(void); /* texture packet */
/* module setup */
void pdp_3d_windowcontext_setup(void);
void pdp_3d_draw_setup(void);
void pdp_3d_view_setup(void);
void pdp_3d_light_setup(void);
void pdp_3d_color_setup(void);
void pdp_3d_push_setup(void);
void pdp_3d_snap_setup(void);
void pdp_3d_dlist_setup(void);
void pdp_3d_drawmesh_setup(void);
void pdp_3d_for_setup(void);
void pdp_3d_state_setup(void);
void pdp_3d_subcontext_setup(void);
//#define D(x) { pdp_post_n( #x ".." ); x; pdp_post("done"); }
#define D(x) x
void pdp_opengl_setup(void)
{
int i;
post("PDP: pdp_opengl extension library");
/* setup system */
D(pdp_opengl_system_setup());
/* setup packet types */
D(pdp_3Dcontext_glx_setup());
D(pdp_3Dcontext_common_setup());
D(pdp_texture_setup());
/* setup modules */
D(pdp_3d_windowcontext_setup());
D(pdp_3d_draw_setup());
D(pdp_3d_view_setup());
D(pdp_3d_push_setup());
D(pdp_3d_light_setup());
D(pdp_3d_dlist_setup());
D(pdp_3d_color_setup());
D(pdp_3d_snap_setup());
D(pdp_3d_drawmesh_setup());
D(pdp_3d_for_setup());
D(pdp_3d_state_setup());
D(pdp_3d_subcontext_setup());
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_3dp_base.c ---
#include "pdp_opengl.h"
#include "pdp_3dp_base.h"
#define THIS(b) t_pdp_3pd_base *b = (t_pdp_3pd_base *)x
/* destructor */
void pdp_3dp_base_free(void *x)
{
// free super
pdp_dpd_base_free(x);
}
/* init method */
void pdp_3dp_base_init(void *x)
{
// init super
pdp_dpd_base_init(x);
// set processing queue to pdp_opengl system queue
pdp_dpd_base_set_queue(x, pdp_opengl_get_queue());
}
/* class setup method */
void pdp_3dp_base_setup(t_class *class)
{
// setup super
pdp_dpd_base_setup(class);
}
--- NEW FILE: pdp_texture.c ---
/*
* OpenGL Extension Module for pdp - texture packet implementation
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* this modules implemtents the opengl texture packet
it contains only portable opengl code */
#include <stdio.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "pdp_opengl.h"
#include "pdp_texture.h"
#include "pdp_dpd_command.h"
static t_pdp_class *texture_class;
static t_pdp_dpd_commandfactory _tex_cf;
typedef struct _texture_command
{
t_pdp_dpd_command base;
int p_src;
int p_dst;
} t_texture_command;
/* all symbols are C-style */
#ifdef __cplusplus
extern "C"
{
#endif
/* returns a pointer to the packet subheader given the pdp header */
static t_texture *_pdp_tex_info(t_pdp *x)
{
return (t_texture *)&(x->info.raw);
}
/* create a pow of 2 texture dimension, ge than 8 */
static int _round_to_pow_2(int n){
int r = 8;
while (n > r) r <<= 1;
return r;
}
t_pdp_symbol *_pdp_get_tex_description_from_params(GLsizei width, GLsizei height, GLint format)
{
char description[1024];
char *c = description;
c += sprintf(c, "texture");
switch(format){
case GL_LUMINANCE: c += sprintf(c, "/grey"); break;
case GL_RGB: c += sprintf(c, "/rgb"); break;
case GL_RGBA: c += sprintf(c, "/rgba"); break;
default:
c += sprintf(c, "/unknown"); goto exit;
}
c += sprintf(c, "/%dx%d", width, height);
exit:
return pdp_gensym(description);
}
t_pdp_symbol *_pdp_tex_get_description(t_pdp *header)
{
t_texture *texture = _pdp_tex_info(header);
int encoding;
if (!header) return pdp_gensym("invalid");
else if (!header->desc){
if (header->type == PDP_TEXTURE){
/* if description is not defined, try to construct it */
return _pdp_get_tex_description_from_params(texture->width, texture->height, texture->format);
}
else return pdp_gensym("unknown");
}
else return header->desc;
}
static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format);
static void _pdp_packet_gentexture(int packet);
static void texture_command_convert_bitmap_to_texture(t_texture_command *c)
{
t_texture *t = (t_texture *)pdp_packet_subheader(c->p_dst);
/* make sure packet contains a texture, since it is created with _pdp_packet_reuse_texture */
_pdp_packet_gentexture(c->p_dst);
/* flip source image before uploading */
pdp_packet_bitmap_flip_top_bottom(c->p_src);
/* fill texture */
pdp_packet_texture_make_current(c->p_dst);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t->sub_width, t->sub_height,
t->format, GL_UNSIGNED_BYTE, (char *)pdp_packet_data(c->p_src));
/* decrease refcount */
pdp_packet_mark_unused(c->p_src);
pdp_packet_mark_unused(c->p_dst);
//post("conversion done");
pdp_dpd_command_suicide(c);
}
/* converters to standard pdp types */
int _pdp_packet_texture_convert_image_to_texture(int packet, t_pdp_symbol *dest_template)
{
int p_temp, p;
//post ("converting to bitmap");
p_temp = pdp_packet_convert_rw(packet, pdp_gensym("bitmap/*/*"));
if (p_temp == -1) return -1;
//post ("converting to texture");
p = pdp_packet_convert_rw(p_temp, pdp_gensym("texture/*/*"));
pdp_packet_mark_unused(p_temp);
return p;
}
/* converters to standard pdp types */
int _pdp_packet_texture_convert_bitmap_to_texture(int packet, t_pdp_symbol *dest_template)
{
t_pdp *header = pdp_packet_header(packet);
void *data = pdp_packet_data (packet);
int new_p;
u32 w;
u32 h;
t_texture_command *c;
if (!pdp_packet_bitmap_isvalid(packet)) return -1;
w = header->info.image.width;
h = header->info.image.height;
switch (header->info.image.encoding){
case PDP_BITMAP_GREY:
/* create greyscale texture */
new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_LUMINANCE);
break;
case PDP_BITMAP_RGB:
/* create rgb texture */
new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGB);
break;
case PDP_BITMAP_RGBA:
/* create greyscale texture */
new_p = _pdp_packet_texture_old_or_dummy(w,h, GL_RGBA);
break;
default:
new_p = -1;
break;
}
if (new_p != -1){
/* remark: this is a hack. a texture has to be created
when a rendering context is active. this means it has
to be created in the correct thread. therefore a dpd
command is added to the 3dp queue. this seems to work,
but without a dropping mechanism, this can overload the
queue. the real solution would be to add a converter
object to a 3dp chain, or to accept image or bitmap
packets in 3dp objects */
/* dispatch command */
c = (t_texture_command *)pdp_dpd_commandfactory_get_new_command(&_tex_cf);
c->p_src = pdp_packet_copy_rw(packet);
c->p_dst = pdp_packet_copy_ro(new_p);
pdp_procqueue_add(pdp_opengl_get_queue(), c, texture_command_convert_bitmap_to_texture, 0, 0);
}
return new_p;
}
int _pdp_packet_texture_convert_texture_to_bitmap(int packet, t_pdp_symbol *dest_template0)
{
post("_pdp_packet_texture_convert_texture_to_bitmap not implemented.");
return -1;
}
t_texture *pdp_packet_texture_info(int packet)
{
t_pdp *header = pdp_packet_header(packet);
if (pdp_packet_texture_isvalid(packet)) return _pdp_tex_info(header);
else return 0;
}
/* check if valid texture packet. all other methods assume packet is valid */
int pdp_packet_texture_isvalid(int packet)
{
t_pdp *header;
if (!(header = pdp_packet_header(packet))) return 0;
if (PDP_TEXTURE != header->type) return 0;
return glIsTexture(_pdp_tex_info(header)->tex_obj);
}
static void _tex_init_obj(t_texture *t)
{
//u8 *dummydata;
//int i;
glBindTexture(GL_TEXTURE_2D, t->tex_obj);
glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
/* debug
dummydata = (u8 *)malloc(t->width*t->height*4);
for (i=0; i<t->width*t->height*4; i++){dummydata[i] = random(); }
glTexImage2D(GL_TEXTURE_2D, 0, t->format, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummydata);
free(dummydata);
*/
}
static void _pdp_tex_copy(t_pdp *dst, t_pdp *src);
static void _pdp_tex_clone(t_pdp *dst, t_pdp *src);
static void _pdp_tex_reinit(t_pdp *dst);
static void _pdp_tex_cleanup(t_pdp *dst);
static void _pdp_tex_init_methods(t_pdp *h)
{
h->theclass = texture_class;
}
static void _pdp_tex_reinit(t_pdp *dst)
{
/* this does nothing. texture is assumed to be in a valid state */
}
static void _pdp_tex_clone(t_pdp *dst, t_pdp *src)
{
t_texture *dst_t = _pdp_tex_info(dst);
t_texture *src_t = _pdp_tex_info(src);
//post("WARNING: _pdp_tex_clone: should not be called from outside 3d thread");
/* determine if destination texture is valid */
if (glIsTexture(dst_t->tex_obj)){
/* check format */
if ((dst_t->width >= src_t->width)
&& (dst_t->height >= src_t->height)
&& (dst_t->format == src_t->format)){
dst_t->sub_width = src_t->sub_width;
dst_t->sub_height = src_t->sub_height;
return;
}
}
/* not initialized, so we need to create a new one */
else {
glGenTextures(1, (GLuint*)&dst_t->tex_obj);
}
/* setup header */
dst_t->width = src_t->width;
dst_t->height = src_t->height;
dst_t->format = src_t->format;
dst_t->sub_width = src_t->sub_width;
dst_t->sub_height = src_t->sub_height;
/* setup packet methods */
_pdp_tex_init_methods(dst);
/* init description */
dst->desc = _pdp_tex_get_description(dst);
}
static void _pdp_tex_copy(t_pdp *dst, t_pdp *src)
{
/* texture copying is inefficient. for the tex extensions there is no analogy
for "efficient in-place processing"
this means the pdp_packet_register_rw() call should be avoided
this inconsistency should be tucked away in a texture base class */
/* todo: use texture combining extensions for this */
post("WARNING: fanout is not yet implemented correctly for texture packets");
/* not implemented yet, just a call to the clone method */
_pdp_tex_clone(dst, src);
}
static void _pdp_tex_cleanup(t_pdp *dst)
{
t_texture *t = _pdp_tex_info(dst);
glDeleteTextures(1, (GLuint*)&t->tex_obj);
t->tex_obj = -1; /* is this value guaranteed to be invalid? */
}
/* texture constructors */
/* reuse a texture, or create a "dummy" == packet with everything except a valid texture object */
static int _pdp_packet_texture_old_or_dummy(u32 width, u32 height, s32 format)
{
int p = -1;
t_pdp *h;
t_texture *t;
int p2_w = _round_to_pow_2(width);
int p2_h = _round_to_pow_2(height);
/* try to reuse a texture packet or get a new one */
p = pdp_packet_reuse(_pdp_get_tex_description_from_params(p2_w, p2_h, format));
if (-1 == p) p = pdp_packet_create(PDP_TEXTURE, 0);
if (-1 == p) return -1;
h = pdp_packet_header(p);
t = _pdp_tex_info(h);
/* check if alloc succeded */
if (!h) return -1;
/* check if tex is already initialized */
if (pdp_packet_texture_isvalid(p)){
/* check format */
if ((t->width >= width) && (t->height >= height) && (t->format == format)){
//post("pdp_packet_new_tex: reused");
t->sub_width = width;
t->sub_height = height;
return p;
}
post("ERROR: pdp_packet_new_texture: pdp_packet_reuse returned wrong type");
}
/* determine the texture dims * setup rest of data struct */
t->width = 64;
t->height = 64;
while (t->width < width) t->width <<= 1;
while (t->height < height) t->height <<= 1;
t->format = format;
t->sub_width = width;
t->sub_height = height;
_pdp_tex_init_methods(h);
/* init the texture */
//_tex_init_obj(t);
/* init description */
h->desc = _pdp_tex_get_description(h);
return p;
}
/* don't call this method on a non-texture object! */
static void _pdp_packet_gentexture(int p)
{
t_texture *t;
if (!pdp_packet_texture_isvalid(p)){
/* not initialized, so we need to create a new one */
// post("generating texture");
t = (t_texture *)pdp_packet_subheader(p);
/* create the texture object */
glGenTextures(1, (GLuint *)&t->tex_obj);
/* init the texture */
_tex_init_obj(t);
}
}
int pdp_packet_new_texture(u32 width, u32 height, s32 format)
{
t_texture *t;
int p = _pdp_packet_texture_old_or_dummy(width, height, format);
//post("WARNING: pdp_packet_new_texture: this method should not be called outside the 3dp thread");
if (p == -1) return -1;
_pdp_packet_gentexture(p);
return p;
}
/* high level texture packet operators */
/* make a texture the current texture context */
void pdp_packet_texture_make_current(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return;
glBindTexture(GL_TEXTURE_2D, t->tex_obj);
}
void pdp_packet_texture_make_current_enable(int packet)
{
glEnable(GL_TEXTURE_2D);
pdp_packet_texture_make_current(packet);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
float pdp_packet_texture_fracx(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return 0.0;
return (float)t->sub_width/t->width;
}
float pdp_packet_texture_fracy(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return 0.0;
return (float)t->sub_height/t->height;
}
u32 pdp_packet_texture_total_width(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return 0;
return t->width;
}
u32 pdp_packet_texture_total_height(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return 0;
return t->height;
}
u32 pdp_packet_texture_sub_width(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return 0;
return t->sub_width;
}
u32 pdp_packet_texture_sub_height(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return 0;
return t->sub_height;
}
float pdp_packet_texture_sub_aspect(int packet)
{
t_texture *t = pdp_packet_texture_info(packet);
if (!t) return 0;
return (float)t->sub_width/t->sub_height;
}
/* setup for 2d operation from texture dimensions */
void pdp_packet_texture_setup_2d_context(int p)
{
u32 w;
u32 h;
float asp;
if (!pdp_packet_texture_isvalid(p)) return;
w = pdp_packet_texture_sub_width(p);
h = pdp_packet_texture_sub_height(p);
asp = pdp_packet_texture_sub_aspect(p);
/* set the viewport to the size of the sub texture */
glViewport(0, 0, w, h);
/* set orthogonal projection, with a relative frame size of (2asp x 2) */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 2*asp, 0, 2);
/* set the center of view */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(asp, 1, 0);
glScalef(1,-1,1);
}
void pdp_texture_setup(void)
{
t_pdp_conversion_program *program;
/* setup packet class */
texture_class = pdp_class_new(pdp_gensym("texture/*/*"), 0);
texture_class->cleanup = _pdp_tex_cleanup;
texture_class->wakeup = _pdp_tex_reinit;
//texture_class->clone = _pdp_tex_clone;
texture_class->copy = _pdp_tex_copy;
/* init command list */
pdp_dpd_commandfactory_init(&_tex_cf, sizeof(t_texture_command));
/* setup programs */
program = pdp_conversion_program_new(_pdp_packet_texture_convert_bitmap_to_texture, 0);
pdp_type_register_conversion(pdp_gensym("bitmap/*/*"), pdp_gensym("texture/*/*"), program);
/* this is a hack to use until the type conversion system has a proper search algo */
program = pdp_conversion_program_new(_pdp_packet_texture_convert_image_to_texture, 0);
pdp_type_register_conversion(pdp_gensym("image/*/*"), pdp_gensym("texture/*/*"), program);
program = pdp_conversion_program_new(_pdp_packet_texture_convert_texture_to_bitmap, 0);
pdp_type_register_conversion(pdp_gensym("texture/*/*"), pdp_gensym("bitmap/*/*"), program);
}
/* all symbols are C-style */
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_opengl.c ---
/*
* OpenGL Extension Module for pdp - opengl system stuff
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "pdp.h"
#include "pdp_control.h"
#define PDP_3DP_QUEUE_LOGSIZE 16
#define PDP_3DP_QUEUE_DELTIME 1.0f
void pdp_3Dcontext_prepare_for_thread_switch(void *);
static t_pdp_procqueue _3dp_queue;
static void pdp_control_thread(void *x, t_symbol *s, int argc, t_atom *argv)
{
int t = 0;
float f;
if (argc != 1) return;
if (argv[0].a_type != A_FLOAT) return;
f = argv[0].a_w.w_float;
t = (f != 0.0f);
post("3dp thread switched %s", t ? "on":"off");
/* when we switch threads, the glx system needs to be notified
because it has to release the render context. this is done
in a process method, so it is run in the correct thread. */
pdp_procqueue_add(&_3dp_queue, 0, pdp_3Dcontext_prepare_for_thread_switch, 0, 0);
pdp_procqueue_wait(&_3dp_queue);
/* fresh start: enable/disable the thread dispatching */
pdp_procqueue_use_thread(&_3dp_queue, t);
}
/* kernel setup */
void pdp_opengl_system_setup(void)
{
/* init the 3dp queue */
pdp_procqueue_init(&_3dp_queue, PDP_3DP_QUEUE_DELTIME, PDP_3DP_QUEUE_LOGSIZE);
/* scheduler uses the thread */
pdp_procqueue_use_thread(&_3dp_queue, 1);
//pdp_procqueue_use_thread(&_3dp_queue, 0); //DEBUG: disable 3dp thread
/* add pdp_control method for thread */
pdp_control_addmethod((t_method)pdp_control_thread, gensym("3dthread"));
}
t_pdp_procqueue* pdp_opengl_get_queue(void){return (&_3dp_queue);}
--- NEW FILE: pdp_3Dcontext_glx.c ---
/*
* OpenGL Extension Module for pdp - opengl system stuff
* Copyright (c) by Tom Schouten <pdp(a)zzz.kotnet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* this file contains the platform dependent opengl setup routines (glx)
and pdp_packet_3Dcontext methods */
#include "pdp_opengl.h"
#include "pdp_xwindow.h"
#include "pdp_internals.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>
//#include <GL/glut.h>
/* all symbols are C-style */
#ifdef __cplusplus
//extern "C"
//{
#endif
// this is buggy: disabled
#define PRIVATE_CONTEXT 0
/* structure to hold the (platform dependent) gl environment setup */
typedef struct _gl_env
{
bool initialized; /* data structure is consistent */
XVisualInfo *visual; /* the visual info structure for the context */
GLXContext context; /* the rendering context used to render to windows or pbufs */
GLXFBConfig *config; /* the framebuffer config object */
t_pdp_xdisplay *xdpy; /* pdp's x display object */
//Display *dpy; /* x display connection */
//int screen; /* x screen */
int last_context_packet; /* the packet that is currently rendered too (for caching) */
} t_gl_env;
static t_gl_env pdp_glx_env;
static t_pdp_class *context_class;
/* PDP_3DCONTEXT packet methods */
/* set/unset ogl rendering context to pbuf */
void pdp_packet_3Dcontext_set_rendering_context(int packet)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (!c) return;
/* don't do a glx call if the context is still the same */
if (pdp_glx_env.last_context_packet == packet) return;
//post("new current context is %d", packet);
/* pbuffer */
switch(c->encoding){
case PDP_3DCONTEXT_WINDOW:
//glFinish();
//glXMakeCurrent(pdp_glx_env.dpy, ((t_pdp_xwindow *)c->drawable)->win, pdp_glx_env.context);
glXMakeCurrent(pdp_glx_env.xdpy->dpy, ((t_pdp_xwindow *)c->drawable)->win, (GLXContext)c->context);
pdp_glx_env.last_context_packet = packet;
break;
case PDP_3DCONTEXT_PBUFFER:
//glXMakeCurrent(pdp_glx_env.dpy, (GLXPbuffer)c->drawable, pdp_glx_env.context);
//glXMakeContextCurrent(c->dpy, c->drawable.pbuf, c->drawable.pbuf, c->context);
pdp_glx_env.last_context_packet = -1;
break;
default:
pdp_glx_env.last_context_packet = -1;
break;
}
}
void pdp_packet_3Dcontext_unset_rendering_context(int packet)
{
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (!c) return;
/* pbuffer */
switch(c->encoding){
case PDP_3DCONTEXT_WINDOW:
glXMakeCurrent(pdp_glx_env.xdpy->dpy, None, NULL);
pdp_glx_env.last_context_packet = -1;
break;
case PDP_3DCONTEXT_PBUFFER:
//glXMakeCurrent(pdp_glx_env.dpy, None, NULL);
//glXMakeContextCurrent(c->dpy, c->drawable.pbuf, c->drawable.pbuf, c->context);
break;
default:
break;
}
}
/* cons/des */
static void _3Dcontext_clone(t_pdp *dst, t_pdp *src)
{
post("ERROR: clone not supported for 3Dcontext packets");
}
static void _3Dcontext_copy(t_pdp *dst, t_pdp *src)
{
post("ERROR: copy not supported for 3Dcontext packets");
}
static void _3Dcontext_reinit(t_pdp *dst)
{
/* leave the packet as is */
}
static void _3Dcontext_cleanup(t_pdp *dst)
{
t_3Dcontext *c = (t_3Dcontext *)(&dst->info.raw);
/* reset context packet cache, in case this packet was the current context. */
pdp_glx_env.last_context_packet = -1;
switch(c->encoding){
case PDP_3DCONTEXT_WINDOW:
#if PRIVATE_CONTEXT
glXDestroyContext (pdp_glx_env.dpy, (GLXContext)c->context);
#endif
pdp_xwindow_cleanup((t_pdp_xwindow *)c->drawable);
free(c->drawable);
break;
case PDP_3DCONTEXT_PBUFFER:
break;
//glXDestroyContext(c->dpy, c->context);
//glXDestroyPbuffer(c->dpy, c->drawable.pbuf);
default:
break;
}
}
/* setup packet methods */
static void _3Dcontext_init_methods(t_pdp *header)
{
header->theclass = context_class;
header->flags = PDP_FLAG_DONOTCOPY;
}
/* window specific methods */
void _pdp_3Dcontext_set_window_size(t_3Dcontext *c, t_pdp_xwindow *xwin)
{
c->width = xwin->winwidth;
c->sub_width = xwin->winwidth;
c->height = xwin->winheight;
c->sub_height= xwin->winheight;
}
/* resize the window */
void pdp_packet_3Dcontext_win_resize(int packet, int width, int height)
{
t_pdp_xwindow *xwin;
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (!c) return;
if (PDP_3DCONTEXT_WINDOW != c->encoding) return;
xwin = (t_pdp_xwindow *)c->drawable;
pdp_xwindow_resize(xwin, width, height);
_pdp_3Dcontext_set_window_size(c, xwin);
}
t_pdp_list *pdp_packet_3Dcontext_win_get_eventlist(int packet)
{
t_pdp_list *eventlist;
t_pdp_xwindow *xwin;
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (!c) return 0;
if (PDP_3DCONTEXT_WINDOW != c->encoding) return 0;
xwin = (t_pdp_xwindow *)c->drawable;
eventlist = pdp_xwindow_get_eventlist(xwin);
_pdp_3Dcontext_set_window_size(c, xwin);
return eventlist;
}
void pdp_packet_3Dcontext_win_cursor(int packet, bool toggle)
{
t_pdp_xwindow *xwin;
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (!c) return;
if (PDP_3DCONTEXT_WINDOW != c->encoding) return;
xwin = (t_pdp_xwindow *)c->drawable;
pdp_xwindow_cursor(xwin, toggle);
}
void pdp_packet_3Dcontext_win_swapbuffers(int packet)
{
t_pdp_xwindow *xwin;
t_3Dcontext *c = pdp_packet_3Dcontext_info(packet);
if (!c) return;
if (PDP_3DCONTEXT_WINDOW != c->encoding) return;
xwin = (t_pdp_xwindow *)c->drawable;
glXSwapBuffers(xwin->xdisplay->dpy,xwin->win);
//glFinish();
}
/* constructors */
/* construct (or reuse) a window packet */
int pdp_packet_new_3Dcontext_win(void)
{
/* $$$FIXME: this assumes packet can't be reused */
int p = pdp_packet_new(PDP_3DCONTEXT, 0);
t_pdp_xwindow *xwin;
t_3Dcontext *c;
t_pdp *header = pdp_packet_header(p);
if (!header) return -1; /* pool full ? */
c = (t_3Dcontext *)&header->info.raw;
if (c->drawable){
xwin = (t_pdp_xwindow *)c->drawable;
}
else{
xwin = (t_pdp_xwindow *)malloc(sizeof(*xwin));
}
pdp_xwindow_init(xwin);
pdp_xwindow_create_on_display(xwin, pdp_glx_env.xdpy);
/* init subheader */
#if PRIVATE_CONTEXT
if (NULL == (c->context = (void *)glXCreateContext(pdp_glx_env.dpy, pdp_glx_env.visual, pdp_glx_env.context, True))){
post("pdp_packet_new_3Dcontext_wind: ERROR: can't create rendering context");
}
#else
c->context = (void *)pdp_glx_env.context;
#endif
c->drawable = xwin;
c->encoding = PDP_3DCONTEXT_WINDOW;
_pdp_3Dcontext_set_window_size(c, xwin);
/* init packet methods */
_3Dcontext_init_methods(header);
/* init header */
header->desc = pdp_gensym("3Dcontext/window");
header->flags = PDP_FLAG_DONOTCOPY;
return p;
}
/* pbuf constructor */
int pdp_packet_new_3Dcontext_pbuf(u32 width, u32 height, u32 depth)
{
post("ERROR: 3Dcontext/pbuffer packets not implemented");
return -1;
}
/* this is a notifier sent when the processing thread which
executes gl commands is changed. we need to release the current context
before another thread can take it. */
void pdp_3Dcontext_prepare_for_thread_switch(void)
{
pdp_packet_3Dcontext_unset_rendering_context(pdp_glx_env.last_context_packet);
}
/* setup routine */
static void pdp_3Dcontext_glx_setup_inthread(void)
{
/* this opens the connection to the x server and creates a render context
for windows (glx < 1.3) or windows/pbufs (glx >= 1.3) */
static int dblBuf24[] = {GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 0,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None};
pdp_glx_env.initialized = 0;
/* init xlib for thread usage */
if (!XInitThreads()){
post("pdp_opengl_system_setup: can't init Xlib for thread usage.");
goto init_failed;
}
/* open display:
the first display on the local machine is opened, not DISPLAY.
since pdp_opengl is all about direct rendering, and there
is no way to specify another display, or even close it and
open it again, this seems to be the "least surprise" solution.
it enables the pd interface to be displayed on another display,
using the DISPLAY environment variable. */
if (NULL == (pdp_glx_env.xdpy = pdp_xdisplay_new(":0"))){
post("pdp_opengl_system_setup: can't open display");
goto init_failed;
}
/* get visual */
if (NULL == (pdp_glx_env.visual = glXChooseVisual(pdp_glx_env.xdpy->dpy, pdp_glx_env.xdpy->screen, dblBuf24))){
post("pdp_opengl_system_setup: can't find appropriate visual");
goto init_failed_close_dpy;
}
/* create a (direct) rendering context */
if (NULL == (pdp_glx_env.context = glXCreateContext(pdp_glx_env.xdpy->dpy, pdp_glx_env.visual, 0, True))){
post("pdp_opengl_system_setup: can't create rendering context");
goto init_failed_close_dpy;
}
//post("pdp_opengl_system_setup: pdp_opengl init OK.");
pdp_glx_env.last_context_packet = -1;
pdp_glx_env.initialized = 1;
/* setup class object */
context_class = pdp_class_new(pdp_gensym("3Dcontext/*"), 0);
context_class->cleanup = _3Dcontext_cleanup;
context_class->wakeup = _3Dcontext_reinit;
//context_class->clone = _3Dcontext_clone;
context_class->copy = _3Dcontext_copy;
/* setup conversion programs: NOT IMPLEMENTED */
return;
init_failed_close_dpy:
pdp_xdisplay_free(pdp_glx_env.xdpy);
pdp_glx_env.xdpy = 0;
init_failed:
post("pdp_opengl_system_setup: FATAL ERROR: pdp_opengl init failed.");
exit(1);
}
/* run the setup routine in the procqueue thread, and wait for it to finish */
/* NOTE: this seems to make an Xlib deadlock problem go away when running
pd with realtime scheduling. frankly, i'm very puzzled by this problem
and even more by the way this workaround solves it. anyhow... */
void pdp_3Dcontext_glx_setup(void)
{
t_pdp_procqueue *q = pdp_opengl_get_queue();
pdp_procqueue_add(q, 0, pdp_3Dcontext_glx_setup_inthread, 0, 0);
pdp_procqueue_flush(q);
}
#ifdef __cplusplus
//}
#endif