Skip to content

Archive

Tag: Debugging

Not quite. For now just a few links that you may find helpful.

Know the tricks

There are several essential tricks for Blender 2.6.1 (much of this works in 2.5x/2.49 or can inspire you). Presented as a list of tips, honestly it’s more of a survival kit if you’re serious about scripting Blender – read it or learn the hard, frustrating way.

And if you’re still an OS-X newbie (I am), learn how to run programs from the terminal.

What if I wanted to use a Python IDE with Blender?

The main problem I see here is that bpy and Blender may not be recognized by Python IDEs (I tried PyCharm). I think there might be a workaround but it looks heavy handed.

  • There is/was/used to be Stani’s Python editor. I think there is an old version on sourceforge. Maybe you can access his blog in which case you might get a later version (untested).
  • It may be possible to setup Eclipse in a useful way (see ‘Programming add-ons for 2.5′ below) (untested).
  • Wing IDE provides a solution that is somehow compatible with Blender (untested).

I want to set breakpoints

There is a community add-on for that (2.5x, untested)

Programming add-ons for 2.5…

Getting started with writing add ons is a little harder than with 2.49b. I wrote a little about this (search?). More notably, there is a free e-book in PDF format by Witold Jaworksi (haven’t read it yet, looks useful)

Not everything that shows in a 3D view will earn you credit, especially when you get an amorphous, spiky, translucent mass of pixels.

If you do, you may be having a ‘memory issue’. Let’s remind ourselves quickly how this is most likely to occur:

  1. Allocate memory with malloc() and call free(), but forget that another object is still using this memory block.
  2. Access memory beyond the bounds of your allocation.
  3. Attempt using an uninitialized section of a memory block.

I feel tempted to make a kind of buffer class, so I can manage malloc-ated block. Or maybe a few buffer classes. Here’s why:

  • Reference counting needn’t be great, but it’s better than **nothing**. If we wrap our memory blocks and don’t leak the underlying pointers, the worse we can get is a zombie buffer, still much better than a wild card.
  • Unless we’re getting fanatical about performance (that will happen, eventually), we can afford wrapping allocations using objects.

The bug I fixed today had been lying around for nearly three months. It was intermittent, didn’t cause crashes, and sometimes got so quiet that I thought I would eventually forget about it.

So I did a minor improvement to my vertex color interpolator and it came back, with the familiar spiky blobs.

Cleaning the mess.

I don’t use alpha just yet, but I have to use four components per color. So I could figure what rendered incorrectly by testing alpha. Abusively, this meant iterating meshes before rendering them (!)

Every mesh had about 15 to 25% garbage at the end of the matching memory block, so I could tell that either (a) I rendered more than I had allocated or (b) I had initialized less than I intended to use.

Just looking at the output wouldn’t tell me that my models were incomplete. Because the models in this case are… …procedural grass. How obvious can it be that we’re missing every other blade?

This falls into category 3. Getting increments wrong isn’t rare – so every time I wanted 7 blades of grass, I generated only 6.

Lesson learned?

Maybe… …maybe not. Here’s what I think:

  • Feels like a typical case where writing a test and fully validating the output would help.
  • Part of the danger when manipulating sensitive code is that it can also fail idiotically. malloc() makes me think about ways I can crash my game, leak memory, etc… but finally I just somehow missed out on filling up a memory block till it’s all done and done.
  • Next time I see the tell-tale signs of mis-managing memory, I really shouldn’t wait. Not initializing memory can also cause a program to crash. Plus I’ve been dragging along wondering whether I would get a repro on this. And yea. Sure, I finally did. It wasn’t even on my list anymore.

Status update

I’m getting a new app icon on monday. Will try to submit sometimes next week. Dev stack is clean today. I calibrated/cleaned up sound today. Cleaned up the artwork stack, then regenerated small chores. A lot of instrumentation on the roadmap for today (as in, Sunday).

Getting there. Sigh.

Here’s a few fun facts I collected about haXe:

  • HaXe doesn’t like classes that begin with a lowercase letter.
  • You can write three consecutive return statements in a haXe function. It compiles (same in Obj-C).
  • haXe doesn’t allow spaces after the dot operator:
    this. foo = “bar” // doesn’t compile
  • while java/C#/AS3 style annotations aren’t defined as core language features, haXe can support whatever annotation style you wish – check this link for limited supported for java style annotations.
  • haXe supports multiple inheritance (but not all haXe targets do).

You can debug haXe code

At least, if you are targetting AS3, FlashDevelop 3.2.1 supports debugging haXe code, viz., setting breakpoints, checking locals and globals, even profiling.

At this stage, my Script class includes about 35 statement forms. A lot of this is a little redundant. The aim was to cover many significant cases related to decision, action and interaction.

A test suite

Today I am writing a test suite for the Script class and the underlying APIs. This is necessary because testing production graphs is, as we’ve seen before, expensive.

I won’t get into unit testing using XCode/Cocoa. Instead, I’ll just write my own tests from scratch – this is because I need to invest a little time and effort into making scripts easier to test.

This will be a fairly large test suite (for me, because i’m not terribly fond of testing), however, all cases are very simple and I can take advantage of some design features for the behavior API.

  1. Given model/view separation, I need only setup the model, not the view.
  2. There is no need to setup timers to test behavior, we can just iterate the action graph as far as we need and check the data model to test the output.

Writing the tests

Macros came in really handy to keep the tests concise, but also to avoid having to create ad-hoc data structures. Each test is about 10 lines long and I have 34 tests. Here’s a sample:

// this defines a function and stores the test name
TEST(test_observe_actor,"test observe actor")

// setup a stage and actors, with B 100 units away from A
SETUP_A_B(100);

// the actual script to test
[s type:ACTOR_A];
   [s observe:ACTOR_B];
[s xType];

// bind the script to the stage and iterate the system once.
BIND; STEP(1);

// some code to check the output
Vector* u=[[Vector alloc]initWithX:1 y:0 z:0];
Vector* v=a.orientation;

// this checks the specified condition and prints the result
CHECK([Vector angle:u with:v]<0.01);

// just a macro defining a closing bracket, because a dangling
// bracket would be odd.
END_TEST

Granted this is not a very clean use of macros, and won’t scale up to a really large test suite – but we’re not into ‘test-first’ development here – just running a few tests.

I hacked a function firing up the tests into the main.m file associated with my XCode project. Another time I’ll look into a nicer way of doing all that stuff. (need to move the framework to a library project and create a separate project for the test suite).

Pending, sample output looks like this:

2009-11-16 22:14:55.837 Generic2DBoardGame[5191:207] X test observe actor

(X tells us that the test failed :( )

Debugging

Unsurprisingly (given the way I drafted my code), a lot of tests are failing. I even had to quarantine 6 tests that seem to get into infinite loops. Since I have many tests, this is a good time to add logging. The first logs I want to produce are snapshots of the system showing the state of each entity. I will only display logs for failed tests.

After debugging a couple of test cases, I find that primarily, diagnosis falls into three broad categories:

  • An event isn’t generated. Because events often occur given conditions related to an actor, I print the condition leading to such actor being rejected by TargetSelector
  • An action isn’t being applied. I don’t expect to see this too often.
  • An action isn’t effective.

These broad categories allow me to channel log output and enable/disable channels to conclude the diagnosis.

That’s about it. I’ve got 11 pass cases so I’m about 1/3 in and should be done tomorrow.