Sunday, January 26, 2025

some beginner c++ from python tips

1_variables

comparing python variables to c++ variables.

example:

d = 20.0  #python
double d = 20.0; //c++

d = 20 #python
int d = 20; //c++

d = True #python
bool d = true; //c++

the first thing to notice is that different from python in c++ we need to specify the type for all variables.  in python it knows how to figure out the type automatically but in c++ we need to specify the type like int, bool, double before the parameter name.


in c++ there are also some variables that don’t exist in python.
for example the c++ variable for a pointer.

int a = 21;
int *pa;
pa = &a;

above we have a variable named pa of type int which is a pointer by the use of the * before the variable name and after the type.

we assign the pointer the address of a so now we have a variable that can access the value of another variable and not only access it but can change it as well.


d = ['a', 'b'] #python
std::vector<std::string> d; //c++
d.push_back("a");
d.push_back("b");

#python
for let in d:
    print(d)

//c++
#include <vector> //for std vector
std::vector<std::string>::iterator iter;
for( iter = d.begin(); iter != d.end(); ++iter)
{
    std::cout << *iter << std::endl;
}

so for looping a list in c++ it takes more lines than in python.
also for the list push_back it needs double quotes around letters.
notice notion of an iterator that will be used to loop through the elements of the list.  the for loop for iterator looks a little different from a normal for loop.  the iterator needs to be based on the same type as the original list.

this is another way to make a list. unlike std::vector this list needs to be told its length ahead of time.

    std::string d[2];
    d[0] = "a";
    d[1] = "b";
   
    for(int i=0; i<2; i++)
    {
        std::cout << d[i] << std::endl;
    }

it also show a regular c++ for loop.

this is another way of creating the list that doesn’t use std::string:

    const char* d[2];
    d[0] = "a";
    d[1] = "b";

an advantage of using std::string variable over const * is because of the api available with std::string to do lots of operations on strings.

2_methods
from python methods start with: def
so like

def fun():
    pass

the name of the method is fun.
it doesn’t take any parameters.
it doesn’t return anything


in c++ the above method would look like:

void fun()
{
    //pass
}

the void tells the method it doesn’t return anything
the name of the method is fun like the python one.
in c++ no colon is needed after the method parenthesis as is needed in python.

in python a method taking an int parameter might look like

def fun( i ):
    print(i)

in c++ it might look like below:

void fun(int i)
{
    printf("%i\n", i);
}

in python a method returning an int might look like:

def getNum():
    return 21

in c++ it might look like

int getNum()
{
    return 21;
}

notice different from python c++ needs to have the return type before the function name. in python no return type is needed before the function name.

and to call it in c++
printf("%i\n", getNum());

this is an example of a method in python that creates a local variable in the method.

def getNum():
    i = 21
    return i

and in c++:

int getNum()
{
    int i = 21;
    return i;
}

like python the variable created in c++ method is "local" to the method or has local scope meaning it is only seen in the method.

the local ness can be tested by running this in main c++ function:

int i = 23;
printf("%i\n", getNum());
printf("%i\n", i);

it prints out last 23 because the i used in the method getNum exists only in the method and does not change the i variable with value 23 in main function.

3_classes

in python a simple class could look like:

class Yaay():
    def __init__(self):
        pass

the word class is used to tell a python class.
the name of the class is Yaay.
the thing that is called when making a class object - the constructor is called __init__ in python.
in the init the word self needs to be the first argument.
the constructor here doesn’t do any work.

in c++

class Yaay
{
    public:
        Yaay()
        {
            //   
        };
};

in c++ no parenthesis is needed after the class name.
the class needs curly braces surrounding it.
the end curly brace needs a semi-colon after it.
the constructor here is the same name as the class.
it doesn’t take any arguments notes by empty parenthesis in Yaay()
no self is needed at beginning of constructor parenthesis as is needed in python.


its a little different creating an object of a class in c++ than it is in python.

for example in python a class could look like:

class Fun:
    def __init__(self, msg):
        self._msg = msg
    def foo(self):
        print(self._msg)

and creating an object of this class in python looks like:

f = Fun("yaay a greeting")

and calling the method in the python class.

f.foo()

which should print
"yaaay a greeting"

in c++ the same class looks different:

#include <iostream.h>

class Fun
{
public:
    Fun(){}

    Fun(std::string msg){ _msg = msg;}
private:
    std::string _msg;
public:
    void foo(){std::cout << _msg << std::endl; }
};

for creating the object in c++ looks like:

Fun f("yaay a greeting");

