You are on page 1of 148

Yup, left blank on purpose.

You can use it to draw whatever you want :-)

Chapter 1

The task I have assigned myself is not an easy one; teach C.O.F.F.E.E.
Not the beverage of course, but the scripting language included in CINEMA
4D. And why is it a daunting task? Because, usually scripting, or anything related
to programming, is considered a subject for geeks, chess club stars, rocket
scientists and non-artistic people in general. This couldnt be farther away from
the truth. Im not a chess club star, although I do know how to play chess. Im
not a rocket scientist, but I did graduate as a graphic designer and I do know
how to code in C.O.F.F.E.E.! OK, I never said I wasnt a geek, but even if many
people consider me as such, I dont think Im one of those :)
What exactly is C.O.F.F.E.E.? Its a scripting language. OK, this is not very
meaningful to all you mouse-drag-mouse-click-doodle-stuff-on-screen guys, is
it? Instead of "scripting language", lets say it is a programming language. Wow!
Now instead of something that you dont understand, it became something you
fear. Let me assure you, there is no reason to be afraid. I intend to make this a
fun experience from beginning to end. Now that you understand C.O.F.F.E.E. is
a programming language, you can, and will, use it to make CINEMA 4D do stuff
that would be, otherwise, very hard or completely impossible to do by hand,
mouse, pen or whatever.
I have no doubt one of the first questions you "artists at heart" asked
yourselves when you first discovered the C.O.F.F.E.E. language:
"Why the hell is it called C.O.F.F.E.E.?
3

Do you need industrial amounts of C.O.F.F.E.E. to learn and tame it? Like
the beverage, is it a "black" art?"
I dont have official confirmation from MAXON, but I assume, and please
DONT quote me on this... I will vehemently deny it, that it is because it is very,
very, very similar to JavaScript, and java is a type of C.O.F.F.E.E.(1).
Oops, I said another "foreign word", JavaScript. JavaScript is another
programming language often used to code stuff, mainly for Internet pages. It
is a very structured programming language based on C and C++. Yes, you got
it... C and C++ (pronounced "see" and "see plus plus") are also programming
languages. As you may have already guessed, there are many, many (a few
hundreds, if not thousands of) programming languages. Until now, to you, all
of them sounded like the forbidden Black Language of Mordor, (sorry for the
Tolkieneske pun) but I promise I will try to make, at least, C.O.F.F.E.E. almost
as easy to understand as plain English. If you already know a bit of JavaScript,
Java, C or C++ you already know a bit of C.O.F.F.E.E. Believe me, they are
almost the same. If you are still a "virgin" at this matter, do carry on reading.
OK, what exactly is a programming language? Its a set of instructions
(commands, functions, operands, operators, etc) that, assembled according
to a specific syntax, instruct the computer (or, in our case, the CINEMA 4D
application) to do stuff. So, what are "commands", "functions", "operands",
"operators" and that "syntax" I talked about? Commands are exactly what their
designation mean: they are "words" that make the application actually perform
an action. Functions are like magic boxes that you place stuff inside and
something different comes out. This means that you feed them with data and,
once some operations are performed on that data, some sort of result will come
out. Operands are the data you work with. It can be a number, a word, a 3D
primitive, a texture, etc. Operators are operations you can perform on operands
(the data, remember?) The "syntax" is the set of rules you must follow to write
correct code, just like the rules of the syntax of your mother language if you
want to write correct sentences. Im telling you all this because, inevitably, I will
have to introduce you to some programming-specific terms (sorry, there is no
escape from that my friends). Even if they sound complex, cryptic or just plain
weird, they will become obvious and even logic after a while.
Lets start with our first program in C.O.F.F.E.E. and, with it, I will introduce
you to all the concepts I presented you with before.
This first program will simply print out the sentence "Hello World". Why?
Well, I cant really explain why but all tutorials about every programming
language, whatever they are, start with a simple program that prints out "Hello
World". I guess it is because all programming languages have, at least, a
command that prints something and, this way, people can get a first "test-drive"
of a programming language in a very soft and easy way. Otherwise, they would
give up at their first try.
(1)
After writing the book, I found out that Maxon coined up an official acronym for C.O.F.F.E.E. which is Cinema Object-oriented Fery
Fast Environment Enhancer. We must all agree that it is not a very good one. but there had to be a reason for the dots between
the letters, besides being an aesthetical decision.

To create your first C.O.F.F.E.E. script


you need to add a new C.O.F.F.E.E. tag
to an object. It can be any object you
want but, for this purpose, lets create
the simplest object there is: a Null.
Now that you have a Null, add to it a
C.O.F.F.E.E. tag. You do that exactly
the same way as you add any other tag.
Once you add the C.O.F.F.E.E. tag, you end up with a nice cup of C.O.F.F.E.E.
in the Object Manager and, automatically, CINEMA
4D opens a C.O.F.F.E.E. Expression Editor. Even if
you close this window, you can always get it back by
double clicking the C.O.F.F.E.E. tag attached to your
object(s).
As you can see, the C.O.F.F.E.E. Expression Editor has already "typed"
some code for you:

In this case, it defines your main function. This is a very special kind of
function because it is the first function that is executed. All C.O.F.F.E.E.
expressions must have, at least, a main function. Otherwise, you would get an
error and nothing would be executed. This function doesnt return any value,
actually, (remember my previous definition of function?) but it does include two
operands: doc and op.
What are those? Well, they are values that you can use inside the function.
Let me give you an example of another function that you may be more familiar
with: The power of two function. If you recall your math in school, you can raise
any number to the power of two. Its as simple as multiplying the number by
itself. So, for instance, 3 raised to the power of two is 9... or 3 x 3. The same
way, 5 raised to the power of two is 25... or 5 x 5. Easy, isnt it?
5

So, lets give this function the name raise_to_power_of_two. For it to make
its mumbo-jumbo (multiply a number by itself) we must feed it with a number,
right? It will then perform whatever operations are needed and spits out a result.
The number we feed it with it called an operand. So, we could code the raise_
to_power_of_two function like this:

raise_to_power_of_two(x)
{
return x*x;
}
The value that we placed between parentheses, after the name of the
function, is the operand that the function will use. Why cant we place a number
there? Well, we are just defining what the function does, not really performing
any calculation. If we placed, for example, the number 3 there, this function
would always calculate 3 raised to the power of two. Not very useful, you must
agree.
In this case we used a letter x. Its a variable. Why is it called a variable?
Well, because it can contain any value.
So, inside the function the commands between the { and the } we
calculate x times x and we return that value. That is exactly what the command
return x*x; does. I believe that return x*x is obvious enough but... what
about the ; at the end? All commands in C.O.F.F.E.E. must end with a semicolon.
This is a way for C.O.F.F.E.E. to know when a command as actually finished
being defined. This is one of the rules of the syntax of C.O.F.F.E.E. See? You
have already learned what a function and an operand are. You also had a little
glimpse of what a variable is, and you had a little taste of what "syntax" really
means.
We have now seen the { and } symbols twice and I havent explained exactly
what they are or mean. They refine a block of code. Everything between them
defines a set of code instructions that relate to each other. The logic of using
them in a function is that, after defining the name and operands of the function,
everything between the { and the } symbols belongs to that specific function.
This means that, right after the name of the function (and operands, if any),
C.O.F.F.E.E. encounters a { symbol. This defines the start of the code of the
function. When it finds the correspondent } symbol it "knows" that the function
ends there. Logic, isnt it?

Now that we know how to interpret the:

main(doc,op)
{
}
...Lets understand what the doc and op are. From what you learned already,
you know they are the operands of the main function, right? And, also, that they
are variables. Before explaining exactly what each one is, I must clarify what a
variable is. Imagine a variable as a storing box. Inside it you can place values.
And what type of values? Well, pretty much everything. You can store numbers,
letters, colors, objects, tags, materials, etc. When I say objects, tags, materials,
etc., I mean a value that points to an actual object, tag, material, whatever,
inside your document. So, variables are invaluably useful. Without them you
would be able to do very little with C.O.F.F.E.E., or any other programming
language.
So, if variables can store so many things, what do the doc and op variables
store? CINEMA 4D politely provides you automatically with the current
document (the one you are working with) in the doc variable and the object that
contains the C.O.F.F.E.E. tag in the op variable. This means that as soon as
you enter the main function you can access info about your document and also
info about the object that contains the C.O.F.F.E.E. tag whose main function is
being executed. This is very valuable information but in this first chapter we will
not need it because we only want to print a simple sentence. No fiddling with
documents or objects is required for now.
If you paid lots of attention to all that you have read here, you may be
wondering why is it that the main(doc, op) doesnt have a ; at the end. If
you asked that question, you are my best student so far!!
Well, because main(doc, op) is not a command. It doesnt instruct the
computer to do anything. It just defines a function. Its an instruction, not a
command. Remember, I said that only commands require the ; at the end.
Syntax rules, you know? ;-)
Place your cursor between the { and the } symbols and type:

Notice that the ln after the print are lowercase L and N, not an uppercase i
and lowercase N.
What have we just typed? The println is a command that instructs CINEMA
4D to print out something. Between the parentheses are its parameters, as in
what you want to print. And why is it between quotes? Well, because what
we want to print is a literal expression, not a variable. Ok, ok... Im talking
gibberish again. What is a literal expression? Well, its something that should
be interpreted as is! Want an example? Ok, no problem...
Imagine you had written

println(hello);
instead of

println("hello");
And you had a variable named hello that is storing the word goodbye.
Should CINEMA 4D print hello or the content of the variable hello that is,
actually, goodbye?
To not confuse CINEMA 4D, we must enclose all literal expression
(as in, they should evaluate exactly as they are presented) in quotes. So,
println(hello); would print goodbye because, since hello is not enclosed
in quotes, it is evaluated as a variable. The command println("hello");
will print hello because, since it is between quotes, it should be taken as it is
written. This is pure syntax at work. See how important the syntax is?
Ok, you just wrote your first C.O.F.F.E.E. script. You must now check if it
has any errors. To do so, click the Compile button on the top of the Expression
Editor window. If it all goes fine, you should get a report of No Errors! at the
bottom of the Expression Editor window.

Now, hit the Execute button at the top of the Expression Editor window.
8

Wow! Amazing! Nothing happened! This Rui guy is a charlatan!! Wait... the
printout is in there... somewhere. You just need to know where to look for it. If
you are using an 8.x version of CINEMA 4D, press Shift+F10. If you are using
a 9.x version of CINEMA 4D or higher, press Alt+F9 or simply choose Console
from the Window menu, in any version of CINEMA 4D.
Now you see your Hello World at the bottom of the window? Ah, this Rui
guy is not a charlatan, after all. Do you see more stuff printed in the Console
window? If you do, that is all the stuff that plug-ins print when they load. Actually,
the Console is a very useful place to go to check to see if something is wrong
with any plug-in that is not loading or simply misbehaving.
Now, from the File menu of the Console window, choose Clear. You are
now staring at a clean Console window. With the Console window still open,
press Play, like you would do to check out an animated scene in CINEMA 4D.
Wow, lots and lots of Hello World sentences! You now know that your script is
executed for each frame of your animation. Actually, it is executed each time
something changes in your scene. Choose Clear again from the Console File
menu and try moving the Null around. Again, lots
of Hello World sentences. This is not particularly
useful right now, but its good to know, for future
reference, how often the C.O.F.F.E.E. scripts are
executed.
One final thing before we wrap-up this first
chapter about C.O.F.F.E.E. Why the hell is the
print command named println and not just
print? In this case, ln (lowercase L and N) stands
for line. You are instructing CINEMA 4D to print
out a line of text. A line of text means that a return
is added at the end, automatically, just like if you
had pressed Enter, otherwise it would print out
all the Hello World sentences "glued" together,
as in:
Hello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello World...

If you want to try it out, replace the println with print. As soon as CINEMA
4D fills out an internal container of the Console, it will print out a whole line of
neatly glued together Hello World. You can force the print command to add a
return, but why bother if you already have the command println, right?
This is it for this first chapter. I hope I didnt frighten you too much with all this
code stuff. I also hope I was able to interest you enough to keep you reading on
through the rest of the chapters. Lets move on to Chapter 2.
9

Chapter 2