and calling the method of the class looks like:

f.foo();

which should print:
"yaay a greeting"

so the syntax for making the object is different in c++ than it is in python.

in c++ the parenthesis is to the right of the name of the instance.
in c++ the class name is to the left of the name of the instance.

Fun f("yaay a greeting");

in python the parenthesis comes to the right of an equal sign.
in python the class name is to the right of the name of the instance.

f = Fun("yaay a greeting")

and c++ has trailing semi-colon which python doesn't have.

4_class_methods


in python a simple class method could look like:

class Yaay()
    def __init__(self):
        pass

    def fun():
        print("yaay lots of fun")

and to create an object and call method would look like:
y = Yaay()
y.fun() #should print the methods statement


in c++ the same class and method would look like:

#include <iostream.h>
class Yaay
{
    public:
        Yaay(){}
        
    public:
        void fun(){std::cout << "yaay lots of fun";}
};

in c++ to use std::cout to print needed the #include at top.

and to create object and call method.

Yaay y;  //will call the default constructor
y.fun();   //will print the method statement

c++ similar to python in calling the method from the class with c++ needing a semicolon at end.
c++ is different than python in creating instance of class.
in c++ the type of class comes first.
Yaay y;  versus  y=Yaay()


if created object on the heap would look like
Yaay *ptrY = new Yaay();
ptrY->fun();
delete ptrY;

c++ has notion of heap versus stack.
i think heap is memory that is kept for the life of the program.
where as stack variables are kept in memory where they exist in scope. like local stack variables disappear when outside of the function curly braces.

using new keyword in c++ is how can create an instance in the heap.  new Yaay() returns a pointer to a Yaay object.

to call a class method from a pointer to the class need the arrow -> symbol: pointerToObject->functionName()

because heap memory is kept for life of program we delete the pointer after its done being used if want to free up its memory.
using: delete ptrY;
  

5_method_passByRefVsPointer
different from python, in c++ we can edit the parameter being passed into a method. 

in python a method could look like

def fun(a):
    a = a + 1

and called via:

num = 20
fun(num)

but printing num after calling num should get
print(num)
#20
num unchanged.

but in c++ we can actually have change of parameter preserved.

in c++ the similar method could look like:

void fun(int a)
{
    a = a + 1;
}
calling above in c++ via
int num = 20;
fun(num);
std::cout << num << std::endl;

should also leave num unchanged yielding
//20

but in c++ we can pass the parameter as reference using ampersand sign like so:

void fun(int &a)
{
    a = a + 1;
}
now calling function in c++ like
int num = 20;
fun(num);
std::cout << num << std::endl;

should yield:
21

the parameter is changing in the method and preserved by the callee.

in c++ we could also use a pointer to have similar effect.  i think would want to use pointer if could pass in a null value to parameter.

the c++ method with pass by pointer would look like:
void fun(int *pa)
{
    *pa = *pa + 1;
}
now calling function in c++ like
int num = 20;
fun(&num);
std::cout << num << std::endl;

printing result should yield
21

like the result from passing by reference.
notice how accessing the value of the pointer using dereference operation * before the pointer.
also notice how when calling the function we pass in the pointer by using num’s address.  a pointer is a variable just like int. but its value is an address.

6_class_inheritance 



in python a simple inheritance with class could look like:

class Base(object):
    def __init__(self):
        pass
    def fun(self):
        print("yaay a base class")

and a subclass of Base could look like

class Thing(Base):
    def __init__(self):
        super(Thing, self).__init__()

and calling a method of Thing could look like:
t = Thing()
t.fun()
#yaay a base class

we called a method on a Thing object which doesn't exist in the class Thing.  because we used: class Thing(Base):  we are inheriting Base classes methods and variables.

still in python if we modify our Thing class a bit we can call a method from Thing class that overrides base class like so:

class Thing(Base):
    def __init__(self):
        super(Thing, self).__init__()
    def fun(self):
        print("yaay fun from Thing class")

t = Thing()
t.fun()

yielding:
yaay fun from Thing class


doing something similar in c++ looks like:
first the base class:

class Base
{
    public:
        Base(){}
    public:
        void fun(){ std::cout << "yaay a base class" << std::endl; }
};

then the subclass

class Thing : public Base
{
    public:
        Thing() : Base(){ }
};

different from python for the subclass we need to specify something before the Base here the public keyword.
class Thing : public Base

also notice the difference in calling the Base class constructor in the Thing's constructor via:
Thing() : Base(){ }

we need both of the parenthesis above.