Here we are, back in the C.O.F.F.E.E. classroom once again. I hope you
enjoyed the first chapter and are eager to learn more. I promise we will learn
and do a bit more. As in the previous chapter, this one is a bit challenging. This is
the first time I will write a full textual chapter. Yes, thats right! No pictures in this
one, so the challenge is doubled this time around. Trying to keep you interested
in a tricky subject, and doing it without pictures is quite a task. If I succeed, I will
be more than motivated to go on with writing/teaching this programming stuff.
In this chapter I will present lots of C.O.F.F.E.E. code snippets. To test
them, do like you did in the first chapter: create a Null, add to it a C.O.F.F.E.E.
expression tag and type the code into it. Dont forget to keep the Console
window open. This enables you to check the code messages and any eventual
error message that may show up. Enough with the small talk! Lets move onto
the juicy stuff!
Do you remember what I said about variables in the last lesson? I said that
they were like container boxes that could hold lots of different things. That, by
itself, makes them very powerful and useful. Of course you want examples and
I have no fear of showing them. Imagine you have this little C.O.F.F.E.E. script:
main(doc,op)
{
println("Please select a Null.");
println("If you dont select a Null and a Null only, I
will not be able to go on with this script.");
println("So, please, humor me and select a Null before
you choose this script.");
}
10

From what you learned in Chapter 1, you already know what this script does.
Now, just between us... The word "Null" is repeated a few times, isnt it? What
if you decided that instead of a Null, your script would need to have a Sphere
selected? Mmmmmmm, lots of changes to make, even with the invaluable help
of our beloved couple of friends: Copy and Paste.
What if we had written the previous script this way?

main(doc, op)
{
var obj;
obj="Null";
println("Please select a "+obj);
println("If you dont select a "+obj+" and a "
+obj+" only, I will not be able to go on with this
script.");
println("So, please, humor me and select a "+obj+"
before you choose this script.");
}
Now, you just need to change the line that reads:

obj="Null";
to

obj="Sphere";
or whatever you want and the sentences will all print a different thing.
This is a very basic and, dare I say, stupid example, but it illustrates the
simplest power of variables: its re-usability.
So, what have we done? First we defined the variable with the instruction
var. This instruction is followed by the name of the variable we want to define.
It can have any name you can think of, but it must start with a letter and can only
contain letters, numbers and underscores. No spaces are allowed. Samples of
valid variable names are:
name
number
thingy
whatever
whatever2
yadayadayada
this_is_a_very_long_variable_name
11

Invalid variable names are, for example:


123name

(it starts with a number)

is_this_a_variable?

(no, because it contains an invalid character:


the question mark)

what about this one

(no can do... it contains spaces)

return

(oops... its not possible to use command


names either)

This last one may sound a bit tricky, as you dont know the name of all the
commands in C.O.F.F.E.E. Dont worry. If you try to declare a variable with the
name of a command, you will get a syntax error. I will not talk about the errors
now but rest assured, as soon as you make a mistake you will get a warning.
So, no misbehaving! ;-) Also, you should try to refrain on the length of the
variable names. Variables are useful and used very often. You dont want to see
yourself typing look_at_this_humongus_variable_name, whenever you
want to use the look_at_this_humongus_variable_name as the name of
a variable.
You can declare more than one variable using the same var instruction. So,
instead of writing:
var
var
var
var
var

name1;
name2;
name3;
my_number;
another_number;

You can type:


var name1,name2,name3,my_number,another_number;
Much more economical, isnt it? A good rule is to join together related
variables. You can also define the variable like this:
var name1,name2,name3;
var my_number,another_number;
Its just that it is easier to read and understand code that is neatly written, but
you can type it, as you prefer within the limits I have already presented.
12

Ok, once you declare your variables, you can start assigning values to them.
You do that, simply, by typing something like:
name1="Mr.";
name2="John";
name3="Smith";
my_number=1;
another_number=2;
In other computer languages you have to define what type of content the
variable will store. So, if you wanted the variable to contain words you would
have to declare it as a String type (string as in... a string of characters). If you
wanted it to contain integer numbers (numbers with no decimal part) you would
have to declare them as Integer. If you wanted non-integer numbers, you would
have to declare them as Float, or as Single or Double.
Ok... forget all I just said!!! Dont worry about it. C.O.F.F.E.E. is a much
friendlier language. You just define the variable names and you can place
whatever you want inside them. C.O.F.F.E.E. does all the juggling necessary
to deal with all the data types. Nice, isnt it? And the good news doesnt end
here. Even if you do have to follow a restricted syntax, that very same syntax is
flexible enough to allow you to write the same sentences in many different ways
and even combine several lines of code into one. So, it is perfectly possible to
write the following:
var name1="Mr.",name2="John",name3="Smith",
my_number=1,another_number=2;
or
var name1,name2="John",name3="Smith",my_number,
another_number=2;
In this case, name1 and my_number are only declared and have no starting
values assigned.
Now that you already know what variables are and how they are created,
how can you use them, besides simply assigning them values and printing them
to the Console? To really start using variables in a productive way, and to start
harnessing the true power of any programming language, we will have to dip
our feet a little deeper into the C.O.F.F.E.E. commands. Fear not... I will guide
you throughout the entire process. The first thing we will learn is how to deal
13

with conditions. In the real world, conditions work, more or less, like this:

IF there is a mad man with a knife coming towards me THEN its a


good idea to start running
Conditions can be more complex, like this:

IF there is a mad man with a knife coming towards me AND I have my


feet tied THEN I may be in deep trouble
And even more complex...

IF there is a mad man with a knife OR a gun, coming towards me AND I


have my feet tied OR there is no place to run to THEN I better start saying
my prayers

Conditions can also offer alternatives:

IF there is a lion in my living room THEN I should call my psychiatrist


or ELSE I should leave home, just to be safe
In all programming languages, you can test out conditions and take action
accordingly. I mean, if a certain affirmation is true some action is taken. And how
does this translate into C.O.F.F.E.E.? Try to figure out what this script does:
main(doc,op)
{
var a=1;
if(a==1) println("The variable a is equal to one");
}
I believe this is obvious enough, except maybe for the two equal signs (==).
Why two? That is a syntax imposition again. When you use just one equal sign
you are assigning a value. If you look up in the script listing, that is exactly what
is happening when I typed:
var a=1;
I was ASSIGNING a value to the variable. When two equal signs are used,
we are comparing. So, a==1 returns a logical value. What is a logical value? Its
either TRUE or FALSE, depending on the result of the comparison. In our case,
the expression a==1 (a equals one?) is true, right? So, the println("The
variable a is equal to one"); statement is executed. Try pressing the
14

Execute button, in the Expression Editor (first click the Compile button to check
for errors). If you check out the Console, there should be at least one "The
variable a is equal to one" sentence there. Now, try changing the line:
var a=1;
to
var a=3;
Now, press Execute again. No additional sentence is added to the Console
because now the variable a contains the value 3 and the comparison with 1
fails. What if you wanted to execute more operations if the condition tested is
true? Remember, from Chapter 1 that I said that the { and } symbols were used
to define a block of code? So, check out this script to see if it sounds logical to
you:
main(doc,op)
{
var a=1;
if(a==1)
{
println("The variable a is equal to one");
println("That is why the condition evaluated to a true
value");
println("and these sentences are showing on the
Console.");
}
}
You may have noticed that the sentences are indented. I mean... I pressed
the Tab key before each line that is part of the block of code between the {
and } symbols (including the { and } symbols themselves). That is not really
necessary but it makes for clearer code. We will see later why indenting lines is
so helpful. Have you executed this script? It should print the whole sentences to
the console. If not, check for any syntax error.
What if I wanted something else to happen if the variable a was not 1? Well,
I could write this:
main(doc,op)
{
var a=1;
if(a==1) println("The variable a is equal to one");
if(a!=1) println("The variable a is NOT equal to one");
}
15

Yes, yes... the C.O.F.F.E.E. expression for NOT EQUAL is:


!=
So, != actually means DIFFERENT whereas == mean EQUAL.
The previous code is perfectly legitimate. But not very compact and not as
elegant as:
main(doc,op)
{
var a=1;
if(a==1) println("The variable a is equal to one");
else println("The variable a is NOT equal to one");
}
Logical, isnt it? As you may already guess, you can do the same with code
blocks, as in:
main(doc,op)
{
var a=1;
if(a==1)
{
println("The variable a is equal to one");
println("Nice to know, isnt it?");
}
else
{
println("The variable a is NOT equal to one");
println("Why, oh, why?");
}
}
Oh, by the way, you really must enclose the conditional expression you are
testing inside parentheses. Syntax requirements, sorry, but I believe this also
makes it easier to read the conditional expression.
16

Inside the conditional expression (the stuff between the parentheses) you
can perform any comparisons. I mean, you can check out everything that would
evaluate to a true or false value. Examples of valid expressions are:
Expression

Meaning

a==1

a is EQUAL to 1

a!=3

a is DIFFERENT than 3

b==1.56

b is EQUAL to 1.56

c!="word"

c is DIFFERENT than "word"

a>10

a is LARGER than 10

b<-5

b is LESS than minus 5

c>=20

c is LARGER or EQUAL to 20

a==b

a is EQUAL to b

c!=b

c is DIFFERENT than b

As you can see, lots of possible comparisons are possible. But beware!!
Some things are simply not possible. For example, check out this script:
main(doc,op)
{
var a=10;
var c="10";
if(a==c) println("The variable a is equal to variable
c");
}
This will NOT print the sentence "The variable a is equal to variable c"
simply because they are not equal. The variable a stores a numeric value and
the variable c stores an alphanumeric value. Wow!! A new word: alphanumeric.
Well, alphanumeric is, in this case, just another way of saying "string", as in
"a string of characters". So, the variable c stores the character "1" and the
character "0", not the numeric value of 10.
Before we wrap up this chapter, the only thing missing from the comparison
expressions is a way to test for more than one condition at the same time.
As I stated in my previous textual examples of conditional expressions, you
could test for something AND something and something OR something.
17

You can even combine them. Just check this out:


main(doc,op)
{
var a=10;
var b=20;
var c="10";
if(a==10 && c=="10") println("The variable a and c store
the value 10, even if not in the same way");
if(a==5 || b==20) println("The variable a stores the
number 5 or, maybe, the variable b stores the number 20");
}
Executing this script will print both sentences. In the first condition both a
is equal to 10 AND c is equal to "10" so, the whole expression is true. The
operand for AND is, as you may have noticed, &&.
Why two & ? Not only to maintain consistency with the other conditional
operands (== and !=) but there is another logical operation that uses the single
character &. But there is no need to worry about that other operation right
now.
Using the && operand, only if ALL expressions evaluate to a true value, the
result will also be true. So, if any of the expressions is false, everything else fails
and the condition will become false. You can use as many && as you want, like
this, for example:
if(a==10 && c=="10" && b==20) println("Everything is
true!!");
If, any of the comparisons failed lets say, for example that the variable b
was set to 21 instead of 20 the whole expression would become false and the
sentence would not be printed.
Now, for the OR operand. Weird symbol, isnt it? Two vertical bars. Depending
on your keyboard it can be in several different places, but it usually is on the
same key as the backslash symbol. So, usually, pressing shift+\ will get you a
vertical bar symbol. By the way, it is called a "pipe" symbol. Why? Beats me...
but has a nice sound, you must agree.
So, two pipe characters stand for OR. The same way as with the && operand,
you can place as many || operands as you need inside an expression. The
difference is that as long as at least one of the conditions is true, the whole
expression will be true. This means that if all conditions are false but at least
18

one of them is true, BINGO, the whole expression will be okeedokee!


You can also combine && and || in the same expression, like this:
if(a==10 && c=="10" || b==20) println("Getting complicated?
Nah!!");
And, like you learned in math classes, you can also enclose expressions
between parentheses to force some parts of the expression to evaluate first,
like this:
if(a==10 && (c=="10" || b==20)) println("Not complicated...
just more powerful.");
When you use parentheses in conditional or mathematical expressions pay
special attention to make sure you match all opening parentheses with a closing
parenthesis. Otherwise, you will get a syntax error.
Ok, lets wrap this chapter. What have you learned? You learned lots of
stuff about variables: how to create them, how to assign them values, how to
manipulate them, somehow. You also learned how to make decisions, based on
conditions. Until now the only thing you can do with variables and conditions is
to print stuff based on them.
Be patient, young grasshopper. At least you are able to have some feedback
on the Console about your actions. This may not seem very exciting now,
but dont forget we are just laying down the foundations for more juicy stuff in
the future. Once you master the general structure of programming, we will start
manipulating real objects and documents. In the next chapter we will learn a
couple more basic commands and we will start learning what object-oriented
programming is all about. And that, my friends, is all you need to know to start
doing the really powerful mumbo-jumbo.

19

Chapter 3

Once again we meet here on these pages. I truly hope that the previous two
chapters were not boring, since it is such a dry theme to most of you artisticallybiased-people. Anyway, just to make sure Im not bothering you much, I decided
to break the rules a bit and teach you something more exciting in this chapter.
I say that Im breaking the rules because, following the correct time-continuum
of programming teachings, I should be giving you more insights about more
general programming concepts. But, you guys (and girls, I hope) have been
such good students that I decided that it was about time you started doing more
productive stuff and jump right into specific C.O.F.F.E.E. stuff.
To do so, I must introduce you to object-oriented programming. Dont
confuse this "object" with the objects you have in CINEMA 4D (Cubes, Spheres,
Cones, Lights, Splines, etc). Even so, they are closely related, as you will soon
understand.
So, what is an "object" in programming? (in our case, in C.O.F.F.E.E.)
Put in a very simple way, its an assembly of data and tools to manipulate
that data that can also inherit or bequeath data and tools from/to other objects.
Doesnt seem like a very simple explanation, does it? I will give some
examples. Objects can be anything and, in my first example, I will say that my
object is a car. To define a simple car (our object), I can have several items and
those items are my data or, more precisely, the data of the car object. Lets keep
it simple. The data I want to use to define my object is:
- base_color
- weight
- year_of_manufacture
20

What? Just that? Yes... because Im just defining a car and ALL cars have, at
least a color, a weight and a year when they were made. You may have noticed
that the base_color and year_of_manufacture use the variable naming syntax
(the underscore instead of a space). This is because all data associated with an
object is, in fact, a variable... as in, it stores values. Attached to the object car
we can have a tool that calculates, for example, the value of devaluation of the
car, based on the year it was made.
How do we access the data from the car object? Simple... like this:
car.name_of_data
for example:
car.color
or, to access a tool:
car->name_of_tool();
for example:
car->devaluation()
Now we want to define a more specific car. Lets say, a family car. So, we
will define a new object named family, based on the object car. This is VERY
IMPORTANT!! It is a new object based on another object. We define an object
named family and we add to it some more data:
- number_of_seats
- number_of_doors
- trunk_volume
Lets just keep it this way... I want to keep it simple.
Attached to the object family we can also define a couple more tools.
Let us say, for example, that we have a tool that calculates the maximum
weight of the car called, appropriately, maximum_weight(). Notice the opening
and closing parentheses! This means that maximum_weight is a "tool" (a
function), not some data (a variable). Now comes the fun part. Since we based
the family object on the car object, the family object, automatically, inherited all
the data and the tools from the car object. So, the family object also has a color, a
weight and a year of manufacture. The family object also has access to all the tools
21

that the car object has. So, if we want to define, yet, another object, lets say a
more specific family car, we can do the following: we define a new object named
renault (hey! Im European... I can very well choose a European brand. You can
add to it a few more data:
- country_of_origin
- main_factory_location
And, just to wrap it up nicely, we define yet another object. This time a very
specific car. This one, based on the renault object, we will call it twingo (it was
my first car, so bear with me, ok?) We can add to it a lot more data now:
- custom_color
- licence_plate
- max_speed
- number_of_cylinders
etc...
You could also define many tools associated with the object twingo. For
instance, average_speed or fuel_consumption. Notice that the tools names
must also conform to the functions naming syntax. But, they are exactly the
same as the variable naming syntax so, no worries here.
Now that we have four objects defined, all of them based on a more generic
object we can create a new object. Notice the difference between define and
create!! First we defined the objects: we defined what data could they contain
and what tools they could have attached but we havent created any real object,
just the definition of it. Now we create a new object and feed it with some real
data. In C.O.F.F.E.E. that is done with the new command but Im just giving you
a very generic example of what objects are so dont worry about programming
language terms, ok?
So, lets say I want to create an object that describes my own car. So, I create
a new "variable" whose type is, lets say, twingo... since my car was a twingo...
dah!!!
So, I call it my_car. If we were to do it in C.O.F.F.E.E., I would write something
like:
var my_car;
my_car=new(twingo);
Dont type these C.O.F.F.E.E. scripts!! They are just for the sake of example.
22

Real, valid, C.O.F.F.E.E. scripts are enclosed between main(doc,op) {... },


remember?
So, now we have a new variable of type twingo. We can assign values to
this variable this way:
my_car.country_of_origin="France";
my_car.number_of_seats=4;
my_car.year_of_manufacture=1995;
we can also perform calculations using its tools, like:
println(my_car->maximum_weight());
... well, if only we had given it enough information by filling in all the data it
requires.
Lets summarize the characteristics of objects:
- they can have data attached.
- that data is easy to understand because it is properly named.
- they can have tools (functions) attached.
- those functions can work with all the data that is attached to the
object.
- its possible to derive objects from other objects and they inherit
all the data and functions from the "parent" object.
I know I didnt even show you code to create new objects. It was all very
abstract so, why did I bother to talk so much about objects? Because almost
everything in C.O.F.F.E.E. is based on objects and, if you understand the
philosophy behind objects, EVERYTHING I will teach from now on will be much
simpler.
I didnt bother telling you how to create your own objects (a new object
type, in C.O.F.F.E.E., is called a class, by the way) because most of you will
never need to create new objects anyway. CINEMA 4D already has lots and
lots (and I really mean LOTS!!) of object types defined for you. You just need to
understand what they are and how to deal with them.
Now, I have a little surprise for you. Did you know that you have already
seen a couple of objects since the very first lesson? No way!! Really?!?!
Yup... remember those inconspicuous variables between the parentheses,
after the name of the main function? The doc and op variables? You got it!! They
23

are objects. Both have data and functions attached. Wanna see something fun?
Create a Null object (yes, this time a real CINEMA 4D geometric object) and
add to it a C.O.F.F.E.E. tag and type this:
main(doc,op)
{
println(op->GetName());
}
Press Execute and check out the Console. The last entry there should be the
name of the object that contains the C.O.F.F.E.E. tag, probably, "Null Object".
Try the following: Create a few different objects (cubes, spheres, cones, lights,
splines, etc.). Now, keeping the Console window open, drag the C.O.F.F.E.E.
tag to each of the objects you created. On the Console, you should see each
object name appear printed. Cool, isnt it? What exactly does op->GetName()
do?
GetName() is a function that is attached to the object op. And what is the
object op? Its a (programming) object that "contains" the (geometric) object
whose C.O.F.F.E.E. tag is running the main function. I closed the word contains
between quotes because it doesnt really contain anything... it is just pointing
to the object, as in, referencing it. You should pay special attention to the
capitalization of the names of the functions that are attached to objects. For
example, getname will not work. Neither will Getname or even GETname. Only
GetName will execute the relevant function that, in this case, simply returns the
name of the object it is attached to.
And, is doc an object too? Sure it is. Lets write a more complex script to
prove that:
main(doc,op)
{
var obj;
obj=doc->GetFirstObject();
println(obj->GetName());
}
This script will print the name of whatever object is on the top of the Object
Manager list. Wow!! We are already using variables and objects to do something
more than print silly stuff!
The object doc is different from the object op, of course, even if they follow
the same rules. The doc object is a kind of object that deals with CINEMA
4D documents and the op object is a kind of object that deals with CINEMA
24

4D objects (Cubes, Spheres, Lights, Nulls, HyperNURBS, etc.). Sorry, no pun


intended, really. It may sound a bit confusing using the word "object" to refer to
programming objects and 3D objects but you should figure out which one Im
referring to out of context. Anyway, to make it simpler, I will from now on call
primitives to all 3D objects inside CINEMA 4D.
I can show you a few more functions associated with primitives and
documents now that I assume you understand the philosophy behind objectoriented programming. For example, if I wanted to search for a primitive with a
specific name, inside the current document, I could do this:
main(doc,op)
{
var obj;
obj=doc->FindObject("PalmTree");
}
This would search for an object named "PalmTree" (without the quotes, of
course). This object could be anything: a Cube (not a very pretty palm tree, let
us face it), a Sphere (not a great improvement, from a Cube), a polygonal object
(now, that could very well be a palm tree), a Null (that could contain a set of
objects that would, in fact, assemble into a palm tree), or anything else.
If it finds any object named "PalmTree", starting from the very first object in
the document, it will assign that object to the variable obj. If it doesnt find any
matching object, the variable obj will get a value of Nil. Nil is the equivalent of a
Null, but for programming. The name is almost the same, isnt it?
So, in programming, Nil stands for Nothing, an empty value, something with
no defined value.
So, we could improve the last script a bit by doing:
main(doc,op)
{
var obj;
obj=doc->FindObject("Torus");
if(!obj) println("Are you crazy? There is no such object
in the document!");
else
println("Mmmmmm, I did find a nice looking Torus somewhere
in here.");
}
25

I believe the only thing that is a bit weird - although, somehow familiar, if you
remember the last lesson - is the (!obj)
Do you remember what was the expression for NOT EQUAL? It was !=, right?
So, the exclamation point stands for NOT, right? In that case, we could read
the line:
if(!obj)...
as
If Not Object...
Ok, ok... it is not correct English but I guess you got the point, didnt you?
This means that "if not obj" or... if the obj variable has a value of Nil, we do
something. Actually, using a reverse syntax, if you check for the non-existence
of a value inside a variable by typing !variable_name, you can check that it
contains something by simply typing the variable_name after the if command.
Like this:
main(doc,op)
{
var obj;
obj=doc->FindObject("Torus");
if(obj) println("What the heck!! There is an object named
Torus!");
else
println("Oh, it was a wild-goose chase... no Torus in
here.");
}
This is getting more fun now, isnt it?
By the way, the FindObject() function returns the first occurrence of the
object you searched for, if it finds any. So, if you have more than one object
named "Torus", the FindObject() function will return the one that is more on
top.
I will introduce another type of object now. Let us see if you can spot which
object is. Type this C.O.F.F.E.E. script, but DONT execute it!!
main(doc,op)
{
var obj,pos;
obj=doc->FindObject("Torus");
if(obj)
26

{
pos=obj->GetPosition();
println("The object Torus is placed at position ("
+pos.x+","+pos.y+","+pos.z+")");
}
}
Before executing this script (if you havent already, you hasty coder!!) let us
see if you spotted the new type of object. The doc variable holds an object of
the type "document". The obj variable holds an object of the type "primitive".
This naming ("document " and "primitive") is arbitrary, of course... its only for
you to understand what type of data each object deals with.
The new type of object is held by the pos variable and is of type "position". It
has three data values attached: x, y and z. Since you assigned it to the variable
pos, you can access its data by typing pos.x, pos.y and pos.z
So, the object of type "primitive" (that is held by the variable obj) has a
function attached to it, called GetPosition(). As you can see by the opening
and closing parentheses, it requires no parameters but it returns an object of
type "position" that holds the position coordinates of the object it points to.
Understood? It may sound hard at first, but its quite logical. Really! Believe
me, if you dont, just read the last explanations a few more times and, if
necessary, scribble some doodles to "graphicalize" the concepts.
Now, execute the script. Oops... there is an error message in the Console.
It reads something like:
C.O.F.F.E.E. ERROR!
(5) Incompatible values... STRING / FLOAT
File:expression
Line:9
It is telling you that there is an error in line 9 of the file expression. A file?
Well, C.O.F.F.E.E. code can appear in tags (they are considered expressions)
or in files (they are, usually, plug-ins). So, it is telling you that this code is from
an expression. And it also tells you that is an error number 5, namely, you are
using a value that is not compatible with that particular context. What could it
be?
Well, the println command requires a string of characters and that is what
we are feeding it with... until the point we typed pos.x
27

Oops, pos.x holds a numerical value, not a real text. So, we must transform
the number it holds into a string of characters, in order to make it compatible
with what the println command requires. Luckily, there is such a function in
C.O.F.F.E.E.. Its called tostring and it changes the parameter we feed it with
into its equivalent representation with characters.
For example, tostring(3.14) will return "3.14" or, in other words, the
character "3", followed by the character ".", followed by the character "1" and,
finally, the character "4".
To get rid of the error, retype the offending line:
println("The object Torus is placed at position ("
+tostring(pos.x)+","+tostring(pos.y)+","+tostring(pos.
z)+")");
As you can see, we can place any value that evaluates to a number as
the parameter for tostring. It could be a literal number like the example
above (yes, the 3.14) or any variable or expression that evaluates to a number.
This is true for all functions. If a function requires a string, you can feed it with
whatever value that evaluates to a string, be it a literal expression, a variable,
an expression or even another function whose result is a string.
You should have, printed in the Console, something like this:
The object Torus is placed at position (0.000000,0.000000,0.000000)
Try moving the Torus around. Oh, I assume that, for all this to work, you
DO HAVE, in fact, an object named "Torus" in your document.
The C.O.F.F.E.E. tag can be attached to any object (even the Torus itself).
Since it is searching for an object, there is no special requirement as to where
the tag must be placed.
Moving the Torus around, you should get something like this in the
Console:
The object Torus is placed at position (0.000000,0.000000,0.000000)
The object Torus is placed at position (3.834658,-6.183756,5.047592)
The object Torus is placed at position (6.098374,-3.027564,8.905743)
The object Torus is placed at position (9.983744,-10.658736,6.234875)
The object Torus is placed at position (12.347572,-15.657584,9.577455)
The object Torus is placed at position (14.665849,-17.023374,10.123497)
The object Torus is placed at position (18.835734,-19.002347,12.039457)
28

...
Just to finish, and to keep all this coherent, now that we know how to read
the position of a primitive, how do we set its position to a specific value?
As you will notice as you learn C.O.F.F.E.E., when we have a function that
reads a value, there is usually an equivalent function to set the correspondent
value. So, if there is a function named GetPosition, there is also another
named SetPosition.
Let us now write a script that prevents an object that is a child of another, to
move in the Y axis. This is useful for objects that we want to keep on the ground,
for example.
Create a Cube, add to it a C.O.F.F.E.E. tag and type the following:
main(doc,op)
{
var pos;
pos=op->GetPosition();
pos.y=0;
op->SetPosition(pos);
}
Of course, the SetPosition function requires a parameter. After all, it has
to know what position we are assigning to the primitive. The GetPosition
function requires no parameters... it simply returns a value.
You may have also noticed that the parameter we used in the SetPosition
function is the whole pos variable. No, we cant simply give it the Y position; even
if that is the only coordinate we want to change. The SetPosition function
requires a parameter of type "vector" and that parameter holds all axes: x, y
and z. So, you simply give it the whole object (in this case, stored inside the pos
variable) and the SetPosition function uses whatever it needs from it.
You can drag the C.O.F.F.E.E. tag that is assigned to the Cube to any other
object and it will work with whatever object it is attached to. That is because we
used the op object that holds the primitive whose C.O.F.F.E.E. tag is executing.
You can even clone the tag to as many objects as you want. It will work with all.
Wanna see a nice trick? Make sure the C.O.F.F.E.E. tag is assigned to
the Cube. Now create a plane and place the Cube inside it, as a child. Now,
rotate the Plane. The Cube rotated accordingly, as expected, right? Now move
the Cube around. Wow!! It ALWAYS stays on the plane ground level!!! As you
29

can see, the GetPosition and SetPosition functions work with the local
coordinates of the primitives. But Im starting to wander... All those concepts fit
much more nicely in a future chapter, when you already have a more in-depth
knowledge of C.O.F.F.E.E..
Im gonna wrap this chapter now. I believe that, after reading it, you have a
lot more info to deal with. Finally, you are starting to do interesting stuff arent
you?
My final advice is to read this chapter as many times as you need if you
didnt fully understand the concept of objects. Because, like I said before: if
you master the concept of objects, understanding all the following C.O.F.F.E.E.
commands and functions will be much easier.

30

Chapter 4

Remember those classes, in school, when then teacher would give you reruns of previous classes? Usually, that happened because there was a test
approaching or simply because some subjects were, in fact, too complex
and required extra attention. This is exactly what is going to happen in this
chapter: we will revisit our "old friends", the objects. Why? Because this is in
fact a complex subject and since I have the luck of getting feedback from my
"students", I realized that I should not advance any further into new subjects
until this very important concept is fully understood.
In the last chapter, I introduced you to objects, as in "object-oriented
programming". Since its an abstract concept, dealing with data and functions
accessed like they were super-variables, I gave you all a more graphical
example, making use of an analogy with cars.
Since the "ice" was already broken with the last chapter, I decided that I
could explain the concept again but, this time, using the "real-life" objects,
used by CINEMA 4D. This way, the ones that already understood the concept
of objects will not get disappointed with this "repeated" lesson. For the ones
whose concept of objects is still drifting outside your heads, fear not! This time,
I will use some pictures!
Ok, lets start (again) with this objects stuff. What the hell is an object?
(Objects of the programming kind of course... the CINEMA 4D geometrical
objects will be referred to, from now on, as primitives.)
31

Imagine an object as a structural entity. It can contain data and functions that
deal with these data or any additional data that we may provide.

That structure is simply a definition of the object, not the object itself. It
defines what type of data the object stores and what functions it has. Those data
fields (still empty) have names (in our sample object, the names are #A1, #A2,
#A3 and #A4). The functions also have names, of course (in our sample object,
the names are #A5, #A6 and #A7). Its by those names that we access the
data and the functions. When you create new objects (usually they are created
automatically, without you even noticing it, as you perform other operations),
what you are creating are, in fact, clones of that initial "master" definition. The
powerful part comes when you start creating objects based on other objects.
For example, object B is defined like this:

But, when it was created it was based on object A. So, object B will inherit all
the attributes of object A (its data structure and functions).
32

It is a more powerful object than object A because it can do all that object A
does and, in addition, some more things.
You can create an object C, also based on object A. but provide it with
different data structures and functions. You now have two objects, B and C that
have all what object A has, but also, each one, with something more.

33

If you now create an object D, based on, for example, object B, it will have
all the characteristics of object A and B and, of course, you can add to it some
more data structures and functions.

If this is still difficult to understand (I hope I dont have to repeat this many
times more) I will now present a real world example of objects, inside CINEMA
4D.
Let us take, for example, a spline primitive; of those that you draw with your
mouse or pen. So, you have drawn a little wavy curve and now you have a
new spline primitive in your Object Manager. As everything else inside CINEMA
4D, this primitive is an object. What type of object? Internally, the spline is
defined as a SplineObject. The name is logical enough? Dont forget that the
SplineObject is the name of a type of object. When you created the spline
(using your mouse or pen), CINEMA 4D created a clone of the internal definition
it has of a SplineObject and filled it with all the relevant data.
What type of things can you do with a SplineObject? Well, for example,
you can get its length with the function GetLength() because GetLength()
is a function that is attached to all SplineObjects. You can also get the number
34

of segments of the spline (if you have drawn the spline yourself, without any
further editing, you should only have one segment but splines can have many
more). You can also calculate a position along any of the spline segments.
There are many other functions associated with the SplineObject.
But, you may think, a spline primitive has more than just segments. It has
control points, for example. Does a SplineObject also provide ways to have
access to those points?
Yes, of course. A SplineObject was derived from another class, called
PointObject. And the PointObject type of object provides lots more
functions. Functions to get the number of points of an object, to get or set the
location of any point, to get or set the selection of points, etc.
Besides points and segments, a spline primitive also has a few more
parameters. It has a name, a position, a scale, a rotation, etc.
Can we access all those parameters too? Sure we can, because the
PointObject object is derived from yet another class called BaseObject.
This type of object has many, many functions. As its name implies, a
BaseObject is a class that holds all those informations (and functions) that
are common to all types of primitive objects inside CINEMA 4D. As you know,
all objects have, at least, a name, a position, a scale, a rotation, and an editor
and render state (those semaphores that define if an object is visible or not, in
the editor or when rendering), etc.
This is big "family" already, isnt it? We have the SplineObject class
that is a descendent of the PointObject class that is a descendent of the
BaseObject class. Are there any more members of this family? Sure there
are: the BaseObject class is a descendent of the BaseList4D class. This
class gives us access to the parent (if any) of the object or to its first child (if
any). What are those? You know... in the Object manager, you can place objects
inside others, creating hierarchies. Well, the BaseList4D functions allow you
to have access to those hierarchies, namely the parent and child of our object
and a couple more functions related to them.
Finally, the BaseList4D class is a descendent of the BaseList2D class.
This last class controls even more basic stuff. Stuff like little bits of internal
information (if an object is selected in the Object Manager for example) the
editor color of the object, the type of object and some basic search functions,
etc.
You didnt have to do anything more than just draw the spline, but CINEMA
4D internally created all this. Well, it just had to create a new SplineObject.
All the other objects and their correspondent attributes are already implicitly
attached to it. So, its like the newly created SplineObject already has all this
35

amazing amount of functions and data attached, just because it inherits all the
stuff from all the members of its "family".
Let us now review the whole family again:

What if you had created a new polygonal object? A polygonal object can
be created in several ways but one of the simplest and fastest ways is to
create a primitive (a cube, a sphere, a plane, etc.) and hit C to convert it to
a polygonal object. How is it described internally? Its exactly the same as the
SplineObject, until the PointObject part. Then, instead of it deriving into a
SplineObject, it derives into a PolygonObject. Since the PolygonObject
derives from a PointObject, it has all the characteristics of a PointObject,
a BaseObject, a BaseList4D object and, finally, a BaseList2D object.
Are you starting to get all this object and inheritance stuff?
To put all this theory into practice, lets see some actual code that does
something. Create a new Null primitive, add to it a C.O.F.F.E.E. tag and type
this script:
main(doc,op)
{
var new_sphere;
if(!(doc->FindObject("My_Sphere")))
{
new_sphere=new(SphereObject);
doc->InsertObject(new_sphere,NULL,NULL);
new_sphere->SetName("My_Sphere");
}
}
36

If all goes well (no typing errors), as soon as you execute the code (or do
anything to your document, like dragging the time slider or zooming in or out),
a new Sphere primitive named "My_Sphere" should appear in your viewport
and, consequently, at the top of your Object Manager list. It is a faceted sphere
because it has no Phong tag attached. We would have to add it ourselves.
Dont forget that we are creating everything from scratch, using C.O.F.F.E.E.;
not using the shortcuts CINEMA 4D provides you.
So, what is happening in this script?
First, we define a new variable named new_sphere. It will store the object/
primitive we want to create. Yes, it will be an object because, as we learned at the
beginning of this lesson, all primitives are, in fact, objects (of the programming
kind... this is the last time I will say it).
Now we must check if there is already an object named "My_Sphere" in
the document. If we didnt do this, the script would create a limitless amount
of sphere primitives and fill the whole document with them. That is not a good
thing, is it?
So, how do we check for the presence of an object with a specific name?
Since we are searching the document and the doc variable - kindly provided
by the main function - already points to the current document, we can use one
of its functions. Wait!! A function of a variable?!? Do variables have functions?
They were supposed to only store data, right? Right, but if a variable is storing
an object, it behaves like an object and objects DO have functions. So, the doc
variable is, in fact, an object of type BaseDocument with all the data values and
functions related with documents already attached.
One of the functions present in a BaseDocument object is FindObject.
It requires a parameter that is the name of the primitive we want to search
for. It will return an object of type BaseObject pointing to the first primitive it
finds with that name. If it finds none, it returns Nil.
So, the line:
if(!(doc->FindObject("My_Sphere")))
could be read as:
if NOT found in the document an object named "My_Sphere"
Sorry for the lame English, but its hard to keep the same sequence of
statements present in the script and translate that into a coherent English
sentence.
37

Did you notice all of the parentheses? They are necessary and its very
important to assure that they are balanced. With this, I mean that there must be
as many opening parentheses and there are closing parentheses. Otherwise,
you will get a syntax error.
The most inner parentheses are the ones surrounding the "My_Sphere"
parameter. They are required because all functions require that their parameters
be enclosed in parentheses, even if the functions have no parameters. Really!!
For those you simply type an opening and a closing parenthesis, like this: ()
The next set of parentheses enclose the doc->FindObject("My_
Sphere") statement. They are not really required but, since I want to test for
the negative of this whole expression with the operator !, this whole expression
becomes more legible. If I hadnt placed the parentheses surrounding this
expression, it may look as if I was testing for the negative in the document, not
for the presence of a primitive. Its just a matter of style.
The outer parentheses surround the whole expression and they are required
by the if statement. Imagine that the if statement is a function and it also
requires that its parameters are inside quotes (but this is just to serve as an
example because the if statement is NOT really a function).
Ok, we tested for the presence of a primitive named "My_Sphere" in the
document and, if there isnt any, all the code inside the { and } symbols after
the if statement is executed.
The first instruction to be executed is:
new_sphere=new(SphereObject);
The new command creates a new instance of an object of type SphereObject
and this new object is stored in the new_sphere variable. The SphereObject
object is already internally defined and it is just like the SplineObject example
I presented at the beginning. It already has all the "family" of objects attached,
up to the BaseList2D object. Luckily, CINEMA 4D also provides with it, all the
default parameters already stored inside the data part of the SphereObject.
What this means is that the newly created sphere already has the default
"Sphere" name, the default 200 units of radius, the default 24 segments, etc.
We have a new sphere object stored inside a variable but it still has to be
placed into the document. That is done by using the statement:
doc->InsertObject(new_sphere,NULL,NULL);

38

Since it is a task we are performing on the document (placing something


in it), we use the doc variable again. This time we use its InsertObject()
function. It requires three parameters: the object to be placed, a parent object
inside which we want to place the object and an object, after which we want to
place the object. Weird!! Must we provide all that? Not really. The only really
required parameter is the object we want to insert in the document. The other
two are optional and, in this case, I simply replaced both parameters with the
constant NULL (a constant is like a variable that you cant change.
CINEMA 4D already has lots of constants defined and NULL is one of
them.
It simply stands for... nothing).
So, what happens if I dont tell the InsertObject() function what primitive
I want to use as a parent of my newly inserted object or after what primitive I
want to place my newly inserted object? Nothing special. It simple places the
object at the top of the primitives list, in the Object Manager, just like if I had
created a new primitive by clicking its icon.
Now, we do have a new sphere inserted in the document. But it has the
default name of "Sphere". We must change it to "My_Sphere" to make sure the
conditional expression at the beginning will, in fact, find such a primitive the next
time it runs and doesnt create yet another, and another and another sphere (ad
infinitum).
The new_sphere variable still stores the newly created sphere. In fact,
everything we do to this variable, we are doing to the sphere primitive that is
now in the document.
So, to change the name of the primitive, we use the function SetName(),
like this:
new_sphere->SetName("My_Sphere");
I believe this is clear enough and requires no explanation. Even so, I will
tell you something that may not be too obvious. The new_sphere variable
holds an object of type SphereObject, right? Right! What if I told you that the
SphereObject object HAS NO SetName() FUNCTION DEFINED!
But we just used such a function... you may say. Well, the SphereObject
object itself has no such function defined but the BaseObject object does
and the SphereObject is a child of BaseObject, inheriting everything from
it (and from his "grand-daddy", BaseList4D and its "great-grand-daddy",
BaseList2D). Do you understand how powerful objects are now? I hope you
do.
Try deleting the new sphere. A new one is automatically created. Try
39

renaming it. It stays with the new name you typed but, instantly, a new sphere
named "My_Sphere" appears in the document. Wanna fool CINEMA 4D? Create
a new primitive that is NOT a sphere, a Null for example. Name it "My_Sphere"
(without the quotes, of course). Now delete the sphere named "My_Sphere".
No more spheres are created. Why? Because the C.O.F.F.E.E. script found a
primitive named "My_Sphere", even if is not a real sphere, and, like instructed,
created nothing. We could check out if the object with that name is, in fact, a real
sphere but we can leave that for later.
Oh, you may have noticed that, like I said before, the newly created spheres
are faceted. That is because we only created a primitive, not any tags, namely
a Phong tag. When you click the primitive icons, CINEMA 4D fills out lots of
stuff for you, in advance. This is usually useful because, most of the time, the
defaults are what most people require. But, in C.O.F.F.E.E., you have complete
control in everything and you only create what you need, as it is needed.
I have been talking about all these objects and functions, but you may have
already wondered, where did all this information come from? Isnt there a book or
something about C.O.F.F.E.E. that explains all this? About this question, there is
good news and bad news. The good news is that there is, in fact, documentation.
The bad news are that it is not a book and it is written by technicians so, if you try
to learn C.O.F.F.E.E. from this documentation without some sort of support (like
the one on these pages), it would be like being blindfolded, taken to an airplane,
fly for a couple of hours and being dropped in a completely foreign country.
So, to finalize this chapter, I will tell you where to get that information. You
may download it and start browsing it. It will do you no harm... on the contrary
it will give you some insight on how the information is structured. In the next
chapter, I will teach you how to use that documentation to find out what you
need. Just for you to understand how important this documentation is, 90% of
what I know about C.O.F.F.E.E. came from it and I always keep it open when Im
coding any script or plug-in. I always keep it near, as it is invaluable.
To get it, go to www.
plugincafe.com and click
on the link that says SDK
Downloads R9.5
You should, now, download
the C.O.F.F.E.E. SDK 95. You
have the choice of downloading
the HTML version or the
Windows HTMLHelp version.
40

Choose the one you prefer. Oh, by the way, SDK stands for Software
Development Kit.

If you downloaded the HTML version, you simply have to drag the index.
html file to a browser (or double click it).

If you downloaded the Windows HTMLHelp version, then you are on your
own. I dont work with Windows (I would only do it if threatened by some sort of
weapon) and I dont know how to install the help files. But if you are a Windows
user, chances are that you do know how to do that. Any way you do it, you will
41

be presented with a window similar to this one:

(I assume the Windows HTMLHelp version is similar).


As you can see, there are a few links to interesting stuff like "Introduction"
or "The C.O.F.F.E.E. language" or even "Tutorials". You should also read
the "About this documentation" page, as it contains some references about
additional sources of information. I will not talk any more about this document in
this chapter. Simply keep it accessible and wait for the next chapter.
Oh, by the way, the www.plugincafe.com site has lots more useful stuff,
besides the C.O.F.F.E.E. documentation. One of the greatest sources of
information is the forum. I advise you to register there (dont worry, it is free) and
to use it often. If you have a doubt or even a problem you cant solve, chances
are that someone else went through the same situation. Do a search in the
forum before starting to pull out your hair.

42

Chapter 5

This is already the fifth chapter about C.O.F.F.E.E. and I do hope that you all
are following it with interest. More than that, I hope you understand everything
thus far. In the last chapter I told you where to get support documentation. I hope
you already have the documentation in a place where it is easily accessible
because, in this chapter, we will learn how to use all that information and a few
tools to make your life easier.
Open the index.html file, inside the SDK 95 folder. You can use any browser
for that. When you click the Reference link in the main C.O.F.F.E.E. SDK page,
you are directed to a page that displays a list of topics. Below each topic you
have more specific subjects to click on. When you do, you are directed to a page
describing that particular item. On each page that describes an item, at the top
you have a short description of that item, followed by its definition. This is where
you know what type of item that is and what is his parent, if any. Remember
the hierarchical nature of objects? Objects can have parents, inheriting all their
characteristics.
For example, when you click the PointObject item, its definition starts
with something like this:
class PointObject : BaseObject
{
public:
PointObject();
43

[int] GetPointCount();
[vector] GetPoint([int] num);
[bool] SetPoint([int] num, [vector] p);
...
As you can see, at the top, you have a statement that reads class
PointObject : BaseObject
This means that the class named PointObject derives from the class
BaseObject.
If you click the BaseObject name (its in blue, so it is a link like on a regular
Internet page) you are directed to the page describing the BaseObject.
In it you can see that its definition starts with something like this:
[BaseObject] AllocObject([int] type);
class BaseObject : BaseList4D
{
public:
BaseObject();
...
Notice the class BaseObject : BaseList4D ? This tells you that the
BaseObject class derives from the BaseList4D class. You could go on
clicking the parents links all the way up until there are no parents left. This is an
easy way for you to understand all that is attached to any specific object.
Oh, I have been talking about classes, but what exactly is a class?
Well, a class is just another way to say object. A class defines all that
is inherent to an object: its parent, all its parameters, all its functions and
commands, etc. So, when I say class (the terminology used in C.O.F.F.E.E.
and most other programming languages), Im referring to objects... the stuff you
have been learning on the last two chapters.
Ok, now I will present to you a short description of what you can find inside
each topic showed in the Reference page.

Document classes
Inside this topic you can find all functions and commands that deal with your
document. Stuff like getting the current document, access to the objects inside
your document, insertion of new objects, access to the current tools, Undo/
Redo, access to the time/animation, etc.

44

Objects
With the functions and commands inside this topic you can manipulate the
objects inside your document. You can get or set their position, scale or rotation,
their name, their semaphore mode, etc. You also have access to some specific
characteristics of some special kinds of objects, namely polygonal (as in, nonparametric) objects or spline objects.

Tags
In here reside the functions and commands that allow us to create new tags
and read and write data into them.

Animation
Lots of functions and commands dealing with the timeline. Unfortunately,
it is still impossible to create new tracks or keys in C.O.F.F.E.E., but we can
manipulate the ones already there.

Materials
Want to create new materials or manipulate the ones that already exist?
This is the place to find all you need to do it.

Plugins
If you want to create new plug-ins and not just simple C.O.F.F.E.E.
expressions, this is where you can find all the necessary information about
doing so.

Shaders
Shaders are also plug-ins. But they appear at the materials list. In this topic
is all the information you may need to create your own shaders.

GUI
This is where all the commands for creating dialogs - the interface elements
that appear in windows - are explained.

Resources
The same as the previous subject, but this time using resources to define
the dialogs instead of C.O.F.F.E.E. commands. What are resources? Resources
are files that describe dialog elements. They have several advantages over
defining the dialogs with commands. First, they are independent of the code
itself so, if we want, we can edit the dialogs without ever touching the code. One
other advantage is that the text is separated from the rest of the description of
the dialog so, if we want to change any text its easier. Also, translating the text
to different languages is straightforward.

45

Utilities
Sundry commands and functions related to different subjects. They deal with
bitmaps, movies, time, containers (more about containers in the next chapter),
and selections of points and/or polygons, render parameters, etc.

Functions
A big collection of functions that deal with stuff like modeling commands,
textures (paths), events (an event is something that happens inside your
document like, for example, notifying that an object just changed or was
deleted), etc.
It also contains functions that return useful information, like which version
of CINEMA 4D the C.O.F.F.E.E. code is running, on what platform is the
C.O.F.F.E.E. code being executed, loading of documents, execution of external
applications, opening of external files, etc.

Files
If you need to access files this is where you can find all the commands and
functions to do so. You can, for example, rename files, delete files, check the file
type, open a file for reading, write in a file, get paths from a file, etc.

Math
This is usually the most feared subject.
But it really does contain a set of very useful mathematical functions.
Stuff like trigonometric functions, square roots, raising to powers, rounding,
generation of random numbers, conversions between degrees and radians,
conversions between color models, etc.

Casts
With these functions you can convert an integer number into a floating
point number and vice versa. You can also change numbers into characters,
for example.

Types
Like I said in previous chapters, variables can be of many types. They can
be floating point numbers, integer numbers, strings of characters, a vector (a
group of three floating points as in X,Y,Z or R,G,B), etc. This section shows the
available types.

Memory
Computers have memory, right? It is usually called RAM. Inside that
memory, huge amounts of numbers get stored, swapped, managed somehow.
With the functions inside this section you can manipulate chunks of data, using
a memory management metaphor.
46

String
A string of characters is a type of data that C.O.F.F.E.E. can deal with. Using
the functions and commands of this section you can manipulate those strings.
You can add them together, you can compare them, you can get a specific
character from somewhere inside them, etc.
Vector
Just like strings, vectors are another type of data that C.O.F.F.E.E. can deal
with. There are a few functions that deal specifically with vectors and this is
where you can find them.
Standard Functions
Half a dozen commands/functions that do miscellaneous things. For
example, the println() command that you already know very well can be
found here. Also, ways to know the size of variables or what their type is can
be found here.
Class
Like I said before, objects are called, in programming terms, classes.
So, objects and classes can be considered the same. Access to classes is
dealt with these functions.
Program Structure
Here you can find all the commands you could also find in regular JavaScript
or C++ scripts. These are not specific to C.O.F.F.E.E. and allow you to define
the workflow of your script. If you want to create conditional expressions or
cycles, for example, these are the commands to use. More on these at the end
of this chapter.
Declaration
When you need to create new variables, constants, data structures or
objects (known as classes as you know now), these are the commands to use.
Exception Handling
The commands in this topic are mostly useful when debugging - debugging
is the process of hunting down programming errors and solve them. It deserves
an entire lesson just for that. With these commands you can try out blocks of
code that could be prone to errors and you can intercept those errors to manage
them in any special way you want.
I know that this explanation is very sparse but it should give you an idea of
what you have in your hands. Almost everything you need to write C.O.F.F.E.E.
code is in there. Unfortunately, it is almost impossible to explain everything
47

that is in the SDK, in these chapters. But, as soon as you start to use the
SDK, everything will become easier and easier. Believe me, I know... the same
happened with me.
Now, to wrap this chapter, I would like to teach you all a few more commands,
this way this lesson will not be completely theoretical.
You usually want to use programming because you want to automatize
repetitive tasks. For example, you may want to go through all the points of
an object to check for something. For those tasks we use loops. Loops, in
programming language, are cycles that repeat a certain number of times. We
do have tools to create loops that we know, in advance, the number of iterations
or loops that will repeat until a certain condition is met. Let us get to know both.
If you already know, in advance, how many iterations you need to perform, the
best choice is a for loop.
How does it work? Well, the for sentence (its not a command, nor a
function... its simply a sentence) has the following syntax:
for(initialization; verification; update) code_to_execute;
Before explaining all the parameters of the for loop, I need to tell you that a
counter is required. For that, the for loop uses a simple variable. That means
that the variable used as a counter inside the for loop already needs to have
been declared. But you already know how to do that, using the var sentence.
The best way to explain the parameters of the for loop is to give you a real
life example:
main(doc,op)
{
var a;
for(a=0;a<10;a=a+1) println(a);
}
If you execute this script, in the console you will see that a column of numbers
will appear, like this:
0
1
2
3
4
5
6
48

7
8
9
What happened in the script? First, a variable was declared:
var a;
You can use any variable name, as long as you stick with the rules of variable
naming, presented in chapter 2.
After that, we create a for loop:
for(a=0;a<10;a=a+1)
I believe the sentences between the semicolons are quite obvious but I will
explain them anyway. First, the variable is initialized with a=0. This sets the
initial value of the variable. The next sentence checks if the cycle as reached
the end. In this case, it checks if the value inside the variable a is less than 10.
While this condition is true, the cycle will repeat itself. As soon as this sentence
becomes false, the cycle will end. Finally, the variable has to be updated
somehow; otherwise the verification of the end of the cycle will never become
false. So, in this case, we increase the value inside the a variable by one (using
a=a+1).
After the for sentence you place the code you want to get repeated. If you
have been paying attention to all the chapters, you may have noticed that the
for sentence lacks a semicolon in the end. That is because, like I said before,
the for is NOT a command. Only commands have semicolons at the end.
But, the command(s) after the for cycle DO HAVE to end with semicolons if
they are in fact commands. In our example, the command that is repeated is
println(a);
If you need to repeat more than one command, you need to enclose them
inside { and }, like this:
main(doc,op)
{
var a;
for(a=0;a<6;a=a+1)
{
println("The variable a holds the value:");
println(a);
println("-----");
}
}
49

This would print in the console:


The variable a holds the value:
0
----The variable a holds the value:
1
----The variable a holds the value:
2
----The variable a holds the value:
3
----The variable a holds the value:
4
----The variable a holds the value:
5
----You can skip the initialization, if the variable is already initialized, like this:
main(doc,op)
{
var a;
a=0;
for(;a<6;a=a+1) println(a);
}
Notice that the semicolon still has to be there. In fact, for loops ALWAYS
require all the semicolons (just two), even if nothing is placed inside them. So,
if you want to create an infinite loop, you could write this:
main(doc,op)
{
var a=0;
for(;a<1;)println("This will last forever. You better
force quit the application!");
}
I dont advise you to try this script. If you try to execute it, you will have to
press Command+Alt+Esc (if you are on a Mac) or Ctrl+Alt+Del (if you are on a
PC) to force quit CINEMA 4D.
In future chapters we will see how flexible the for loop can be but, for now,
50

is only necessary that you know how it works and what it is used for.
What if you dont know when you must finish a loop?
For that you can use a do...while loop. It works like this:
main(doc, op)
{
var a;
a=0;
do
{
println(a);
a=a+1;
} while (a<100);
}
Of course, in this example I know that I want to repeat the loop while a is still
less than 100. But imagine I would increase the variable a by an arbitrary value
like, for example, the Y coordinate of a set of objects. This way, I would not know
in advance when the loop condition would be met. So, the loop would repeat
until the sum of all Y coordinates of the objects would add to 100 or more.
The loop could also be written in a different way:
main(doc, op)
{
var a;
a=0;
while(a<100)
{
println(a);
a=a+1;
}
}
As you may have noticed, this form of creating a loop requires no do, just
the while. Also, it has a difference from the first version. Since the test for the
end of the loop is performed before the code that is to be executed, this code
may never be executed, if the test fails. In the first example, the code runs at
least once, and then the test is performed. This may be very important!! You
may want this behavior to help you out, so decide wisely when choosing the
required method. If you want your code to run, at least once, use the do {...}
while method. If you want your code to never get executed if the test fails, use
51

the while {...} method.


What if you need to get out of a loop due to an unexpected situation? If, for
some reason, you need to get out of a loop, even if the verification test doesnt
fail, you can always use the break command. Check out this example:
main(doc, op)
{
var obj;
obj=doc->GetFirstObject();
while(obj)
{
if(obj->GetName()=="Light")

{

println("Found a light.");

break;

}
println(obj->GetName()+" is not a light.");
obj=obj->GetNext();
}
println("End of search.");
}

This script will search all objects inside a document. Well, not all... it will stop
as soon as it finds an object named "Light". If it does, it prints "Found a light." to
the console and breaks the loop, executing the code right after it. In this case, it
prints "End of search." because that is the code right after the loop. If the name
of the object is not "Light", it prints the name of the object followed by "is not
a light". Then it advances to the next object. This is VERY IMPORTANT. If we
dont advance to the next object, the script will go on checking the first object of
the document and it will never get out of the loop.
So, this loop can end for two reasons:
when it finds an object named "Light" (in that case, it breaks the loop)
when the obj variable ends up with the value nil (that is what the
while(obj) checks)
That will happen if there is no object in the document (very hard to happen
because you need, at least, one object in your document to hold the C.O.F.F.E.E.
tag that contains this script) or when the obj->GetNext(); function reaches the
end of the objects list.
Ok, this is it. Now you know how to create loops. Loops are VERY important
in programming, so get used to them.
52

Chapter 6

We have finally reached a level of knowledge (I hope) that allows us to start


exploring fully working examples of C.O.F.F.E.E. scripts. Most of the things you
will see in such scripts will not sound so "foreign" any more. You all know now
what variables are, what conditional expressions are, what an object is, what a
loop/cycle is, etc. You may have not noticed, but if you have been following these
articles, you are ready to start at least understanding a few simple C.O.F.F.E.E.
scripts. From here on, I will be presenting fully working C.O.F.F.E.E. scripts
and dissecting them. We will be learning much more now that all the required
" programming infrastructure" was learned. Enough with the small talk. Let us
proceed to the juicy stuff.
After long consideration (and painful one-person brainstorm sessions), I
decided that a good script to present as the first one would be a modeling
aid script. It is not extremely complex, but it is already a true C.O.F.F.E.E.
programming example.
What exactly will this script do? Consider the following scenario:
One often-used modeling technique involves the creation of a half-model
that is "completed" by using a parent Symmetry object. The Symmetry object
is a very useful tool but has some limitations. One of those limitations is that
the points near the mirroring plane should not move in the perpendicular of
that same plane, otherwise the welding will not occur. Of course, we have a
Tolerance value that we can set, but if you are using the Brush tool or the
Magnet tool (two tools that are often used for organic modeling), it is very easy
53

to mess up the position of these points. We could increase the Tolerance value
but that would not allow us to work with very dense models, as some points that
are not supposed to be welded would be merged together.
So, I decided to create a script that would allow us to model with any tools
we want (move, rotate, scale, magnet, brush, etc.) and still have complete
control without the fear of messing up our model too much. Besides, I do model
many times using this Symmetry technique and this is a script that is particularly
useful to me. I will not write a step-by-step tutorial about how to create the mesh
and how to assign the C.O.F.F.E.E. expression to it. I assume you already know
how to do that. Let us just say that you will have to end up with something like
this:

To type the C.O.F.F.E.E. expression you just need to have an object to attach
it to. It can really be any type of object because the C.O.F.F.E.E. expression will
be smart enough to understand if it is affecting a polygonal object, and if not,
will do nothing.
Create a Null and add to it a C.O.F.F.E.E. expression tag. Before typing
any code, we need to create some User Data in this tag. Start by adding a
Boolean User Data named On/Off. This will allow us to turn on and off the
expression. Yes, we could simply turn the Enable option on and off from the
Basic Proprieties tab of the C.O.F.F.E.E. tag. But adding this as a User Data will
place all options in a "central" place, making it easier to manipulate.
Now, add a new User Data of type Real, named Tolerance. You can set its
upper limit to whatever value you believe is good enough. Since this will be the
distance from the symmetry plane after which the points will not be considered,
you may want to set the upper limit to no more than 200, and this is already a big
value. You can set its interface to whatever you feel better with (I like sliders).
Now, add a new User Data of type Integer, named Axis. This one will include
a "trick" that will make this User Data field into a drop-down list. Before hitting
OK, type the following in the Options field:
0;YZ
1;XY
2;XZ
54

You need to type Enter after each line (except the last one, of course).
This will create a drop-down list with the items YZ, XY and XZ. When the
user chooses YZ, a value of 0 (zero) will be returned. When the user chooses
XY, a value of 1 will be returned. And when the user chooses XZ, a value of 2
will be returned.

You will end up with a User Data tab that looks something like this:

You can now press OK and type the following script in the C.O.F.F.E.E. tag
itself.
55

Wow!! This is a big one, isnt it? At least it is the biggest one in all C.O.F.F.E.E.
chapters, so far. Now we will explore each line of code to understand what it
does.
56

The first lines should be pretty clear right now (I will not even mention the
main(doc,op) sentence). In these lines I simply declare a few variables that
will be necessary inside the code. I will explain what each one will be used for as
we use them, inside the script. Since this is a C.O.F.F.E.E. lesson let me tell you
that I didnt know in advance how many and what kind of variables I would be
needing. So, as I was creating the script, and as I was needing more variables,
I was adding them at the beginning. Dont forget that programming is a dynamic
process and you will be adjusting your scripts (sometimes having to edit very
different parts of them) as you progress.
You may ask, why did I distribute the variables in three lines and didnt
use a single line to declare all of them? I could have done that but as a matter
of personal style (you will develop your own, dont worry), I like to, at the end
of writing the script, group the variable declaration by "theme" or what type of
action they will perform inside the script. In this case, the first line declares all
variables that deal with the list of points of the object. The second line declares
all (in this case, just one) variables used for programming structure, like cycle
counters or variables that hold temporary values. Finally, I declare all variables
that deal with the tag itself and all its values (this tag will include User Data).
After declaring the variables I start doing some checks.
First thing I check is if the object is selected. If it isnt, we are not editing it
(as in... modeling), so the script has nothing to do. How do we check if an object
is selected?
We check for some special bits of information. Actually, we do REALLY check
for bits, because that information is stored inside a few bytes of information that
contain lots of information in each one of their bits. For those that dont know
much about computer science, a byte is a storage unit. It can hold a number
between 0 and 255, or in binary, between 00000000 and 11111111. Why am I
talking about binary?!? Because its very important that you know that a byte
is made out of eight bits (like a meter is made out of 100 centimeters and a
centimeter is made out of 10 millimeters). When we need to store values that
can only have two possible states, it would be a waste of space (as in, a waste
of computer memory) to store such a value as a whole byte. To store these
true/false states, if we use bits, we can stuff eight states of information inside a
single byte. The selection state of an object is one of those things that can only
be true or false (an object cant be just "slightly" selected).
Each object has a set of bits of information and the selection state is stored
somewhere in there. Actually, the selection state is stored in bit number 2 but
Cinema 4D has that number stored inside a variable for easy recollection. It is
stored inside the variable BIT_AOBJ. Warning!! The case does matter!! BIT_
AOBJ is not the same as Bit_Aobj or bit_aobj.
Now that we know that, we only need to know what function returns the state
of a specific bit of an object. That function has the obvious name GetBit().
57

So, op->GetBit(BIT_AOBJ) will return to us the bit number 2 of object op.


You could also type op->GetBit(2) but using the variable is more readable.
Since the value of a bit is either true or false, the result of op->GetBit(BIT_
AOBJ) is a logical value. That is why we can use the expression:
if(! (op->GetBit(BIT_AOBJ))) return;
Meaning that... if the bit is NOT set (meaning that the object is not selected)
we can return immediately. After this (and now that we know the object is
selected), we must check if it is a polygonal object. We can get the type of an
object with the function GetType(), like this:
op->GetType()
Luckily, there are already lots of variables inside CINEMA 4D that store
important values (like the BIT_AOBJ variable). And, in this case, we also have
a variable that holds the value that means that an object is a polygonal object. It
is the variable OBJECT_POLYGON. If you dont know the variable names you can
easily check what values correspond to each type of object by simply creating
the object you want to check and add to it a C.O.F.F.E.E. expression tag. If you
type the code:
main(doc,op)
{
println(op->GetType());
}
... and press Execute, in the Console you will get a number that corresponds
to that type of object. In our case, a polygonal object has a type value of 5100
but using the variable will make the whole script much more readable.
We check if the object is a polygonal object, and if not, we return immediately,
with the following sentence:
if(! (op->GetType()==OBJECT_POLYGON)) return;
Now we will read its point list. If it werent a polygonal object, it would not have
a points list and trying to read it would return an error. Because the execution
reached this far, we know for sure that it is a true polygonal object.
There is a function associated with polygonal objects that returns the number
of points of an object. As you will start to realize, most have very logical names
and this one is no exception. Its named GetPointCount().
So, now we store that value inside the variable npoints, like this:
58

npoints=op->GetPointCount();
We must now check if the polygonal object is not empty. This could be
empty if we had just created a new Polygon object from the Objects menu.
Those polygon objects have no points and we must create some, before they
have any faces or edges. If there are no points, we leave...
if(!npoints) return;
Ok, now that we know that everything is fine with the object itself, we must
check the C.O.F.F.E.E. expression tag. Since the data that the C.O.F.F.E.E. tag
gives us is only the document (variable doc) and the object where it resides
(variable op), we must search for the C.O.F.F.E.E. expression tag itself.
So, we start by getting the first tag of the object with:
C.O.F.F.E.E._tag=op->GetFirstTag();
This sounds logical, doesnt it? Now the first tag of the object is stored in
the coffee_tag variable. If the object had no tags, the coffee_tag variable
would be holding a value of nil (meaning nothing). But this is very unlikely
because the object needs to have at least one tag: the C.O.F.F.E.E. expression
tag!! Since the C.O.F.F.E.E. expression tag may not be the first one, we must go
through all of them until we find what we need.
That is done with:
while(coffee_tag)
{
As long as there is a valid tag stored in the coffee_tag variable, execute
this loop...
if(instanceof(coffee_tag,CoffeeExpressionTag)) break;
As soon as the coffee_tag variable stores an instance of a C.O.F.F.E.E.
expression tag, we get out of the loop with the coffee_tag variable pointing
to the correct tag. Do you remember that everything inside CINEMA 4D is an
object? So, the C.O.F.F.E.E. expression tag in this object is just an instance of
the globally defined C.O.F.F.E.E. expression tag object. That is why we must
check for an instance with the function instanceof.
coffee_tag=coffee_tag->GetNext();
}
59

Since we are still inside the loop, we must get the next tag and repeat
the loop. As soon as we reach the last tag, the expression coffee_tag>GetNext() will return a result of nil. This is stored inside the coffee_tag
variable and when the loop check is made (with while(coffee_tag)), it will
fail. That will also get us out of the loop but this time with the coffee_tag variable
holding the value nil.
We now check to see if we found a C.O.F.F.E.E. expression tag, with:
if(!coffee_tag) return;
This is VERY UNLIKELY TO OCCUR, but we should make these checks
anyway, as it is good practice to check out everything... just in case.
I should point out that we should make another check here... imagine
that you have more than one C.O.F.F.E.E. expression tag assigned to the
object. This simple search loop stops as soon as it finds the first occurrence
of a C.O.F.F.E.E. expression tag. But nothing assures us that the first one is
the correct. We could now, for example, check out the name of the tag, and
assuming that we had named it a proper name, search for another one if this
was not the correct one.
But let us not complicate this further.
Now that we have a variable pointing to the C.O.F.F.E.E. expression tag, we
can start getting the User Data values. The first one to check is, of course, if
the expression is turned on or off. To get the values of User Data fields we must
type something like:
coffee_tag#ID_USERDATA:1
This will get us the value of the first User Data field. But there is an easier
way to "type" this, without typing it all. Just type the part that refers to the object
that points to the object that contains the User Data, like this (in our case):
if(! (coffee_tag
Now, make sure that the Attribute Manager is displaying the User Data tab
and drag the title of the User Data you want to use to the location you want to
place it, like this:

60

You will end up with this:


if(! (coffee_tag#ID_USERDATA:1
Now just type the rest:
if(! (coffee_tag#ID_USERDATA:1)) return;
Since the first User Data field is a Boolean operator, it simply returns a true
or false value. If it holds a value of false (checked with the ! operator), meaning
that the expression is turned off, we simply return.
Now we get the tolerance value and store it in the tolerance variable,
with this line:
tolerance=coffee_tag#ID_USERDATA:2;
Obvious enough, isnt it? Now we check if the value of tolerance is 0
(zero). If it is, there is nothing to do and we return also.
if(tolerance==0) return;
Ok!! We have made all the necessary checks. We can now safely run
through all the points and perform the real action.
We just need to get the value of the last User Data field:
axis=coffee_tag#ID_USERDATA:3;
61

We now get the list of all points, with:


p_list=op->GetPoints();
This will store a list of all points inside the variable p_list. How can a
variable store ALL the points of an object, you may ask? Like I said in one of
the first chapters, variables in C.O.F.F.E.E. are very versatile. And they take the
"shape" of whatever type of data they store. In this case, the p_list variable
turns into an array of vectors. Darn!! "Complicated stuff", your brain warns you!!
Not really. Let us dissect what an array of vectors is. First, let me explain what
an array is. When I explained to you what variables were, I said that they were
like containers or boxes that could store values inside, right? Well, an array is
like a warehouse where you store several containers. It still has a single name,
just like any regular variable. But you can access any of its elements by means
of an index.
Something like this:
variable_name[10]
This would return to us the eleventh element (indexes start at zero).
Remember when I told you that a variable could contain many types of
values? Ok, so imagine that an array is just like several variables in a row, all
containing the same type of content (a number, a character, a Boolean value,
etc.). They are all accessible by the name of the array followed by an index
value enclosed inside [ and ].
So, what is a vector? A vector is an object. It has a set of commands and
functions associated with it, just like any other object, of course. But the most
important characteristic of a vector, at least for us, is that it can store three
independent values - namely x, y and z.
So, for the sake of example, if a variable named rotat is of type vector, you
can access (read, write, manipulate...) three independent values in the form:
rotat.x
rotat.y
rotat.z
This type of object is used very often, because as you may imagine, there
is lots and lots of stuff that needs to deal with x, y and z.
So, the list of points is an array of vectors. If the variable that holds the list
is named p_list (like in our example), the array of vectors it contains has this
type of structure:
62

p_list[0].x
p_list[1].x
p_list[2].x
p_list[3].x
p_list[4].x
...

,
,
,
,
,

p_list[0].y
p_list[1].y
p_list[2].y
p_list[3].y
p_list[4].y

,
,
,
,
,

p_list[0].z
p_list[1].z
p_list[2].z
p_list[3].z
p_list[4].z

Until the very last elements (the number of points minus one, because like
I said, the arrays start at index zero).
Now that we have all the data that we need, we may start a cycle that goes
through all the points of the object. We do that with the help of a for loop, like
this:
for(f=0;f<npoints;f++)
{
Inside the for loop parameters, we initialize our counter variable (the f
variable) at zero. Then we define that it will repeat the loop as long as the
variable f is less than the number of points. Finally, for each iteraction of the
cycle, we increase the value of variable f. We do that with f++ because its
faster than typing f=f+1. Its one of those useful shortcuts that C.O.F.F.E.E.
allows us to use.
Now, inside the loop, we store the value of each point in the variable pt.
Why do we do that? Well, because we are going to make several checks on
many elements of each point and it is much easier to type pt.x or pt.y instead
of p_list[f].x or p_list[f].y. Also, the code will run faster because
each time we use an expression that deals with an array, C.O.F.F.E.E. has to
calculate where each specific element is located (multiply the index by the size
of the elements of the array and retrieve that value). Since we only do that once
when we read each point of the array into a single independent variable, all
subsequent calculations will run much faster.
Now I will present to you a new, very powerful, command: the switch.
With just one switch you can perform a huge set of conditional verifications,
replacing a lot of if commands. Also, the readability of your code will be
much clearer. At least a whole lot more so than if you had used lots of if
commands.
63

It works like this:


switch(variable)
{
case value1:

stuff to do

break;

if the variable has a value equal to value1

case value2:

stuff to do

break;

if the variable has a value equal to value2

case value3:

stuff to do

break;

if the variable has a value equal to value3

default:

this

is optional but its the stuff to do if none of


the previous cases applies

In our case, we must perform different actions depending upon the axis we
choose in the User Data parameters. So, our switch structure looks like this:
switch(axis)
{
case 0:

if(abs(pt.x)<=tolerance) pt.x=0.0;

break;
case 1:

if(abs(pt.z)<=tolerance) pt.z=0.0;

break;
case 2:

if(abs(pt.y)<=tolerance) pt.y=0.0;

break;
}

What this does should be pretty obvious, but I will explain it anyway.
64

The variable axis is evaluated by the


switch command. If it happens to be equal
to zero, the following conditional expression
is performed:
if(abs(pt.x)<=tolerance)
pt.x=0.0;
What this does is to check if the absolute value
of the x coordinate of the point is less than or equal to the
tolerance value, stored inside the tolerance variable. If that is
true, the x coordinate should become 0.0. And why 0.0 and not simply 0?
Because coordinates are not integer values and just to make sure, we should
keep them as float values, even if they are zero.
We check for the absolute value abs(x) always returns the positive value
of x so that you can delete either side of the object. Otherwise you would only
be allowed to delete the part that had negative values in the points coordinates.
After that, a break command must be present. This break command will
make the execution of the script go on after the switch structure. If there
were no break command, all the code after the first successful case would be
executed, even if it didnt match the other case statements.
The same conditional expressions are evaluated for the y and z coordinates,
depending on the value of the axis variable. In our case, there is no need for a
default case because our axis variable will always be 0, 1 or 2.
When we leave the switch structure, the pt variable already has one of its
components updated (x, y or z, depending on the axis variable value).
So we just need to store the updated point, stored inside the pt variable (as
type vector), back into the points array, p_list.
Finally we end the for loop with the closing }. This will assure that all the
points inside the p_list array are updated.
The last thing we need to do is to load the p_list array into the object,
updating its point list. That is done with:
op->SetPoints(p_list);
This last sentence should be very logical by now. We just need to close the
script with the last closing }. I hope you have been saving your file.
At least now that you finished typing the script, you should save your file
before testing it. This is because some C.O.F.F.E.E. scripts may be potentially
dangerous since you could be messing with the inner structures of a file. This
specific script is not particularly dangerous but saving, at least at this stage, is
a good practice to get used to.
Before running the script we should check for syntax errors. Press the
Compile... button. If there are any errors, check out the relevant lines until
everything is fine.
65

You can now close the Expression Editor window and test out your script. To
do this, create a Cube with, lets say, 4x4x4 subdivisions, make it editable and
delete half of it. Place your half-cube inside a Symmetry object. Depending on
which half you deleted, choose the correct Mirror Plane in the Symmetry object.
Now before dragging the C.O.F.F.E.E. Expression tag into your polygonal object,
make sure it is turned off and that the Axis value is the same as the Mirror Plane
parameter of the Symmetry object.
Also, make sure the Tolerance value is a very low value. It can even be
zero.
Why all these worries? Because as soon as you drag the C.O.F.F.E.E.
Expression tag to your polygonal object, it will adjust all the points that fall within
the Tolerance distance from the chosen Axis. You can always Undo, but its a
pain to see your object collapse even before you start editing it.
OK, now that all is correctly set, drag the C.O.F.F.E.E. Expression tag from
the Null to your polygonal object. You can now turn the expression on and adjust
the Tolerance.
I hope you have learned a lot more about C.O.F.F.E.E. with this practical
example, and at the same time, I hope you find this tool a useful addition for
your modeling sessions.

66

Chapter 7

When these chapters were being released, one each month in 3D Attack
The CINEMA 4D Magazine, I was asked to add an Undo function to the
script I presented in the last chapter. Well, I will not... not because I dont want
to, but because it is not possible. At least not with the current way things are
being done. Let me explain a bit further. This is a script that is executed as
an expression (it is inside a C.O.F.F.E.E. Expression, after all). All expressions
are executed automatically every time something in your document changes.
And what CINEMA 4D considers as a change can be a lot of different things:
changing a parameter (either by typing a value or adjusting a slider), dragging
an object around the editor (changing its position, size or rotation), selecting a
new object, a texture, a tag, a face, an edge, a point, etc., scrubbing the time
bar, etc... If any expression has the Camera Dependent option turned on, the
simple act of rotating the camera or zooming in or out will trigger the evaluation
of that expression.
So almost anything triggers a new evaluation of expressions. On my
machine, the script I presented in chapter 6 will be executed, roughly 20 to 30
times each second. So if I would include some code to store the current state of
the object every time the expression is evaluated, I would end up with 20 to 30
new clipboard states each second. If you set the Undo Depth in the CINEMA 4D
Preferences to, lets say, 30, the undo buffer would fill up pretty fast (in roughly
a second, to be more precise).
Some of you may ask if I could not store the current state of the object only if
fiddling with the parameters of the expression would cause a real change in the
67

state of the object (mainly, increasing the tolerance). Yes, I could, but for that I
would have to store the current state of all the points of the object and compare
that state with the potentially modified point list. That, besides making the script
a whole lot slower, is a bit beyond the scope of these lessons. I mean... it is a
bit too advanced for the level we are now. So, sorry folks... no undo with this
expression.
In this chapter I will present you with yet another utility expression. This
way we will learn C.O.F.F.E.E. at the same time as we increase our arsenal of
tools.
I will also make it in a way that is a bit different. I assume now that if you have
been following these lessons, you already have, at least, a less than superficial
knowledge of CINEMA 4D. So, I will not explain EVERY SINGLE STEP needed
to recreate this tutorial. We all need to learn the juicy stuff, and wasting time and
space with the little details is not very productive.
Before we begin, I must warn you that the C.O.F.F.E.E. code we will use will
only work for CINEMA 4D version 9.5 and up. If you still use an older version,
you can still learn from this lesson, of course, but you will not be able to make the
code function. So, enough with the yada-yada... on to the stuff that matters.
In an empty document, create a new instance. It will have a red cross on its
icon because it still has no object to reference. No problem. The C.O.F.F.E.E.
code will provide all that it needs.
Now, you need to create a lot of User Data fields for this Instance Object.
The fastest and easiest way is to choose Manage User Data... from the User
Data menu. You will be presented with a window where you can create all the
necessary User Data fields. Just follow the directions of the following table:

68

Oh, about the first User Data value, the maximum value should be adjusted
according to the needs of your scene. I defined it as 100000 units but this could
be changed, as you need. Just make sure you DONT SET THE MINIMUM TO
ZERO!! We will understand why later.
Now that you have all the required User Data attached to the Instance object,
add to it a C.O.F.F.E.E. tag.
Type the following code:
distance(p1,p2)
{
var x,y,z;
x=p2.x-p1.x;
y=p2.y-p1.y;
z=p2.z-p1.z;
return sqrt(x*x+y*y+z*z);
}
main(doc,op)
{
var max_dist;
var obj1;
var dist2,val2,obj2;
var dist3,val3,obj3;
var curr_obj,curr_cam,curr_dist,perc;
var matrix,mat1,mat2;

69

if(!instanceof(op,InstanceObject)) return;
max_dist=op#ID_USERDATA:1;
Distance
if(!max_dist) return;

//

the

user

data

named

Max.

dist2=op#ID_USERDATA:5; // the user data named Dist. 2 (%)


dist3=op#ID_USERDATA:9; // the user data named Dist. 3 (%)
if(dist2>dist3) dist3=dist2;
op#ID_USERDATA:5=dist2; // the user data named Dist. 2 (%)
op#ID_USERDATA:9=dist3; // the user data named Dist. 3 (%)
val2=max_dist*dist2;
val3=max_dist*dist3;
op#ID_USERDATA:6=tostring(val2,".2f"); // the user data named
Dist. 2
op#ID_USERDATA:10=tostring(val3,".2f"); // the user data
named Dist. 3
obj1=op#ID_USERDATA:3; // the user data named Object 1
obj2=op#ID_USERDATA:7; // the user data named Object 2
obj3=op#ID_USERDATA:11; // the user data named Object 3
curr_cam=doc->GetRenderBaseDraw()#BASEDRAW_DATA_CAMERA;
matrix=op->GetMg();
mat1=matrix->GetV0();
matrix=curr_cam->GetMg();
mat2=matrix->GetV0();
curr_dist=distance(mat1,mat2);
if(curr_dist>max_dist) curr_dist=max_dist;
perc=curr_dist/max_dist;
op#ID_USERDATA:13=tostring(curr_dist,".2f")+"
(perc*100.0,".1f")+"%)";
// the user data named Distance
curr_obj=obj1;

70

("+tostring

if(perc>dist2) curr_obj=obj2;
if(perc>dist3) curr_obj=obj3;
op#INSTANCEOBJECT_LINK=curr_obj;
}

Ok, now lets dissect the code. I will not explain the parts that you should
already know. And yes, you should already know enough, if you have been
following these lessons.
The first part of the script is:
distance(p1,p2)
{
var x,y,z;
x=p2.x-p1.x;
y=p2.y-p1.y;
z=p2.z-p1.z;
return sqrt(x*x+y*y+z*z);
}
This is a sub-routine. This means that it is a kind of "sub-program" or a
routine that will be called elsewhere inside the main routine. You provide it with
a name (in this case, distance) and the parameters (in this case, p1 and p2).
Then, inside the { and } you define what the sub-routine does. Its almost as
if you defined a completely new command or function. So, if inside the main
routine you type something like distance(a,b), CINEMA 4D will call the
distance sub-routine while storing the value of the variable a inside the variable
p1 and the value of the variable b inside the variable p2. Then, it will perform
whatever actions it needs with those variables and returns a value, using the
return command.
Oh, why did I define this sub-routine before everything else? Because
CINEMA 4D needs to know how it is defined and what parameters it uses.
Otherwise, when you use it in the main routine it would not know if you provided
it with the correct parameters.
You could also define the sub-routines after the main routine, but to do
so without CINEMA 4D returning any errors you need to declare them all to
CINEMA 4D at the beginning. In our case, it would be something like this:
71

distance(p1,p2);
main(doc,op)
{
...
}
distance(p1,p2)
{
var x,y,z;
x=p2.x-p1.x;
y=p2.y-p1.y;
z=p2.z-p1.z;
return sqrt(x*x+y*y+z*z);
}
This allows for cleaner code, but if you define all your sub-routines at the
beginning (in which case you dont need declarations, just the sub-routines
themselves), the code will run slightly faster. Dont get me wrong... when I say
slightly it is really just slightly - just a few microseconds faster. But if your subroutine is called many, many times inside a big loop, that could be a bit more
relevant.
This sub-routine calculates the distance between two points (p1 and p2).
I will not explain the mathematical explanation of how to calculate that (just to
save time and space here), but you can get a good explanation here:
http://freespace.virgin.net/hugo.elias/routines/r_dist.htm
or
http://www.purplemath.com/modules/distform.htm
Now, on to the main routine. The first part is:
main(doc,op)
{
var max_dist;
var obj1;
var dist2,val2,obj2;
var dist3,val3,obj3;
var curr_obj,curr_cam,curr_dist,perc;
var matrix,mat1,mat2;
72

if(!instanceof(op,InstanceObject)) return;
max_dist=op#ID_USERDATA:1; // the user data named Max.
Distance
if(!max_dist) return;
dist2=op#ID_USERDATA:5; // the user data named Dist.2 (%)
dist3=op#ID_USERDATA:9; // the user data named Dist.3 (%)
You should already know what all this stuff does. Just notice that I added
a few comments to the code, they are preceded by the characters //. These
comments tell you what User Data parameters you should drag into the
Expression Editor, like you learned in the last lesson.
Did you know you could drag the User Data parameter names into the
Expression Editor window? Like this:

Why would you drag the User Data instead of typing it all?
Two reasons:
First because it is faster and less prone to errors.
Second, because if you didnt define all the User Data fields in the same
order as I did, the numbers after the ID_USERDATA: will not match and the
code will not work properly. That is why I provided the code with the comments
that tell what User Data parameters you should drag into the code.

73

The next section of code reads:


if(dist2>dist3) dist3=dist2;
op#ID_USERDATA:5=dist2; //the user data named Dist. 2 (%)
op#ID_USERDATA:9=dist3; //the user data named Dist. 3 (%)
This checks if the value of the dist2 variable is larger than the value of the
dist3 variable. This should not happen because the distance 2 should not be
larger than the distance 3. If that happens, we make the variable dist3 equal
to the value of the variable dist2. Then we reload the adjusted values into the
corresponding User Data fields.
Since dist2 and dist3 come from User Data fields that hold percentage
values, they store values that vary between 0 and 1 where 1 stands for 100%,
0.5 stands for 50%, .33 stands for 33% and so on.
Now we multiply their value by the value of the maximum distance, stored in
the max_dist variable and store those results in the val2 and val3 variables,
respectively. This will give us the correct values of the distance, in units instead
of percentages. So, why did I define the distances as percentages of a maximum
distance? Because, if you redefine the maximum distance all the other distances
will adapt accordingly. If the distances were set as absolute values, you would
have to adjust ALL the distances, not just the maximum distance.
Now that we have the true values of the distance 2 and distance 3, we will
load those values into the User Data fields that were created just for display
purposes. But those User Data fields are of type String so they require strings
(as in, characters), not numeric values as the ones we have in the variables
val2 and val3. So, we change them into strings using the function tostring,
like this:
op#ID_USERDATA:6=tostring(val2,".2f");
op#ID_USERDATA:10=tostring(val3,".2f");
The function tostring can use one or two parameters. In previous chapters
I showed you how to use the tostring function with just one parameter.
Now I will explain how to use it with two parameters. The first is the value to
change into a string (usually its a variable, like in our case, val2). The second
parameter instructs the tostring function how to convert that value. You can
tell CINEMA 4D to format the string as a floating-point number with a specific
number of decimal places or as an exponential value, for example.
By default, all floating-point numbers have 6 decimal places. That is a lot!!
74

So, we change that to just two with the parameter ".2f" that stands for "float
with just two decimal places".
Now we get all the possible objects that will be instantiated from the relevant
User Data fields, with:
obj1=op#ID_USERDATA:3; // the user data named Object 1
obj2=op#ID_USERDATA:7; // the user data named Object 2
obj3=op#ID_USERDATA:11; // the user data named Object 3
And now we get the current camera with:
curr_cam=doc->GetRenderBaseDraw()#BASEDRAW_DATA_CAMERA;
The BaseDraw is an internal structure of each document that holds lots of
data. Usually, the user doesnt care less about this, as CINEMA 4D deals with
it without us even noticing it. But we can access it to get useful information, like
in this case, the current camera.
So, we access the value by addressing the BaseDraw structure of the
document (doc->GetRenderBaseDraw()) and getting a specific parameter
from it (#BASEDRAW_DATA_CAMERA). This has the added benefit of not only
getting the current camera that is a real camera object, but also the virtual editor
camera. Usually you cant access that camera (as it is not a real object), but in
C.O.F.F.E.E. you can.
Now we must calculate the distance between the current camera and the
object (our Instance object). To do that, we must get the global position of both.
The global position is the position of an object in world coordinates. It is always
the same, no matter how deep inside a hierarchy it is. Its global position is
stored inside its global matrix - the explanation of what its matrix is, is beyond
the scope of this lesson, but you can read about it in the SDK.
So, we get the matrix of the Instance object with:
matrix=op->GetMg();
Then we get the position of the object that is stored inside the matrix with:
mat1=matrix->GetV0();
Now we get the matrix of the camera (we can use the same variable matrix
as we already have the position stored in another variable):
75

matrix=curr_cam->GetMg();
Then we get the position of the camera that is stored inside the matrix with:
mat2=matrix->GetV0();
Finally, we calculate the distance between them with the function we defined
at the beginning of our script:
curr_dist=distance(mat1,mat2);
If the distance is larger than the maximum distance allowed (the one we
define with the User Data), we make it equal to the maximum allowed.
if(curr_dist>max_dist) curr_dist=max_dist;
Now, we transform this distance into a number between 0 and 1 with:
perc=curr_dist/max_dist;
This is why we cant have a minimum value of the maximum distance equal
to zero. If, by any chance, we divide by zero, the script will stop with an error.
This is because dividing something by zero will lead to an infinity error.
As added information for the user, we now display the current distance
between the camera and the Instance object and what percentage that is in
relation to the maximum distance allowed. This way, it will be easier to adjust
the values of Dist. 2 and Dist. 3. This information is supplied with:
op#ID_USERDATA:13=tostring(curr_dist,".2f")+"
+tostring(perc*100.0,".1f")+"%)";

("

As you can see, we have to transform all numerical values to strings


using the tostring function. It is also easy to understand that the distance
is displayed with only two decimal places and the percentage (multiplied by
100.0 because it currently holds a value between 0 and 1) is displayed with only
one decimal place. That is more than enough but you can adjust that to your
personal taste.

76

Now we store the first object (the one that is allocated to the instance when
the distance from the camera is less than Dist. 2) into the curr_obj variable:
curr_obj=obj1;
Now, if the current distance (mapped to a value between 0 and 1) is larger
than Dist. 2, we must change the object to the one defined by obj2.
if(perc>dist2) curr_obj=obj2;
But, if the current distance is even larger than Dist. 3, we must change to the
object stored in obj3.
if(perc>dist3) curr_obj=obj3;
Ok, we now have the correct object (depending on the distance) stored in
the curr_obj variable. It is now simply a matter of loading this object into the
Reference Object field of the Instance object. That is done with:
op#INSTANCEOBJECT_LINK=curr_obj;
I hope you found it all to be pretty logical, because... it is!!
Now, when you select your Instance object (that I named D-Instance, in a
smart moment of inspiration), you will have a list of User Data that should look
like this:

77

In the Max. Distance field you will input the maximum distance from which
the lowest resolution object will be displayed. This means that, at least from this
distance on, you know that the lowest resolution object will be used for sure.
In the Object 1 field you drag the object that has the most resolution. This is
the object that is displayed as long as the distance from the camera is less than
Dist. 2. As soon as the current distance reaches Dist. 2, the Object 1 is switched
to Object 2. Between Dist. 2 and Dist. 3, Object 2 is used. As soon as Dist. 3 is
reached (and from that distance on), Object 2 is switched to Object 3.
What is the best way to organize your scene? I usually use something like
this:

I create a Null for which I turn the display off for both the editor and render.
Inside it, I place the variable resolution objects that I will use inside the Instance
object. This way, they will not display in the editor or render because they inherit
the display attribute of the parent Null, but the objects themselves have their
display attributes turned on and they will display properly once instantiated by
the Instance object.
I really hope you have learned a bit more about C.O.F.F.E.E. in this chapter.
As you may have noticed, we are getting deeper and deeper into C.O.F.F.E.E.

78

Chapter 8

In this chapter, I have two surprises to you. The first one is that I feel we
are ready to start coding a full length plug-in. Yes, a plug-in that will reside
inside CINEMA 4D with its own icon and parameter window (interface). Since
it requires more than just a simple script like the ones we have been doing, I
decided that the best way is to split the explanations in two chapters. So, in this
chapter, we will learn how to create the interface. That is exactly my second
surprise... we will not learn any C.O.F.F.E.E. in this C.O.F.F.E.E. lesson. In the
next chapter, we will learn how to code the plug-in using the interface we will
create now.
To create an interface, you can use C.O.F.F.E.E. commands. Actually,
C.O.F.F.E.E. has a whole class of commands with the specific purpose of
creating user interface elements. The other possible way to create an interface
is to use resources. What exactly are resources? Well, they are external files
that define and describe what user interface elements are used and how they
should be displayed. Personally, 99% of the time, I use resources because they
are much more powerful than defining the user interface with commands. With
resources, since they are external to your code, you can adjust the interface
without ever touching a single line of your code. You can even adjust the
interface after the code has been compiled (changed into a non-editable, nonhumanly-readable format, suitable for distribution). Also, additional languages
can be associated to the interface dialog. So if you want, the same interface can
show up in several different languages, depending on the main language set by
the CINEMA 4D application.
79

Interfaces defined with C.O.F.F.E.E. commands are "set in stone" and cant
be changed. The only real advantage I can see in using C.O.F.F.E.E. to define
an interface is that you can create "dynamic" interfaces that can have different
elements depending on some specific conditions. Besides that (not a very
usual situation), I strongly recommend using resources to define your plug-ins
interface.
So, how do you create interface resources? Easy - you use ResEdit (the
name is quite self-explanatory, isnt it?)
You can get it from:
http://www.maxon.net/pages/support/plugincafe_downloads_e.html
Search for Resource Editor, or get it directly from:
ftp://ftp.maxon.net/pub/sdk/91/resedit17.zip
...and you install it just like any other CINEMA 4D plug-in (inside the plugins
folder). It includes several tools, as you can see from the drop-down menu of
ResEdit, but to create interfaces, you just need the Resource Editor.

Choose it from the ResEdit drop-down menu and you will be presented
with...

80

Wow!! What a mess! To me, this is a bug but it has always behaved like this,
so following Microsoft philosophy, its not a bug, its a "feature" ;-)
Luckily, this "feature" it easily fixable. Just close one of the windows that
appeared.

And now choose "Execute Last Plugin" from your Plugins menu.

Now the toolbox window (that is unmovable in MacOS) is out of the way and
you can rearrange all other windows to your taste.

81

ResEdit opens four windows:


the Toolbox window where all the interface elements that you can use
are available.
the Properties window where you can set parameters for all your interface
elements.
the Structure window where a hierarchical representation of your
interface is displayed.
your interface window as in... your interface document.
But this last window (your interface
document window) is a bit weird at first. Its
waaaaaay too small. Actually, its not that
weird, since you havent created anything
in it yet.
To make it more pleasant to look at - and
to allow us to see the interface elements we
will create - let us enlarge it a bit. So, just
grab the size handles (depends on what
OS you are using, of course) and make it
a decent size.
OK, we are ready to go! By the
way, these steps Ive presented here
must be executed every time you open
CINEMA 4D and you choose Resource
Editor from the ResEdit menu for the
first time. But like I said, its not a bug...
its a "feature"... at least by Microsoft
standards. ;-)
Even before we start creating our
interface, we need to do an additional
task: we must create a folder with a specific hierarchy where we will build our
plug-in and its interface. So, start by creating a folder named InBetweener (that
82

will be the name of our plug-in) and inside it, create the following hierarchy:

OK, back to CINEMA 4D where you should have all your Resource Editor
windows opened. The first thing you should do is to change the name of your
main dialog into something related to your plug-in. So, instead of the name
IDD_DIALOG1, change it to IDD_INBETWEENER, like this:

Now, press the Check Box item from the Toolbox window three times.

83

You should now have a Structure window and Dialog window looking like
this:

Select the first Check Box item in the Structure window (the first one below
the Dialog item).
In the Properties window, you should read an Element ID with the name
IDC_CHECK1 and a Name of Check Box. Change the Element ID to POS and
the name to Position.

Now select the second Check Box item in the Structure window. Change
the Element ID to SCL and the name to Scale.
Finally select the third Check Box item in the Structure window. Change
the Element ID to ROT and the name to Rotation.
Now hit the Update Preview button in the Properties window and you
should end up with a Structure window and Dialog window looking like this:

84

Now, hit the Button item (


) from the Toolbox window two times (its the
second item from the top, at the left, below the
item).
Select the first Button item from the Structure window and change the
Element ID to B_CANCEL and the name to Nevermind.
Select the second Button item from the Structure window and change the
Element ID to B_OK and the name to Oh yeah!.
Now hit the Update Preview button and you should have something like
this:

Now its a good time to save your work. Choose Save as... from the File
menu of the Structure window. In the save dialog, navigate to the InBetweener/
res/dialogs/ folder and save.

Now, a second dialog will appear asking you to locate your resources path.
Simply select the main folder (named InBetweener, in our case) and hit Save.
To check if everything is ok, close any of the Resource Editor windows. It
will close all of them. Now choose Resource Editor again, from the Plug-ins
menu. All windows should appear in the position they were before you closed
them.
Now, from the File menu of the Structure window, choose Open. Navigate
to InBetweener/res/dialogs/ and open the IDD_INBETWEENER.res file. Your
interface should reappear with all the check boxes and the buttons.
But the buttons should appear side by side, not one on top of the other. By
default, all items appear in a new "line", so to place items side by side, we
need to create a Group. Click the
item from the Toolbox window. A new
85

item named Group appears in the Structure window, but apparently nothing
has changed in the Dialog window. Groups have no visual feedback, by
default. Actually, their main purpose is to serve as structural helpers. So, drag
the Nevermind item and the Oh yeah! item into the Group item, like this:

You do this just like you create hierarchies in a CINEMA 4D scene, in the
Object manager. Nothing changed in the Dialog window... yet! Select the
Group item and in the Properties window, set the number of Columns to 2.
Ah!!! Now the Dialog window shows the two buttons side by side.
We could end the dialog definition right now, but I want to make it look a
little better. So, create another Group and drag it (in the Structure window) all
the way to the top so that it appears below the Dialog item and on top of the
Position item. Drag all Check Box items inside this Group.

With the Group item selected in the Properties window, set its name to
InBetween and the Border type to Thin in (its set at None, by default).
You now have all the Check Boxes inside a nice little rectangle with a title
named InBetween. But its all the way to the left, leaving lots of empty space at
the right. Ugly!! What would be nice was if it would fill the width of the window,
no matter what size it was, right? So, set its Horizontal Alignment to Scale Fit.
86

Your Properties window should look like this now:

Now while you are at it, select the other Group and set its Horizontal
Alignment to Scale Fit, too. Also, set the Horizontal Alignment of the two
buttons to Scale Fit.
Only one thing is bothering me now - the limits of the graphic elements of
the interface are touching the limits of the window. It would all look much better
if there was some space around them, wouldnt it?
So, create another Group and drag it (in the Structure window) all the way
to the top so that it appears below the Dialog item and on top of the InBetween
item. Drag the other two Groups into it, so that you now have a Structure
window content looking like this:

87

Now, select the new Group item and in the Properties window, set its
Border space parameters to:

I dont usually increase the Top space because it already looks fine. But all
others need some adjustments and I usually set them to 4.
Choose Save from the File menu of the Structure window. Close the
Resource Editor (closing any of its windows) and choose Execute Last Plugin
from the Plugins menu. The Resource Editor window should appear again
(this time, with no interface showing, of course). To test out the new dialog,
resize the Dialog window to the smallest size it allows. Now choose Open
from the File menu of the Structure window and navigate to InBetweener/
res/dialogs/ and open the IDD_INBETWEENER.res file. Your newly defined
interface should look like this:

Well, if you are in Windows or simply using a different scheme, the look will
be slightly different. But what matters is that you just finished creating your very
first dialog resource. Keep it in a safe place (the InBetweener folder) and we
will start coding our plug-in in the next chapter.
Dont bother with the Element ID names we chose in this lesson. They will
become clear when we start coding. Also, if you open the files that ResEdit
created inside the folders you created with a text editor, you will realize that the
dialogs are defined with a kind of programming language. The dialog resource
(the IDD_INBETWEENER.res file) looks like this:
// C4D-DialogResource
DIALOG IDD_INBETWEENER
{
NAME IDS_DIALOG; CENTER_V; CENTER_H;
GROUP IDC_STATIC

88

NAME IDS_STATIC2; ALIGN_TOP; ALIGN_LEFT;


BORDERSTYLE BORDER_NONE; BORDERSIZE 4, 0, 4, 4;
COLUMNS 1;
GROUP IDC_STATIC
{
NAME IDS_STATIC1; ALIGN_TOP; SCALE_H;
BORDERSTYLE BORDER_THIN_IN; BORDERSIZE 4, 4, 4, 4;
COLUMNS 1;
CHECKBOX POS { NAME IDS_CHECK; ALIGN_TOP; ALIGN_LEFT;

CHECKBOX SCL { NAME IDS_CHECK1; ALIGN_TOP; ALIGN_LEFT;

CHECKBOX ROT { NAME IDS_CHECK2; ALIGN_TOP; ALIGN_LEFT;

}
GROUP IDC_STATIC
{
NAME IDS_STATIC; ALIGN_TOP; SCALE_H;
BORDERSTYLE BORDER_NONE; BORDERSIZE 0, 0, 0, 0;
COLUMNS 2;
BUTTON B_CANCEL { NAME IDS_BUTTON; ALIGN_TOP; SCALE_H;

BUTTON B_OK { NAME IDS_BUTTON1; CENTER_V; SCALE_H; }

And the file that stores the names of your items (the IDD_INBETWEENER.
str file, inside InBetweener/strings_us/dialogs/) looks like this:
// C4D-DialogResource
DIALOGSTRINGS IDD_INBETWEENER
{
IDS_BUTTON
"Nevermind";
IDS_BUTTON1 "Oh yeah!";
IDS_CHECK
"Position";
IDS_CHECK1
"Scale";
IDS_CHECK2
"Rotation";
IDS_DIALOG
"Dialog";
IDS_STATIC
"Group";
IDS_STATIC1 "InBetween";
IDS_STATIC2 "Group";
}

89

This means that if you want (and know what you are doing), you can even
use a text editor to create or modify an interface of a plug-in. That is the simplicity
and beauty of resources.
Well, thats all for now. Explore the Resource Editor items and options.
I assure you... its lots of fun.

90

Chapter 9

Now that we are approaching the end of this C.O.F.F.E.E. series, Ive decided
to play some mind games on you. Remember I told you that I would teach you
all how to program a full plug-in in this chapter? Well... I wont. But I will...OK,
let me explain.
I will present you with the listing of the plug-in but I will only explain it, line
by line, in the next chapter. This way I will give you time to go through the code
and try to understand it... or get very scared. I assure you, there is no reason
to get frightened by the code. It may seem complex at first, but most of the stuff
in there you only need to understand once because it will be almost the same
for all plug-ins you may be creating. So most of the coding from now on will be
a matter of Copy/Paste, with only a part of the code being specific to your plugins. The rest of the code (the stuff that may scare you at first) is just for structural
purposes, being absolutely fundamental for the definition of the plug-in itself.
You can create several kinds of plug-ins. For example, you can create menu
plug-ins that are plug-ins that you can pick from the Plugins menu. These usually
have a dialog and do their mumbo-jumbo when you press the OK button. You
can also create shader plug-ins. These will, of course, create new shaders that
appear in the shaders list in the Material Manager. You can also create Tag
plug-ins and many other types of plug-ins. You can check out what possibilities
you have by clicking the Plugin types link, in the SDK.
The ones that are most useful (and easier to create) are Menu and Tag plug91

ins. And our first plug-in will be one of those, namely a Tag plug-in.
There are two types of Tag plug-ins: plug-in tags and Expression plug-in
tags.
The first one has no dialog and is usually used to add custom data to your
objects. For example, the Anchor tag is one such tag plug-in.
The second one is the one that interests us
more. Most tags that you know have some type
of parameters to adjust and perform some action
on the objects they are attached to, depending on
those parameters.
Another nice characteristic of plug-in tags or
Expression plug-in tags is that they are executed
each time something in your scene changes, just
like the C.O.F.F.E.E. expressions you have been
using so far. So, we will be creating an Expression
plug-in tag!
First of all, make sure you have the hierarchy
presented on the right, somewhere on your
disk (you should have it, if you followed the last
chapter).

92

Inside the res/dialogs folder, there must exist a file named IDD_
INBETWEENER.res, whose content is:
// C4D-DialogResource
DIALOG IDD_INBETWEENER
{
NAME IDS_DIALOG; CENTER_V; CENTER_H;
GROUP IDC_STATIC
{
NAME IDS_STATIC2; ALIGN_TOP; ALIGN_LEFT;
BORDERSIZE 4, 0, 4, 4;
COLUMNS 1;
SPACE 4, 4;

4;

GROUP IDC_STATIC
{
NAME IDS_STATIC1; ALIGN_TOP; SCALE_H;
BORDERSTYLE BORDER_THIN_IN; BORDERSIZE 4, 4, 4,
COLUMNS 1;
SPACE 4, 4;

LEFT;

LEFT;

LEFT;

CHECKBOX POS { NAME IDS_CHECK1; ALIGN_TOP; ALIGN_


CHECKBOX SCL { NAME IDS_CHECK2; ALIGN_TOP; ALIGN_

CHECKBOX ROT { NAME IDS_CHECK3; ALIGN_TOP; ALIGN_


}
}
GROUP IDC_STATIC
{
ALIGN_TOP; SCALE_H;
BORDERSIZE 0, 0, 0, 0;
COLUMNS 2;
SPACE 4, 4;

BUTTON B_CANCEL { NAME IDS_BUTTON; ALIGN_TOP;


SCALE_H; }
BUTTON B_OK { NAME IDS_BUTTON1; CENTER_V;
SCALE_H; }
}
}
}

93

You can also create this file using any text editor, if you didnt use ResEdit.
Also, inside the res folder itself, there must exist a file named c4d_symbols.h
whose content is:
//*****************************************************
****************\
// File name
: c4d_symbols.h
// Description
: symbol definition file for the
plugin
// Created at
:
// Created by
: Resource editor
// Modified by
:
//*****************************************************
****************/
// WARNING : Only edit this file, if you exactly know
what you are doing.
// WARNING : The comments are important, too.
enum
{
_FIRST_ELEMENT_
= 10000,
// Dialog definitions of IDD_INBETWEENER start here
IDD_INBETWEENER,
POS,
SCL,
ROT,
B_CANCEL,
B_OK,
// Dialog definitions of IDD_INBETWEENER end here
// End of symbol definition
_DUMMY_ELEMENT_
};
You can also create this file using any text editor, if you didnt use ResEdit.
Inside the strings_us/dialogs folder, you must have a file named IDD_
INBETWEENER.str, whose content is:
// C4D-DialogResource
DIALOGSTRINGS IDD_INBETWEENER
{
94

IDS_BUTTON
IDS_BUTTON1
IDS_CHECK1
IDS_CHECK2
IDS_CHECK3
IDS_DIALOG
IDS_STATIC1
IDS_STATIC2

"Nevermind";
"Oh yeah!";
"Position";
"Scale";
"Rotation";
"Dialog";
"InBetween";
"Group";

I know this is getting a little boring but you can also create this file using any
text editor, if you didnt use ResEdit. But its more fun to create all these files
using ResEdit, like I showed in the last chapter.
Now, inside the res folder you must also place the icon of our plug-in. Since
it will be a tag plug-in, this icon will be the one that will appear in the Object
Manager when you add the tag to any object. You have a few restrictions when
creating this icon, though. It must have a size of 24 by 24 pixels (because it
will be the icon for a tag, otherwise, it has to be 32 by 32 pixels) and it must be
saved in a format that CINEMA 4D can read. Usually, if you save in TIFF it will
be just fine. Just make sure it only has the usual three channels, R, G and B,
and no additional alpha channels. Also, save it without compression. If you are
using a Mac, you could save it with compression because Quicktime deals with
it but if you want to make sure your plug-in works fine on Windows too, save
as a non-compressed TIFF because you cant be sure if Quicktime is installed
in Windows. Actually, having Quicktime installed will assure that CINEMA 4D
will be able to read a whole lot more formats than it natively can. So, Windows
users... hint, hint. ;-) Also, if you want the tag icon to seamlessly integrate with
the background of the Object Manager, make sure its background is set to RGB:
153,153,153.

95

You can use whatever application you prefer to create the icon.
The one I provide in the Goodies folder was created in CINEMA 4D and
edited in Photoshop. But nothing stops you from using Paint Shop, Paint,
FreeHand, Illustrator, Corel, etc. So, create the icon and save it inside the res
folder with the name inbetweener.tif
Now you should have this hierarchy:
Its now time to write our plug-in.
Use your favorite text editor to type
the code. Attention!! I said text editor,
not a word processor. If you use a
word processor, like Word, make sure
you save your file as a plain text file,
with no formatting. On a Windows
machine, you can use NotePad or
WordPad which come natively with it.
As a nice freeware solution, you
can use EditPlus (perform a Google
search for it). There may be many more
freeware text editors for Windows,
but since I dont use Windows often
(actually, I try to keep away from it as
much as I can), I cant really tell you
about more options.
If you are on a Mac, you can use TextEdit that comes natively with the
system (dont forget that you must save as a plain text document).
But there are many more options. For example, you can use mi that you can
download from http://www.asahi-net.or.jp/~gf6d-kmym/en/.
Another option is iText, from http://members.aol.com/iText/. Another great
option is TextWrangler, from http://www.barebones.com and yet another is
SubEthaEdit, from http://www.codingmonkeys.de/subethaedit/.
Anyway, always make sure you save your file as plain text. Also, make sure
the extension is .cof and not .txt
On a Mac, to make sure the extension ends up being just .cof, select your
file and press Command+I from the Finder and check for the name in the
Name&Extension section of the Info window. If you simply add .cof to the end
of your file, you may end up with a file named inbetween.txt.cof.
When you have finished typing the code and saved it as inbetween.cof, place
the file inside your inbetween folder, right next to the res and string_us folders.
96

Place the inbetween folder inside the plugins folder that resides inside
the Cinema4D folder. Now run CINEMA 4D. When it finishes loading, open
the Console window to check for errors. If it all runs fine, you should see,
somewhere in the Console window, the sentence:
Inbetweener v1.0 was successfully loaded.
If not, quit CINEMA 4D, open inbetween.cof in your text editor, and check
it against the listing presented here. The line number of the error should be
displayed in the Console window, so it is easy to hunt for the offending bug.
Without any further delays, here is the code of our plug-in:
include "c4d_symbols.h"
var PLUGIN_ID = 1020857;
var inbetweener_version = "1.0";
var
var
var
var
var
var

icon_map;
dialog_res;
owner;
doc;
inbetweenerTag;
cControls;

GetActiveTagOwner(op)
{
while (op)

{

var active_tag=GetActiveTag(op);

if (active_tag) return (active_tag);

active_tag=GetActiveTagOwner(op->GetDown());

if (active_tag) return active_tag;

op=op->GetNext();

}
return NULL;
}
GetTheActiveTag(doc)
{
return GetActiveTagOwner(doc->GetFirstObject());
}
GetOwner()
{
doc = GetActiveDocument();
if (!doc) return NULL;
var active_tag=GetTheActiveTag(doc);
if (active_tag)

{

var ob=active_tag->GetObject();

return ob;

97


else


}
{
return NULL;
}

class inbetweener_gui : GeDialog


{
public:

inbetweener_gui();

CreateLayout();

Init();

Command(id,msg);

LoadControls();

SaveControls();
}
inbetweener_gui::inbetweener_gui() {super(PLUGIN_ID);}
inbetweener_gui::CreateLayout()
{
var dialog_path = GeGetRootFilename();
if (!dialog_path) return false;
dialog_path->RemoveLast();
dialog_res = new(GeResource, dialog_path);
var ret = LoadDialogResource(IDD_INBETWEENER,dialog_res,
BFH_SCALEFIT | BFV_SCALEFIT);
SetTitle(" Inbetweener v"+inbetweener_version);
return ret;
}
inbetweener_gui::Init()
{
inbetweenerTag = GetActiveTag(owner);
cControls = inbetweenerTag->GetContainer();
LoadControls();
return true;
}
inbetweener_gui::Command(id,msg)
{
switch (id)

{

case B_CANCEL:

Close();

break;

case B_OK:
SaveControls();

Close();

GeEventAdd(DOCUMENT_CHANGED);

break;

default:

98


}
return false;
}
inbetweener_gui::LoadControls()
{
var ret;
ret = SetItem(POS, cControls->GetInt(POS, false));
ret = SetItem(SCL, cControls->GetInt(SCL, false));
ret = SetItem(ROT, cControls->GetInt(ROT, false));
}
inbetweener_gui::SaveControls()
{
cControls->SetData(POS, GetItem(POS));
cControls->SetData(SCL, GetItem(SCL));
cControls->SetData(ROT, GetItem(ROT));
inbetweenerTag->SetContainer(cControls);
}
class inbetweener_plug : ExpressionPluginTag
{
public:

inbetweener_plug();










}

GetID();
GetName();
GetHelpText();
GetIcon();
UseMenu();
MultipleAllowed();
Edit();
Save(hf);
Load(hf);
Execute(doc,op);

inbetweener_plug::inbetweener_plug()
{
var bc;
super();
bc=GetContainer();
bc->SetData(POS,false);
bc->SetData(SCL,false);
bc->SetData(ROT,false);
SetContainer(bc);
}
inbetweener_plug::Save(hf)
{
var bc=GetContainer();
hf->WriteContainer(bc);

99

}
inbetweener_plug::Load(hf)
{
var bc=hf->ReadContainer();
SetContainer(bc);
}
inbetweener_plug::GetID() {return PLUGIN_ID;}
inbetweener_plug::GetName() {return "Inbetweener";}
inbetweener_plug::GetHelpText() {return "Interpolates Position,
Scale and/or Rotation of the children of the object it is applied
to.";}
inbetweener_plug::GetIcon() {return icon_map;}
inbetweener_plug::UseMenu() {return true;}
inbetweener_plug::MultipleAllowed() {return false;}
inbetweener_plug::Edit()
{
owner = GetOwner();
var dlg = new(inbetweener_gui);
dlg->Open(true, -1, -1);
return true;
}
inbetweener_plug::Execute(doc,op)
{
var bc,pos_var,scl_var,rot_var;
var pos1,pos2;
var scl1,scl2;
var rot1,rot2;
var first_obj,last_obj,num_obj,step,f;
op=op->GetDown();
first_obj=op;
num_obj=0;
while(op)
{
num_obj++;
last_obj=op;
op=op->GetNext();
}
if(num_obj<3) return;
num_obj--;

100

step=1.0/num_obj;
pos1=first_obj->GetPosition();
scl1=first_obj->GetScale();
rot1=first_obj->GetRotation();
pos2=last_obj->GetPosition();
scl2=last_obj->GetScale();
rot2=last_obj->GetRotation();
first_obj=first_obj->GetNext();
bc=GetContainer();
pos_var=bc->GetData(POS);
scl_var=bc->GetData(SCL);
rot_var=bc->GetData(ROT);
for(f=1;f<num_obj;f++)
{
if(pos_var) first_obj->SetPosition(Mix(pos1,pos2,(f*
step)));

if(scl_var) first_obj->SetScale(Mix(scl1,scl2,(f*step))
);
if(rot_var) first_obj->SetRotation(Mix(rot1,rot2,(f*
step)));
first_obj=first_obj->GetNext();
}
}
main()
{
icon_map = new(BaseBitmap,24,24);





var file = GeGetRootFilename();


if (!file) return;
file->RemoveLast();
file->AddLast("res");
file->AddLast("inbetweener.tif");
icon_map->Load(file);

Register(inbetweener_plug);
println(" Inbetweener v"+inbetweener_version+" was
successfully loaded.");
}

Once again, dont feel scared by all this potentially complex


code. I didnt comment on any line, on purpose. All the
explanations will come in the next chapter. In the meantime,
you already have a fully working plug-in tag. To check it out,
once it loads correctly, create a Null object. Inside it, place
as many objects you want. Something like this picture on the
right.
101

You can use whatever object you want but just for testing, make them all the
same. Pyramids or Cones are great for a simple test.
Now, add an Inbetweener tag to the parent Null.

You will be presented with a dialog similar to this:

Select whatever options you want. For example, Position and Rotation.
Press "Oh, Yeah!" and then move the first or last child of the Null. All the objects
in between will interpolate the selected properties. A word of warning, though!
If you select Scale, you must use the Object tool to scale the objects, not the
Model tool. So, have fun with your new tool and... until the next chapter.

102

Chapter 10

We finally reach chapter number 10 and that means we are also reaching
the end of the C.O.F.F.E.E. series. Before wrapping things up, like promised, I
will explain what each line of code of the plug-in I presented in the last chapter
does.
I hope none of you had any trouble making the plug-in work, and above
all, I truly hope that you understood most of the actual code that does the dirty
work inside the plug-in. I assume that the stuff you didnt understand was the
"boring" stuff that actually defines the structure of the plug-in. Luckily, once you
learn what that "boring" stuff is (and what it does), you can re-use it on all your
subsequent plug-ins. You will only need to re-adjust the variables and a few
names, and from now on, most of the plug-ins you may do will mainly be a
matter of Copy/Paste. Of course, the structure I present here is for Tag plug-ins,
so this structure will only be able to produce that kind of plug-ins. But worry not!!
Before we end these lessons, I will present you with another type of plug-in:
the menu plug-in. These are the ones that are evoked from the Plugins menu
and perform some action on your document. Fortunately, the menu plug-ins are
almost a carbon copy of the Tag plug-ins as you will see later. Ok, enough with
the small talk... on to the explanations.
The first line of the code is:
include "c4d_symbols.h"
This will search for a file named "c4d_symbols.h" (without the quotes, of
course) that should reside inside the res folder that is inside your plug-in folder.
If it doesnt find that file, the plug-in will not load, presenting you with an error
103

in the Console instead. But we are very professional and we DO have a file
named "c4d_symbols.h" inside our res folder, so that file is included in the
beginning of our code. What exactly does it mean, that the file is include(d)?
Well, it is as if the line...
include "c4d_symbols.h"
... was replaced with the content of the file it refers to. In this way, the code
is clean and more flexible. If you need to change anything inside the "c4d_
symbols.h" file, you will not need to touch the plug-in code itself. And you can even
change it after your code is compiled (more about that in the next chapters).
And what exactly is inside the "c4d_symbols.h" file? The file contains this
information:
//*****************************************************
****************\
// File name
: c4d_symbols.h
// Description
: symbol definition file for the
plugin
// Created at
:
// Created by
: Resource editor
// Modified by
:
//*****************************************************
****************/
// WARNING : Only edit this file, if you exactly know
what you are doing.
// WARNING : The comments are important, too.
enum
{
_FIRST_ELEMENT_
= 10000,
// Dialog definitions of IDD_INBETWEENER start here
IDD_INBETWEENER,
POS,
SCL,
ROT,
B_CANCEL,
B_OK,
// Dialog definitions of IDD_INBETWEENER end here
// End of symbol definition
_DUMMY_ELEMENT_
};
The stuff that is important to us is what is between the { and } symbols that
follow the enum statement (the rest are comments, even if they are important
too, to the structure of the file).
104

The statement enum serves to enumerate a list of values. You only need to
explicitly assign a numerical value to the first element of the list. All others will
be sequentially numbered. So, the first element of the list is named _FIRST_
ELEMENT_ (yes, its a dummy name) and is numbered 10000. After that, all other
elements get a sequential number, so IDD_INBETWEENER will be numbered
10001, POS will be numbered 10002, SCL will be numbered 10003, and so on.
Finally, the last element, with the suitable name of _DUMMY_ELEMENT_, finishes
the list.
This list names the elements of the graphical user interface of the window of
your plug-in. This way, you will be able to refer to them by names, instead of by
numbers. Easier, isnt it?
So, after including the list of GUI elements, we start defining variables:
var PLUGIN_ID = 1020857;
var inbetweener_version = "1.0";
var
var
var
var
var
var

icon_map;
dialog_res;
owner;
doc;
inbetweenerTag;
cControls;

The first variable (PLUGIN_ID) is the ID number


of the plug-in. All plug-ins need a unique ID number
so that there is no conflict between them. And how
do you know how to choose a number that will not
conflict with any other plug-in? Easy, you go to www.
plugincafe.com and request an ID from Maxon.
This way, the ID you are provided with will be
stored inside Maxons database and no one else will
receive that ID number again. But if you are just testing
out code for a possible plug-in, you can use any ID
number between 1000001 and 1000010 (inclusive)
because these are reserved for developing purposes.
As soon as you
have your plug-in
running, make sure
you get a unique ID from www.plugincafe.
com. Then a variable named inbetweener_
version is created with the current version of
the plug-in (in this case "1.0"). This is not really
necessary but it will make things easier later if
105

you decide to develop your plug-in further and create more advanced versions.
After that, six additional variables are defined. I will explain them as they are
used, later in the code.
Now I define a procedure. This procedure returns the active tag of an object
that is passed into it. If it has none, it will search inside its children. If there is no
active tag in any of its children, it will go on searching until it reaches the end
of the objects list of your document. This procedure is a recursive procedure.
Wow!! A new word!! Recursive! This means that the procedure calls itself to
perform its task. You may wonder how it is that we dont end up inside an infinite
loop, if the code calls itself. Well, all recursive procedures must have a condition
that, if met, will terminate them. I will explain how that happens, using comments
on the code (the stuff in green, after the // symbols at each line of code):
GetActiveTagOwner(op)
{
while (op) // as long as we have a valid pointer to
an object (it will not be when the end of the document or
the end of a "family")

{

var active_tag=GetActiveTag(op); // we get a
variable pointing to the active tag of the object

if (active_tag) return (active_tag); // if there
is any, we can return it. Finished!!

active_tag=GetActiveTagOwner(op->GetDown()); //
if we dont, we call the procedure again, but this time
pointing to the child of our current object and store the
returned value inside the same variable as before.

if (active_tag) return active_tag; // if there
is any active tag, we can return it. Finished!!

op=op->GetNext(); // still no active tag found.
We move to the next object of the list

} // this will return to the beginning of the
while loop
return NULL; // no active tags were found. Return
NULL
}
There is one thing you must know about recursive procedures, if you havent
asked yourself this already. How do they know if they need to return to the
instruction after the call to themselves, or if they need to return to the instruction
after the place where they were called in the main code? To understand that,
I need to introduce a new concept: the stack. The stack is exactly what its
106

name means: a stack of something, as in a pile. And what is this "something"?


Well, its the address that follows the call and all the variables from the calling
procedure. So, when a recursive procedure calls itself, it stores inside a stack
all the variable values that it is using and also the return address. Then, when
a return command is reached, the return address is popped out of the stack
and followed. This means that a recursive routine can rapidly fill a stack with
lots of data. This can lead to out-of-memory situations. So, beware!! Recursive
procedures are very compact and efficient, but they must be used wisely.
Next, we define a procedure that will simply call our tag-finding-procedure,
starting out with the first object of the document.
GetTheActiveTag(doc)
{
return GetActiveTagOwner(doc->GetFirstObject());
}
The next procedure does the opposite of the first procedure. It returns the
first object that contains an active tag, if any. The explanation, as usual, will be
given by the comments in the code:
GetOwner()
{
doc = GetActiveDocument(); // get the current
document
if (!doc) return NULL; // there is no document!
Return a NULL
var active_tag=GetTheActiveTag(doc); // get the first
active tag, if any
if (active_tag) // if an active tag was found...

{

var ob=active_tag->GetObject(); // get the
object that contains it...

return ob; // ... and return that object

}
else // otherwise...

{

return NULL; // return a NULL because no object
was found that contained an active tag.

}
}
We now reach a completely new part of the code. Remember all the talk we
107

had in previous lessons about objects (as in... object oriented programming)?
Objects have data and procedures attached and can inherit characteristics from
the objects that generated them, can delegate characteristics to objects that are
generated from them, and so on, and so on... Ok, its time for us to create a new
class of objects. This new class will be generated from the class GeDialog
that deals with... guess what... Dialogs. Obvious, isnt it? Since this new class
will deal with the dialog of our plug-in, we will name it something relevant, like...
inbetweener_gui.
We start by defining it, based on the GeDialog class and, inside it we define
a few public procedures.
class inbetweener_gui : GeDialog
{
public:

inbetweener_gui();

CreateLayout();

Init();

Command(id,msg);

LoadControls();

SaveControls();
}
By public, we mean that they can be accessed from anywhere and their data
is also available everywhere. They could also be private and, in that case, they
would only be available inside the scope of the inbetweener_gui class. They
could also be protected and in that case they could not even be modified... but
1
that is not important here, really. We only need public stuff, at this point .
So, we declare the constructor function, named just like the class that
contains it. The constructor is a special function that creates a new instance
of the class. We also declare a few additional procedures (CreateLayout,
Init, Command, etc.).
Actually, the GeDialog class already defines all of these procedures but
they are generic. We want them to deal with our plug-in stuff, specifically!! So,
we overload them. What does that mean? Overloading a procedure means that
we are defining a new version of it, replacing the one that is already defined.
This means that, for example, if we hadnt overloaded the CreateLayout
procedure, there would already be one defined, but it would only open an
empty window (thats its default behavior). Since our plug-in has a dialog, with
graphical user interface elements in it, we need to create a new CreateLayout
procedure that loads our dialog resource and displays it on the window. And that
is exactly what we will do, in a while.
1

See the Editors Note in the Appendix on page 139 for a thorough explanation.

108

So, in a nutshell, we created a new class for our plug-in dialog that is based
on the GeDialog class (internally defined by CINEMA 4D). This new class
has all the characteristics of the GeDialog class, but since we need some of
its characteristics to be specific to our plug-in, we overload (overwrite) some
of those characteristics. The ones that can be left alone, we dont even bother
with them.
Now that we declared the procedures we want to overload, we need to
define what exactly they do.
inbetweener_gui::inbetweener_gui() {super(PLUGIN_ID);}
This one was simple. It simply calls its super (the original procedure,
defined by its parent class, GeDialog) with the parameter it requires: the plugin ID number.
The next one, since it is longer, is commented.
inbetweener_gui::CreateLayout()
{
var dialog_path = GeGetRootFilename(); // we get the
path to the plug-in that is running
if (!dialog_path) return false; // if something went
wrong, return
dialog_path->RemoveLast(); // remove the last part of
the path because the path includes the name of the plugin itself
dialog_res = new(GeResource, dialog_path); // we get
the resource from the res folder and create a new class
from it
var ret = LoadDialogResource(IDD_INBETWEENER,dialog_
res,BFH_SCALEFIT | BFV_SCALEFIT); // the resource we need
is the dialog resource and that is what we get. Read more
below...
SetTitle(" Inbetweener v"+inbetweener_version); // we
now set the title of our plug-in preview, adding it the
version number
return ret; // return the dialog return
}
When we load the dialog resource, we use the name of the resource file
(without the .res extension, of course). We load the resource file into the
dialog_res variable (one of the variables that were defined at the beginning
109

of the code). Also, we set the dialog to fit horizontally and vertically into the
available space of the window. You can find a list of these parameters in the
SDK, in the GeUserDialog session.
Now we define the initialization procedure:
inbetweener_gui::Init()
{
inbetweenerTag = GetActiveTag(owner); // get the
active tag of the current object. See below how to we
define the "owner"
cControls = inbetweenerTag->GetContainer(); // we get
the container of the tag and store it in the cControls
variable. More about this below...
LoadControls(); // The controls of the dialog are
loaded
return true; // return true. This means that the
initialization was successful
}
Its now time to introduce to you all of the concepts of a container. A
container, as its name implies, contains something. Usually, it contains data,
lots of data, a lot of different types of data. Containers are very important in
CINEMA 4D because almost everything in CINEMA 4D contains a container
(no pun intended).
For example, when you create a sphere, the sphere object has a container
that holds its Radius, the number of segments, what type of sphere it is and if it
has to render as a perfect sphere or not.
As an example, try the following... oh, by the way, this has nothing to do with
the plug-in. Its just an example for you to better understand what a container
is (it will be displayed in red, so that you dont confuse it with the plug-in code,
in blue).
So, in an empty document, create a sphere. Now add to it a new C.O.F.F.E.E.
expression tag and type the following:
main(doc,op)
{
var cnt;
cnt=op->GetContainer();
println(cnt->GetData(PRIM_SPHERE_SUB));
}
110

If you modify the number of segments of the sphere, you will get a read out
of the current number of segments, in the Console window.
I used the function GetData since this function can retrieve any type of
data, but if I wanted to force a specific type of data, I could use other types
of functions. For example, if I wanted to get the value of the segments as a
floating-point number, I could use GetFloat instead of GetData. But GetData
is much more versatile.
Of course, if you try to read a type of data using a function that relates to a
completely different type of data, you will get nothing, or even worse, useless
data. For example, if I had used GetString to get the number of segments,
I would get nothing.
So, to get data out of the container you use an expression like:
container_variable->GetData(name_of_parameter)
You may ask how I knew that the segments parameter was named PRIM_
SPHERE_SUB. I confess that I didnt know. Well, at least I didnt remember when
I typed the code, but its quite easy to know once I typed...
println(cnt->GetData(
... I pointed the cursor at the Segments parameter in the Attributes Manager
(the actual name Segments, not the numeric field in front of it) and dragged it
in front of the ( symbol. CINEMA 4D typed the name of the parameter for me,
like this:
println(cnt->GetData(#PRIM_SPHERE_SUB
I just had to delete the # symbol and finish typing the )); symbols.
Besides reading data out of a container, you can also write data into it, as
you will see below.
Now, inside the Command procedure, we can define what each element of
our interface does.
inbetweener_gui::Command(id,msg)
{
switch (id)

{

case B_CANCEL: // if the Cancel button was
pressed... (B_CANCEL is the name of the button that we
set when creating the interface in ResEdit)

Close(); // we close the window
111


structure

break; // and jump out of the switch


case B_OK: // if the Ok button was pressed...
(B_OK is the name of the button that we set when creating
the interface in ResEdit)
SaveControls(); // we save current state of
the GUI elements

Close(); // we close the window

GeEventAdd(DOCUMENT_CHANGED); // notify
Cinema4D that the document needs updating

break; // jump out of the switch structure.
Not really necessary but nice to keep things looking good

default: // if anything else happens... well,
nothing else could happen, really ;-)

}
return false; // return false because everything is
OK. Weird, but believe me... it should be like this :)
}
Now we define the procedures that load and save the controls in and out of
the interface, respectively.
inbetweener_gui::LoadControls()
{
var ret;
ret = SetItem(POS, cControls->GetInt(POS, false)); //
we load the value of the Position check box from the POS
item of the tag container into the POS item of the dialog
container
ret = SetItem(SCL, cControls->GetInt(SCL, false));
// we load the value of the Scale check box from the SCL
item of the tag container into the SCL item of the dialog
container
ret = SetItem(ROT, cControls->GetInt(ROT, false)); //
we load the value of the Rotation check box from the ROT
item of the tag container into the ROT item of the dialog
container
// we should check the return value of the ret variable
to check if the assignment was successful. But I think I
can trust everything went just fine.
}
112

inbetweener_gui::SaveControls()
{
cControls->SetData(POS, GetItem(POS)); // we load the
value of the Position check box from the POS item of the
dialog container into the POS item of the tag container
cControls->SetData(SCL, GetItem(SCL)); // we load
the value of the Scale check box from the SCL item of the
dialog container into the SCL item of the tag container
cControls->SetData(ROT, GetItem(ROT)); // we load the
value of the Rotation check box from the ROT item of the
dialog container into the ROT item of the tag container
inbetweenerTag->SetContainer(cControls); // load the
changed values into the actual container of the tag
}
The GetSomething function (the Something here can be Int, Float,
String, etc.) can have one or two parameters. The first parameter is always
the name of the element from which we want to get a value out of. If a second
parameter is given, that will be the returned value if the element that is named
in the first parameter is empty. So...
GetInt(POS,false)
...will return the value of the POS element of the dialog (it can be either one
or zero, depending on the state of the check box being on or off, respectively). If
the POS element is empty, a value of false (zero) will be returned. How can an
element be empty? Well, it could be in an undefined state when the tag is first
created, but since we are good coders, we will initialize the elements to suitable
values. But it is a good practice to code "on the safe side".
Well, all the stuff that we need to deal with the dialog is done. Now we will
define a new class: the plug-in itself. It is in this class that we will create all the
stuff that will make the plug-in tag really work. Just like before, we will create a
new class derived from an already defined class. Then we will overload all the
stuff that we need to be specific to our plug-in.
Depending on the type of plug-in you want to create, you need to derive this
new class from different parent classes. Since we want to create a Tag plug-in,
we need to derive the class from the ExpressionPluginTag class. You can
see all the other types in the SDK. and like I promised, we will create another
type of plug-in before finishing the C.O.F.F.E.E. lessons, so you will see how
different (or how similar) that will be.

113

class inbetweener_plug : ExpressionPluginTag


{
public:

inbetweener_plug();










}

GetID();
GetName();
GetHelpText();
GetIcon();
UseMenu();
MultipleAllowed();
Edit();
Save(hf);
Load(hf);
Execute(doc,op);

Theres nothing very new in the listing above; its just like what we did for the
GUI class. We declare some public procedures and name the ones we will be
overloading, in addition to the name of the constructor itself (named after our
inbetweener_plug class, derived from the ExpressionPluginTag class).
Actually, that is exactly what we will do first... define the constructor
procedure:
inbetweener_plug::inbetweener_plug()
{
var bc;
super(); // call the parent procedure (the one
defined by the ExpressionPluginTag class)
bc=GetContainer(); // get the container of the tag
bc->SetData(POS,false);
// set the POS element
to a value of false
bc->SetData(SCL,false);
// set the SCL element
to a value of false
bc->SetData(ROT,false);
// set the ROT element
to a value of false
SetContainer(bc); // load the adjusted values back
into the container
}
The Save and Load procedures will save the container inside a hyper file.
What is a hyper file? Its a file that is associated with the document and serves
114

to store values that cant be saved in a container. This means that even if you
close the document, when you open it again, the values you have set for the
plug-in options will get loaded again, properly. The hyper file is stored inside the
C4D document, so you will never actually see an icon for this file.
inbetweener_plug::Save(hf)
{
var bc=GetContainer();
hf->WriteContainer(bc);
}
inbetweener_plug::Load(hf)
{
var bc=hf->ReadContainer();
SetContainer(bc);
}
Now we define the other procedures. I will comment them to explain what
each one does:
inbetweener_plug::GetID() {return PLUGIN_ID;} //
obvious!! returns the plug-in ID number
inbetweener_plug::GetName() {return "Inbetweener";} //
This is the name that will show up in the menu
inbetweener_plug::GetHelpText() {return "Interpolates
Position, Scale and/or Rotation of the children of the
object it is applied to.";} // This is the text that
appear in the info area, when the cursor hovers over the
plug-in in the menu or its icon in the layout. Actually,
this is not possible with tag plug-ins but it is a good
habit to include this in the code
inbetweener_plug::GetIcon() {return icon_map;} //
return the icon of the plug-in tag
inbetweener_plug::UseMenu() {return true;} // setting
this to true makes the plug-in tag appear in the Tags
menu of the Object Manager
inbetweener_plug::MultipleAllowed() {return false;}
// since it is not logical that multiple inbetweener
tags could be assigned to the same object, we set this
to false. But some tags can appear more than once, for
example, the Selection tags.
115

The Edit procedure is called when the user needs to change something (by
double-clicking the tag or when it opens for the first time). Here it is what it does:
inbetweener_plug::Edit()
{
owner = GetOwner(); // we get the owner of the tag.
It will be easy to find because the inbetweener tag should
be the only one active at this point. Why? Because the
Edit procedure is called with the user double clicks the
tag or when it is first created.
var dlg = new(inbetweener_gui); // we create a new
instance of the dialog class (the one we defined above)
dlg->Open(true, -1, -1); // we open the window. The
first parameter of true means that the dialog will open as
a nonmodal window. This means that we can still do other
stuff while the window is open. The other two parameters
are the coordinates where we want the window to appear.
Since they are both set to -1, the window will appear at
the mouse location.
return true; // everything went fine so we return true
}
FINALLY!! The code that follows is what actually does the stuff that the
plug-in should do. All the code before and after it is just to define the functional
structure of the plug-in itself. The following code is what will really differ a lot
from plug-in to plug-in. As usual, I will comment the lines of code but you should
already understand most of it after all these lessons about C.O.F.F.E.E.
inbetweener_plug::Execute(doc,op)
{
var bc,pos_var,scl_var,rot_var;
var pos1,pos2;
var scl1,scl2;
var rot1,rot2;
var first_obj,last_obj,num_obj,step,f; // all the
variables used to perform the actions are declared
op=op->GetDown(); // we get the first child of the
object that contains the tag
first_obj=op; // store it again in another variable
because we will need it again, later
num_obj=0; // start a counter at zero
while(op) // as long as there is a valid object...
116

variable

{
num_obj++; // the counter is increased
last_obj=op; // store the last object in a
op=op->GetNext(); // get the next object
}

if(num_obj<3) return; // if the number of children


of the object that contains the tag is less than 3,
return.
num_obj--; // decrease the number of children of
the object that contains the tag, by one.
step=1.0/num_obj; // calculate the value of the
incremental step, based on the number of children
pos1=first_obj->GetPosition(); // get the position
of the first child of the object the contains the tag
scl1=first_obj->GetScale(); // get the scale of the
first child of the object the contains the tag
rot1=first_obj->GetRotation(); // get the rotation
of the first child of the object the contains the tag
pos2=last_obj->GetPosition(); // get the position
of the last child of the object the contains the tag
scl2=last_obj->GetScale(); // get the scale of the
last child of the object the contains the tag
rot2=last_obj->GetRotation(); // get the rotation
of the last child of the object the contains the tag
first_obj=first_obj->GetNext(); // point to the
second child of the object the contains the tag
bc=GetContainer(); // get
pos_var=bc->GetData(POS);
position check box
scl_var=bc->GetData(SCL);
scale check box
rot_var=bc->GetData(ROT);
rotation check box

the container of the tag


// get the value of the
// get the value of the
// get the value of the

for(f=1;f<num_obj;f++) // cycle through all the


objects between the first and the last
{
if(pos_var) first_obj->SetPosition(Mix(pos1,
pos2,(f*step))); // if the position check box is set,
adjust the position of the current object to a mix
between the position of the first and last objects
if(scl_var) first_obj->SetScale(Mix(scl1,scl2,
(f*step))); // if the scale check box is set, adjust the
scale of the current object to a mix between the scale of
117

the first and last objects


if(rot_var) first_obj->SetRotation(Mix(rot1,
rot2,(f*step))); // if the rotation check box is set,
adjust the rotation of the current object to a mix
between the rotation of the first and last objects
first_obj=first_obj->GetNext(); // advance to the
next object
}
}
The last segment of code, like I said, is the code that does the hard stuff. It
is the equivalent to the main routine you know from the expressions you have
been writing. But like I said in chapter number one, all C.O.F.F.E.E. scripts need
a main procedure. It is the first procedure that is executed and even plug-ins
need one. So, here is the main procedure of our plug-in:
main()
{
icon_map = new(BaseBitmap,24,24); // a new 24 by 24
pixels bitmap is allocated
var file = GeGetRootFilename(); // we get the path to
the plug-in that is running
if (!file) return; // something went wrong... return
file->RemoveLast(); // remove the last part of the
path because the path includes the name of the plug-in
itself
file->AddLast("res"); // add the res folder to the end
of the path
file->AddLast("inbetweener.tif"); // add the name of
the icon file to the end of the path
icon_map->Load(file); // load the file
Register(inbetweener_plug); // register the plug-in
println(" Inbetweener v"+inbetweener_version+" was
successfully loaded."); // print a message to the Console
signaling that all is running fine
}
I hope all this explanation was not too scary. Like I said (more than once),
most of the code you saw here is almost 100% re-usable, with just minor
adjustments. That is good news, right?
So, when you want to create a plug-in, you usually perform some tests with
C.O.F.F.E.E. tag expressions. When you have your code working, you use this
framework, paste your code into the Execute part and adjust the rest.
Of course you have to deal with the dialog stuff, but that is fun to do, right?

118

Chapter 11

Here we are in chapter number eleven. As promised, I will present a fully


working plug-in in this chapter, with fully commented code. Actually, I will not
include much text in this lesson, except for the actual code, because most of
what you need to know was already explained in the previous chapter. You will
see that there are many similarities with the code of the tag plug-in from chapter
number ten.
Anyway, I will comment the whole code, even some parts that were already
explained previously. When additional explanations are required, I will interrupt
the flow of the code to tell you about them. Oh, another thing... I will not explain or
show the content of the resource files, namely, the files named c4d_symbols.h,
IDD_DIALOG_PRS.res and IDD_DIALOG_PRS.str.
They were already explained in previous lessons and you will get them inside
the required folders of the plug-in that you can get from the Goodies folder. They
were created with Resedit, like I explained in chapter number eight and, if you
want, you can inspect them with a text editor or by opening the IDD_DIALOG_
PRS.res file in Resedit.
Before moving on to the code, I believe it would be a good idea to explain
what the plug-in does, right? Well, I needed to make a simple plug-in that would
allow me to include it in a single chapter, but at the same time, I wanted to
make something that would be useful to everyone. So, I remembered that one
of the omissions of CINEMA 4D is that, in the Render Settings dialog, you cant
rescale the dimensions of your final render, proportionally. Meaning that, if you
have your render set to, lets say, 1200 x 900, if you want to make a smaller
119

render with, lets say, 700 pixels wide, you will have to calculate what the new
vertical size should be (to maintain the same aspect ratio). The same applies if
you want a new vertical size and you will have to calculate the new horizontal
size. What would be great was if you could simply say that you wanted a new
(horizontal or vertical) measure and the other dimension would adjust itself
automatically, maintaining proportions. That is exactly what the plug-in does.
It is named Proportional Render Size, or PRS for short. When you choose it,
from the plug-ins menu, you will get this dialog:

At the top you have a display of the current render size, and below it, you
can set the new render size. When you first open the plug-in, the new render
size is the same as the current render size. As soon as you adjust one of the
dimensions, if you press Enter (or Tab to move to the next field), the other
dimension will proportionally adjust itself. If you hit Cancel, the render size
will remain the same, but if you hit OK, the new proportional dimensions will
automatically be set in the Render Settings dialog.
Ok, enough with the chit-chat... on to the code:
include "c4d_symbols.h" // you can see what this does
in the previous lesson
var PLUGIN_ID = 1021121; // this ID is unique,
requested from www.plugincafe.com
// now, all variables that are used inside the plug-in
are declared,
// except for the ones that are exclusive to classes
var prs_version = "1.0";
var PLUGIN_RES, PLUGIN_PATH, RENDER_DATA, RD, BASE_
BITMAP;
120

var WIDTH_VAR,HEIGHT_VAR;
var TEMP_X,TEMP_Y;
var doc,icon_map;
var dialog_res,dialog;
// **************************************************
// this is the first class we define. It will be used to
deal with the dialog interface
class prs_gui : GeDialog
{
private:
var bc;
ContainerToDialog();
DialogToContainer();
Ok, this is our first stop. I know I already talked about this in the previous
chapter but it is the first time we really deal with such a thing as private
variables and methods.
Defining a variable and/or method as private means that they are only
accessible (and relevant) inside the scope of the class in which they are defined.
This means that the variable bc is only accessible by methods of the class
prs_gui. By the way, different classes can use the same variable names and
they will only use their own variable, not the ones defined inside other classes.
As we will see, we will define yet another class that will have its own variable
called bc. Each class will use its own variable, even if they share the same
name.
As you can see, we also declare two methods as private. You know they
are methods because they dont have a var statement preceding them and
they also have opening and closing parenthesis after their name.
Now we go on defining some overloading methods (if you want to know what
that is, read the previous chapter).
public:

prs_gui();

CreateLayout();

Init();

Command(id,msg);
121

GetContainer();
SetContainer(bc2);

prs_gui::prs_gui()
{
super(PLUGIN_ID);
bc=new(BaseContainer);
}
The previous method is the contructor. It is named after itself ;-)
The first thing it does is to call its super which does whatever generic stuff
it needs to do. Then we use the private variable bc to store a new container.
Remember all the talk about containers in the previous chapter? Well, we will
use our own container to store a copy of the values of the interface elements
of our dialog.
It is usually a good rule to store the values in some place safe (and a container
is the best choice because it can contain several types of data) because, this
way, you can manipulate the data without it messing up the interface. When you
have all the data neatly arranged, you can load it all at once into the dialog.
prs_gui::GetContainer() {return bc->GetClone();} //
this function returns a copy of the container.
prs_gui::SetContainer(bc2) {bc=bc2->GetClone();} //
this function stores in bc, a copy of the content of the
parameter passed into it.
prs_gui::CreateLayout() // you can see what this does
in the previous chapter
{
var ret = LoadDialogResource(IDD_DIALOG_PRS,
PLUGIN_RES,BFH_SCALEFIT |BFV_SCALEFIT);
SetTitle(" PRS v"+prs_version);
return ret;
}
prs_gui::Init() // this method will initialize all the
values inside the dialog
{
doc=GetActiveDocument(); // we get the active
document
122

RENDER_DATA = doc->GetFirstRenderData(); // we get


the active render settings for this document
RD=RENDER_DATA->GetContainer(); // we get the
container of the render settings. Its inside the
container that all the values you define in the Render
Settings dialog reside.

WIDTH_VAR=RD->GetFloat(RDATA_XRES);
HEIGHT_VAR=RD->GetFloat(RDATA_YRES);
Ok, time to stop again. We are getting the size of the render now... but how
did I know the name of the parameters (RDATA_XRES and RDATA_YRES)? Well,
you can get this information from a few places. For example, there is a file
named COFFEEsymbols.h that resides in your CINEMA 4D folder, inside the
resource folder. In this file - that you can open with any text editor - you will find
ALL the names of ALL the accessible data fields in CINEMA 4D which can be
used with C.O.F.F.E.E. The problem is that none of the names are commented,
so its a matter of finding out by "approximate name" and trial/error what each
name refers to.
Another way to do it is to perform some detective work. Open up the SDK
for release 9.6, referred to in chapter number four (even if you are using release
10, you should be using the SDK for 9.6) and go to the Reference link. In it,
go to the Document link. In the Document link you should find a reference to
RenderData. Click it and you will see all the names of the data fields in it.
Or, if you want to be very lazy and you are not in a hurry, go to www.
plugincafe.com and ask at the forum. ;-)
Oh, I used GetFloat to get a floating point value because of two reasons:
the value inside the RDATA_XRES and RDATA_YRES fields is a long value,
meaning a very big integer, so using a float Im sure it will fit entirely in the
variable. Besides, I will be making calculations with those values that involve
floating point numbers so it is better to start out with a float.
// now that we have the values we need, we load them
into our containers fields
bc->SetData(CURR_SIZE_STR,tostring(int(
WIDTH_VAR))+" x "+tostring(int(HEIGHT_VAR)));
bc->SetData(NEW_X,WIDTH_VAR);
bc->SetData(NEW_Y,HEIGHT_VAR);
// and now we pass the content of our container into
the dialog
123

ContainerToDialog();

The following two methods load the contents of our container into the dialog
and vice-versa, respectively.
prs_gui::ContainerToDialog()
{
SetString(CURR_SIZE_STR,bc->GetData(CURR_SIZE_STR));
SetInt(NEW_X,bc->GetFloat(NEW_X),1,16000,1);
SetInt(NEW_Y,bc->GetFloat(NEW_Y),1,16000,1);
}
I believe an explanation would be helpful at this point. Why did I use the more
specific function GetFloat for some cases and the more general GetData for
others? Well, the GetData is advisable because it can get ANY kind of data, no
mater what type it is. But if we want to force a specific type of data, we should
use the specific functions (GetFloat, GetInt, GetString, etc.).
To set values inside a dialog, we cant use SetData. Instead, we must
use specific commands (SetFloat, SetInt, SetString, etc.). Besides,
the commands that set numbers - like SetFloat or SetInt - also define the
minimum, maximum and step values of a field. Like this:
SetFloat(FIELD_ID,value,minimum,maximum,step);
The step value is how much the value increases or decreases when the
user clicks the arrows of the numerical field.
Now, to load the values to a general container (not the specific case of a
dialog container) we can/should use the SetData and GetData statements:
prs_gui::DialogToContainer()
{
bc->SetData(CURR_SIZE_STR,GetString(CURR_SIZE_STR));
bc->SetData(NEW_X,GetFloat(NEW_X));
bc->SetData(NEW_Y,GetFloat(NEW_Y));
}
The following is the method that is called when the dialog is displayed and
the user is interacting with it.
124

prs_gui::Command(id,msg)
{
DialogToContainer(); // we get the values of the
dialog into our container
switch (id) // new we decide what to do, depending
on what element of the dialog the user is interacting
with.

{

case BUT_CANCEL: // these are the names of the
interface elements, defined when creating the dialog in
Resedit

Close(); // the user pressed the Cancel
button, so we only need to close the dialog window

break;

case BUT_OK: // the user pressed the Ok button
so we need to update the render settings values
TEMP_X=bc->GetFloat(NEW_X); // we get the
value of the new width, set by the user

TEMP_Y=bc->GetFloat(NEW_Y); // we get the
value of the new height, set by the user

RD->SetData(RDATA_RESOLUTION,0); // we set
the Resolution list value to Manual

RD->SetData(RDATA_XRES,TEMP_X); // we set
the Resolution width value to the value set in the plugin

RD->SetData(RDATA_YRES,TEMP_Y); // we set
the Resolution height value to the value set in the plugin

RD->SetData(RDATA_FILMFORMAT,0); // we set
the Film Format list value to Automatic

RD->SetData(RDATA_XFILM,TEMP_X); // we set
the Film Format width value to the value set in the plugin

RD->SetData(RDATA_YFILM,TEMP_Y); // we
set the Film Format height value to the value set in the
plug-in

RENDER_DATA->SetContainer(RD); // the
container, with the adjusted values, is loaded to the
Render Settings

GeEventAdd(DOCUMENT_CHANGED); // notify
Cinema 4D that the document was changed

Close(); // we can now close the dialog
window

break;

case NEW_X: // the user pressed Enter while
in the NEW_X field or just left the new NEW_X field by
pressing TAB
TEMP_X=GetFloat(NEW_X);
TEMP_Y=(TEMP_X/WIDTH_VAR)*HEIGHT_VAR; //
125

the NEW_Y value is calculated, proportionally...


bc->SetData(NEW_Y,TEMP_Y); // ... and
loaded into our container
ContainerToDialog(); // our container is
loaded back into the container of the dialog
break;
case NEW_Y: // the user pressed Enter while
in the NEW_Y field or just left the new NEW_Y field by
pressing TAB
TEMP_Y=GetFloat(NEW_Y);
TEMP_X=(TEMP_Y/HEIGHT_VAR)*WIDTH_VAR; //
the NEW_X value is calculated, proportionally...
bc->SetData(NEW_X,TEMP_X); // ... and
loaded into our container
ContainerToDialog(); // our container is
loaded back into the container of the dialog
break;

default: // well, there are no other possible
choices... but its good to make things nice and clean

}
return false; // report that there are no errors
}
The following section of code is the definition of the plug-in itself. It is very
similar to the section of code of the previous lesson. But instead of defining an
ExpressionPluginTag, we define a MenuPlugin. Most of the code below
requires no comments because it is almost the same as the code presented in
the previous chapter.
class PRSPlugin : MenuPlugin
{
private:
var bc;
public:
PRSPlugin();
GetID();
GetName();
GetHelp();
GetIcon();
Execute(doc);
RestoreLayout(secret); // this is the only one
that sounds weird... more about it below
}
PRSPlugin::PRSPlugin() {super();}
PRSPlugin::GetID() {return PLUGIN_ID;}
126

PRSPlugin::GetName() {return "PRS";}


PRSPlugin::GetHelp() {return "Adjust render size
proportionally.";}
PRSPlugin::GetIcon() {return icon_map;}
PRSPlugin::Execute(doc)
{
if(!bc) bc=new(BaseContainer); // if there is still
no container, create a new one
dialog = new(prs_gui); // allocate a new dialog
dialog->SetContainer(bc); // assign it the newly
created container
dialog->Open(true,-1,-1); // open the dialog. The
parameters were already explained in the previous chapter
bc=dialog->GetContainer(); // get the container
from the newly opened dialog
}
The following section of code is new because the menu plug-ins have
dialogs that can be dockable anywhere in the CINEMA 4D layout. Their dialog
must be refreshed right after the layout is loaded (when you start CINEMA 4D),
even if they are not explicitly invoked from the Plug-ins menu. That is what this
method does.
PRSPlugin::RestoreLayout(secret)
{
var doc = GetActiveDocument(); // get the active
document
RENDER_DATA = doc->GetFirstRenderData(); // get the
Render Settings from the current document
RD=RENDER_DATA->GetContainer(); // get the container
of the Render Settings

WIDTH_VAR=RD->GetInt(RDATA_XRES); // get the render
width
HEIGHT_VAR=RD->GetInt(RDATA_YRES); // get the render
height

if(!dialog) dialog = new(prs_gui); // if there is no
dialog yet, create a new one...
dialog->RestoreLayout(secret); // ... and restore
it.
}
Finally, we reach the main routine. This is where we prepare all the stuff that
the plug-in will need.
127

main()
{
icon_map = new(BaseBitmap,32,32); // the plug-in
icons have 32 by 32 pixels (the tag plug-ins have 24 by
24, remember?)
var file = GeGetRootFilename();
if (!file) return;
file->RemoveLast();
PLUGIN_RES=new(GeResource,file); // we store the
location of the res folder in the variable PLUGIN_RES
file->AddLast("res");
file->AddLast("prs.tif"); // we get inside the res
folder, locate the file "prs.tif"...
icon_map->Load(file); // ...and load the icon
// you should already know what the following lines
do because it has been done several times before
doc=GetActiveDocument();
RENDER_DATA = doc->GetFirstRenderData();
RD=RENDER_DATA->GetContainer();
WIDTH_VAR=RD->GetFloat(RDATA_XRES);
HEIGHT_VAR=RD->GetFloat(RDATA_YRES);
Register(PRSPlugin); // finally we register the
plug-in, making it appear in the Plugins menu
println("prs v"+prs_version+" was successfully
loaded."); // ...and signal it was loaded successfully
}
And this is it. To check it out, just load the folder from the Goodies into the
Plugins folder in CINEMA 4D. This is the basis of all menu plug-ins so you can
use it - adjusting it accordingly - to code any menu plug-in. Besides, I have
additional good news. If you download the SDK from version 9.5 (I strongly
recommend that you have both SDKs, for 9.5 and 9.6), there is a folder in
there, named examples. Inside this folder, there is another folder, named Basic
Frameworks. Inside it, you will find basic structures for all types of plug-ins you
can code. For example, the plug-in I present in this lesson, started out by using
a duplicate of the file menuplugin.cof.
You can also find another folder named XLent Framework inside the
examples folder. This one is even more versatile, because inside the same file
you have the code for all types of plug-ins. You just have to delete what you
dont need and then adjust what is left. Inside the examples folder there are
quite a few additional files that are quite useful to dissect.

128

Chapter 12

Finally we reach the end of this series about C.O.F.F.E.E. I dont intend to
fool you (or even myself) into thinking that these twelve lessons are all that you
need to become a proficient C.O.F.F.E.E. coder - far from it. But now you have
the basis - maybe even a little more than that - to start coding your own scripts
and plug-ins.
You will step on a lot of difficulties and doubts, just like I still do. Yes, I still
have to ask a lot of stuff in the forums, do lots of research and a whole lot of
trial & error attempts, but I told you from the start of these lessons that Im not a
programmer, remember? Knowing now that you will still face some difficulties,
let me also tell you that the joy of finally, having something we did, working just
the way we wanted, is tremendously rewarding. Anyway, when you get stuck in
some situation that apparently has no solution, you can always ask someone or
perform a search at the forum at www.plugincafe.com.
So, what will I teach in this last chapter? I decided to talk about miscellaneous
things... the stuff that is usually referred to as hints and tips. The stuff that you
all like, isnt it? :-)
Ok, lets start...
Imagine you created the greatest plug-in of the universe - well, at least a
nice one - and you want to distribute it (freely or commercially, that is up to
you). But you would like to keep your code to yourself, preventing others from
finding out how you accomplished the tasks your plug-in performs. To be able
to do that, you compile your plug-in. Compiling is the process of converting
all your source code - from a format that (hopefully) you understand - into a
129

compact binary format that only CINEMA 4D understands. When you open a
compiled C.O.F.F.E.E. script in a text editor, you get what is usually referred to
as gibberish. Here is a sample of it:
C4D-C.O.F.F.E.E.-100008}x
o??????
^^^^^^
RRRRQQQQ
RRRRQQQQ
RRRRQQQQ
???????????????????????????? ??? ??
/:0A 0%-7@
GNU[agoz
.5;AGOZchrx*5AKT[fr"-7AKValv!)19AIQZclxxxxxxzxxxxxxxxxxx
xxxzzzzzzzzzzzzxxxx%x-!!--))-/11//99/1AA11II13EJEEJE3EOJEEW_
p3ppWtpx~pp~!~-)~-1~/9~/A~1I~1Q~-Z~/c~1xxxpxppWO!xxxx!!)19AI_!(x
3pxxx3xp33tp3!3)31393A3I3Q3Z3c9pppHOp9pOppWX`fpxpppO`ppppWp9pTT
T
[f"-7Ar-7A-7A-).@KSK^invTTT
KValvVlvVlv/).@KSK^inv!!T8!!TT!8 !-8888888888888888!!!1-).@KSK^invBOX^dj|BBBBBB*X^d!B [
%f -r 7

@
G
N" U- [7 aA g
K
V
a
l
v


.
5
;
A
G
c
hjB

X
^
d
[
@
G
N
U
[
a
z

g











.
5
;
A
Z
c
Gf @
G
N


1" 2@ 2G 2N
@
G
N" @
G
N 2[7
2g
U
[
a
z

g




1KVa 2
2
2
K
V
a



2v 2








.
c
1
2
2 2.


.


. 2; 2G
5
;
A
Z
c
Gr
"
2@
2G
2N
@
G
N
U
[
a
z

g

...

This is a snippet of my Aligner plug-in, after compiling. I believe I can rest


assured that no one will be able to understand how I coded it. ;-)
At least it looks a whole lot different than:
include "c4d_symbols.h"
enum{
COUNT=1,
STORE=2
}
enum{
XMAX=1,
XMED=2,

130

XMIN=3,
YMAX=4,
YMED=5,
YMIN=6,
ZMAX=7,
ZMED=8,
ZMIN=9,
XAXIS=10,
YAXIS=11,
ZAXIS=12
}
var PLUGIN_ID=1011605;
var MENU_NAME="Aligner";
var HELP_STR="Aligns, distributes and adjusts object
positions.";

...

This is a snippet of the actual code that I wrote. So, how do you compile a
plug-in? The good news is that there is a plug-in that compiles other plug-ins.
You have it inside the examples folder that resides inside the SDK folder for
CINEMA 4D 9.5:

So, just drag (or copy) the Compiler folder into your CINEMA 4D plug-ins
folder. Once you restart CINEMA 4D, you will get a new item in the Plugins
menu.
131

Choose it and you will be presented with a file selector dialog. Navigate to
the folder where your plug-in resides and pick the file with the extension .cof.

After hitting Open, you may think that nothing happened, but navigate to the
folder where your plug-in resides and you will see that a new file was created
there. It has the same name as your .cof file but with an extension of .cob,
standing for Binary C.O.F.F.E.E.
I advise you to keep a folder with the .cof file saved in a safe place and
keep the folder with the .cob file inside your CINEMA 4D plug-ins folder. You
132

cannot keep both versions in the plug-ins folder


because at startup, CINEMA 4D will try to load
both and the second one will conflict with the first
one, since they both have the same ID. Nothing
dangerous will happen, but you will get an error
message in the Console and that is boring. Also,
the .cob file will load and run slightly faster. Really,
its only very, very, and very slightly. But even a
few microseconds faster is faster, right?
Your newly created .cob file still requires all
the other files and folders inside its folder. In fact,
the .cob file is just a substitute for the .cof file. So,
once again, remember to keep the .cof file in a
safe place, in case you want to make changes, or
heaven forbid, clean a bug you found.
Ok, speaking about bugs, I bet there will be many of them lurking around
your code, when you start writing your C.O.F.F.E.E. scripts. Even when you
become a seasoned coder, rest assured that bugs will always appear, uninvited,
ready to make you feel lost and confused. Dont get me wrong. I only say this
because it is the plain truth. I started programming when I was fourteen (with a
little interregnum of a few years when I was at college), and I still meet face to
face with a huge crowd of bugs in almost all of my projects. Oh, and Im almost
36 years old, now. ;-)
So, how do you prevent bugs? You dont, because they are there almost
always. So, you hunt them down and exterminate them until they are all gone.
But, as with almost every other "hunting" situation, it helps to know the enemy.
So, what types of bugs can you find? There are several types of bugs. I will
show you a few of them and tell you how to fix them.
For example, check out this script:
main(doc,op)
{
var child,num;
num=0;
child=op->GetDown();
if(!child) return;
while(child)
133

{
println("Name of child: "+child->GetName());
num++;
}

println("The object "+op->GetName()+" has "+num+


" children.");
}
Ok, can you spot the bugs in here? When you hit Compile (after typing it
inside a C.O.F.F.E.E. tag, of course), it returns no errors, so apparently it has
no bugs in it.
Or does it? Well, it does. It has two bugs and these are ones that are not
spotted by the compiler.

DONT TRY TO EXECUTE THIS SCRIPT!!


Otherwise you will have to force quit CINEMA 4D because one of the bugs
is fatal. This fatal bug will create an infinite loop that will bring CINEMA 4D into a
crash situation, so we must hunt for it first. Oh, this also shows that it is a good
idea to always save your file before executing any script. This is especially true
with scripts that are written inside a C.O.F.F.E.E. tag because these scripts
are constantly being executed whenever you do anything to change your
document.
For this kind of bug you will have to trace your code, line by line, and maybe
create a hand-drawn chart for it. Dont worry, its easy. You start with something
like this:

As you can see we have a fictitious hierarchy just to serve as an example,


and we also have a little table with our variables. Below, we will fill in the values
of the variables as we follow the script code.
134

Our num variable starts out with a value of zero and the child variable starts
out pointing to the first child of the op object (we can be sure about that because
the script returns if no child is found). We fill in the values of the variables below
the corresponding column and also add a little arrow to designate the child that
the child variable is pointing to, like this:

Now we follow the script... it prints out the name of the child, increases the
value of the num variable by one and repeats the cycle. So, we annotate the
current value of the variables, like this:

Ops... shouldnt the child variable be already pointing to the next child?
Ok, it seems that we found the bug. Since the child variable never gets
updated, the while cycle never reaches the end, so we end up in an endless
135

loop. So we just have to add a single line of code to the script, like this:
while(child)

{

println("Name of child: "+child->GetName());

child=child->GetNext();

num++;

}
It is now safe to run the script. But now, after printing the name of all children,
we get an error telling us:
C.O.F.F.E.E. ERROR!
(5)Incompatible values... STRING / INTEGER
File: expression
Line: 16
The line number 16 is:
println("The object "+op->GetName()+" has "+num+
" children.");
The error is telling us that we are using a value that is incompatible with
the instruction we are using. Mmmmmm, what could be wrong? The println
instruction requires a string of characters, right? We are feeding it an
expression.
The first part is a true string: "The object ".
Then we add to it a function: op->GetName()
Since GetName() returns a string, all is ok.
Then we add to it another true string: " has ".
Then we add to it the variable num. But num holds a number!!! That is our
culprit. We need to change the number into a string of characters that represents
that number. Luckily, we have such a function, so change the line to:
println("The object "+op->GetName()+" has "+tostring(num)+"
children.");
Tadah!! Our script is now working fine. Those two bugs are very common
and the first one (the lethal one) is harder to track. But as you can see, with a
little methodical thinking, we can track down most bugs.
Other types of bugs can be even subtler, like trying to use a value in degrees
when it should be in radians, or vice-versa. You must pay special attention to
136

the types of data you must provide to the functions and what type of data they
return.
Dont forget you can always place println instructions in strategic places
in your code to display the content of specific variables or simply to check
if some segment of code is being executed (for those purposes, a simple
println("+++"); will do).
You may also type your expressions incorrectly. For example:
var1+var2*var3
is not the same as
(var1+var2)*var3
You must pay special attention to the order of evaluation of expressions,
otherwise you will get different values than what you expected.
Another possible bug is that the method you chose to do what you want
is simply wrong. Well, that is not exactly a bug, but it will make for a nonfunctioning script. Make sure you document yourself enough - there are lots
of good resources on the net - and make as many
hand-written sketches/layouts as you find necessary.
Dont forget that you have a huge help reference
in the SDK documents. Explore them as much as
possible and all the folders that they include.
If you are really into this coding stuff, there are
a few books that can help you a lot. One of them is
"The C Programming Language" by Brian Kernighan
and Dennis Ritchie (http://www.amazon.com/CProgramming-Language2nd/dp/0131103628/ref=pd_bbs_2/102-5942985-013
2913?ie=UTF8&s=books&qid=1179834018&sr=8-2)
The other one is "The C++ Programming Language",
by Bjarne Stroustrup (http://www.amazon.com/
C%2B%2B-Programming-Language-Special-3rd/
dp/0201700735/ref=pd_bbs_sr_1/102-59429850132913?ie=UTF8&s=books&qid=1179834042&
sr=8-1)

137

The first one will teach you all the basics about the C language and the
second one will give a more deep knowledge about C++ (C.O.F.F.E.E. is a type
of C++).
Finally, dont forget about the www.plugincafe.com site. It is the home of a
proficient community of C.O.F.F.E.E. and C++ programmers and they will do
their best to help you out when you are in trouble or simply lost.
Its now time to wrap things up. After twelve lessons about C.O.F.F.E.E., I
hope you guys have at least the desire and curiosity to dig a little deeper into
coding. I also hope that I was able to destroy the misconception that coding is a
very complex thing that is only for those with a degree in computer science. Its
not as simple as picking flowers, I agree, but it is not that multi-headed monster
that you thought it was before reading these lessons, is it? Rest assured, the
more you code, the better you become at coding, like almost everything else.
Have a lot of good cups of C.O.F.F.E.E. :-)

138

Appendix
Editors Note
If youre wondering why everything isnt always declared as public so that
it would always be available wherever it might be needed, thats a good
question, but a little beyond the scope of this book.
It could take a whole curriculum on software design to really drive that point
home. But to give you a quick glimpse into the subject, imagine that a bunch
of really smart guys with names like Gandalf, Obi-wan, some Stoustrup
fellow, and so forth, all thought it over long and hard and came up with a
way to design complex software to be maintainable and extensible for future
enhancement. In doing so, they conjured up the concept of abstraction which
is based upon something called implementation-hiding which, in turn, is
established using access-specifiers. You guessed it: theyre known as public,
protected, and private.
You see, if every portion of code knows and depends upon the specific details
of how other parts of the code are implemented, then you get to a point where
you cannot make any changes without affecting - and often breaking - the
parts of code that have come to depend upon those implementation details.
So sophisticated techniques have been developed to hide implementation
details in a black box approach where one part of the code just asks for
something to be done and doesnt get involved in the specifics of how it
actually gets done. When skillfully employed, that can alleviate the problem of
having many parts of code unnecessarily dependent upon other parts of code.

139

Acknowledgements
I would like to thank Tavy Ann (http://www.3dattack.us) for doing the first revision
of the text. Without her preliminary work, this book would be filled with flagrant
mistakes in misspelling. Im sure it would be a funnier text to read but this type
of book should be as accurate as possible, you all must agree.
Unfortunately, some modifications were made to the text after Tavy finished
proofing it.

I would like to thank Jeff Andrews (http://www.chromecity.com) for doing the final
review, going through the whole text of this book - including the code listings and correcting my English down to each individual comma or period.
Since English is not my native language (Im Portuguese, for those who didnt
know that), I knew I would misspell something or, even worse, mess up the
grammar.

Once again, a big thank you to Tavy Ann and Jeff Andrews for making this book
a more pristine work.

140

Chapters Index
Chapter 1.......................................................................................................................3
Introduction to programing languages, focusing specially on C.O.F.F.E.E.
Presentation of some basic concepts related to programming languages.

Chapter 2.....................................................................................................................10
Practical examples of some basic programming in C.O.F.F.E.E.
Introduction to variables, conditional and logical expressions.

Chapter 3.....................................................................................................................21
Introduction to one of the more important concepts of C.O.F.F.E.E. programming: objects

Chapter 4.....................................................................................................................31
Lots more about objects.

Chapter 5.....................................................................................................................43
Learn how to use the SDK. Introduction to the concept of loops and cycles.

Chapter 6.....................................................................................................................53
Fully working example of a script, using all the concepts learned so far
while introducing a few more.

Chapter 7.....................................................................................................................67
Fully working example of a more complex script, using all the concepts learned so far.

Chapter 8.....................................................................................................................79
Learn how to use Resedit, the official tool to create GUI dialogs for plug-ins.

Chapter 9.....................................................................................................................91
Fully working C.O.F.F.E.E. tag plug-in.

Chapter 10.................................................................................................................103
Complete and exhaustive explanation of the plug-in presented in the previous chapter.

Chapter 11.................................................................................................................119
Fully working C.O.F.F.E.E. menu plug-in with explanation of the whole code.

Chapter 12.................................................................................................................129
Wrapping up... Learn how to compile your plug-ins and hunt for bugs.

141

Alphabetic Index

Symbols
!=............................................................................................................................15, 17
[ ... ]..............................................................................................................................62
{...}..................................................................................................................................6
==...........................................................................................................................14, 17
3D Attack.................................................................................................................... 67
&& (and)..................................................................................................................... 18
> (larger than)............................................................................................................. 17
>= (larger than or equal to)......................................................................................... 17
< (less than)................................................................................................................ 17
<= (less than or equal to)........................................................................................... 17
! (not)............................................................................................................................26
|| (or)........................................................................................................................... 18
; (semicolon)................................................................................................................. 6
A
AddLast............................................................................................................ 118, 128
and............................................................................................................................. 14
Animation................................................................................................................... 45
array........................................................................................................................... 62
B
BaseBitmap...................................................................................................... 118, 128
BaseDocument........................................................................................................... 37
BaseDraw................................................................................................................... 75
BASEDRAW_DATA_CAMERA............................................................................. 70, 75
BaseList2D................................................................................................................. 35
BaseList4D................................................................................................................. 35
BaseObject..................................................................................................... 35, 37, 43
Basic Frameworks.................................................................................................... 128
BIT_AOBJ............................................................................................................ 56, 57
Books....................................................................................................................... 137
break...................................................................................................... 52, 64, 65, 125
bugs.......................................................................................................................... 133
C
C........................................................................................................................... 4, 137
C++....................................................................................................................... 4, 137
case.............................................................................................................. 56, 64, 125
Casts.......................................................................................................................... 46
class............................................................................................... 23, 35, 44, 108, 121

142

Class.......................................................................................................................... 47
Close................................................................................................................ 112, 125
C.O.F.F.E.E................................................................................................................... 3
CoffeeExpressionTag........................................................................................... 56, 59
Command..................................................................................... 4, 108, 111, 121, 125
Compile.................................................................................................................... 129
Conditional (expression)............................................................................................. 16
Conditions.................................................................................................................. 14
Console........................................................................................................................ 9
CreateLayout.................................................................................................... 108, 121
Cycle.......................................................................................................................... 49
D
Debugging................................................................................................................ 133
Declaration................................................................................................................. 47
default................................................................................................................... 64, 65
Dialog......................................................................................................................... 84
do............................................................................................................................... 51
doc (operand)..................................................................................................... 5, 7, 24
Documentation......................................................................................................... 137
DOCUMENT_CHANGED................................................................................. 112, 125
Document classes...................................................................................................... 44
Double........................................................................................................................ 13
E
Edit........................................................................................................................... 114
EditPlus...................................................................................................................... 96
else....................................................................................................................... 14, 16
enum........................................................................................................................ 104
Exception Handling.................................................................................................... 47
Execute............................................................................................................ 114, 126
Expression.................................................................................................................. 92
ExpressionPluginTag........................................................................................ 113, 126
F
Files............................................................................................................................ 46
FindObject...................................................................................................... 25, 26, 36
Float................................................................................................................... 13, 113
for............................................................................................................................... 48
Function........................................................................................................................ 4
Functions.............................................................................................................. 46, 47
G
GeDialog..........................................................................................................
GeEventAdd.....................................................................................................
GeGetRootFilename........................................................................................
GeResource.....................................................................................................

143

108, 121
112, 125
109, 128
109, 128

GetActiveDocument......................................................................... 107, 122, 127, 128


GetActiveTag............................................................................................................ 106
GetBit............................................................................................................. 56, 57, 58
GetClone.................................................................................................................. 122
GetContainer.................................................................................................... 110, 123
GetData.................................................................................................... 110, 111, 124
GetDown.................................................................................................................. 106
GetFirstObject.............................................................................................. 24, 52, 107
GetFirstRenderData................................................................................. 123, 127, 128
GetFirstTag........................................................................................................... 56, 59
GetFloat.................................................................................................... 111, 123, 124
GetHelp.................................................................................................................... 126
GetHelpText.............................................................................................................. 114
GetIcon............................................................................................................. 114, 126
GetID................................................................................................................ 114, 126
GetInt................................................................................................................ 112, 124
GetItem..................................................................................................................... 113
GetLength................................................................................................................... 34
GetMg................................................................................................................... 70, 75
GetName.............................................................................................. 24, 52, 114, 126
GetNext........................................................................................................ 52, 60, 106
GetObject................................................................................................................. 107
GetPointCount................................................................................................ 56, 58, 59
GetPoints.............................................................................................................. 56, 62
GetPosition................................................................................................... 27, 29, 117
GetRenderBaseDraw........................................................................................... 70, 75
GetRotation.............................................................................................................. 117
GetScale................................................................................................................... 117
GetString.......................................................................................................... 111, 124
GetType................................................................................................................ 56, 58
GetV0................................................................................................................... 70, 75
GUI............................................................................................................................. 45
I
Icon............................................................................................................................. 95
ID.............................................................................................................................. 105
ID_USERDATA..................................................................................................... 60, 73
if.................................................................................................................................. 14
include.............................................................................................................. 103, 120
Index......................................................................................................................... 139
Init............................................................................................................. 108, 121, 122
InsertObject.......................................................................................................... 36, 39
InstanceObject........................................................................................................... 70
instanceof....................................................................................................... 56, 59, 70
Instruction..................................................................................................................... 4
Int............................................................................................................................. 113
Integer........................................................................................................................ 13
iText............................................................................................................................ 96

144

J
Java.............................................................................................................................. 4
JavaScript..................................................................................................................... 4
L
Language..................................................................................................................... 3
Literal (expression)....................................................................................................... 8
Load................................................................................................................. 114, 128
LoadControls.................................................................................................... 108, 110
LoadDialogResource........................................................................................ 109, 122
Loops.......................................................................................................................... 48
M
main.............................................................................................................................. 5
Materials..................................................................................................................... 45
Math........................................................................................................................... 46
Memory....................................................................................................................... 46
MenuPlugin.............................................................................................................. 126
mi................................................................................................................................ 96
MultipleAllowed........................................................................................................ 114
N
new............................................................................................................... 22, 36, 109
Nil............................................................................................................................... 25
NotePad..................................................................................................................... 96
O
object (oriented programming)............................................................................. 20, 31
OBJECT_POLYGON............................................................................................ 56, 58
Objects....................................................................................................................... 45
Open......................................................................................................................... 116
Operand....................................................................................................................... 4
Operator....................................................................................................................... 4
op (operand)....................................................................................................... 5, 7, 24
or................................................................................................................................ 14
P
plugincafe........................................................................................................... 40, 129
PLUGIN_ID.............................................................................................................. 105
Plugins........................................................................................................................ 45
PointObject........................................................................................................... 35, 43
PolygonObject............................................................................................................ 36
print.............................................................................................................................. 9
println........................................................................................................................ 8, 9
private............................................................................................................... 108, 121
Program Structure...................................................................................................... 47

145

protected.................................................................................................................. 108
public................................................................................................................ 108, 121
R
RDATA_XRES.................................................................................................. 123, 127
RDATA_YRES.................................................................................................. 123, 127
ReadContainer......................................................................................................... 115
Recursive................................................................................................................. 106
Register.................................................................................................................... 118
RemoveLast..................................................................................................... 109, 128
ResEdit....................................................................................................................... 80
Resource Editor.......................................................................................................... 80
Resources............................................................................................................ 45, 79
RestoreLayout.......................................................................................................... 126
Return........................................................................................................................... 6
S
Save......................................................................................................................... 114
SaveControls.................................................................................................... 108, 112
Script............................................................................................................................ 5
Scripting....................................................................................................................... 3
SDK.............................................................................................................. 40, 43, 128
SetContainer............................................................................................................ 114
SetData.................................................................................................... 113, 123, 124
SetFloat.................................................................................................................... 124
SetInt........................................................................................................................ 124
SetItem..................................................................................................................... 112
SetName.............................................................................................................. 36, 39
SetPoints.............................................................................................................. 56, 65
SetPosition......................................................................................................... 29, 117
SetRotation............................................................................................................... 118
SetScale................................................................................................................... 117
SetString................................................................................................................... 124
SetTitle............................................................................................................. 109, 122
Shaders...................................................................................................................... 45
Single......................................................................................................................... 13
SphereObject....................................................................................................... 36, 38
SplineObject............................................................................................................... 34
sqrt............................................................................................................................. 69
Stack........................................................................................................................ 106
String............................................................................................................ 13, 47, 113
SubEthaEdit............................................................................................................... 96
super................................................................................................................ 109, 122
switch..................................................................................................... 56, 63, 64, 125
Syntax.......................................................................................................................... 4

146

T
Tag.............................................................................................................................. 92
Tags............................................................................................................................ 45
TextEdit....................................................................................................................... 96
TextWrangler.............................................................................................................. 96
then............................................................................................................................ 14
tostring.................................................................................................................. 28, 74
Types.......................................................................................................................... 46
U
Undo........................................................................................................................... 67
UseMenu.................................................................................................................. 114
User Data....................................................................................................... 54, 60, 68
Utilities........................................................................................................................ 46
V
var.............................................................................................................................. 11
Variable................................................................................................................... 7, 10
Vector......................................................................................................................... 47
W
while........................................................................................................................... 51
Word........................................................................................................................... 96
WordPad..................................................................................................................... 96
WriteContainer.......................................................................................................... 115
X
XLent Framework..................................................................................................... 128

147

rui_mac 2007-2008
No contents - part or whole - of this document can be reproduced without expressed
permission of Rui Batista (rui_mac@ruimac.com)

148

You might also like