and creating an object from Thing class and calling a method

Thing t;
t.fun();

should yield
//yaay a base class
because we are using the Base class's method
 

7_header



its often helpful when first looking at c++ code in tools to first look at the .h header files.  this is because the header files often don’t contain all the details of implementation, so it should generally be shorter than the .cpp file.

headers can contain definitions for classes and methods.

i don’t think there is an equivalent in python to header files - so this makes c++ and python different.


at the top of a header file in c++ could see something like

#include <iostream>

this is like a python import statement

import iostream

so includes in c++ are like import statements in python.

some includes in c++ look like:

#include "myFile.h"

this is also like python import statement but the above looks in a different directory than the previous carrot like includes.  i think for more custom locations would use the quoted includes and for using system wide header files would use the carrot surrounded includes.
 

8_other


main method
compiling and running c++ program
const
struct
typedef
namespace
define
enum class




main method

the notion of main is different in c++ from python.
in c++ a main method could look like.

int main()
{
    //do stuff
    return 0;
}

where can put the primary things to do in the main method
##


compiling and running c++ program

in python to run a python program from command line could look like:

python fun.py

in c++ it could look like:

g++ -o prog fun.cpp

the above compiles the file fun.cpp and outputs an executable name prog which can be run with:

./prog

for projects with multiple c++ files example if had two files named fun.cpp and main.cpp and possible fun.h header. could use:
g++ -o prog fun.cpp main.cpp

and can run with same

./prog
##


const

const is a notion that is in c++ but not in python.
it is a way to say do not change this thing for variables.
or for class methods a way to say this method doesn’t change any class variables.

here is an example for a const variable:

const int i = 21;
i = 23; //should give compile error

notice how const comes before the variable name.
when try to compile we get an error because we are trying to change a variable that should not be changed.

here is an example for a class method

class Fun
{
    public:
        Fun(){
                mVar = 21;
                };
                
        void test() const
        {
            mVar = 23; //should give a compile error trying to change a class variable
        }
    private:
        int mVar;
};


and to test in main function:

Fun f;
f.test(); //should give a compile error
##


struct

struct is a lot like a c++ class but it has that methods are public by default where as for class they are private by default.

here’s an example of a struct:

struct Fun
{
    Fun(int val){ mParam = val;} //this is the constructor
    int mParam;
    void greet(){ printf("yaay a struct with parameter: %i \n", mParam);}
};

and to use it:

Fun f(21);
f.greet();

##


typedef

typedef is a way to have custom type names.  like instead of int could use a custom type example customInt. so it would look like:

typedef int customInt;

and to use it:

customInt p = 21;

it is most useful when we have a long variable type like a vector so could create the custom type for a vector as:

typedef std::vector<int> customVector;

and use it:

customVector vec;
vec.push_back(21);
printf("item %i\n", vec[0]);

##


namespace

namespace is a way to help avoid naming clashes if used the same name for classes, variables, methods in multiple files.

here is an example where get an error if defined the same variable twice without namespaces:

int m = 21;

int m = 25;

here is an example to avoid the error by using namespaces. the namespaces were created outside of main method:

namespace A
{
    int m = 21;
}

namespace B
{
    int m = 25;
}

and usage in example main method:
std::cout << A::m << std::endl;    //21
std::cout << B::m << std::endl;    //25
##


define

define is a way can have c++ write c++ code.
it can be used to define constants or custom macro methods.

here’s an example:

#define CONST 21

and usage

printf("%i \n", CONST);

and here's another example with a custom method

#define FUN(i) std::cout << i << std::endl;

and its usage:
FUN(21);

and here's another example with a multi line custom macro

#define FUN(i) \
std::cout << i << std::endl; \
std::cout << "yaay" << std::endl; \

some additional info on define macros:
https://stackoverflow.com/questions/6004963/why-use-define-instead-of-a-variable
##

enum class

enum's can be used to give meaningful names to integers. its kindof similar to a python dictionary with keys string and values another type ex: numbers.

for example:

enum class OPTIONS
{
    low = 0,
    mid = 1,
    hi = 2
};

and its usage

OPTIONS o = OPTIONS::low;
if(o == OPTIONS::low)
{
    printf("low option \n");
}

to compile need to use c++ 11
g++ -o prog -std=c++11 nameOfFile.cpp

notice need the double semicolons to use it.

to print value need to use casting to change to its type ex:
int choice = static_cast<int>(OPTIONS::hi);
std::cout << choice << std::endl; //2

##

9_furtherReading

for further reading on c++ i highly recommend studying
Pixar’s openUsd project on github.  also could study the commits on Blender’s open source code base on github.

also reading Maya c++ plugins online is helpful to learn about how various c++ api’s are used for writing computer animation tools.

in reading could write out the syntax that is not understood.  Then can google search to try to find out what the syntax means.  hopefully with the previous chapters there is enough info for keywords to search for.


Thanks for looking

some python tips for scripting

 list comprehension
 if else
 logger
 isinstance
 raise error
 try except
 set intro
 unittest



list comprehension:
use:
a way to loop through a list quickly in a single line of code

things = ['a', 'b', 'a']

result = [let for let in things]
would give back the same list that we started with:
['a', 'b', 'a']

now if 
result = [let for let in things if let == 'a']
would give back:
['a', 'a']

so we can add if statements to the list comprehension to only get certain items of the list.

where not used:
if need to do multiple things on each item of the loop a for loop would be better.
for example if needed to create an object of a class using the letter and call a class method.
then for loop could be.

result = []
for let in things:
	y = Yaay(let)
	res = y.fun()
	result.append(res)

the above for loop would be harder to do in list comprehension.


if else statement

if else is helpful for getting something if a condition holds and something else if it doesn't.
for example.

useA = True
result = 'a' if useA else 'b'
#should give result
#'a'
because useA boolean is True

if it was like this:
useA = False
result = 'a' if useA else 'b'

then result would be: 'b'
instead.


try except

helpful when not sure if a piece of code could potentially error and we want our tool to continue working even if it errors.

for example:

import traceback

def funThatCouldError(x):
	return 1/x

try:
	funThatCouldError(2)
except Exception as e:
	print(traceback.format_exc()) #so we can print detailed error

above shouldn’t error but if we do below it should:
try:
	funThatCouldError(0)
except Exception as e:
	print(traceback.format_exc()) #so we can print detailed error


so if we had a situation like below where we have a list of things to process and we want to
get our last item we could use try except.

import traceback
def funThatCouldError(x):
	return 1/x
	
nums = [2.0, 0.0, 4.0]
for n in nums:
    try:
        print(funThatCouldError(n))
    except Exception as e:
        print(traceback.format_exc())

#prints
0.5
the traceback error
0.25

but if we didn’t have the try except and ran:

import traceback
def funThatCouldError(x):
	return 1/x
	
nums = [2.0, 0.0, 4.0]
for n in nums:
    print(funThatCouldError(n))

#we wouldn’t get to the third element
0.5
the traceback error



logger

when writing or debugging tools whether they be big or small, loggers are essential.
they allow us to see how the tool is doing and if there are bugs with specific data we can see where in tool the bug is happening and with what specific data.

a very simple example

import logging
logging.basicConfig(level=logging.DEBUG)

logging.info("yaay a log message")
logging.warn("yaay a log warn message")

the warn message is helpful to put in the tool for places we want to warn the artist about something happening in tool.


raise error

useful for debugging in python where want to stop the script at a certain point.
could raise an error.

ex:

raise RuntimeError("exiting at this point")


isinstance

helpful for checking where an object is of a given type.

ex:
a = 'yeah'
isinstance(a, str)
#True

above checks where the a object is of type string.

could use similar if had a method that excepts a particular class type
could add an isinstance in method to check whether user passed the correct
object type.


set

here creating two sets out of lists:
setA = set(['a', 'b'])
setB = set(['b', 'c', 'd'])

here printing intersection of two sets
setA.intersection(setB)

gives result:
set(['b'])

also can use sets to get a unique list

list(set(['a', 'b', 'a']))

gives:
['a', 'b']


unittest

tests can be used to test example classes.
here's an example of writing a test using unittest:

import unittest


class TestStuff(unittest.TestCase):
    def test_a(self):
        self.assertTrue(10==10)
    def test_b(self):
        self.assertEqual(21, 21)

class TestStuffB(unittest.TestCase):
    def setUp(self):
        self.param = 10
    def test_a(self):
        self.assertTrue(self.param==10)
    def test_b(self):
        self.assertEqual(self.param+11, 21)
        
        
if __name__ == '__main__':
    unittest.main()

and can test it by saving the python file and running in terminal:
python nameOfFile.py -v

Thanks for looking

Tuesday, January 14, 2025

Doodle designing for Storyboarding

Was finding it fun starting by making contrasting shapes. Then adding brows eyes nose mouth and ears. Then adding body. Then adding some expressions. Then drawing a story panel with the characters.



Thanks for looking.